{"id":19966752,"url":"https://github.com/aptpod/iscp-swift","last_synced_at":"2026-03-03T22:33:02.041Z","repository":{"id":63270549,"uuid":"560362043","full_name":"aptpod/iscp-swift","owner":"aptpod","description":"iSCP client library for Swift. iSCP (intdash Stream Control Protocol) is an L7 network protocol authored by aptpod, Inc.","archived":false,"fork":false,"pushed_at":"2025-11-28T04:04:12.000Z","size":27074,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-12-09T01:59:58.243Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aptpod.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-11-01T10:25:47.000Z","updated_at":"2025-11-28T03:59:11.000Z","dependencies_parsed_at":"2025-09-19T18:30:58.124Z","dependency_job_id":"487ffb53-a438-4c91-b3c4-fd72f7c422d7","html_url":"https://github.com/aptpod/iscp-swift","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/aptpod/iscp-swift","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aptpod%2Fiscp-swift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aptpod%2Fiscp-swift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aptpod%2Fiscp-swift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aptpod%2Fiscp-swift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aptpod","download_url":"https://codeload.github.com/aptpod/iscp-swift/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aptpod%2Fiscp-swift/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30064361,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-03T18:21:05.932Z","status":"ssl_error","status_checked_at":"2026-03-03T18:20:59.341Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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-11-13T02:38:06.225Z","updated_at":"2026-03-03T22:33:02.030Z","avatar_url":"https://github.com/aptpod.png","language":"Objective-C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# iSCP 2.0 Client Library for Swift\n\niSCP Client for Swift は、iSCP version 2 を用いたリアルタイムAPIにアクセスするためのクライアントライブラリです。\n\n## Requirements\n\n- iOS 13 or later\n- macOS 10.15 (Catalina) or later\n- Xcode 16 (16A242d) or later\n\n## Installation\n\n### Cocoapods\n\niscp-swiftは [CocoaPods](https://cocoapods.org/) から入手可能です。\n\n```\ntarget '{YOUR_APP_SCHEME}' do\n  ...\n  pod 'iSCP'\n  ...\nend\n```\n\n### Swift Package Manager\n\niscp-swiftは [Swift Package Manager](https://swift.org/package-manager/) からも利用できます。\n\n## Implementation\n\n### *Connect To intdash API*\n\nこのサンプルではiscp-swiftを使ってintdash APIに接続します。\n\n```swift\n// iSCPをインポート\nimport iSCP\n\n/// 接続するintdashサーバー\nvar targetServer: String = \"https://example.com\"\n/// ノードUUID（ここで指定されたノードとして送受信を行います。\n/// intdash APIでノードを生成した際に発行されたノードUUIDを指定します。）\nvar nodeID: String = \"00000000-0000-0000-0000-000000000000\"\n/// アクセストークン\n///\n/// intdash APIで取得したアクセストークンを設定して下さい。\nvar accessToken: String = \"\"\n/// コネクション\nvar connection: Connection?\n\nextension ExampleViewController {\n    \n    func connect() {\n        // 接続情報のセットアップをします。\n        let urls = targetServer.components(separatedBy: \"://\")\n        var address: String\n        var enableTLS = false\n        if urls.count == 1 {\n            address = urls[0]\n        } else {\n            enableTLS = urls[0] == \"https\"\n            address = urls[1]\n        }\n        // WebSocketを使って接続するように指定します。\n        let connector: IConnector = Transport.WebSocketConnector(\n            enableTLS: enableTLS\n        )\n        Connection.connect(\n            address: address,\n            connector: connector,\n            tokenSource: { token in\n                // アクセス用のトークンを指定します。接続時に発生するイベントにより使用されます。\n                // ここでは固定のトークンを返していますが随時トークンの更新を行う実装にするとトークンの期限切れを考える必要がなくなります。\n                token(accessToken)\n            },\n            nodeID: nodeID) { [weak self] con, error in\n            guard let con = con else {\n                // 接続失敗。\n                return\n            }\n            // 接続成功。\n            connection = con\n            connection?.delegate = self // ConnectionDelegate\n            // 以降、openUpstreamやopenDownstreamなどが実行可能になります。\n        }\n    }\n}\n\nextension ExampleViewController : ConnectionDelegate {\n    \n    func didReconnect(connection: Connection) {\n        // Connectionが再オープンされた際にコールされます。\n    }\n    \n    func didDisconnect(connection: Connection) {\n        // Connectionがクローズされた際にコールされます。\n    }\n    \n    func didFailWithError(connection: Connection, error: Error) {\n        // Connection内部で何らかのエラーが発生した際にコールされます。\n    }\n    \n}\n```\n\n### *Start Upstream*\n\nアップストリームの送信サンプルです。このサンプルでは、基準時刻のメタデータと、文字列型のデータポイントをiSCPサーバーへ送信しています。\n\n```swift\n/// 送信するデータを永続化するかどうか\nvar upstreamPersist: Bool = false\n/// オープンしたストリーム一覧\nvar upstreams: [Upstream] = []\n\nextension ExampleViewController {\n    \n    func startUpstream() {\n        // セッションIDを払い出します。\n        let sessionID = UUID().uuidString.lowercased()\n        \n        // Upstreamをオープンします。\n        connection?.openUpstream(sessionID: sessionID,\n                                 persist: upstreamPersist,\n                                 completion: { [weak self] upstream, error in\n            guard let upstream = upstream else {\n                // オープン失敗。\n                return\n            }\n            // オープン成功。\n            upstreams.append(upstream)\n            \n            // 送信するデータポイントを保存したい場合や、アップストリームのエラーをハンドリングしたい場合はデリゲートを設定します。\n            upstream.delegate = self // UpstreamDelegate\n            \n            let baseTime = Date().timeIntervalSince1970 // 基準時刻です。\n            \n            // 基準時刻をiSCPサーバーへ送信します。\n            connection?.sendBaseTime(\n                baseTime: BaseTime(\n                    sessionID: sessionID,\n                    name: \"manual\",\n                    priority: 60,\n                    elapsedTime: 0,\n                    baseTime: baseTime),\n                persist: upstreamPersist) { error in\n                    if error != nil {\n                        // 基準時刻の送信に失敗。\n                        return\n                    }\n                    // 基準時刻の送信に成功。\n                \n                    // 文字列型のデータポイントをiSCPサーバーへ送信します。\n                    upstream.writeDataPoint(\n                        dataID: DataID(\n                            name: \"greeting\",\n                            type: \"string\"),\n                        dataPoint: DataPoint(\n                            elapsedTime: Date().timeIntervalSince1970-baseTime, // 基準時刻からの経過時間をデータポイントの経過時間として打刻します。\n                            payload: \"hello\".data(using: .utf8) ?? Data())\n                    )\n                }\n        })\n    }\n    \n}\n\nextension ExampleViewController : UpstreamDelegate {\n    \n    func didGenerateChunk(upstream: Upstream, message: UpstreamChunk) {\n        // バッファへ書き込んだデータポイントが実際に送信される直前にコールされます。\n    }\n    \n    func didReceiveAck(upstream: Upstream, message: UpstreamChunkAck) {\n        // データポイントの送信後に返却されるACKを受信できた場合にコールされます。\n    }\n    \n    func didFailWithError(upstream: Upstream, error: Error) {\n        // 内部でエラーが発生した場合にコールされます。\n    }\n    \n    func didCloseWithError(upstream: Upstream, error: Error) {\n        // 何らかの理由でストリームがクローズした場合にコールされます。\n        // 再度アップストリームをオープンしたい場合は、 `Connection.reopenUpstream()` を使用することにより、ストリームの設定を引き継いで別のストリームを開くことが可能です。\n    }\n    \n    func didResume(upstream: Upstream) {\n        // 自動再接続機能が働き、再接続が行われた場合にコールされます。\n    }\n    \n}\n```\n\n### *Start Downstream*\n\n前述のアップストリームで送信されたデータをダウンストリームで受信するサンプルです。\n\nこのサンプルでは、アップストリーム開始のメタデータ、基準時刻のメタデータ、 文字列型のデータポイントを受信しています。\n\n```swift\n/// 受信したいデータを送信している送信元ノードのUUID\n/// （アップストリームを行っている送信元でConnection.Configで設定したnodeIDを指定してください。）\nvar targetDownstreamNodeID: String = \"00000000-0000-0000-0000-000000000000\"\n/// オープンしたダウンストリーム一覧\nvar downstreams: [Downstream] = []\n\nextension ExampleViewController {\n    \n    func startDownstream() {\n        // ダウンストリームをオープンします。\n        connection?.openDownstream(\n            downstreamFilters: [\n                DownstreamFilter(\n                    sourceNodeID: targetDownstreamNodeID, // 送信元ノードのIDを指定します。\n                    dataFilters: [\n                        DataFilter(\n                            name: \"#\", type: \"#\" // 受信したいデータを名称と型で指定します。この例では、ワイルドカード `#` を使用して全てのデータを取得します。\n                        )\n                    ])\n                ],\n            completion: { downstream, error in\n            guard let downstream = downstream else {\n                // オープン失敗。\n                return\n            }\n            // オープン成功。\n            downstreams.append(downstream)\n            // 受信データを取り扱うためにデリゲートを設定します。\n            downstream.delegate = self // DownstreamDelegate\n        })\n    }\n}\n\nextension ExampleViewController : DownstreamDelegate {\n    \n    func didReceiveChunk(downstream: Downstream, message: DownstreamChunk) {\n        // データポイントを読み込むことができた際にコールされます。\n        print(\"Received dataPoints sequenceNumber[\\(message.sequenceNumber)], sessionId[\\(message.upstreamInfo.sessionID)]\")\n        for g in message.dataPointGroups {\n            for dp in g.dataPoints {\n                print(\"Received a dataPoint dataName[\\(g.dataID.name)], dataType[\\(g.dataID.type)], payload[\\(String(data: dp.payload, encoding: .utf8) ?? \"\")]\")\n            }\n        }\n    }\n    \n    func didReceiveMetadata(downstream: Downstream, message: DownstreamMetadata) {\n        // メタデータを受信した際にコールされます。\n        print(\"Received a metadata sourceNodeID[\\(message.sourceNodeID)], metadataType:\\(String(describing: message.metadata))\")\n        switch message.metadata {\n        case .baseTime(let baseTime):\n            print(\"Received baseTime[\\(Date(timeIntervalSince1970: baseTime.baseTime))], priority[\\(baseTime.priority)], name[\\(baseTime.name)]\")\n        default: break\n        }\n    }\n    \n    func didFailWithError(downstream: Downstream, error: Error) {\n        // 内部でエラーが発生した場合にコールされます。\n    }\n    \n    func didCloseWithError(downstream: Downstream, error: Error) {\n        // 何らかの理由でストリームがクローズした場合にコールされます。\n        // 再度ダウンストリームをオープンしたい場合は、 `Connection.reopenDownstream()` を使用することにより、ストリームの設定を引き継いで別のストリームを開くことが可能です。\n    }\n    \n    func didResume(downstream: Downstream) {\n        // 自動再接続機能が働き、再接続が行われた場合にコールされます。\n    }\n    \n}\n```\n\n### *E2E Call*\n\nE2E（エンドツーエンド）コールのサンプルです。\n\nコントローラーノードが対象ノードに対して指示を出し、対象ノードは受信完了のリプライを行う簡単なサンプルです。\n\n```swift\nimport Foundation\nimport UIKit\n\n// iSCPをインポート。\nimport iSCP\n\nclass E2ECallExampleViewController : UIViewController {\n    /// 接続するintdashサーバー\n    var targetServer: String = \"https://example.com\"\n\n    /// コントローラーノードのUUID\n    var controllerNodeID: String = \"00000000-0000-0000-0000-000000000000\"\n    /// 対象ノードのUUID\n    var targetNodeID: String = \"11111111-1111-1111-1111-111111111111\"\n\n    /// コントローラーノード用のアクセストークン\n    ///\n    /// intdash APIで取得したアクセストークンを設定して下さい。\n    var accessTokenForController: String = \"\"\n    /// 対象ノード用のアクセストークン\n    ///\n    /// intdash APIで取得したアクセストークンを設定して下さい。\n    var accessTokenForTarget: String = \"\"\n\n    /// コントローラーノード用のコネクション\n    var connectionForController: Connection?\n    /// 対象ノード用のコネクション\n    var connectionForTarget: Connection?\n}\n\n// コントローラーノードからメッセージを送信するサンプルです。このサンプルでは文字列メッセージを対象ノードに対して送信し、対象ノードからのリプライを待ちます。\nextension E2ECallExampleViewController {\n    \n    func connectForController() {\n        // 接続情報のセットアップをします。\n        let urls = targetServer.components(separatedBy: \"://\")\n        var address: String\n        var enableTLS = false\n        if urls.count == 1 {\n            address = urls[0]\n        } else {\n            enableTLS = urls[0] == \"https\"\n            address = urls[1]\n        }\n        // WebSocketを使って接続するように指定します。\n        let connector: IConnector = Transport.WebSocketConnector(\n            enableTLS: enableTLS\n        )\n        Connection.connect(\n            address: address,\n            connector: connector,\n            tokenSource: { [weak self] token in\n                // アクセストークンを指定します。接続時に発生するイベントにより使用されます。\n                // ここでは固定のトークンを返していますが、随時トークンの更新を行う実装にするとトークンの期限切れを考える必要がなくなります。\n                token(self?.accessTokenForController)\n            },\n            nodeID: controllerNodeID) { [weak self] con, error in\n                guard let con = con else {\n                    // 接続失敗。\n                    return\n                }\n                // 接続成功。\n                self?.connectionForController = con\n        }\n    }\n    \n    func sendCall() {\n        // コールを送信し、リプライコールを受信するとコールバックが発生します。\n        connectionForController?.sendCallAndWaitReplayCall(\n            upstreamCall: UpstreamCall(\n                destinationNodeID: targetNodeID,\n                name: \"greeting\",\n                type: \"string\",\n                payload: \"hello\".data(using: .utf8)!\n            ),\n            completion: { downstreamReplyCall, error in\n                if error != nil {\n                    // コールの送信もしくはリプライの受信に失敗。\n                    return\n                }\n                // コールの送信及びリプライの受信に成功。\n            })\n    }\n}\n\n// コントローラーノードからのコールを受け付け、すぐにリプライするサンプルです。\nextension E2ECallExampleViewController {\n    \n    func connectForTarget() {\n        // 接続情報のセットアップをします。\n        let urls = targetServer.components(separatedBy: \"://\")\n        var address: String\n        var enableTLS = false\n        if urls.count == 1 {\n            address = urls[0]\n        } else {\n            enableTLS = urls[0] == \"https\"\n            address = urls[1]\n        }\n        // WebSocketを使って接続するように指定します。\n        let connector: IConnector = Transport.WebSocketConnector(\n            enableTLS: enableTLS\n        )\n        Connection.connect(\n            address: address,\n            connector: connector,\n            tokenSource: { [weak self] token in\n                // アクセストークンを指定します。接続時に発生するイベントにより使用されます。\n                // ここでは固定のトークンを返していますが、随時トークンの更新を行う実装にするとトークンの期限切れを考える必要がなくなります。\n                token(self?.accessTokenForTarget)\n            },\n            nodeID: targetNodeID) { [weak self] con, error in\n                guard let con = con else {\n                    // 接続失敗。\n                    return\n                }\n                // 接続成功。\n                self?.connectionForTarget = con\n                // DownstreamCallの受信を監視するためにデリゲートを設定します。\n                self?.connectionForTarget?.e2eCallDelegate = self // ConnectionE2ECallDelegate\n        }\n    }\n}\n\nextension E2ECallExampleViewController : ConnectionE2ECallDelegate {\n    \n    func didReceiveCall(connection: Connection, downstreamCall: DownstreamCall) {\n        // DownstreamCallを受信した際にコールされます。\n        // このサンプルではDownstreamCallを受信したらすぐにリプライコールを送信します。\n        connection.sendReplyCall(\n            upstreamReplyCall:\n                UpstreamReplyCall(\n                    requestCallID: downstreamCall.callID,\n                    destinationNodeID: downstreamCall.sourceNodeID,\n                    name: \"reply_greeting\",\n                    type: \"string\",\n                    payload: \"world\".data(using: .utf8)!\n                )\n        ) { error in\n            if error != nil {\n                // リプライコールの送信に失敗。\n                return\n            }\n            // リプライコールの送信に成功。\n        }\n    }\n    \n    func didReceiveReplyCall(connection: Connection, downstreamReplyCall: DownstreamReplyCall) {\n        // DownstreamReplyCallを受信した際にコールされます。\n    }\n    \n}\n```\n\n## Third-Party License Notices\niscp-swiftはサードパーティ製オープンソースソフトウェアを同梱・利用しています。\n\nこれらコンポーネントのライセンス条文およびクレジットの詳細は [THIRD-PARTY-LICENSES.txt](https://github.com/aptpod/iscp-swift/blob/main/THIRD-PARTY-LICENSES.txt) を参照してください。\n\n## Dependencies\n- [SwiftProtobuf](https://github.com/apple/swift-protobuf)  \n  - Licensed under the Apache License, Version 2.0.\n\n## References\n- [APIリファレンス](https://docs.intdash.jp/api/intdash-sdk/swift/latest/)\n  - 過去のバージョンのリファレンスは [こちら](https://docs.intdash.jp/api/intdash-sdk/swift-versions)\n- [GitHub](https://github.com/aptpod/iscp-swift)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faptpod%2Fiscp-swift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faptpod%2Fiscp-swift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faptpod%2Fiscp-swift/lists"}