From 83d988828256eb66d72affa3032469ff9c8dc958 Mon Sep 17 00:00:00 2001 From: Callum Todd Date: Wed, 1 Jul 2020 14:33:03 +0100 Subject: [PATCH 1/2] Exposed sender information --- .../Internal API/MockMultipeerConnection.swift | 12 +++++++++--- .../Internal API/Models/MultipeerMessage.swift | 14 +++++++++----- .../Internal API/MultipeerConnection.swift | 8 ++++++-- .../Internal API/MultipeerProtocol.swift | 2 +- .../Public API/MultipeerTransceiver.swift | 9 ++++++--- Tests/MultipeerKitTests/MultipeerKitTests.swift | 5 +++-- .../MultipeerKitExample/SceneDelegate.swift | 8 ++++---- 7 files changed, 38 insertions(+), 20 deletions(-) diff --git a/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift b/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift index f6e257b..7e58550 100644 --- a/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift +++ b/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift @@ -1,8 +1,14 @@ import Foundation +import MultipeerConnectivity.MCPeerID final class MockMultipeerConnection: MultipeerProtocol { - var didReceiveData: ((Data, PeerName) -> Void)? + let localPeer: Peer = { + let underlyingPeer = MCPeerID(displayName: "MockPeer") + return try! Peer(peer: underlyingPeer, discoveryInfo: nil) + }() + + var didReceiveData: ((Data, Peer) -> Void)? var didFindPeer: ((Peer) -> Void)? var didLosePeer: ((Peer) -> Void)? var didConnectToPeer: ((Peer) -> Void)? @@ -19,7 +25,7 @@ final class MockMultipeerConnection: MultipeerProtocol { } func broadcast(_ data: Data) throws { - didReceiveData?(data, "MockPeer") + didReceiveData?(data, localPeer) } func send(_ data: Data, to peers: [Peer]) throws { @@ -31,7 +37,7 @@ final class MockMultipeerConnection: MultipeerProtocol { } func getLocalPeerId() -> String? { - return "MockId" + return localPeer.id } } diff --git a/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift b/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift index a535eb5..890802f 100644 --- a/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift +++ b/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift @@ -27,6 +27,8 @@ import Foundation struct MultipeerMessage: Codable { + static let senderUserInfoKey = CodingUserInfoKey(rawValue: "sender")! + let type: String let payload: Any? @@ -40,17 +42,17 @@ struct MultipeerMessage: Codable { case payload } - private typealias MessageDecoder = (KeyedDecodingContainer) throws -> Any + private typealias MessageDecoder = (KeyedDecodingContainer, Peer) throws -> Any private typealias MessageEncoder = (Any, inout KeyedEncodingContainer) throws -> Void private static var decoders: [String: MessageDecoder] = [:] private static var encoders: [String: MessageEncoder] = [:] - static func register(_ type: T.Type, for typeName: String, closure: @escaping (T) -> Void) { - decoders[typeName] = { container in + static func register(_ type: T.Type, for typeName: String, closure: @escaping (T, Peer) -> Void) { + decoders[typeName] = { container, peer in let payload = try container.decode(T.self, forKey: .payload) - DispatchQueue.main.async { closure(payload) } + DispatchQueue.main.async { closure(payload, peer) } return payload } @@ -67,9 +69,11 @@ struct MultipeerMessage: Codable { init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) type = try container.decode(String.self, forKey: .type) + + let sender = decoder.userInfo[MultipeerMessage.senderUserInfoKey]! as! Peer if let decode = Self.decoders[type] { - payload = try decode(container) + payload = try decode(container, sender) } else { payload = nil } diff --git a/Sources/MultipeerKit/Internal API/MultipeerConnection.swift b/Sources/MultipeerKit/Internal API/MultipeerConnection.swift index 0ed0bfe..e8420a0 100644 --- a/Sources/MultipeerKit/Internal API/MultipeerConnection.swift +++ b/Sources/MultipeerKit/Internal API/MultipeerConnection.swift @@ -27,7 +27,7 @@ final class MultipeerConnection: NSObject, MultipeerProtocol { self.me = MCPeerID.fetchOrCreate(with: configuration) } - var didReceiveData: ((Data, PeerName) -> Void)? + var didReceiveData: ((Data, Peer) -> Void)? var didFindPeer: ((Peer) -> Void)? var didLosePeer: ((Peer) -> Void)? var didConnectToPeer: ((Peer) -> Void)? @@ -145,7 +145,11 @@ extension MultipeerConnection: MCSessionDelegate { func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) { os_log("%{public}@", log: log, type: .debug, #function) - didReceiveData?(data, peerID.displayName) + if let peer = try? Peer(peer: peerID, discoveryInfo: nil) { + didReceiveData?(data, peer) + } else { + os_log("Received data, but cannot create peer for %s", log: log, type: .error, #function, peerID.displayName) + } } func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) { diff --git a/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift b/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift index cab54b9..97f63b5 100644 --- a/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift +++ b/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift @@ -4,7 +4,7 @@ typealias PeerName = String protocol MultipeerProtocol: AnyObject { - var didReceiveData: ((Data, PeerName) -> Void)? { get set } + var didReceiveData: ((Data, Peer) -> Void)? { get set } var didFindPeer: ((Peer) -> Void)? { get set } var didLosePeer: ((Peer) -> Void)? { get set } var didConnectToPeer: ((Peer) -> Void)? { get set } diff --git a/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift b/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift index 2b0828d..0ab3447 100644 --- a/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift +++ b/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift @@ -74,12 +74,13 @@ public final class MultipeerTransceiver { /// - type: The `Codable` type to receive. /// - closure: The closure that will be called whenever a payload of the specified type is received. /// - payload: The payload decoded from the remote message. + /// - sender: The remote peer who sent the message. /// /// MultipeerKit communicates data between peers as JSON-encoded payloads which originate with /// `Codable` entities. You register a closure to handle each specific type of entity, /// and this closure is automatically called by the framework when a remote peer sends /// a message containing an entity that decodes to the specified type. - public func receive(_ type: T.Type, using closure: @escaping (_ payload: T) -> Void) { + public func receive(_ type: T.Type, using closure: @escaping (_ payload: T, _ sender: Peer) -> Void) { MultipeerMessage.register(type, for: String(describing: type), closure: closure) } @@ -127,11 +128,13 @@ public final class MultipeerTransceiver { } } - private func handleDataReceived(_ data: Data, from peer: PeerName) { + private func handleDataReceived(_ data: Data, from peer: Peer) { os_log("%{public}@", log: log, type: .debug, #function) do { - let message = try JSONDecoder().decode(MultipeerMessage.self, from: data) + let decoder = JSONDecoder() + decoder.userInfo[MultipeerMessage.senderUserInfoKey] = peer + let message = try decoder.decode(MultipeerMessage.self, from: data) os_log("Received message %@", log: self.log, type: .debug, String(describing: message)) } catch { diff --git a/Tests/MultipeerKitTests/MultipeerKitTests.swift b/Tests/MultipeerKitTests/MultipeerKitTests.swift index 6e993a8..4cdbc8d 100644 --- a/Tests/MultipeerKitTests/MultipeerKitTests.swift +++ b/Tests/MultipeerKitTests/MultipeerKitTests.swift @@ -36,8 +36,9 @@ final class MultipeerKitTests: XCTestCase { let expect = XCTestExpectation(description: "Receive payload") - mock.receive(TestPayload.self) { p in - XCTAssertEqual(p, tsPayload) + mock.receive(TestPayload.self) { payload, sender in + XCTAssertEqual(payload, tsPayload) + XCTAssertEqual(sender.id, mock.localPeerId!) expect.fulfill() } diff --git a/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift b/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift index 9f0143c..9de1890 100644 --- a/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift +++ b/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift @@ -24,10 +24,10 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { let t = MultipeerTransceiver(configuration: config) - t.receive(ExamplePayload.self) { [weak self] payload in + t.receive(ExamplePayload.self) { [weak self] payload, peer in print("Got payload: \(payload)") - self?.notify(with: payload) + self?.notify(with: payload, peer: peer) } return t @@ -37,9 +37,9 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { MultipeerDataSource(transceiver: transceiver) }() - private func notify(with payload: ExamplePayload) { + private func notify(with payload: ExamplePayload, peer: Peer) { let content = UNMutableNotificationContent() - content.body = payload.message + content.body = "\"\(payload.message)\" from \(peer.name)" let request = UNNotificationRequest(identifier: payload.message, content: content, trigger: nil) UNUserNotificationCenter.current().add(request) { _ in From 9ad42b497545e311c2df66df863fb6d5435d4ea8 Mon Sep 17 00:00:00 2001 From: Callum Todd Date: Wed, 1 Jul 2020 14:46:57 +0100 Subject: [PATCH 2/2] Updated documentation --- .../MultipeerConfiguration/index.html | 1231 +-------------- .../index.html | 1194 +-------------- .../index.html | 1220 +-------------- Documentation/MultipeerDataSource/index.html | 1193 +-------------- Documentation/MultipeerTransceiver/index.html | 1325 ++--------------- Documentation/Peer/index.html | 1213 +-------------- Documentation/all.css | 1 + Documentation/index.html | 1187 +-------------- README.md | 6 +- 9 files changed, 262 insertions(+), 8308 deletions(-) create mode 100755 Documentation/all.css diff --git a/Documentation/MultipeerConfiguration/index.html b/Documentation/MultipeerConfiguration/index.html index b27382d..863f29d 100755 --- a/Documentation/MultipeerConfiguration/index.html +++ b/Documentation/MultipeerConfiguration/index.html @@ -4,1178 +4,7 @@ MultipeerKit - MultipeerConfiguration - +
@@ -1197,7 +26,7 @@ @@ -1213,11 +42,25 @@

Configures several aspects of the multipeer communication.

- +
+ + +

Nested Types

+
+
MultipeerConfiguration.Invitation
+

Defines how the multipeer connection handles newly discovered peers. +New peers can be invited automatically, invited with a custom context and timeout, +or not invited at all, in which case you must invite them manually.

+
+
MultipeerConfiguration.Security
+

Configures security-related aspects of the multipeer connection.

+
+
+

Initializers

-
+

init(service​Type:​peer​Name:​defaults:​security:​invitation:​)

@@ -1240,31 +83,41 @@

Parameters

service​Type String -

This must be the same accross your app running on multiple devices, it must be a short string. Check Apple's docs on MCNearbyServiceAdvertiser for more info on the limitations for this field.

+
    +
  • serviceType: This must be the same accross your app running on multiple devices, it must be a short string. Check Apple's docs on MCNearbyServiceAdvertiser for more info on the limitations for this field.
  • +
peer​Name String -

A display name for this peer that will be shown to nearby peers.

+
    +
  • peerName: A display name for this peer that will be shown to nearby peers.
  • +
defaults User​Defaults -

An instance of UserDefaults that's used to store this peer's identity so that it remains stable between different sessions. If you use MultipeerKit in app extension make sure to use a shared app group if you wish to maintain a stable identity.

+
    +
  • defaults: An instance of UserDefaults that's used to store this peer's identity so that it remains stable between different sessions. If you use MultipeerKit in app extension make sure to use a shared app group if you wish to maintain a stable identity.
  • +
security Security -

The security configuration.

+
    +
  • security: The security configuration.
  • +
invitation Invitation -

Defines how the multipeer connection handles newly discovered peers. New peers can be invited automatically, invited with a custom context or not invited at all, in which case you must invite them manually.

+
    +
  • invitation: Defines how the multipeer connection handles newly discovered peers. New peers can be invited automatically, invited with a custom context or not invited at all, in which case you must invite them manually.
  • +
@@ -1274,7 +127,7 @@

Parameters

Properties

-
+

service​Type

@@ -1285,11 +138,11 @@

-

Check Apple's docs on MCNearbyServiceAdvertiser for more info on the limitations for this field.

- +

Check Apple's docs on MCNearbyServiceAdvertiser for more info on the limitations for this field.

+
-
+

peer​Name

@@ -1299,7 +152,7 @@

-
+

defaults

@@ -1311,7 +164,7 @@

-
+

security

@@ -1321,7 +174,7 @@

-
+

invitation

@@ -1331,7 +184,7 @@

-
+

`default`

@@ -1351,7 +204,7 @@

- Generated on using swift-doc. + Generated on using swift-doc 1.0.0-beta.3.

diff --git a/Documentation/MultipeerConfiguration_Invitation/index.html b/Documentation/MultipeerConfiguration_Invitation/index.html index c333c92..27655a5 100755 --- a/Documentation/MultipeerConfiguration_Invitation/index.html +++ b/Documentation/MultipeerConfiguration_Invitation/index.html @@ -4,1178 +4,7 @@ MultipeerKit - MultipeerConfiguration.Invitation - +
@@ -1197,7 +26,7 @@ @@ -1215,11 +44,20 @@

or not invited at all, in which case you must invite them manually.

- +
+ + +

Member Of

+
+
MultipeerConfiguration
+

Configures several aspects of the multipeer communication.

+
+
+

Enumeration Cases

-
+

automatic

@@ -1229,7 +67,7 @@

-
+

custom

@@ -1240,7 +78,7 @@

-
+

none

@@ -1259,7 +97,7 @@

- Generated on using swift-doc. + Generated on using swift-doc 1.0.0-beta.3.

diff --git a/Documentation/MultipeerConfiguration_Security/index.html b/Documentation/MultipeerConfiguration_Security/index.html index eb3445a..23b4af5 100755 --- a/Documentation/MultipeerConfiguration_Security/index.html +++ b/Documentation/MultipeerConfiguration_Security/index.html @@ -4,1178 +4,7 @@ MultipeerKit - MultipeerConfiguration.Security - +
@@ -1197,7 +26,7 @@ @@ -1213,11 +42,20 @@

Configures security-related aspects of the multipeer connection.

- +
+ + +

Member Of

+
+
MultipeerConfiguration
+

Configures several aspects of the multipeer communication.

+
+
+

Nested Type Aliases

-
+

Invitation​Handler

@@ -1227,7 +65,7 @@

Initializers

-
+

init(identity:​encryption​Preference:​invitation​Handler:​)

@@ -1237,7 +75,7 @@

Properties

-
+

identity

@@ -1247,17 +85,17 @@

-

The first object in this array should be a SecIdentity object that provides the local peer’s identity.

- -

The remainder of the array should contain zero or more additional SecCertificate objects that provide any +

The first object in this array should be a SecIdentity object that provides the local peer’s identity.

+ +

The remainder of the array should contain zero or more additional SecCertificate objects that provide any intermediate certificates that nearby peers might require when verifying the local peer’s identity. These certificates should be sent in certificate chain order.

- -

Check Apple's MCSession docs for more information.

- + +

Check Apple's MCSession docs for more information.

+
-
+

encryption​Preference

@@ -1267,7 +105,7 @@

-
+

invitation​Handler

@@ -1277,15 +115,15 @@

-

It receives the Peer that sent the invitation, a custom Data value +

It receives the Peer that sent the invitation, a custom Data value that's a context that can be used to customize the invitation, and a closure to be called with true to accept the invitation or false to reject it.

- -

The default implementation accepts all invitations.

- + +

The default implementation accepts all invitations.

+
-
+

`default`

@@ -1304,7 +142,7 @@

- Generated on using swift-doc. + Generated on using swift-doc 1.0.0-beta.3.

diff --git a/Documentation/MultipeerDataSource/index.html b/Documentation/MultipeerDataSource/index.html index 36c6795..7048ab7 100755 --- a/Documentation/MultipeerDataSource/index.html +++ b/Documentation/MultipeerDataSource/index.html @@ -4,1178 +4,7 @@ MultipeerKit - MultipeerDataSource - +
@@ -1211,8 +40,8 @@

@available(tvOS 13.0, *) @available(OSX 10.15, *) @available(iOS 13.0, *) public final class MultipeerDataSource: ObservableObject
-
- +
+ - + Peer->Identifiable @@ -1254,7 +83,7 @@ Hashable - + Peer->Hashable @@ -1263,18 +92,34 @@ - -
+ +

Conforms To

Hashable
Identifiable
+
+

Initializers

+ +
+

+ init(peer:​discovery​Info:​) +

+
init(peer: MCPeerID, discoveryInfo: [String: String]?) throws
+
+

Properties

-
+
+

+ underlying​Peer +

+
let underlyingPeer: MCPeerID
+
+

id

@@ -1284,7 +129,7 @@

-
+

name

@@ -1294,7 +139,7 @@

-
+

discovery​Info

@@ -1304,7 +149,7 @@

-
+

is​Connected

@@ -1323,7 +168,7 @@

- Generated on using swift-doc. + Generated on using swift-doc 1.0.0-beta.3.

diff --git a/Documentation/all.css b/Documentation/all.css new file mode 100755 index 0000000..4e9b4a7 --- /dev/null +++ b/Documentation/all.css @@ -0,0 +1 @@ +:root{--system-red:#ff3b30;--system-orange:#ff9500;--system-yellow:#fc0;--system-green:#34c759;--system-teal:#5ac8fa;--system-blue:#007aff;--system-indigo:#5856d6;--system-purple:#af52de;--system-pink:#ff2d55;--system-gray:#8e8e93;--system-gray2:#aeaeb2;--system-gray3:#c7c7cc;--system-gray4:#d1d1d6;--system-gray5:#e5e5ea;--system-gray6:#f2f2f7;--label:#000;--secondary-label:#3c3c43;--tertiary-label:#48484a;--quaternary-label:#636366;--placeholder-text:#8e8e93;--link:#007aff;--separator:#e5e5ea;--opaque-separator:#c6c6c8;--system-fill:#787880;--secondary-system-fill:#787880;--tertiary-system-fill:#767680;--quaternary-system-fill:#747480;--system-background:#fff;--secondary-system-background:#f2f2f7;--tertiary-system-background:#fff;--system-grouped-background:#f2f2f7;--secondary-system-grouped-background:#fff;--tertiary-system-grouped-background:#f2f2f7}@supports (color:color(display-p3 1 1 1)){:root{--system-red:color(display-p3 1 0.2314 0.1882);--system-orange:color(display-p3 1 0.5843 0);--system-yellow:color(display-p3 1 0.8 0);--system-green:color(display-p3 0.2039 0.7804 0.349);--system-teal:color(display-p3 0.3529 0.7843 0.9804);--system-blue:color(display-p3 0 0.4784 1);--system-indigo:color(display-p3 0.3451 0.3373 0.8392);--system-purple:color(display-p3 0.6863 0.3216 0.8706);--system-pink:color(display-p3 1 0.1765 0.3333);--system-gray:color(display-p3 0.5569 0.5569 0.5765);--system-gray2:color(display-p3 0.6824 0.6824 0.698);--system-gray3:color(display-p3 0.7804 0.7804 0.8);--system-gray4:color(display-p3 0.8196 0.8196 0.8392);--system-gray5:color(display-p3 0.898 0.898 0.9176);--system-gray6:color(display-p3 0.949 0.949 0.9686);--label:color(display-p3 0 0 0);--secondary-label:color(display-p3 0.2353 0.2353 0.2627);--tertiary-label:color(display-p3 0.2823 0.2823 0.2901);--quaternary-label:color(display-p3 0.4627 0.4627 0.5019);--placeholder-text:color(display-p3 0.5568 0.5568 0.5764);--link:color(display-p3 0 0.4784 1);--separator:color(display-p3 0.898 0.898 0.9176);--opaque-separator:color(display-p3 0.7765 0.7765 0.7843);--system-fill:color(display-p3 0.4706 0.4706 0.502);--secondary-system-fill:color(display-p3 0.4706 0.4706 0.502);--tertiary-system-fill:color(display-p3 0.4627 0.4627 0.502);--quaternary-system-fill:color(display-p3 0.4549 0.4549 0.502);--system-background:color(display-p3 1 1 1);--secondary-system-background:color(display-p3 0.949 0.949 0.9686);--tertiary-system-background:color(display-p3 1 1 1);--system-grouped-background:color(display-p3 0.949 0.949 0.9686);--secondary-system-grouped-background:color(display-p3 1 1 1);--tertiary-system-grouped-background:color(display-p3 0.949 0.949 0.9686)}}:root{--large-title:600 32pt/39pt sans-serif;--title-1:600 26pt/32pt sans-serif;--title-2:600 20pt/25pt sans-serif;--title-3:500 18pt/23pt sans-serif;--headline:500 15pt/20pt sans-serif;--body:300 15pt/20pt sans-serif;--callout:300 14pt/19pt sans-serif;--subhead:300 13pt/18pt sans-serif;--footnote:300 12pt/16pt sans-serif;--caption-1:300 11pt/13pt sans-serif;--caption-2:300 11pt/13pt sans-serif;--icon-case:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%2389c5e6' height='90' rx='8' stroke='%236bb7e1' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M20.21 50c0-20.7 11.9-32.79 30.8-32.79 16 0 28.21 10.33 28.7 25.32H64.19C63.4 35 58.09 30.11 51 30.11c-8.79 0-14.37 7.52-14.37 19.82s5.54 20 14.41 20c7.08 0 12.22-4.66 13.23-12.09h15.52c-.74 15.07-12.43 25-28.78 25C32 82.81 20.21 70.72 20.21 50z' fill='%23fff'/%3E%3C/svg%3E");--icon-class:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%239b98e6' height='90' rx='8' stroke='%235856d6' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='m20.21 50c0-20.7 11.9-32.79 30.8-32.79 16 0 28.21 10.33 28.7 25.32h-15.52c-.79-7.53-6.1-12.42-13.19-12.42-8.79 0-14.37 7.52-14.37 19.82s5.54 20 14.41 20c7.08 0 12.22-4.66 13.23-12.09h15.52c-.74 15.07-12.43 25-28.78 25-19.01-.03-30.8-12.12-30.8-32.84z' fill='%23fff'/%3E%3C/svg%3E");--icon-enumeration:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23eca95b' height='90' rx='8' stroke='%23e89234' stroke-miterlimit='10' stroke-width='4' width='90' x='5.17' y='5'/%3E%3Cpath d='M71.9 81.71H28.43V18.29H71.9v13H44.56v12.62h25.71v11.87H44.56V68.7H71.9z' fill='%23fff'/%3E%3C/svg%3E");--icon-extension:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23eca95b' height='90' rx='8' stroke='%23e89234' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cg fill='%23fff'%3E%3Cpath d='M54.43 81.93H20.51V18.07h33.92v12.26H32.61v13.8h20.45v11.32H32.61v14.22h21.82zM68.74 74.58h-.27l-2.78 7.35h-7.28L64 69.32l-6-12.54h8l2.74 7.3h.27l2.76-7.3h7.64l-6.14 12.54 5.89 12.61h-7.64z'/%3E%3C/g%3E%3C/svg%3E");--icon-function:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M24.25 75.66A5.47 5.47 0 0130 69.93c1.55 0 3.55.41 6.46.41 3.19 0 4.78-1.55 5.46-6.65l1.5-10.14h-9.34a6 6 0 110-12h11.1l1.09-7.27C47.82 23.39 54.28 17.7 64 17.7c6.69 0 11.74 1.77 11.74 6.64A5.47 5.47 0 0170 30.07c-1.55 0-3.55-.41-6.46-.41-3.14 0-4.73 1.51-5.46 6.65l-.78 5.27h11.44a6 6 0 11.05 12H55.6l-1.78 12.11C52.23 76.61 45.72 82.3 36 82.3c-6.7 0-11.75-1.77-11.75-6.64z' fill='%23fff'/%3E%3C/svg%3E");--icon-method:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%235a98f8' height='90' rx='8' stroke='%232974ed' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M70.61 81.71v-39.6h-.31l-15.69 39.6h-9.22l-15.65-39.6h-.35v39.6H15.2V18.29h18.63l16 41.44h.36l16-41.44H84.8v63.42z' fill='%23fff'/%3E%3C/svg%3E");--icon-property:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%2389c5e6' height='90' rx='8' stroke='%236bb7e1' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M52.31 18.29c13.62 0 22.85 8.84 22.85 22.46s-9.71 22.37-23.82 22.37H41v18.59H24.84V18.29zM41 51h7c6.85 0 10.89-3.56 10.89-10.2S54.81 30.64 48 30.64h-7z' fill='%23fff'/%3E%3C/svg%3E");--icon-protocol:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23ff6682' height='90' rx='8' stroke='%23ff2d55' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cg fill='%23fff'%3E%3Cpath d='M46.28 18.29c11.84 0 20 8.66 20 21.71s-8.44 21.71-20.6 21.71H34.87v20H22.78V18.29zM34.87 51.34H43c6.93 0 11-4 11-11.29S50 28.8 43.07 28.8h-8.2zM62 57.45h8v4.77h.16c.84-3.45 2.54-5.12 5.17-5.12a5.06 5.06 0 011.92.35V65a5.69 5.69 0 00-2.39-.51c-3.08 0-4.66 1.74-4.66 5.12v12.1H62z'/%3E%3C/g%3E%3C/svg%3E");--icon-structure:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23b57edf' height='90' rx='8' stroke='%239454c2' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M38.38 63c.74 4.53 5.62 7.16 11.82 7.16s10.37-2.81 10.37-6.68c0-3.51-2.73-5.31-10.24-6.76l-6.5-1.23C31.17 53.14 24.62 47 24.62 37.28c0-12.22 10.59-20.09 25.18-20.09 16 0 25.36 7.83 25.53 19.91h-15c-.26-4.57-4.57-7.29-10.42-7.29s-9.31 2.63-9.31 6.37c0 3.34 2.9 5.18 9.8 6.5l6.5 1.23C70.46 46.51 76.61 52 76.61 62c0 12.74-10 20.83-26.72 20.83-15.82 0-26.28-7.3-26.5-19.78z' fill='%23fff'/%3E%3C/svg%3E");--icon-typealias:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M42 81.71V31.3H24.47v-13h51.06v13H58v50.41z' fill='%23fff'/%3E%3C/svg%3E");--icon-variable:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M39.85 81.71L19.63 18.29H38l12.18 47.64h.35L62.7 18.29h17.67L60.15 81.71z' fill='%23fff'/%3E%3C/svg%3E")}body,button,input,select,textarea{-moz-font-feature-settings:"kern";-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;direction:ltr;font-synthesis:none;text-align:left}h1:first-of-type,h2:first-of-type,h3:first-of-type,h4:first-of-type,h5:first-of-type,h6:first-of-type{margin-top:0}h1 code,h2 code,h3 code,h4 code,h5 code,h6 code{font-family:inherit;font-weight:inherit}h1 img,h2 img,h3 img,h4 img,h5 img,h6 img{margin:0 .5em .2em 0;vertical-align:middle;display:inline-block}h1+*,h2+*,h3+*,h4+*,h5+*,h6+*{margin-top:.8em}img+h1{margin-top:.5em}img+h1,img+h2,img+h3,img+h4,img+h5,img+h6{margin-top:.3em}:is(h1,h2,h3,h4,h5,h6)+:is(h1,h2,h3,h4,h5,h6){margin-top:.4em}:matches(h1,h2,h3,h4,h5,h6)+:matches(h1,h2,h3,h4,h5,h6){margin-top:.4em}:is(p,ul,ol)+:is(h1,h2,h3,h4,h5,h6){margin-top:1.6em}:matches(p,ul,ol)+:matches(h1,h2,h3,h4,h5,h6){margin-top:1.6em}:is(p,ul,ol)+*{margin-top:.8em}:matches(p,ul,ol)+*{margin-top:.8em}ol,ul{margin-left:1.17647em}:matches(ul,ol) :matches(ul,ol){margin-bottom:0;margin-top:0}nav h2{color:#3c3c43;color:var(--secondary-label);font-size:1rem;font-feature-settings:"c2sc";font-variant:small-caps;font-weight:600;text-transform:uppercase}nav ol,nav ul{margin:0;list-style:none}nav li li{font-size:smaller}a:link,a:visited{text-decoration:none}a:hover{text-decoration:underline}a:active{text-decoration:none}a+a{display:inline-block}b,strong{font-weight:600}.discussion,.summary{font:300 14pt/19pt sans-serif;font:var(--callout)}article>.discussion{margin-bottom:2em}.discussion .highlight{background:transparent;border:1px solid #e5e5ea;border:1px solid var(--separator);font:300 11pt/13pt sans-serif;font:var(--caption-1);padding:1em;text-indent:0}cite,dfn,em,i{font-style:italic}:matches(h1,h2,h3) sup{font-size:.4em}sup a{color:inherit;vertical-align:inherit}sup a:hover{color:#007aff;color:var(--link);text-decoration:none}sub{line-height:1}abbr{border:0}:lang(ja),:lang(ko),:lang(th),:lang(zh){font-style:normal}:lang(ko){word-break:keep-all}form fieldset{margin:1em auto;max-width:450px;width:95%}form label{display:block;font-size:1em;font-weight:400;line-height:1.5em;margin-bottom:14px;position:relative;width:100%}input[type=email],input[type=number],input[type=password],input[type=tel],input[type=text],input[type=url],textarea{border-radius:4px;border:1px solid #e5e5ea;border:1px solid var(--separator);color:#333;font-family:inherit;font-size:100%;font-weight:400;height:34px;margin:0;padding:0 1em;position:relative;vertical-align:top;width:100%;z-index:1}input[type=email],input [type=email]:focus,input[type=number],input [type=number]:focus,input[type=password],input [type=password]:focus,input[type=tel],input [type=tel]:focus,input[type=text],input [type=text]:focus,input[type=url],input [type=url]:focus,textarea,textarea:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}input[type=email]:focus,input[type=number]:focus,input[type=password]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=url]:focus,textarea:focus{border-color:#08c;box-shadow:0 0 0 3px rgba(0,136,204,.3);outline:0;z-index:9}input[type=email]:-moz-read-only,input[type=number]:-moz-read-only,input[type=password]:-moz-read-only,input[type=tel]:-moz-read-only,input[type=text]:-moz-read-only,input[type=url]:-moz-read-only,textarea:-moz-read-only{background:none;border:none;box-shadow:none;padding-left:0}input[type=email]:read-only,input[type=number]:read-only,input[type=password]:read-only,input[type=tel]:read-only,input[type=text]:read-only,input[type=url]:read-only,textarea:read-only{background:none;border:none;box-shadow:none;padding-left:0}::-webkit-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::-moz-placeholder{color:#8e8e93;color:var(--placeholder-text)}:-ms-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::-ms-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::placeholder{color:#8e8e93;color:var(--placeholder-text)}textarea{-webkit-overflow-scrolling:touch;line-height:1.4737;min-height:134px;overflow-y:auto;resize:vertical;transform:translateZ(0)}textarea,textarea:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}select{background:transparent;border-radius:4px;border:none;cursor:pointer;font-family:inherit;font-size:1em;height:34px;margin:0;padding:0 1em;width:100%}select,select:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}select:focus{border-color:#08c;box-shadow:0 0 0 3px rgba(0,136,204,.3);outline:0;z-index:9}input[type=file]{background:#fafafa;border-radius:4px;color:#333;cursor:pointer;font-family:inherit;font-size:100%;height:34px;margin:0;padding:6px 1em;position:relative;vertical-align:top;width:100%;z-index:1}input[type=file]:focus{border-color:#08c;outline:0;box-shadow:0 0 0 3px rgba(0,136,204,.3);z-index:9}button,button:focus,input[type=file]:focus,input[type=file]:focus:focus,input[type=reset],input[type=reset]:focus,input[type=submit],input[type=submit]:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}:matches(button,input[type=reset],input[type=submit]){background-color:#e3e3e3;background:linear-gradient(#fff,#e3e3e3);border-color:#d6d6d6;color:#0070c9}:matches(button,input[type=reset],input[type=submit]):hover{background-color:#eee;background:linear-gradient(#fff,#eee);border-color:#d9d9d9}:matches(button,input[type=reset],input[type=submit]):active{background-color:#dcdcdc;background:linear-gradient(#f7f7f7,#dcdcdc);border-color:#d0d0d0}:matches(button,input[type=reset],input[type=submit]):disabled{background-color:#e3e3e3;background:linear-gradient(#fff,#e3e3e3);border-color:#d6d6d6;color:#0070c9}body{background:#f2f2f7;background:var(--system-grouped-background);color:#000;color:var(--label);font-family:ui-system,-apple-system,BlinkMacSystemFont,sans-serif;font:300 15pt/20pt sans-serif;font:var(--body)}h1{font:600 32pt/39pt sans-serif;font:var(--large-title)}h2{font:600 20pt/25pt sans-serif;font:var(--title-2)}h3{font:500 18pt/23pt sans-serif;font:var(--title-3)}h4,h5,h6{font:500 15pt/20pt sans-serif;font:var(--headline)}a{color:#007aff;color:var(--link)}label{font:300 14pt/19pt sans-serif;font:var(--callout)}input,label{display:block}input{margin-bottom:1em}hr{border:none;border-top:1px solid #e5e5ea;border-top:1px solid var(--separator);margin:1em 0}table{width:100%;font:300 11pt/13pt sans-serif;font:var(--caption-1);caption-side:bottom;margin-bottom:2em}td,th{padding:0 1em}th{font-weight:600;text-align:left}thead th{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator)}tr:last-of-type td,tr:last-of-type th{border-bottom:none}td,th{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);color:#3c3c43;color:var(--secondary-label)}caption{color:#48484a;color:var(--tertiary-label);font:300 11pt/13pt sans-serif;font:var(--caption-2);margin-top:2em;text-align:left}.graph text,code{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-weight:300}.graph>polygon{display:none}.graph text{fill:currentColor!important}.graph ellipse,.graph path,.graph polygon,.graph rect{stroke:currentColor!important}body{width:90vw;max-width:1280px;margin:1em auto}body>header{font:600 26pt/32pt sans-serif;font:var(--title-1);padding:.5em 0}body>header a{color:#000;color:var(--label)}body>header span{font-weight:400}body>header sup{text-transform:uppercase;font-size:small;font-weight:300;letter-spacing:.1ch}body>footer,body>header sup{color:#3c3c43;color:var(--secondary-label)}body>footer{clear:both;padding:1em 0;font:300 11pt/13pt sans-serif;font:var(--caption-1)}@media screen and (max-width:768px){body{width:96vw;max-width:100%}body>header{font:500 18pt/23pt sans-serif;font:var(--title-3);text-align:left;padding:1em 0}body>nav{display:none}body>main{padding:0 1em}}@media screen and (max-width:768px){#relationships figure{display:none}section>[role=article][class] pre{margin-left:-2.5em}section>[role=article][class] div{margin-left:-2em}}main,nav{overflow-x:scroll}main{background:#fff;background:var(--system-background);border-radius:8px;padding:0 2em}main section{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);margin-bottom:2em;padding-bottom:1em}main section:last-of-type{border-bottom:none;margin-bottom:0}nav{float:right;margin-left:1em;max-height:100vh;overflow:scroll;padding:0 1em 3em;position:-webkit-sticky;position:sticky;top:1em;width:20vw}nav a{color:#3c3c43;color:var(--secondary-label)}nav ul a{color:#48484a;color:var(--tertiary-label)}nav ol,nav ul{padding:0}nav ul{font:300 14pt/19pt sans-serif;font:var(--callout);margin-bottom:1em}nav ol>li>a{display:block;font-size:smaller;font:500 15pt/20pt sans-serif;font:var(--headline);margin:.5em 0}nav li{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}blockquote{--link:var(--secondary-label);border-left:4px solid #e5e5ea;border-left:4px solid var(--separator);color:#3c3c43;color:var(--secondary-label);font-size:smaller;margin-left:0;padding-left:2em}blockquote a{text-decoration:underline}article{padding:2em 0 1em}article>.summary{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);margin-bottom:2em;padding-bottom:1em}article>.summary:last-child{border-bottom:none}.parameters th{text-align:right}.parameters td{color:#3c3c43;color:var(--secondary-label)}.parameters th+td{text-align:center}dl{padding-top:1em}dt{font:500 15pt/20pt sans-serif;font:var(--headline)}dd{margin-left:2em;margin-bottom:1em}dd p{margin-top:0}.highlight{background:#f2f2f7;background:var(--secondary-system-background);border-radius:8px;font-size:smaller;margin-bottom:2em;overflow-x:scroll;padding:1em 1em 1em 3em;text-indent:-2em;white-space:pre-line}.highlight .p{white-space:nowrap}.highlight .placeholder{color:#000;color:var(--label)}.highlight a{text-decoration:underline;color:#8e8e93;color:var(--placeholder-text)}.highlight .attribute,.highlight .keyword,.highlight .literal{color:#af52de;color:var(--system-purple)}.highlight .number{color:#007aff;color:var(--system-blue)}.highlight .declaration{color:#5ac8fa;color:var(--system-teal)}.highlight .type{color:#5856d6;color:var(--system-indigo)}.highlight .directive{color:#ff9500;color:var(--system-orange)}.highlight .comment{color:#8e8e93;color:var(--system-gray)}main summary:hover{text-decoration:underline}figure{margin:2em 0;padding:1em 0}figure svg{max-width:100%;height:auto!important;margin:0 auto;display:block}h1 small{font-size:.5em;line-height:1.5;display:block;font-weight:400;color:#636366;color:var(--quaternary-label)}dd code,li code,p code{font-size:smaller;color:#3c3c43;color:var(--secondary-label)}a code{text-decoration:underline}dl dt[class],nav li[class],section>[role=article][class]{background-image:var(--background-image);background-size:1em;background-repeat:no-repeat;background-position:left .25em;padding-left:3em}dl dt[class]{background-position-y:.125em}section>[role=article]{margin-bottom:1em;padding-bottom:1em;border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);padding-left:2em!important}section>[role=article]:last-of-type{margin-bottom:0;padding-bottom:0;border-bottom:none}dl dt[class],nav li[class]{list-style:none;text-indent:-1em;margin-bottom:.5em}nav li[class]{padding-left:2.5em}.case,.enumeration_case{--background-image:var(--icon-case);--link:var(--system-teal)}.class{--background-image:var(--icon-class);--link:var(--system-indigo)}.enumeration{--background-image:var(--icon-enumeration)}.enumeration,.extension{--link:var(--system-orange)}.extension{--background-image:var(--icon-extension)}.function{--background-image:var(--icon-function);--link:var(--system-green)}.initializer,.method{--background-image:var(--icon-method);--link:var(--system-blue)}.property{--background-image:var(--icon-property);--link:var(--system-teal)}.protocol{--background-image:var(--icon-protocol);--link:var(--system-pink)}.structure{--background-image:var(--icon-structure);--link:var(--system-purple)}.typealias{--background-image:var(--icon-typealias)}.typealias,.variable{--link:var(--system-green)}.variable{--background-image:var(--icon-variable)}.unknown{--link:var(--quaternary-label);color:#007aff;color:var(--link)} \ No newline at end of file diff --git a/Documentation/index.html b/Documentation/index.html index ece4a00..9b2d3ac 100755 --- a/Documentation/index.html +++ b/Documentation/index.html @@ -4,1178 +4,7 @@ MultipeerKit - MultipeerKit - +
@@ -1207,7 +36,7 @@

On This Page

Classes

- + Multipeer​Data​Source
@@ -1215,7 +44,7 @@

Classes

- + Multipeer​Transceiver
@@ -1229,7 +58,7 @@

Classes

Structures

- + Peer
@@ -1238,7 +67,7 @@

Structures

- + Multipeer​Configuration
@@ -1247,7 +76,7 @@

Structures

- + Multipeer​Configuration.​Security
@@ -1261,7 +90,7 @@

Structures

Enumerations

- + Multipeer​Configuration.​Invitation
@@ -1278,7 +107,7 @@

Enumerations

diff --git a/README.md b/README.md index 55a2b53..1ea415f 100644 --- a/README.md +++ b/README.md @@ -22,8 +22,8 @@ let transceiver = MultipeerTransceiver() transceiver.resume() // Configure message receivers -transceiver.receive(SomeCodableThing.self) { payload in - print("Got my thing! \(payload)") +transceiver.receive(SomeCodableThing.self) { payload, sender in +print("Got my thing from \(sender.name)! \(payload)") } // Broadcast message to peers @@ -45,4 +45,4 @@ let package = Package( ], ... ) -``` \ No newline at end of file +```