{"id":1605,"url":"https://github.com/nathankot/NKMultipeer","last_synced_at":"2025-08-02T04:31:56.011Z","repository":{"id":35822901,"uuid":"40105693","full_name":"nathankot/NKMultipeer","owner":"nathankot","description":"MOVED, please see: https://github.com/RxSwiftCommunity/RxMultipeer","archived":false,"fork":false,"pushed_at":"2016-04-24T04:25:06.000Z","size":183,"stargazers_count":15,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-12-01T03:36:07.863Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nathankot.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-08-03T04:55:16.000Z","updated_at":"2022-11-19T20:24:04.000Z","dependencies_parsed_at":"2022-09-08T17:42:14.921Z","dependency_job_id":null,"html_url":"https://github.com/nathankot/NKMultipeer","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nathankot%2FNKMultipeer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nathankot%2FNKMultipeer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nathankot%2FNKMultipeer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nathankot%2FNKMultipeer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nathankot","download_url":"https://codeload.github.com/nathankot/NKMultipeer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228439016,"owners_count":17920017,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-01-05T20:15:51.194Z","updated_at":"2024-12-06T08:31:17.854Z","avatar_url":"https://github.com/nathankot.png","language":"Swift","funding_links":[],"categories":["Networking","Libs"],"sub_categories":["Video","Other free courses","Network"],"readme":"**This project has been moved to [RxSwiftCommunity/RxMultipeer][rxmultipeer].**\nPlease update your projects to use the new repository, as this one will no\nlonger be maintained.\n\n# A testable, Rx* wrapper around MultipeerConnectivity\n\nUsing the adapter pattern, we can test multipeer code with heavy mocking. In effect, we are trying to isolate all the\nuntestable bits of `MultipeerConnectivity` into one library.\n\nThis library also gives you the flexibility to swap out the underlying mechanics of p2p with some other protocol such as\nwebsockets. At the moment it only comes with support for Apple's MultipeerConnectivity, however you can easily write\nyour own adapters for different protocols.\n\nPlease note that NKMultipeer makes heavy use of [RxSwift][RxSwift] which you should read up on if unfamiliar with Rx\\*\nlibraries. The mantra for this library: **everything is a stream**.\n\n## Installation\n\n#### Carthage\n\nAdd this to your `Cartfile`\n\n```\ngithub \"nathankot/NKMultipeer\" ~\u003e 1.0.0\n```\n\n#### CocoaPods\n\n```\nuse_frameworks!\npod \"NKMultipeer\"\n```\n\n## Example code\n\n_For a working example check out the `NKMultipeer Example` folder._\n\n#### Advertise and accept nearby peers\n\n```swift\nimport RxSwift\nimport RxCocoa\nimport NKMultipeer\n\nlet acceptButton: UIButton\nlet client: CurrentClient\u003cMCPeerID\u003e\n\nclient.startAdvertising()\nlet connectionRequests = client.incomingConnections().shareReplay(1)\n\nacceptButton.rx_tap\n  .withLatestFrom(connectionRequests)\n  .subscribeNext { (peer, context, respond) in respond(true) }\n  .addDisposableTo(disposeBag)\n```\n\n#### Browse for and connect to peers\n\n```swift\nimport RxSwift\nimport NKMultipeer\n\nlet client: CurrentClient\u003cMCPeerID\u003e\n\nclient.startBrowsing()\n\nlet nearbyPeers = client.nearbyPeers().shareReplay(1)\n\n// Attempt to connect to all peers\nnearbyPeers\n  .map { (peers: [Client\u003cMCPeerID\u003e]) in\n    peers.map { client.connect($0, context: [\"Hello\": \"there\"], timeout: 12) }.zip()\n  }\n  .subscribe()\n  .addDisposableTo(disposeBag)\n```\n\n#### Sending and receiving strings\n\nSending them:\n\n```swift\nimport RxSwift\nimport RxCocoa\nimport NKMultipeer\n\nlet client: CurrentClient\u003cMCPeerID\u003e\nlet peer: Observable\u003cClient\u003cMCPeerID\u003e\u003e\nlet sendButton: UIButton\n\nsendButton.rx_tap\n  .withLatestFrom(peer)\n  .map { client.send(peer, \"Hello!\") }\n  .switchLatest()\n  .subscribeNext { _ in print(\"Message sent\") }\n  .addDisposableTo(disposeBag)\n```\n\nAnd receiving them:\n\n```swift\nimport RxSwift\nimport NKMultipeer\n\nlet client: CurrentClient\u003cMCPeerID\u003e\n\nclient.receive()\n.subscribeNext { (peer: Client\u003cMCPeerID\u003e, message: String) in\n  print(\"got message \\(message), from peer \\(peer)\")\n}\n.addDisposableTo(disposeBag)\n```\n\n#### Establishing a data stream\n\nRxSwift makes sending streaming data to a persistent connection with another\npeer very intuitive.\n\nThe sender:\n\n```swift\nimport RxSwift\nimport NKMultipeer\n\nlet client: CurrentClient\u003cMCPeerID\u003e\nlet peer: Observable\u003cClient\u003cMCPeerID\u003e\u003e\nlet queuedMessages: Observable\u003c[UInt8]\u003e\n\nlet pipe = peer.map { client.send(peer, streamName: \"data.stream\") }\npipe.withLatestFrom(queuedMessages) { $0 }\n  .subscribeNext { (sender, message) in sender(message) }\n  .addDisposableTo(disposeBag)\n```\n\nThe receiver:\n\n```swift\nimport RxSwift\nimport NKMultipeer\n\nlet client: CurrentClient\u003cMCPeerID\u003e\nlet peer: Observable\u003cClient\u003cMCPeerID\u003e\u003e\n\nlet incomingData = client.receive(peer, streamName: \"data.stream\").shareReplay(1)\nincomingData.subscribeNext { (data) in print(data) }\n  .addDisposableTo(disposeBag)\n```\n\n## Usage\n\n#### Imports\n\n```swift\nimport RxSwift\nimport NKMultipeer\n```\n\n#### Make a new build configuration for testing\n\nYour project comes with `Debug` and `Release` build configurations by default, we need to make a new one called\n`Testing`. [Please check here for step-by-step instructions][buildconfig].\n\n#### Setting up the client\n\n```swift\n// See the link above,\n// You'll need to define a new build configuration and give it the `TESTING` flag\nlet name = UIDevice.currentDevice().name\n#if TESTING\ntypealias I = MockIden\nlet client = CurrentClient(session: MockSession(name: name))\n#else\ntypealias I = MCPeerID\nlet client = CurrentClient(session: MultipeerConnectivitySession(\n                 displayName: name,\n                 serviceType: \"multipeerex\",\n                 encryptionPreference: .None))\n#endif\n```\n\n## Supported transfer resource types\n\n#### String\n\n```swift\nfunc send(other: Client, _ string: String, _ mode: MCSessionSendDataMode = .Reliable) -\u003e Observable\u003c()\u003e\nfunc receive() -\u003e Observable\u003c(Client, String)\u003e\n```\n\n#### NSData\n\n```swift\nfunc send(other: Client, _ data: NSData, _ mode: MCSessionSendDataMode = .Reliable) -\u003e Observable\u003c()\u003e\nfunc receive() -\u003e Observable\u003c(Client, NSData)\u003e\n```\n\n#### JSON\n\n```swift\nfunc send(other: Client, _ json: [String: AnyObject], _ mode: MCSessionSendDataMode = .Reliable) -\u003e Observable\u003c()\u003e\nfunc receive() -\u003e Observable\u003c(Client, [String: AnyObject])\u003e\n```\n\n#### NSURL\n\n```swift\nfunc send(other: Client, name: String, url: NSURL, _ mode: MCSessionSendDataMode = .Reliable) -\u003e Observable\u003cNSProgress\u003e\nfunc receive() -\u003e Observable\u003c(Client, String, ResourceState)\u003e\n```\n\n#### NSStream\n\n```swift\nfunc send(other: Client, streamName: String, runLoop: NSRunLoop = NSRunLoop.mainRunLoop()) -\u003e Observable\u003c([UInt8]) -\u003e Void\u003e\nfunc receive(other: Client, streamName: String, runLoop: NSRunLoop = NSRunLoop.mainRunLoop(), maxLength: Int = 512) -\u003e Observable\u003c[UInt8]\u003e\n```\n\n## Testing\n\nWhen testing, use preprocesser macros to ensure that your code uses a `MockSession` instance instead of\n`MultipeerConnectivitySession` one. In order to achieve this you need to use preprocessor flags and swap out anywhere\nthat references `Client\u003cT\u003e` (because `T` will be different depending on whether you are testing or not.) First you will\nneed to [set up a new build configuration][buildconfig], and then you can use preprocessor macros like so:\n\n```swift\nlet name = UIDevice.currentDevice().name\n#if TESTING\ntypealias I = MockIden\nlet client = CurrentClient(session: MockSession(name: name))\n#else\ntypealias I = MCPeerID\nlet client = CurrentClient(session: MultipeerConnectivitySession(\n                 displayName: name,\n                 serviceType: \"multipeerex\",\n                 encryptionPreference: .None))\n#endif\n```\n\nDon't worry, you should only really need preprocessor macros in one centralized place, the type of your client can be\ninferred by the compiler thereafter.\n\nMocking other nearby peers in the test environment then becomes as simple as creating other `CurrentClient(session:\nMockSession(name: \"other\"))`. For example, if your app is running in a testing environment the following code will mock\na nearby client:\n\n```swift\nlet otherclient = CurrentClient(session: MockSession(name: \"mockedother\"))\n\n// Accept all connections\notherclient.startAdvertising()\notherclient.incomingConnections()\n.subscribeNext { (client, context, respond) in respond(true) }\n.addDisposableTo(disposeBag)\n\n// Respond to all messages with 'Roger'\notherclient.receive()\n.map { (client: Client\u003cMockIden\u003e, string: String) in return otherclient.send(client, \"Roger\") }\n.concat()\n.subscribeNext { _ in print(\"Response sent\") }\n.addDisposableTo(disposeBag)\n```\n\n## Contributing\n\n* Indent with 2 spaces\n* Strip trailing whitespace\n* Write tests\n* Pull-request from feature branches.\n\n[rx]: http://reactivex.io/\n[RxSwift]: https://github.com/kzaher/RxSwift\n[buildconfig]: https://github.com/nathankot/NKMultipeer/wiki/How-to-define-custom-flags-for-the-testing-environment\n[rxmultipeer]: https://github.com/RxSwiftCommunity/RxMultipeer\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnathankot%2FNKMultipeer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnathankot%2FNKMultipeer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnathankot%2FNKMultipeer/lists"}