├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE-APACHE2.md ├── LICENSE-MIT.md ├── README.md ├── integration ├── Cargo.lock ├── Cargo.toml └── src │ └── main.rs ├── libp2p-webrtc ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── examples │ └── interop.rs ├── src │ ├── lib.rs │ └── ws.rs └── tests │ ├── check-public-server.rs │ ├── interop.rs │ ├── native-native.rs │ └── wasm-wasm.rs ├── rust-toolchain.toml └── signal ├── Cargo.lock ├── Cargo.toml ├── README.md └── src └── main.rs /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: libp2p-webrtc 4 | 5 | jobs: 6 | validation: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | toolchain: [x86_64-unknown-linux-gnu, wasm32-unknown-unknown] 11 | steps: 12 | - name: Checkout sources 13 | uses: actions/checkout@v2 14 | 15 | - name: setup rustup 16 | run: curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain none -y 17 | 18 | - name: cargo fmt 19 | working-directory: libp2p-webrtc 20 | run: cargo fmt --all -- --check 21 | 22 | - name: cargo clippy 23 | working-directory: libp2p-webrtc 24 | run: cargo clippy --target ${{ matrix.toolchain }} --workspace --examples --tests --all-features -- -D warnings 25 | 26 | - name: cargo build 27 | working-directory: libp2p-webrtc 28 | run: cargo build --locked --target ${{ matrix.toolchain }} 29 | 30 | - name: cargo test 31 | if: ${{ matrix.toolchain != 'wasm32-unknown-unknown' }} 32 | working-directory: libp2p-webrtc 33 | run: RUST_LOG=debug cargo test --all-features --target ${{ matrix.toolchain }} 34 | 35 | integration: 36 | runs-on: ubuntu-latest 37 | steps: 38 | - name: Checkout sources 39 | uses: actions/checkout@v2 40 | 41 | - name: setup rustup 42 | run: curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain none -y 43 | 44 | - name: install wasm-pack 45 | run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh 46 | 47 | - name: integration tests 48 | working-directory: integration 49 | run: cargo run 50 | 51 | signaling-server: 52 | runs-on: ubuntu-latest 53 | steps: 54 | - name: Checkout sources 55 | uses: actions/checkout@v2 56 | 57 | - name: setup rustup 58 | run: curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain none -y 59 | 60 | - name: cargo fmt 61 | working-directory: signal 62 | run: cargo fmt --all -- --check 63 | 64 | - name: cargo clippy 65 | working-directory: signal 66 | run: cargo clippy --workspace --examples --tests --all-features -- -D warnings 67 | 68 | - name: cargo build 69 | working-directory: signal 70 | run: cargo build --locked 71 | 72 | - name: cargo test 73 | working-directory: signal 74 | run: RUST_LOG=debug cargo test --all-features 75 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /LICENSE-APACHE2.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Rüdiger Klaehn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libp2p-webrtc 2 | **NOTE: webrtc support has been added to rust-libp2p. browser-to-browser is not 3 | yet supported. This crate will stay as-is and not receive any maintenance 4 | efforts anymore.** 5 | 6 | [![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](https://github.com/wngr/libp2p-webrtc) 7 | [![Cargo](https://img.shields.io/crates/v/libp2p-webrtc.svg)](https://crates.io/crates/libp2p-webrtc) 8 | [![Documentation](https://docs.rs/libp2p-webrtc/badge.svg)](https://docs.rs/libp2p-webrtc) 9 | 10 | WebRTC transport for rust-libp2p for both native and WebAssembly (browser). For 11 | initiating a connection between two peers, both of them need to connect to the 12 | same WebSocket signaling server (via a call to `listen_on`). Either one can dial 13 | the other peer by using the `p2p-webrtc-star` protocol. Note, that this crate is 14 | currently not interoperable with the respective js-libp2p and go-libp2p 15 | implementations. 16 | 17 | Additional, a signaling server implementation is provided within the crate. 18 | 19 | ## Quickstart 20 | 21 | To compile this crate, you need `gcc g++ libssl-dev make cmake clang 22 | pkg-config`. 23 | 24 | ```rust 25 | let base_transport = WebRtcTransport::new(peer_id, vec!["stun:stun.l.google.com:19302"]); 26 | let transport = base_transport.upgrade()... 27 | 28 | .. 29 | 30 | swarm 31 | .listen_on( 32 | "/ip4/127.0.0.1/tcp/8001/ws/p2p-webrtc-star" 33 | .parse() 34 | .unwrap(), 35 | ) 36 | .unwrap(); 37 | ``` 38 | 39 | ## License 40 | 41 | Licensed under either of 42 | 43 | * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 44 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 45 | 46 | at your option. 47 | 48 | #### Contribution 49 | 50 | Unless you explicitly state otherwise, any contribution intentionally submitted 51 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 52 | dual licensed as above, without any additional terms or conditions. 53 | -------------------------------------------------------------------------------- /integration/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "anyhow" 7 | version = "1.0.44" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" 10 | 11 | [[package]] 12 | name = "autocfg" 13 | version = "1.0.1" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 16 | 17 | [[package]] 18 | name = "bitflags" 19 | version = "1.3.2" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 22 | 23 | [[package]] 24 | name = "bytes" 25 | version = "1.1.0" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" 28 | 29 | [[package]] 30 | name = "cfg-if" 31 | version = "1.0.0" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 34 | 35 | [[package]] 36 | name = "futures" 37 | version = "0.3.17" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" 40 | dependencies = [ 41 | "futures-channel", 42 | "futures-core", 43 | "futures-executor", 44 | "futures-io", 45 | "futures-sink", 46 | "futures-task", 47 | "futures-util", 48 | ] 49 | 50 | [[package]] 51 | name = "futures-channel" 52 | version = "0.3.17" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" 55 | dependencies = [ 56 | "futures-core", 57 | "futures-sink", 58 | ] 59 | 60 | [[package]] 61 | name = "futures-core" 62 | version = "0.3.17" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" 65 | 66 | [[package]] 67 | name = "futures-executor" 68 | version = "0.3.17" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" 71 | dependencies = [ 72 | "futures-core", 73 | "futures-task", 74 | "futures-util", 75 | ] 76 | 77 | [[package]] 78 | name = "futures-io" 79 | version = "0.3.17" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" 82 | 83 | [[package]] 84 | name = "futures-macro" 85 | version = "0.3.17" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" 88 | dependencies = [ 89 | "autocfg", 90 | "proc-macro-hack", 91 | "proc-macro2", 92 | "quote", 93 | "syn", 94 | ] 95 | 96 | [[package]] 97 | name = "futures-sink" 98 | version = "0.3.17" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" 101 | 102 | [[package]] 103 | name = "futures-task" 104 | version = "0.3.17" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" 107 | 108 | [[package]] 109 | name = "futures-util" 110 | version = "0.3.17" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" 113 | dependencies = [ 114 | "autocfg", 115 | "futures-channel", 116 | "futures-core", 117 | "futures-io", 118 | "futures-macro", 119 | "futures-sink", 120 | "futures-task", 121 | "memchr", 122 | "pin-project-lite", 123 | "pin-utils", 124 | "proc-macro-hack", 125 | "proc-macro-nested", 126 | "slab", 127 | ] 128 | 129 | [[package]] 130 | name = "hermit-abi" 131 | version = "0.1.19" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 134 | dependencies = [ 135 | "libc", 136 | ] 137 | 138 | [[package]] 139 | name = "instant" 140 | version = "0.1.10" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" 143 | dependencies = [ 144 | "cfg-if", 145 | ] 146 | 147 | [[package]] 148 | name = "integration" 149 | version = "0.1.0" 150 | dependencies = [ 151 | "anyhow", 152 | "futures", 153 | "tokio", 154 | ] 155 | 156 | [[package]] 157 | name = "libc" 158 | version = "0.2.102" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" 161 | 162 | [[package]] 163 | name = "lock_api" 164 | version = "0.4.5" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" 167 | dependencies = [ 168 | "scopeguard", 169 | ] 170 | 171 | [[package]] 172 | name = "log" 173 | version = "0.4.14" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 176 | dependencies = [ 177 | "cfg-if", 178 | ] 179 | 180 | [[package]] 181 | name = "memchr" 182 | version = "2.4.1" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 185 | 186 | [[package]] 187 | name = "mio" 188 | version = "0.7.13" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" 191 | dependencies = [ 192 | "libc", 193 | "log", 194 | "miow", 195 | "ntapi", 196 | "winapi", 197 | ] 198 | 199 | [[package]] 200 | name = "miow" 201 | version = "0.3.7" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 204 | dependencies = [ 205 | "winapi", 206 | ] 207 | 208 | [[package]] 209 | name = "ntapi" 210 | version = "0.3.6" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" 213 | dependencies = [ 214 | "winapi", 215 | ] 216 | 217 | [[package]] 218 | name = "num_cpus" 219 | version = "1.13.0" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 222 | dependencies = [ 223 | "hermit-abi", 224 | "libc", 225 | ] 226 | 227 | [[package]] 228 | name = "once_cell" 229 | version = "1.8.0" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" 232 | 233 | [[package]] 234 | name = "parking_lot" 235 | version = "0.11.2" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 238 | dependencies = [ 239 | "instant", 240 | "lock_api", 241 | "parking_lot_core", 242 | ] 243 | 244 | [[package]] 245 | name = "parking_lot_core" 246 | version = "0.8.5" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 249 | dependencies = [ 250 | "cfg-if", 251 | "instant", 252 | "libc", 253 | "redox_syscall", 254 | "smallvec", 255 | "winapi", 256 | ] 257 | 258 | [[package]] 259 | name = "pin-project-lite" 260 | version = "0.2.7" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" 263 | 264 | [[package]] 265 | name = "pin-utils" 266 | version = "0.1.0" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 269 | 270 | [[package]] 271 | name = "proc-macro-hack" 272 | version = "0.5.19" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" 275 | 276 | [[package]] 277 | name = "proc-macro-nested" 278 | version = "0.1.7" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" 281 | 282 | [[package]] 283 | name = "proc-macro2" 284 | version = "1.0.29" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" 287 | dependencies = [ 288 | "unicode-xid", 289 | ] 290 | 291 | [[package]] 292 | name = "quote" 293 | version = "1.0.9" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 296 | dependencies = [ 297 | "proc-macro2", 298 | ] 299 | 300 | [[package]] 301 | name = "redox_syscall" 302 | version = "0.2.10" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 305 | dependencies = [ 306 | "bitflags", 307 | ] 308 | 309 | [[package]] 310 | name = "scopeguard" 311 | version = "1.1.0" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 314 | 315 | [[package]] 316 | name = "signal-hook-registry" 317 | version = "1.4.0" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 320 | dependencies = [ 321 | "libc", 322 | ] 323 | 324 | [[package]] 325 | name = "slab" 326 | version = "0.4.4" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" 329 | 330 | [[package]] 331 | name = "smallvec" 332 | version = "1.6.1" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" 335 | 336 | [[package]] 337 | name = "syn" 338 | version = "1.0.76" 339 | source = "registry+https://github.com/rust-lang/crates.io-index" 340 | checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" 341 | dependencies = [ 342 | "proc-macro2", 343 | "quote", 344 | "unicode-xid", 345 | ] 346 | 347 | [[package]] 348 | name = "tokio" 349 | version = "1.12.0" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc" 352 | dependencies = [ 353 | "autocfg", 354 | "bytes", 355 | "libc", 356 | "memchr", 357 | "mio", 358 | "num_cpus", 359 | "once_cell", 360 | "parking_lot", 361 | "pin-project-lite", 362 | "signal-hook-registry", 363 | "tokio-macros", 364 | "winapi", 365 | ] 366 | 367 | [[package]] 368 | name = "tokio-macros" 369 | version = "1.3.0" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110" 372 | dependencies = [ 373 | "proc-macro2", 374 | "quote", 375 | "syn", 376 | ] 377 | 378 | [[package]] 379 | name = "unicode-xid" 380 | version = "0.2.2" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 383 | 384 | [[package]] 385 | name = "winapi" 386 | version = "0.3.9" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 389 | dependencies = [ 390 | "winapi-i686-pc-windows-gnu", 391 | "winapi-x86_64-pc-windows-gnu", 392 | ] 393 | 394 | [[package]] 395 | name = "winapi-i686-pc-windows-gnu" 396 | version = "0.4.0" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 399 | 400 | [[package]] 401 | name = "winapi-x86_64-pc-windows-gnu" 402 | version = "0.4.0" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 405 | -------------------------------------------------------------------------------- /integration/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "integration" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | anyhow = "1.0.44" 10 | futures = "0.3.17" 11 | tokio = { version = "1.12.0", features = ["full"] } 12 | -------------------------------------------------------------------------------- /integration/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::process::Stdio; 2 | 3 | use futures::future; 4 | use tokio::{ 5 | io::{AsyncBufReadExt, BufReader}, 6 | process::{Child, Command}, 7 | }; 8 | 9 | async fn start_signaling_server() -> anyhow::Result { 10 | let mut cmd = Command::new("cargo"); 11 | cmd.args(&["run", "--", "--interface", "127.0.0.1", "--port", "8001"]) 12 | .current_dir("../signal") 13 | .stdout(Stdio::piped()) 14 | .stderr(Stdio::inherit()) 15 | .kill_on_drop(true); 16 | let mut server = cmd.spawn()?; 17 | let stdout = server.stdout.take().unwrap(); 18 | let mut reader = BufReader::new(stdout).lines(); 19 | while let Some(line) = reader.next_line().await? { 20 | if line.starts_with("Listening on") { 21 | break; 22 | } 23 | } 24 | println!("Signaling server started!"); 25 | server.stdout.replace(reader.into_inner().into_inner()); 26 | Ok(server) 27 | } 28 | 29 | async fn wasm_wasm() -> anyhow::Result<()> { 30 | let mut _server = start_signaling_server().await?; 31 | 32 | let mut cmd = Command::new("wasm-pack"); 33 | cmd.args(&[ 34 | "test", 35 | "--headless", 36 | "--firefox", 37 | "--chrome", 38 | "--", 39 | "--", 40 | "wasm_wasm", 41 | ]) 42 | .current_dir("../libp2p-webrtc") 43 | .stdout(Stdio::inherit()) 44 | .stderr(Stdio::inherit()) 45 | .kill_on_drop(true); 46 | let mut child = cmd.spawn()?; 47 | let exit = child.wait().await?; 48 | anyhow::ensure!(exit.success()); 49 | Ok(()) 50 | } 51 | 52 | async fn wasm_native() -> anyhow::Result<()> { 53 | let mut _server = start_signaling_server().await?; 54 | 55 | let mut cmd = Command::new("cargo"); 56 | cmd.args(&[ 57 | "run", 58 | "--target", 59 | "x86_64-unknown-linux-gnu", 60 | "--example", 61 | "interop", 62 | ]) 63 | .current_dir("../libp2p-webrtc") 64 | .stdout(Stdio::piped()) 65 | .stderr(Stdio::inherit()) 66 | .kill_on_drop(true); 67 | let mut native = cmd.spawn()?; 68 | 69 | let stdout = native.stdout.take().unwrap(); 70 | let mut reader = BufReader::new(stdout).lines(); 71 | let mut peer = None; 72 | while let Some(line) = reader.next_line().await? { 73 | if line.starts_with("/p2p/") { 74 | println!("native peer: {}", line); 75 | peer.replace(line); 76 | break; 77 | } 78 | } 79 | 80 | let mut cmd = Command::new("wasm-pack"); 81 | cmd.args(&["test", "--headless", "--chrome", "--", "--", "interop"]) 82 | .current_dir("../libp2p-webrtc") 83 | .stdout(Stdio::inherit()) 84 | .stderr(Stdio::inherit()) 85 | .env("TEST_PEER", peer.unwrap()) 86 | .kill_on_drop(true); 87 | 88 | let mut wasm = cmd.spawn()?; 89 | let (exit_native, exit_wasm) = future::try_join(native.wait(), wasm.wait()).await?; 90 | anyhow::ensure!(exit_native.success() && exit_wasm.success()); 91 | Ok(()) 92 | } 93 | 94 | #[tokio::main] 95 | async fn main() -> anyhow::Result<()> { 96 | wasm_wasm().await?; 97 | wasm_native().await?; 98 | Ok(()) 99 | } 100 | -------------------------------------------------------------------------------- /libp2p-webrtc/.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | -------------------------------------------------------------------------------- /libp2p-webrtc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2p-webrtc" 3 | version = "0.3.0" 4 | edition = "2018" 5 | authors = ["Oliver Wangler "] 6 | description = "WebRTC transport for libp2p" 7 | license = "Apache-2.0 OR MIT" 8 | repository = "https://github.com/wngr/libp2p-webrtc" 9 | homepage = "https://github.com/wngr/libp2p-webrtc" 10 | documentation = "https://docs.rs/libp2p-webrtc" 11 | keywords = ["webrtc", "libp2p", "transport"] 12 | readme = "../README.md" 13 | 14 | [dependencies] 15 | anyhow = "1.0.56" 16 | async-stream = "0.3.2" 17 | http = "0.2.6" 18 | libp2p = { version = "0.43.0", default-features = false } 19 | log = "0.4.14" 20 | pin-project = "1.0.10" 21 | serde = { version = "1.0.136", features = ["derive"] } 22 | serde_json = "1.0.79" 23 | streamunordered = "0.5.2" 24 | thiserror = "1.0.30" 25 | 26 | [target.'cfg(not(target_arch = "wasm32"))'.dependencies] 27 | async-datachannel = "0.3.0" 28 | async-tungstenite = { version = "0.17.1", features = ["tokio", "tokio-native-tls"] } 29 | futures-timer = "3.0.2" 30 | parking_lot = "0.12.0" 31 | 32 | [target.'cfg(target_arch = "wasm32")'.dependencies] 33 | async-datachannel-wasm = "0.2.0" 34 | futures-timer = { version = "3.0.2", features = ["wasm-bindgen"] } 35 | send_wrapper = { version = "0.5.0", features = ["futures"] } 36 | libp2p = { version = "0.43.0", features = ["wasm-bindgen"], default_features = false } 37 | ws_stream_wasm = "0.7.3" 38 | 39 | [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] 40 | tokio = { version = "1.17.0", features = ["full"] } 41 | tracing-subscriber = "0.3.9" 42 | 43 | [target.'cfg(target_arch = "wasm32")'.dev-dependencies] 44 | console_log = "0.2.0" 45 | wasm-bindgen-futures = "0.4.29" 46 | wasm-bindgen-test = "0.3.29" 47 | 48 | [dev-dependencies] 49 | libp2p = { version = "0.43.0", features = ["ping", "noise", "mplex", "yamux"], default_features = false } 50 | -------------------------------------------------------------------------------- /libp2p-webrtc/examples/interop.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | mod bin { 3 | use libp2p::{ 4 | core::{self, transport::upgrade, PeerId}, 5 | identity, mplex, noise, 6 | ping::{Ping, PingConfig, PingEvent}, 7 | swarm::SwarmBuilder, 8 | yamux, NetworkBehaviour, Swarm, Transport, 9 | }; 10 | use libp2p_webrtc::WebRtcTransport; 11 | use std::time::Duration; 12 | 13 | pub(crate) fn mk_swarm() -> Swarm { 14 | let identity = identity::Keypair::generate_ed25519(); 15 | 16 | let peer_id = PeerId::from(identity.public()); 17 | let transport = { 18 | let base = WebRtcTransport::new(peer_id, vec!["stun:stun.l.google.com:19302"]); 19 | let noise_keys = noise::Keypair::::new() 20 | .into_authentic(&identity) 21 | .expect("Signing libp2p-noise static DH keypair failed."); 22 | 23 | base.upgrade(upgrade::Version::V1Lazy) 24 | .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) 25 | .multiplex(core::upgrade::SelectUpgrade::new( 26 | yamux::YamuxConfig::default(), 27 | mplex::MplexConfig::default(), 28 | )) 29 | .timeout(std::time::Duration::from_secs(20)) 30 | .boxed() 31 | }; 32 | 33 | SwarmBuilder::new( 34 | transport, 35 | MyBehaviour { 36 | ping: Ping::new( 37 | PingConfig::new() 38 | .with_interval(Duration::from_secs(1)) 39 | .with_keep_alive(true), 40 | ), 41 | }, 42 | peer_id, 43 | ) 44 | .executor(Box::new(|f| { 45 | tokio::spawn(f); 46 | })) 47 | .build() 48 | } 49 | #[derive(Debug)] 50 | pub(crate) enum MyEvent { 51 | Ping(PingEvent), 52 | } 53 | 54 | impl From for MyEvent { 55 | fn from(event: PingEvent) -> Self { 56 | MyEvent::Ping(event) 57 | } 58 | } 59 | 60 | #[derive(NetworkBehaviour)] 61 | #[behaviour(event_process = false)] 62 | #[behaviour(out_event = "MyEvent")] 63 | pub(crate) struct MyBehaviour { 64 | ping: Ping, 65 | } 66 | } 67 | 68 | #[cfg(not(target_arch = "wasm32"))] 69 | #[tokio::main] 70 | async fn main() -> anyhow::Result<()> { 71 | use libp2p::{ 72 | futures::StreamExt, 73 | ping::{PingEvent, PingSuccess}, 74 | swarm::SwarmEvent, 75 | }; 76 | 77 | use log::*; 78 | use tracing_subscriber::fmt; 79 | 80 | use crate::bin::{mk_swarm, MyEvent}; 81 | fmt::init(); 82 | let mut swarm_0 = mk_swarm(); 83 | let peer_0 = *swarm_0.local_peer_id(); 84 | println!("/p2p/{}", peer_0); 85 | 86 | // /ip4/ws_signaling_ip/tcp/ws_signaling_port/{ws,wss}/p2p-webrtc-star/p2p/remote_peer_id 87 | swarm_0 88 | .listen_on( 89 | "/ip4/127.0.0.1/tcp/8001/ws/p2p-webrtc-star" 90 | .parse() 91 | .unwrap(), 92 | ) 93 | .unwrap(); 94 | 95 | while let Some(event) = swarm_0.next().await { 96 | match event { 97 | SwarmEvent::NewListenAddr { address, .. } => { 98 | info!("Listening on {}", address); 99 | } 100 | 101 | SwarmEvent::Behaviour(MyEvent::Ping(PingEvent { 102 | peer, 103 | result: Ok(PingSuccess::Ping { rtt }), 104 | })) => { 105 | info!("Ping to {} is {}ms", peer, rtt.as_millis()); 106 | break; 107 | } 108 | other => { 109 | info!("Unhandled {:?}", other); 110 | } 111 | } 112 | } 113 | Ok(()) 114 | } 115 | 116 | #[cfg(target_arch = "wasm32")] 117 | fn main() { 118 | panic!("not supported on wasm32"); 119 | } 120 | -------------------------------------------------------------------------------- /libp2p-webrtc/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::let_and_return)] 2 | use std::{ 3 | collections::BTreeMap, 4 | pin::Pin, 5 | sync::{ 6 | atomic::{AtomicUsize, Ordering}, 7 | Arc, 8 | }, 9 | time::Duration, 10 | }; 11 | 12 | use crate::ws::{CombinedStream, Message}; 13 | use anyhow::Context; 14 | #[cfg(not(target_arch = "wasm32"))] 15 | use async_datachannel::{DataStream, Message as DataChannelMessage, PeerConnection, RtcConfig}; 16 | #[cfg(target_arch = "wasm32")] 17 | use async_datachannel_wasm::{ 18 | DataStream, Message as DataChannelMessage, PeerConnection, RtcConfig, 19 | }; 20 | use async_stream::try_stream; 21 | use futures_timer::Delay; 22 | use libp2p::{ 23 | core::transport::ListenerEvent, 24 | futures::{ 25 | channel::mpsc, 26 | future::BoxFuture, 27 | pin_mut, select, select_biased, 28 | stream::{BoxStream, FuturesUnordered}, 29 | FutureExt, SinkExt, StreamExt, TryFutureExt, 30 | }, 31 | multiaddr::Protocol, 32 | Multiaddr, PeerId, Transport, 33 | }; 34 | use log::*; 35 | #[cfg(target_arch = "wasm32")] 36 | use send_wrapper::SendWrapper; 37 | use serde::{Deserialize, Serialize}; 38 | use streamunordered::{StreamUnordered, StreamYield}; 39 | use thiserror::Error; 40 | 41 | mod ws; 42 | 43 | #[derive(Clone)] 44 | pub struct WebRtcTransport { 45 | config: RtcConfig, 46 | id: Arc, 47 | own_peer_id: PeerId, 48 | } 49 | // Uniquely identify a signaling request. PeerId is the initiator's peer id and a counter. 50 | #[derive(Serialize, Deserialize, Clone, PartialEq, Debug, Eq, Hash, Ord, PartialOrd)] 51 | pub struct SignalingId { 52 | #[serde(with = "serde_str")] 53 | pub caller: PeerId, 54 | pub counter: usize, 55 | } 56 | 57 | #[derive(Debug, Deserialize, Serialize)] 58 | #[serde(rename_all = "camelCase")] 59 | pub struct SignalingMessage { 60 | pub intent_id: SignalingId, 61 | #[serde(with = "serde_str")] 62 | pub callee: PeerId, 63 | pub signal: DataChannelMessage, 64 | } 65 | 66 | #[derive(Error, Debug)] 67 | pub enum Error { 68 | #[error("Connection to signaling server failed: {0}")] 69 | ConnectionToSignalingServerFailed(String), 70 | #[error("Unexpected Message: {0}")] 71 | UnexpectedMessage(String), 72 | #[error(transparent)] 73 | Internal(#[from] anyhow::Error), 74 | } 75 | 76 | impl WebRtcTransport { 77 | pub fn new(peer_id: PeerId, ice_servers: Vec<&str>) -> Self { 78 | let config = RtcConfig::new(&ice_servers[..]); 79 | 80 | Self { 81 | config, 82 | id: Default::default(), 83 | own_peer_id: peer_id, 84 | } 85 | } 86 | } 87 | 88 | #[allow(clippy::type_complexity)] 89 | impl Transport for WebRtcTransport { 90 | type Output = DataStream; 91 | 92 | type Error = Error; 93 | 94 | type Listener = 95 | BoxStream<'static, Result, Self::Error>>; 96 | 97 | type ListenerUpgrade = BoxFuture<'static, Result>; 98 | 99 | type Dial = BoxFuture<'static, Result>; 100 | 101 | fn listen_on( 102 | self, 103 | addr: libp2p::Multiaddr, 104 | ) -> Result> 105 | where 106 | Self: Sized, 107 | { 108 | debug!("called listen on with {}", addr); 109 | let (signaling_uri, maybe_p2p) = extract_uri(&addr) 110 | .map_err(|_| libp2p::TransportError::MultiaddrNotSupported(addr.clone()))?; 111 | if maybe_p2p.is_some() { 112 | return Err(libp2p::TransportError::MultiaddrNotSupported(addr)); 113 | } 114 | let signaling_uri = format!("{}/{}", signaling_uri, self.own_peer_id); 115 | // input addr 116 | // /ip4/ws_signaling_ip/tcp/ws_signaling_port/{ws,wss}/p2p-webrtc-star/p2p/remote_peer_id 117 | let s = try_stream! { 118 | let local_addr = addr.clone().with(Protocol::P2p(self.own_peer_id.into())); 119 | 120 | let mut backoff: Option = None; 121 | let mut pending_upgrades = FuturesUnordered::new(); 122 | let mut open_upgrades = 123 | BTreeMap::>::new(); 124 | let mut outbound = StreamUnordered::new(); 125 | 126 | loop { 127 | match CombinedStream::connect(&signaling_uri).await { 128 | Ok(ws) => { 129 | 130 | yield ListenerEvent::NewAddress(local_addr.clone()); 131 | backoff.take(); 132 | let (mut ws_tx, ws_rx) = ws.split(); 133 | let mut ws_rx = ws_rx.fuse(); 134 | 'inner: loop { 135 | select! { 136 | from_ws = ws_rx.next() => { 137 | let message = match from_ws { 138 | Some(Ok(Message::Text(t))) => { 139 | serde_json::from_str::(&t) 140 | }, 141 | Some(Ok(Message::Binary(b))) => { 142 | serde_json::from_slice::(&b[..]) 143 | }, 144 | _ => { 145 | info!("Address expired {}", addr); 146 | yield ListenerEvent::AddressExpired(local_addr.clone()); 147 | break 'inner; 148 | } 149 | }; 150 | match message { 151 | Ok(SignalingMessage { intent_id, callee, signal }) => { 152 | if callee != self.own_peer_id { 153 | yield ListenerEvent::Error(Error::UnexpectedMessage(format!("Message for {}", callee))); 154 | continue; 155 | } 156 | debug!("Received {:?} {:?}", intent_id, signal); 157 | if let Some(tx) = open_upgrades.get_mut(&intent_id) { 158 | let _ = tx.start_send(signal); 159 | } else { 160 | let (tx_outbound, rx_outbound) = mpsc::channel(8); 161 | let (mut tx_inbound, rx_inbound) = mpsc::channel(8); 162 | let id = intent_id.clone(); 163 | outbound.insert( 164 | rx_outbound.map(move |m| (id.clone(), m)) 165 | ); 166 | let conn = 167 | PeerConnection::new(&self.config, (tx_outbound, rx_inbound)).map_err(Error::Internal).unwrap(); 168 | tx_inbound.start_send(signal).expect("Channel open"); 169 | open_upgrades.insert(intent_id.clone(), tx_inbound); 170 | let u = conn.accept().map(move |r| (intent_id, r)); 171 | #[cfg(target_arch = "wasm32")] 172 | let u = SendWrapper::new(u); 173 | pending_upgrades.push(u.boxed()); 174 | } 175 | }, 176 | Err(e) => { 177 | error!("Error deserializing message {:?}", e); 178 | } 179 | } 180 | }, 181 | (id, maybe_upgrade) = pending_upgrades.select_next_some() => { 182 | open_upgrades.remove(&id); 183 | yield ListenerEvent::Upgrade { 184 | upgrade: async move { maybe_upgrade.map_err(Into::into) }.boxed(), 185 | remote_addr: addr.clone().with(Protocol::P2p(id.caller.into())), 186 | local_addr: local_addr.clone() 187 | }; 188 | }, 189 | (item, token) = outbound.select_next_some() => { 190 | match item { 191 | StreamYield::Item((intent_id, signal)) => { 192 | let m = SignalingMessage { 193 | intent_id, 194 | signal, 195 | callee: self.own_peer_id 196 | }; 197 | let bytes = serde_json::to_vec(&m).map_err(|e| Error::Internal(e.into())).unwrap(); 198 | let _ = ws_tx.send(Message::Binary(bytes)).await; 199 | } 200 | _ => { 201 | Pin::new(&mut outbound).remove(token); 202 | } 203 | } 204 | } 205 | } 206 | } 207 | }, 208 | Err(e) => { 209 | let wait_for = if let Some(b) = backoff.as_mut() { 210 | *b *= 2; 211 | *b 212 | } else { 213 | backoff.replace(1); 214 | 1 215 | }; 216 | warn!("Outbound connection error to signaling server ({:?}), will retry in {} secs", e,wait_for); 217 | Delay::new(Duration::from_secs(wait_for)).await; 218 | } 219 | } 220 | } 221 | }; 222 | #[cfg(target_arch = "wasm32")] 223 | let s = SendWrapper::new(s); 224 | Ok(s.boxed()) 225 | } 226 | 227 | fn dial( 228 | self, 229 | addr: libp2p::Multiaddr, 230 | ) -> Result> 231 | where 232 | Self: Sized, 233 | { 234 | let (signaling_uri, peer) = extract_uri(&addr) 235 | .ok() 236 | .and_then(|(s, p)| p.map(|p| (s, p))) 237 | .ok_or(libp2p::TransportError::MultiaddrNotSupported(addr))?; 238 | let counter = self.id.fetch_add(1, Ordering::Relaxed); 239 | let signaling_uri = format!("{}/{}/{}", signaling_uri, self.own_peer_id, counter); 240 | 241 | let (tx_outbound, mut rx_outbound) = mpsc::channel(32); 242 | let (mut tx_inbound, rx_inbound) = mpsc::channel(32); 243 | let conn = PeerConnection::new(&self.config, (tx_outbound, rx_inbound)) 244 | .map_err(|e| libp2p::TransportError::Other(e.into()))?; 245 | let identifier = SignalingId { 246 | caller: self.own_peer_id, 247 | counter, 248 | }; 249 | 250 | let fut = async move { 251 | let (mut ws_tx, ws_rx) = CombinedStream::connect(&signaling_uri).await?.split(); 252 | let connection = conn.dial("unused").into_stream().fuse(); 253 | let mut ws_rx = ws_rx.fuse(); 254 | pin_mut!(connection); 255 | loop { 256 | select_biased! { 257 | conn = connection.next() => { 258 | let conn = conn.context("Stream ended")?; 259 | debug!("dial: created data stream"); 260 | break conn; 261 | }, 262 | incoming_ws = ws_rx.next() => { 263 | let incoming_ws = incoming_ws.context("Stream ended")?; 264 | debug!("dial: received message {:?}", incoming_ws); 265 | let message = match incoming_ws { 266 | Ok(Message::Text(t)) => { 267 | Some(serde_json::from_str::(&t)) 268 | }, 269 | Ok(Message::Binary(b)) => { 270 | Some(serde_json::from_slice::(&b[..])) 271 | }, 272 | Ok(Message::Close) => None, 273 | x => anyhow::bail!("Connection to signaling server closed ({:?})", x) 274 | }; 275 | match message { 276 | Some(Ok(m)) if m.intent_id == identifier => tx_inbound.send(m.signal).await?, 277 | Some(Ok(m)) => error!("Received message with unexpected identifier {:?}", m.intent_id), 278 | Some(Err(e)) => error!("Error ws_rxing from WS: {:?}", e), 279 | _ => {}, 280 | } 281 | }, 282 | signal = rx_outbound.next() => { 283 | let signal = signal.context("Stream ended")?; 284 | let m = SignalingMessage { 285 | intent_id: identifier.clone(), 286 | callee: peer, 287 | signal, 288 | }; 289 | debug!("dial: sending message {:?}", m); 290 | let bytes = serde_json::to_vec(&m)?; 291 | ws_tx.send(Message::Binary(bytes)).await?; 292 | }, 293 | } 294 | } 295 | }; 296 | #[cfg(target_arch = "wasm32")] 297 | let fut = SendWrapper::new(fut); 298 | Ok(fut.map_err(Into::into).boxed()) 299 | } 300 | 301 | fn address_translation( 302 | &self, 303 | _listen: &libp2p::Multiaddr, 304 | _observed: &libp2p::Multiaddr, 305 | ) -> Option { 306 | // TODO? 307 | None 308 | } 309 | 310 | fn dial_as_listener( 311 | self, 312 | addr: libp2p::Multiaddr, 313 | ) -> Result< 314 | ::Dial, 315 | libp2p::TransportError<::Error>, 316 | > { 317 | self.dial(addr) 318 | } 319 | } 320 | 321 | pub mod serde_str { 322 | //! Serializes fields annotated with `#[serde(with = "::util::serde_str")]` with their ! 323 | //! `Display` implementation, deserializes fields using `FromStr`. 324 | use std::fmt::Display; 325 | use std::str::FromStr; 326 | 327 | use serde::{de, Deserialize, Deserializer, Serializer}; 328 | 329 | pub fn serialize(value: &T, serializer: S) -> Result 330 | where 331 | T: Display, 332 | S: Serializer, 333 | { 334 | serializer.collect_str(value) 335 | } 336 | 337 | pub fn deserialize<'de, T, D>(deserializer: D) -> Result 338 | where 339 | T: FromStr, 340 | T::Err: Display, 341 | D: Deserializer<'de>, 342 | { 343 | String::deserialize(deserializer)? 344 | .parse() 345 | .map_err(de::Error::custom) 346 | } 347 | } 348 | 349 | // /ip4/ws_signaling_ip/tcp/ws_signaling_port/{ws,wss}/p2p-webrtc-star/p2p/remote_peer_id 350 | fn extract_uri(addr: &Multiaddr) -> anyhow::Result<(String, Option)> { 351 | anyhow::ensure!( 352 | addr.iter().any(|p| p == Protocol::P2pWebRtcStar), 353 | "Only p2p-webrtc-star connections are supported." 354 | ); 355 | let mut protocol = None; 356 | let mut host = None; 357 | let mut port = None; 358 | let mut peer = None; 359 | for i in addr { 360 | if match i { 361 | Protocol::Dns4(h) | Protocol::Dns6(h) => host.replace(h.to_string()).is_some(), 362 | Protocol::Ip4(h) => host.replace(h.to_string()).is_some(), 363 | Protocol::Ip6(h) => host.replace(h.to_string()).is_some(), 364 | Protocol::P2p(p) => peer 365 | .replace( 366 | PeerId::from_multihash(p).map_err(|e| anyhow::anyhow!(format!("{:?}", e)))?, 367 | ) 368 | .is_some(), 369 | Protocol::Tcp(p) => port.replace(p).is_some(), 370 | Protocol::Ws(_) => protocol.replace("ws".to_string()).is_some(), 371 | Protocol::Wss(_) => protocol.replace("wss".to_string()).is_some(), 372 | 373 | _ => false, 374 | } { 375 | anyhow::bail!("Unexpected format: {}", addr) 376 | } 377 | } 378 | if let (Some(protocol), Some(host), Some(port)) = (protocol, host, port) { 379 | Ok((format!("{}://{}:{}", protocol, host, port), peer)) 380 | } else { 381 | anyhow::bail!("Unable to extract signaling uri and peer from {}", addr) 382 | } 383 | } 384 | -------------------------------------------------------------------------------- /libp2p-webrtc/src/ws.rs: -------------------------------------------------------------------------------- 1 | use std::task::Poll; 2 | 3 | #[cfg(not(target_arch = "wasm32"))] 4 | use async_tungstenite::{ 5 | tokio::{connect_async_with_tls_connector, ConnectStream}, 6 | WebSocketStream, 7 | }; 8 | use libp2p::futures::{Sink, Stream}; 9 | use pin_project::pin_project; 10 | 11 | #[pin_project(project = EnumProj)] 12 | enum InnerStream { 13 | #[cfg(not(target_arch = "wasm32"))] 14 | Native(#[pin] WebSocketStream), 15 | #[cfg(target_arch = "wasm32")] 16 | Wasm(#[pin] ws_stream_wasm::WsStream), 17 | } 18 | 19 | #[pin_project] 20 | pub(crate) struct CombinedStream { 21 | #[pin] 22 | inner: InnerStream, 23 | } 24 | 25 | #[derive(Debug)] 26 | #[allow(dead_code)] 27 | pub(crate) enum Message { 28 | Text(String), 29 | Binary(Vec), 30 | Ping(Vec), 31 | Pong(Vec), 32 | Close, 33 | } 34 | 35 | #[cfg(not(target_arch = "wasm32"))] 36 | impl From for Message { 37 | fn from(m: async_tungstenite::tungstenite::Message) -> Self { 38 | use Message::*; 39 | match m { 40 | async_tungstenite::tungstenite::Message::Text(t) => Text(t), 41 | async_tungstenite::tungstenite::Message::Binary(b) => Binary(b), 42 | async_tungstenite::tungstenite::Message::Ping(p) => Ping(p), 43 | async_tungstenite::tungstenite::Message::Pong(p) => Pong(p), 44 | async_tungstenite::tungstenite::Message::Close(_) => Close, 45 | async_tungstenite::tungstenite::Message::Frame(_) => unreachable!(), 46 | } 47 | } 48 | } 49 | #[cfg(not(target_arch = "wasm32"))] 50 | impl From for async_tungstenite::tungstenite::Message { 51 | fn from(o: Message) -> Self { 52 | match o { 53 | Message::Text(t) => async_tungstenite::tungstenite::Message::Text(t), 54 | Message::Binary(b) => async_tungstenite::tungstenite::Message::Binary(b), 55 | Message::Ping(p) => async_tungstenite::tungstenite::Message::Ping(p), 56 | Message::Pong(p) => async_tungstenite::tungstenite::Message::Pong(p), 57 | Message::Close => async_tungstenite::tungstenite::Message::Close(None), 58 | } 59 | } 60 | } 61 | 62 | impl CombinedStream { 63 | pub(crate) async fn connect(uri: &str) -> anyhow::Result { 64 | #[cfg(not(target_arch = "wasm32"))] 65 | let inner = InnerStream::Native(connect_async_with_tls_connector(uri, None).await?.0); 66 | #[cfg(target_arch = "wasm32")] 67 | let inner = InnerStream::Wasm(ws_stream_wasm::WsMeta::connect(uri, None).await?.1); 68 | Ok(Self { inner }) 69 | } 70 | } 71 | 72 | impl Stream for CombinedStream { 73 | type Item = anyhow::Result; 74 | 75 | fn poll_next( 76 | self: std::pin::Pin<&mut Self>, 77 | cx: &mut std::task::Context<'_>, 78 | ) -> Poll> { 79 | match self.project().inner.project() { 80 | #[cfg(not(target_arch = "wasm32"))] 81 | EnumProj::Native(s) => s.poll_next(cx).map_ok(Message::from).map_err(Into::into), 82 | #[cfg(target_arch = "wasm32")] 83 | EnumProj::Wasm(s) => match s.poll_next(cx) { 84 | Poll::Ready(Some(x)) => match x { 85 | ws_stream_wasm::WsMessage::Text(t) => Poll::Ready(Some(Ok(Message::Text(t)))), 86 | ws_stream_wasm::WsMessage::Binary(t) => { 87 | Poll::Ready(Some(Ok(Message::Binary(t)))) 88 | } 89 | }, 90 | Poll::Ready(None) => Poll::Ready(None), 91 | Poll::Pending => Poll::Pending, 92 | }, 93 | } 94 | } 95 | } 96 | 97 | impl Sink for CombinedStream { 98 | type Error = anyhow::Error; 99 | 100 | fn poll_ready( 101 | self: std::pin::Pin<&mut Self>, 102 | cx: &mut std::task::Context<'_>, 103 | ) -> std::task::Poll> { 104 | match self.project().inner.project() { 105 | #[cfg(not(target_arch = "wasm32"))] 106 | EnumProj::Native(s) => s.poll_ready(cx).map_err(Into::into), 107 | #[cfg(target_arch = "wasm32")] 108 | EnumProj::Wasm(s) => s.poll_ready(cx).map_err(Into::into), 109 | } 110 | } 111 | 112 | fn start_send(self: std::pin::Pin<&mut Self>, item: Message) -> Result<(), Self::Error> { 113 | match self.project().inner.project() { 114 | #[cfg(not(target_arch = "wasm32"))] 115 | EnumProj::Native(s) => s.start_send(item.into()).map_err(Into::into), 116 | #[cfg(target_arch = "wasm32")] 117 | EnumProj::Wasm(s) => { 118 | if let Some(msg) = match item { 119 | Message::Text(t) => Some(ws_stream_wasm::WsMessage::Text(t)), 120 | Message::Binary(b) => Some(ws_stream_wasm::WsMessage::Binary(b)), 121 | _ => None, 122 | } { 123 | s.start_send(msg).map_err(Into::into) 124 | } else { 125 | Ok(()) 126 | } 127 | } 128 | } 129 | } 130 | 131 | fn poll_flush( 132 | self: std::pin::Pin<&mut Self>, 133 | cx: &mut std::task::Context<'_>, 134 | ) -> std::task::Poll> { 135 | match self.project().inner.project() { 136 | #[cfg(not(target_arch = "wasm32"))] 137 | EnumProj::Native(s) => s.poll_flush(cx).map_err(Into::into), 138 | #[cfg(target_arch = "wasm32")] 139 | EnumProj::Wasm(s) => s.poll_flush(cx).map_err(Into::into), 140 | } 141 | } 142 | 143 | fn poll_close( 144 | self: std::pin::Pin<&mut Self>, 145 | cx: &mut std::task::Context<'_>, 146 | ) -> std::task::Poll> { 147 | match self.project().inner.project() { 148 | #[cfg(not(target_arch = "wasm32"))] 149 | EnumProj::Native(s) => s.poll_close(cx).map_err(Into::into), 150 | #[cfg(target_arch = "wasm32")] 151 | EnumProj::Wasm(s) => s.poll_close(cx).map_err(Into::into), 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /libp2p-webrtc/tests/check-public-server.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | mod tests { 3 | use libp2p::{ 4 | core::{self, transport::upgrade, PeerId}, 5 | futures::{future, StreamExt}, 6 | identity, mplex, noise, 7 | ping::{Ping, PingConfig, PingEvent, PingSuccess}, 8 | swarm::{SwarmBuilder, SwarmEvent}, 9 | yamux, Multiaddr, NetworkBehaviour, Swarm, Transport, 10 | }; 11 | use libp2p_webrtc::WebRtcTransport; 12 | use log::*; 13 | use std::time::Duration; 14 | use tokio::time::timeout; 15 | use tracing_subscriber::fmt; 16 | 17 | // This test checks the publicly available signaling server for availability and compliance 18 | const SIGNALING_SERVER: &str = "/dns4/local1st.net/tcp/443/wss/p2p-webrtc-star"; 19 | 20 | fn mk_swarm() -> Swarm { 21 | let identity = identity::Keypair::generate_ed25519(); 22 | 23 | let peer_id = PeerId::from(identity.public()); 24 | let transport = { 25 | let base = WebRtcTransport::new(peer_id, vec!["stun:stun.l.google.com:19302"]); 26 | let noise_keys = noise::Keypair::::new() 27 | .into_authentic(&identity) 28 | .expect("Signing libp2p-noise static DH keypair failed."); 29 | 30 | base.upgrade(upgrade::Version::V1Lazy) 31 | .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) 32 | .multiplex(core::upgrade::SelectUpgrade::new( 33 | yamux::YamuxConfig::default(), 34 | mplex::MplexConfig::default(), 35 | )) 36 | .timeout(std::time::Duration::from_secs(20)) 37 | .boxed() 38 | }; 39 | 40 | SwarmBuilder::new( 41 | transport, 42 | MyBehaviour { 43 | ping: Ping::new( 44 | PingConfig::new() 45 | .with_interval(Duration::from_secs(1)) 46 | .with_keep_alive(true), 47 | ), 48 | }, 49 | peer_id, 50 | ) 51 | .executor(Box::new(|f| { 52 | tokio::spawn(f); 53 | })) 54 | .build() 55 | } 56 | 57 | #[tokio::test] 58 | async fn check_public_server() -> anyhow::Result<()> { 59 | fmt::init(); 60 | let mut swarm_0 = mk_swarm(); 61 | let peer_0 = *swarm_0.local_peer_id(); 62 | info!("Local peer id 0: {}", peer_0); 63 | let mut swarm_1 = mk_swarm(); 64 | let peer_1 = *swarm_1.local_peer_id(); 65 | info!("Local peer id 1: {}", peer_1); 66 | 67 | // /ip4/ws_signaling_ip/tcp/ws_signaling_port/{ws,wss}/p2p-webrtc-star/p2p/remote_peer_id 68 | swarm_0 69 | .listen_on(SIGNALING_SERVER.parse().unwrap()) 70 | .unwrap(); 71 | 72 | swarm_1 73 | .listen_on(SIGNALING_SERVER.parse().unwrap()) 74 | .unwrap(); 75 | 76 | let s0 = async move { 77 | swarm_0.dial(format!("{}/p2p/{}", SIGNALING_SERVER, peer_1).parse::()?)?; 78 | 79 | while let Some(event) = swarm_0.next().await { 80 | match event { 81 | SwarmEvent::NewListenAddr { address, .. } => { 82 | info!("Listening on {}", address); 83 | } 84 | 85 | SwarmEvent::Behaviour(MyEvent::Ping(PingEvent { 86 | peer, 87 | result: Ok(PingSuccess::Ping { rtt }), 88 | })) if peer == peer_1 => { 89 | info!("Ping to {} is {}ms", peer, rtt.as_millis()); 90 | return Ok(swarm_0); 91 | } 92 | other => { 93 | info!("Unhandled {:?}", other); 94 | } 95 | } 96 | } 97 | anyhow::Result::<_, anyhow::Error>::Ok(swarm_0) 98 | }; 99 | let s1 = async move { 100 | while let Some(event) = swarm_1.next().await { 101 | match event { 102 | SwarmEvent::NewListenAddr { address, .. } => { 103 | info!("Listening on {}", address); 104 | } 105 | 106 | SwarmEvent::Behaviour(MyEvent::Ping(PingEvent { 107 | peer, 108 | result: Ok(PingSuccess::Ping { rtt }), 109 | })) if peer == peer_0 => { 110 | info!("Ping to {} is {}ms", peer, rtt.as_millis()); 111 | return Ok(swarm_1); 112 | } 113 | other => { 114 | info!("Unhandled {:?}", other); 115 | } 116 | } 117 | } 118 | anyhow::Result::<_, anyhow::Error>::Ok(swarm_1) 119 | }; 120 | timeout(Duration::from_secs(5), future::try_join(s0, s1)).await??; 121 | Ok(()) 122 | } 123 | 124 | #[derive(Debug)] 125 | enum MyEvent { 126 | Ping(PingEvent), 127 | } 128 | 129 | impl From for MyEvent { 130 | fn from(event: PingEvent) -> Self { 131 | MyEvent::Ping(event) 132 | } 133 | } 134 | 135 | #[derive(NetworkBehaviour)] 136 | #[behaviour(event_process = false)] 137 | #[behaviour(out_event = "MyEvent")] 138 | struct MyBehaviour { 139 | ping: Ping, 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /libp2p-webrtc/tests/interop.rs: -------------------------------------------------------------------------------- 1 | #[cfg(target_arch = "wasm32")] 2 | mod tests { 3 | use libp2p::{ 4 | core::{self, transport::upgrade, PeerId}, 5 | futures::StreamExt, 6 | identity, mplex, noise, 7 | ping::{Ping, PingConfig, PingEvent, PingSuccess}, 8 | swarm::{SwarmBuilder, SwarmEvent}, 9 | yamux, Multiaddr, NetworkBehaviour, Swarm, Transport, 10 | }; 11 | use libp2p_webrtc::WebRtcTransport; 12 | use log::*; 13 | use std::time::Duration; 14 | use wasm_bindgen_futures::spawn_local; 15 | use wasm_bindgen_test::{wasm_bindgen_test, wasm_bindgen_test_configure}; 16 | 17 | wasm_bindgen_test_configure!(run_in_browser); 18 | 19 | fn mk_swarm() -> Swarm { 20 | let identity = identity::Keypair::generate_ed25519(); 21 | 22 | let peer_id = PeerId::from(identity.public()); 23 | let transport = { 24 | let base = WebRtcTransport::new(peer_id, vec!["stun:stun.l.google.com:19302"]); 25 | let noise_keys = noise::Keypair::::new() 26 | .into_authentic(&identity) 27 | .expect("Signing libp2p-noise static DH keypair failed."); 28 | 29 | base.upgrade(upgrade::Version::V1Lazy) 30 | .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) 31 | .multiplex(core::upgrade::SelectUpgrade::new( 32 | yamux::YamuxConfig::default(), 33 | mplex::MplexConfig::default(), 34 | )) 35 | .timeout(std::time::Duration::from_secs(20)) 36 | .boxed() 37 | }; 38 | 39 | SwarmBuilder::new( 40 | transport, 41 | MyBehaviour { 42 | ping: Ping::new( 43 | PingConfig::new() 44 | .with_interval(Duration::from_secs(1)) 45 | .with_keep_alive(true), 46 | ), 47 | }, 48 | peer_id, 49 | ) 50 | .executor(Box::new(|f| { 51 | spawn_local(f); 52 | })) 53 | .build() 54 | } 55 | 56 | #[wasm_bindgen_test] 57 | async fn interop() { 58 | console_log::init_with_level(Level::Trace).unwrap(); 59 | 60 | // make sure signaling server is started 61 | let mut swarm_0 = mk_swarm(); 62 | let peer_0 = *swarm_0.local_peer_id(); 63 | info!("Local peer id 0: {}", peer_0); 64 | 65 | // /ip4/ws_signaling_ip/tcp/ws_signaling_port/{ws,wss}/p2p-webrtc-star/p2p/remote_peer_id 66 | swarm_0 67 | .listen_on( 68 | "/ip4/127.0.0.1/tcp/8001/ws/p2p-webrtc-star" 69 | .parse() 70 | .unwrap(), 71 | ) 72 | .unwrap(); 73 | 74 | swarm_0 75 | .dial( 76 | format!( 77 | "/ip4/127.0.0.1/tcp/8001/ws/p2p-webrtc-star{}", 78 | option_env!("TEST_PEER").expect( 79 | "This test is only supposed to be run from the `integration` crate" 80 | ) 81 | ) 82 | .parse::() 83 | .unwrap(), 84 | ) 85 | .unwrap(); 86 | 87 | while let Some(event) = swarm_0.next().await { 88 | match event { 89 | SwarmEvent::NewListenAddr { address, .. } => { 90 | info!("Listening on {}", address); 91 | } 92 | 93 | SwarmEvent::Behaviour(MyEvent::Ping(PingEvent { 94 | peer, 95 | result: Ok(PingSuccess::Ping { rtt }), 96 | })) => { 97 | info!("Ping to {} is {}ms", peer, rtt.as_millis()); 98 | return; 99 | } 100 | other => { 101 | info!("Unhandled {:?}", other); 102 | } 103 | } 104 | } 105 | panic!(); 106 | } 107 | 108 | #[derive(Debug)] 109 | enum MyEvent { 110 | Ping(PingEvent), 111 | } 112 | 113 | impl From for MyEvent { 114 | fn from(event: PingEvent) -> Self { 115 | MyEvent::Ping(event) 116 | } 117 | } 118 | 119 | #[derive(NetworkBehaviour)] 120 | #[behaviour(event_process = false)] 121 | #[behaviour(out_event = "MyEvent")] 122 | struct MyBehaviour { 123 | ping: Ping, 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /libp2p-webrtc/tests/native-native.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | mod tests { 3 | use libp2p::{ 4 | core::{self, transport::upgrade, PeerId}, 5 | futures::{future, FutureExt, StreamExt}, 6 | identity, mplex, noise, 7 | ping::{Ping, PingConfig, PingEvent, PingSuccess}, 8 | swarm::{SwarmBuilder, SwarmEvent}, 9 | yamux, Multiaddr, NetworkBehaviour, Swarm, Transport, 10 | }; 11 | use libp2p_webrtc::WebRtcTransport; 12 | use log::*; 13 | use std::{ 14 | collections::BTreeSet, 15 | process::Stdio, 16 | sync::{ 17 | atomic::{AtomicBool, Ordering}, 18 | Arc, 19 | }, 20 | time::Duration, 21 | }; 22 | use tokio::{ 23 | io::{AsyncBufReadExt, BufReader}, 24 | process::{Child, Command}, 25 | time::timeout, 26 | }; 27 | use tracing_subscriber::fmt; 28 | 29 | fn mk_swarm() -> Swarm { 30 | let identity = identity::Keypair::generate_ed25519(); 31 | 32 | let peer_id = PeerId::from(identity.public()); 33 | let transport = { 34 | let base = WebRtcTransport::new(peer_id, vec!["stun:stun.l.google.com:19302"]); 35 | let noise_keys = noise::Keypair::::new() 36 | .into_authentic(&identity) 37 | .expect("Signing libp2p-noise static DH keypair failed."); 38 | 39 | base.upgrade(upgrade::Version::V1Lazy) 40 | .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) 41 | .multiplex(core::upgrade::SelectUpgrade::new( 42 | yamux::YamuxConfig::default(), 43 | mplex::MplexConfig::default(), 44 | )) 45 | .timeout(std::time::Duration::from_secs(20)) 46 | .boxed() 47 | }; 48 | 49 | SwarmBuilder::new( 50 | transport, 51 | MyBehaviour { 52 | ping: Ping::new( 53 | PingConfig::new() 54 | .with_interval(Duration::from_secs(1)) 55 | .with_keep_alive(true), 56 | ), 57 | }, 58 | peer_id, 59 | ) 60 | .executor(Box::new(|f| { 61 | tokio::spawn(f); 62 | })) 63 | .build() 64 | } 65 | 66 | async fn start_signaling_server() -> anyhow::Result { 67 | let mut cmd = Command::new("cargo"); 68 | cmd.args(&["run", "--", "--interface", "127.0.0.1"]) 69 | .current_dir("../signal") 70 | .stdout(Stdio::piped()) 71 | .stderr(Stdio::inherit()) 72 | .kill_on_drop(true); 73 | let mut server = cmd.spawn()?; 74 | let stdout = server.stdout.take().unwrap(); 75 | let mut reader = BufReader::new(stdout).lines(); 76 | while let Some(line) = reader.next_line().await? { 77 | if line.starts_with("Listening on") { 78 | break; 79 | } 80 | } 81 | println!("Signaling server started!"); 82 | server.stdout.replace(reader.into_inner().into_inner()); 83 | Ok(server) 84 | } 85 | 86 | #[tokio::test] 87 | async fn native_native() -> anyhow::Result<()> { 88 | let _ = fmt::try_init(); 89 | { 90 | // wait for server init 91 | let mut _server = start_signaling_server().await?; 92 | native_native_single().await?; 93 | native_native_concurrent().await?; 94 | } 95 | { 96 | // late server init 97 | future::try_join3( 98 | async move { 99 | tokio::time::sleep(Duration::from_secs(5)).await; 100 | start_signaling_server().await 101 | }, 102 | native_native_single(), 103 | native_native_concurrent(), 104 | ) 105 | .await?; 106 | } 107 | Ok(()) 108 | } 109 | 110 | async fn native_native_single() -> anyhow::Result<()> { 111 | let mut swarm_0 = mk_swarm(); 112 | let peer_0 = *swarm_0.local_peer_id(); 113 | info!("Local peer id 0: {}", peer_0); 114 | let mut swarm_1 = mk_swarm(); 115 | let peer_1 = *swarm_1.local_peer_id(); 116 | info!("Local peer id 1: {}", peer_1); 117 | 118 | // /ip4/ws_signaling_ip/tcp/ws_signaling_port/{ws,wss}/p2p-webrtc-star/p2p/remote_peer_id 119 | swarm_0 120 | .listen_on( 121 | "/ip4/127.0.0.1/tcp/8000/ws/p2p-webrtc-star" 122 | .parse() 123 | .unwrap(), 124 | ) 125 | .unwrap(); 126 | 127 | swarm_1 128 | .listen_on( 129 | "/ip4/127.0.0.1/tcp/8000/ws/p2p-webrtc-star" 130 | .parse() 131 | .unwrap(), 132 | ) 133 | .unwrap(); 134 | 135 | let s0 = async move { 136 | while let Some(event) = swarm_0.next().await { 137 | match event { 138 | SwarmEvent::NewListenAddr { address, .. } => { 139 | info!("Listening on {}", address); 140 | 141 | swarm_0.dial( 142 | format!("/ip4/127.0.0.1/tcp/8000/ws/p2p-webrtc-star/p2p/{}", peer_1) 143 | .parse::()?, 144 | )?; 145 | } 146 | 147 | SwarmEvent::Behaviour(MyEvent::Ping(PingEvent { 148 | peer, 149 | result: Ok(PingSuccess::Ping { rtt }), 150 | })) if peer == peer_1 => { 151 | info!("Ping to {} is {}ms", peer, rtt.as_millis()); 152 | return Ok(swarm_0); 153 | } 154 | other => { 155 | info!("Unhandled {:?}", other); 156 | } 157 | } 158 | } 159 | anyhow::Result::<_, anyhow::Error>::Ok(swarm_0) 160 | }; 161 | let s1 = async move { 162 | while let Some(event) = swarm_1.next().await { 163 | match event { 164 | SwarmEvent::NewListenAddr { address, .. } => { 165 | info!("Listening on {}", address); 166 | } 167 | 168 | SwarmEvent::Behaviour(MyEvent::Ping(PingEvent { 169 | peer, 170 | result: Ok(PingSuccess::Ping { rtt }), 171 | })) if peer == peer_0 => { 172 | info!("Ping to {} is {}ms", peer, rtt.as_millis()); 173 | return Ok(swarm_1); 174 | } 175 | other => { 176 | info!("Unhandled {:?}", other); 177 | } 178 | } 179 | } 180 | anyhow::Result::<_, anyhow::Error>::Ok(swarm_1) 181 | }; 182 | timeout(Duration::from_secs(10), future::try_join(s0, s1)).await??; 183 | Ok(()) 184 | } 185 | 186 | async fn native_native_concurrent() -> anyhow::Result<()> { 187 | info!("Signaling server started!"); 188 | let mut listener = mk_swarm(); 189 | let peer_0 = *listener.local_peer_id(); 190 | info!("Local peer id 0: {}", peer_0); 191 | 192 | // /ip4/ws_signaling_ip/tcp/ws_signaling_port/{ws,wss}/p2p-webrtc-star/p2p/remote_peer_id 193 | listener 194 | .listen_on( 195 | "/ip4/127.0.0.1/tcp/8000/ws/p2p-webrtc-star" 196 | .parse() 197 | .unwrap(), 198 | ) 199 | .unwrap(); 200 | let listener_connected = Arc::new(AtomicBool::new(false)); 201 | let connected = listener_connected.clone(); 202 | 203 | const NUM_DIALERS: usize = 10; 204 | let s0 = async move { 205 | let mut dialed = BTreeSet::new(); 206 | while let Some(event) = listener.next().await { 207 | match event { 208 | SwarmEvent::NewListenAddr { address, .. } => { 209 | info!("Listening on {}", address); 210 | connected.store(true, Ordering::Relaxed); 211 | } 212 | 213 | SwarmEvent::Behaviour(MyEvent::Ping(PingEvent { 214 | peer, 215 | result: Ok(PingSuccess::Ping { rtt }), 216 | })) => { 217 | info!("Ping to {} is {}ms", peer, rtt.as_millis()); 218 | dialed.insert(peer); 219 | if dialed.len() >= NUM_DIALERS { 220 | return Ok(listener); 221 | } 222 | } 223 | other => { 224 | info!("Unhandled {:?}", other); 225 | } 226 | } 227 | } 228 | anyhow::Result::<_, anyhow::Error>::Ok(listener) 229 | } 230 | .boxed(); 231 | let dialers = (0..NUM_DIALERS).map(|_| mk_swarm()).map(move |mut swarm| { 232 | let connected = listener_connected.clone(); 233 | async move { 234 | while !connected.load(Ordering::Relaxed) { 235 | tokio::time::sleep(Duration::from_millis(50)).await; 236 | } 237 | swarm.dial( 238 | format!("/ip4/127.0.0.1/tcp/8000/ws/p2p-webrtc-star/p2p/{}", peer_0) 239 | .parse::()?, 240 | )?; 241 | while let Some(event) = swarm.next().await { 242 | match event { 243 | SwarmEvent::NewListenAddr { address, .. } => { 244 | info!("Listening on {}", address); 245 | } 246 | 247 | SwarmEvent::Behaviour(MyEvent::Ping(PingEvent { 248 | peer, 249 | result: Ok(PingSuccess::Ping { rtt }), 250 | })) if peer == peer_0 => { 251 | info!("Ping to {} is {}ms", peer, rtt.as_millis()); 252 | return Ok(swarm); 253 | } 254 | other => { 255 | info!("Unhandled {:?}", other); 256 | } 257 | } 258 | } 259 | anyhow::Result::<_, anyhow::Error>::Ok(swarm) 260 | } 261 | .boxed() 262 | }); 263 | 264 | timeout( 265 | Duration::from_secs(10), 266 | future::try_join_all(std::iter::once(s0).chain(dialers)), 267 | ) 268 | .await??; 269 | Ok(()) 270 | } 271 | 272 | #[derive(Debug)] 273 | enum MyEvent { 274 | Ping(PingEvent), 275 | } 276 | 277 | impl From for MyEvent { 278 | fn from(event: PingEvent) -> Self { 279 | MyEvent::Ping(event) 280 | } 281 | } 282 | 283 | #[derive(NetworkBehaviour)] 284 | #[behaviour(event_process = false)] 285 | #[behaviour(out_event = "MyEvent")] 286 | struct MyBehaviour { 287 | ping: Ping, 288 | } 289 | } 290 | -------------------------------------------------------------------------------- /libp2p-webrtc/tests/wasm-wasm.rs: -------------------------------------------------------------------------------- 1 | #[cfg(target_arch = "wasm32")] 2 | mod tests { 3 | use libp2p::{ 4 | core::{self, transport::upgrade, PeerId}, 5 | futures::{future, StreamExt}, 6 | identity, mplex, noise, 7 | ping::{Ping, PingConfig, PingEvent, PingSuccess}, 8 | swarm::{SwarmBuilder, SwarmEvent}, 9 | yamux, Multiaddr, NetworkBehaviour, Swarm, Transport, 10 | }; 11 | use libp2p_webrtc::WebRtcTransport; 12 | use log::*; 13 | use std::time::Duration; 14 | use wasm_bindgen_futures::spawn_local; 15 | use wasm_bindgen_test::{wasm_bindgen_test, wasm_bindgen_test_configure}; 16 | 17 | wasm_bindgen_test_configure!(run_in_browser); 18 | 19 | fn mk_swarm() -> Swarm { 20 | let identity = identity::Keypair::generate_ed25519(); 21 | 22 | let peer_id = PeerId::from(identity.public()); 23 | let transport = { 24 | let base = WebRtcTransport::new(peer_id, vec!["stun:stun.l.google.com:19302"]); 25 | let noise_keys = noise::Keypair::::new() 26 | .into_authentic(&identity) 27 | .expect("Signing libp2p-noise static DH keypair failed."); 28 | 29 | base.upgrade(upgrade::Version::V1Lazy) 30 | .authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated()) 31 | .multiplex(core::upgrade::SelectUpgrade::new( 32 | yamux::YamuxConfig::default(), 33 | mplex::MplexConfig::default(), 34 | )) 35 | .timeout(std::time::Duration::from_secs(20)) 36 | .boxed() 37 | }; 38 | 39 | SwarmBuilder::new( 40 | transport, 41 | MyBehaviour { 42 | ping: Ping::new( 43 | PingConfig::new() 44 | .with_interval(Duration::from_secs(1)) 45 | .with_keep_alive(true), 46 | ), 47 | }, 48 | peer_id, 49 | ) 50 | .executor(Box::new(|f| { 51 | spawn_local(f); 52 | })) 53 | .build() 54 | } 55 | 56 | #[wasm_bindgen_test] 57 | async fn wasm_wasm() { 58 | console_log::init_with_level(Level::Trace).unwrap(); 59 | 60 | // make sure signaling server is started 61 | let mut swarm_0 = mk_swarm(); 62 | let peer_0 = *swarm_0.local_peer_id(); 63 | info!("Local peer id 0: {}", peer_0); 64 | let mut swarm_1 = mk_swarm(); 65 | let peer_1 = *swarm_1.local_peer_id(); 66 | info!("Local peer id 1: {}", peer_1); 67 | 68 | // /ip4/ws_signaling_ip/tcp/ws_signaling_port/{ws,wss}/p2p-webrtc-star/p2p/remote_peer_id 69 | swarm_0 70 | .listen_on( 71 | "/ip4/127.0.0.1/tcp/8001/ws/p2p-webrtc-star" 72 | .parse() 73 | .unwrap(), 74 | ) 75 | .unwrap(); 76 | 77 | swarm_1 78 | .listen_on( 79 | "/ip4/127.0.0.1/tcp/8001/ws/p2p-webrtc-star" 80 | .parse() 81 | .unwrap(), 82 | ) 83 | .unwrap(); 84 | 85 | let s0 = async move { 86 | swarm_0.dial( 87 | format!("/ip4/127.0.0.1/tcp/8001/ws/p2p-webrtc-star/p2p/{}", peer_1) 88 | .parse::()?, 89 | )?; 90 | 91 | while let Some(event) = swarm_0.next().await { 92 | match event { 93 | SwarmEvent::NewListenAddr { address, .. } => { 94 | info!("Listening on {}", address); 95 | } 96 | 97 | SwarmEvent::Behaviour(MyEvent::Ping(PingEvent { 98 | peer, 99 | result: Ok(PingSuccess::Ping { rtt }), 100 | })) if peer == peer_1 => { 101 | info!("Ping to {} is {}ms", peer, rtt.as_millis()); 102 | return Ok(()); 103 | } 104 | other => { 105 | info!("Unhandled {:?}", other); 106 | } 107 | } 108 | } 109 | anyhow::Result::<_, anyhow::Error>::Ok(()) 110 | }; 111 | let s1 = async move { 112 | while let Some(event) = swarm_1.next().await { 113 | match event { 114 | SwarmEvent::NewListenAddr { address, .. } => { 115 | info!("Listening on {}", address); 116 | } 117 | 118 | SwarmEvent::Behaviour(MyEvent::Ping(PingEvent { 119 | peer, 120 | result: Ok(PingSuccess::Ping { rtt }), 121 | })) if peer == peer_0 => { 122 | info!("Ping to {} is {}ms", peer, rtt.as_millis()); 123 | return Ok(()); 124 | } 125 | other => { 126 | info!("Unhandled {:?}", other); 127 | } 128 | } 129 | } 130 | anyhow::Result::<_, anyhow::Error>::Ok(()) 131 | }; 132 | 133 | future::try_join(s0, s1).await.unwrap(); 134 | } 135 | 136 | #[derive(Debug)] 137 | enum MyEvent { 138 | Ping(PingEvent), 139 | } 140 | 141 | impl From for MyEvent { 142 | fn from(event: PingEvent) -> Self { 143 | MyEvent::Ping(event) 144 | } 145 | } 146 | 147 | #[derive(NetworkBehaviour)] 148 | #[behaviour(event_process = false)] 149 | #[behaviour(out_event = "MyEvent")] 150 | struct MyBehaviour { 151 | ping: Ping, 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "stable" 3 | components = [ "rustfmt", "rust-src", "clippy" ] 4 | profile = "minimal" 5 | targets = [ "wasm32-unknown-unknown", "x86_64-unknown-linux-gnu" ] 6 | -------------------------------------------------------------------------------- /signal/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "acme-lib" 7 | version = "0.8.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "292ac9d513052341a7f5bdae61f31c4dc93c1dce2598508f52709df08cecc8b0" 10 | dependencies = [ 11 | "base64", 12 | "lazy_static", 13 | "log", 14 | "openssl", 15 | "serde", 16 | "serde_json", 17 | "time 0.1.43", 18 | "ureq", 19 | ] 20 | 21 | [[package]] 22 | name = "ansi_term" 23 | version = "0.12.1" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 26 | dependencies = [ 27 | "winapi", 28 | ] 29 | 30 | [[package]] 31 | name = "anyhow" 32 | version = "1.0.44" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" 35 | 36 | [[package]] 37 | name = "async-tungstenite" 38 | version = "0.15.0" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | checksum = "742cc7dcb20b2f84a42f4691aa999070ec7e78f8e7e7438bf14be7017b44907e" 41 | dependencies = [ 42 | "futures-io", 43 | "futures-util", 44 | "log", 45 | "pin-project-lite", 46 | "rustls-native-certs", 47 | "tokio", 48 | "tokio-rustls", 49 | "tungstenite 0.15.0", 50 | ] 51 | 52 | [[package]] 53 | name = "atty" 54 | version = "0.2.14" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 57 | dependencies = [ 58 | "hermit-abi", 59 | "libc", 60 | "winapi", 61 | ] 62 | 63 | [[package]] 64 | name = "autocfg" 65 | version = "1.0.1" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 68 | 69 | [[package]] 70 | name = "base-x" 71 | version = "0.2.8" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" 74 | 75 | [[package]] 76 | name = "base64" 77 | version = "0.13.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 80 | 81 | [[package]] 82 | name = "bitflags" 83 | version = "1.3.2" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 86 | 87 | [[package]] 88 | name = "block-buffer" 89 | version = "0.9.0" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 92 | dependencies = [ 93 | "generic-array", 94 | ] 95 | 96 | [[package]] 97 | name = "buf_redux" 98 | version = "0.8.4" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" 101 | dependencies = [ 102 | "memchr", 103 | "safemem", 104 | ] 105 | 106 | [[package]] 107 | name = "bumpalo" 108 | version = "3.7.1" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" 111 | 112 | [[package]] 113 | name = "byteorder" 114 | version = "1.4.3" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 117 | 118 | [[package]] 119 | name = "bytes" 120 | version = "1.1.0" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" 123 | 124 | [[package]] 125 | name = "cc" 126 | version = "1.0.70" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" 129 | 130 | [[package]] 131 | name = "cfg-if" 132 | version = "1.0.0" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 135 | 136 | [[package]] 137 | name = "chrono" 138 | version = "0.4.19" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 141 | dependencies = [ 142 | "libc", 143 | "num-integer", 144 | "num-traits", 145 | "winapi", 146 | ] 147 | 148 | [[package]] 149 | name = "chunked_transfer" 150 | version = "1.4.0" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" 153 | 154 | [[package]] 155 | name = "clap" 156 | version = "3.0.0-beta.4" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "fcd70aa5597dbc42f7217a543f9ef2768b2ef823ba29036072d30e1d88e98406" 159 | dependencies = [ 160 | "atty", 161 | "bitflags", 162 | "clap_derive", 163 | "indexmap", 164 | "lazy_static", 165 | "os_str_bytes", 166 | "strsim", 167 | "termcolor", 168 | "textwrap", 169 | "vec_map", 170 | ] 171 | 172 | [[package]] 173 | name = "clap_derive" 174 | version = "3.0.0-beta.4" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "0b5bb0d655624a0b8770d1c178fb8ffcb1f91cc722cb08f451e3dc72465421ac" 177 | dependencies = [ 178 | "heck", 179 | "proc-macro-error", 180 | "proc-macro2", 181 | "quote", 182 | "syn", 183 | ] 184 | 185 | [[package]] 186 | name = "const_fn" 187 | version = "0.4.8" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7" 190 | 191 | [[package]] 192 | name = "cookie" 193 | version = "0.14.4" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" 196 | dependencies = [ 197 | "percent-encoding", 198 | "time 0.2.27", 199 | "version_check", 200 | ] 201 | 202 | [[package]] 203 | name = "cookie_store" 204 | version = "0.12.0" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "3818dfca4b0cb5211a659bbcbb94225b7127407b2b135e650d717bfb78ab10d3" 207 | dependencies = [ 208 | "cookie", 209 | "idna", 210 | "log", 211 | "publicsuffix", 212 | "serde", 213 | "serde_json", 214 | "time 0.2.27", 215 | "url", 216 | ] 217 | 218 | [[package]] 219 | name = "core-foundation" 220 | version = "0.9.1" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" 223 | dependencies = [ 224 | "core-foundation-sys", 225 | "libc", 226 | ] 227 | 228 | [[package]] 229 | name = "core-foundation-sys" 230 | version = "0.8.2" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" 233 | 234 | [[package]] 235 | name = "cpufeatures" 236 | version = "0.2.1" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" 239 | dependencies = [ 240 | "libc", 241 | ] 242 | 243 | [[package]] 244 | name = "digest" 245 | version = "0.9.0" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 248 | dependencies = [ 249 | "generic-array", 250 | ] 251 | 252 | [[package]] 253 | name = "discard" 254 | version = "1.0.4" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" 257 | 258 | [[package]] 259 | name = "fnv" 260 | version = "1.0.7" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 263 | 264 | [[package]] 265 | name = "foreign-types" 266 | version = "0.3.2" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 269 | dependencies = [ 270 | "foreign-types-shared", 271 | ] 272 | 273 | [[package]] 274 | name = "foreign-types-shared" 275 | version = "0.1.1" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 278 | 279 | [[package]] 280 | name = "form_urlencoded" 281 | version = "1.0.1" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 284 | dependencies = [ 285 | "matches", 286 | "percent-encoding", 287 | ] 288 | 289 | [[package]] 290 | name = "futures" 291 | version = "0.3.17" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" 294 | dependencies = [ 295 | "futures-channel", 296 | "futures-core", 297 | "futures-executor", 298 | "futures-io", 299 | "futures-sink", 300 | "futures-task", 301 | "futures-util", 302 | ] 303 | 304 | [[package]] 305 | name = "futures-channel" 306 | version = "0.3.17" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" 309 | dependencies = [ 310 | "futures-core", 311 | "futures-sink", 312 | ] 313 | 314 | [[package]] 315 | name = "futures-core" 316 | version = "0.3.17" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" 319 | 320 | [[package]] 321 | name = "futures-executor" 322 | version = "0.3.17" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" 325 | dependencies = [ 326 | "futures-core", 327 | "futures-task", 328 | "futures-util", 329 | ] 330 | 331 | [[package]] 332 | name = "futures-io" 333 | version = "0.3.17" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" 336 | 337 | [[package]] 338 | name = "futures-macro" 339 | version = "0.3.17" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" 342 | dependencies = [ 343 | "autocfg", 344 | "proc-macro-hack", 345 | "proc-macro2", 346 | "quote", 347 | "syn", 348 | ] 349 | 350 | [[package]] 351 | name = "futures-sink" 352 | version = "0.3.17" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" 355 | 356 | [[package]] 357 | name = "futures-task" 358 | version = "0.3.17" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" 361 | 362 | [[package]] 363 | name = "futures-util" 364 | version = "0.3.17" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" 367 | dependencies = [ 368 | "autocfg", 369 | "futures-channel", 370 | "futures-core", 371 | "futures-io", 372 | "futures-macro", 373 | "futures-sink", 374 | "futures-task", 375 | "memchr", 376 | "pin-project-lite", 377 | "pin-utils", 378 | "proc-macro-hack", 379 | "proc-macro-nested", 380 | "slab", 381 | ] 382 | 383 | [[package]] 384 | name = "generic-array" 385 | version = "0.14.4" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" 388 | dependencies = [ 389 | "typenum", 390 | "version_check", 391 | ] 392 | 393 | [[package]] 394 | name = "getrandom" 395 | version = "0.1.16" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" 398 | dependencies = [ 399 | "cfg-if", 400 | "libc", 401 | "wasi 0.9.0+wasi-snapshot-preview1", 402 | ] 403 | 404 | [[package]] 405 | name = "getrandom" 406 | version = "0.2.3" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" 409 | dependencies = [ 410 | "cfg-if", 411 | "libc", 412 | "wasi 0.10.2+wasi-snapshot-preview1", 413 | ] 414 | 415 | [[package]] 416 | name = "h2" 417 | version = "0.3.4" 418 | source = "registry+https://github.com/rust-lang/crates.io-index" 419 | checksum = "d7f3675cfef6a30c8031cf9e6493ebdc3bb3272a3fea3923c4210d1830e6a472" 420 | dependencies = [ 421 | "bytes", 422 | "fnv", 423 | "futures-core", 424 | "futures-sink", 425 | "futures-util", 426 | "http", 427 | "indexmap", 428 | "slab", 429 | "tokio", 430 | "tokio-util", 431 | "tracing", 432 | ] 433 | 434 | [[package]] 435 | name = "hashbrown" 436 | version = "0.11.2" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 439 | 440 | [[package]] 441 | name = "headers" 442 | version = "0.3.4" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "f0b7591fb62902706ae8e7aaff416b1b0fa2c0fd0878b46dc13baa3712d8a855" 445 | dependencies = [ 446 | "base64", 447 | "bitflags", 448 | "bytes", 449 | "headers-core", 450 | "http", 451 | "mime", 452 | "sha-1", 453 | "time 0.1.43", 454 | ] 455 | 456 | [[package]] 457 | name = "headers-core" 458 | version = "0.2.0" 459 | source = "registry+https://github.com/rust-lang/crates.io-index" 460 | checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" 461 | dependencies = [ 462 | "http", 463 | ] 464 | 465 | [[package]] 466 | name = "heck" 467 | version = "0.3.3" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 470 | dependencies = [ 471 | "unicode-segmentation", 472 | ] 473 | 474 | [[package]] 475 | name = "hermit-abi" 476 | version = "0.1.19" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 479 | dependencies = [ 480 | "libc", 481 | ] 482 | 483 | [[package]] 484 | name = "http" 485 | version = "0.2.5" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" 488 | dependencies = [ 489 | "bytes", 490 | "fnv", 491 | "itoa", 492 | ] 493 | 494 | [[package]] 495 | name = "http-body" 496 | version = "0.4.3" 497 | source = "registry+https://github.com/rust-lang/crates.io-index" 498 | checksum = "399c583b2979440c60be0821a6199eca73bc3c8dcd9d070d75ac726e2c6186e5" 499 | dependencies = [ 500 | "bytes", 501 | "http", 502 | "pin-project-lite", 503 | ] 504 | 505 | [[package]] 506 | name = "httparse" 507 | version = "1.5.1" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" 510 | 511 | [[package]] 512 | name = "httpdate" 513 | version = "1.0.1" 514 | source = "registry+https://github.com/rust-lang/crates.io-index" 515 | checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" 516 | 517 | [[package]] 518 | name = "hyper" 519 | version = "0.14.13" 520 | source = "registry+https://github.com/rust-lang/crates.io-index" 521 | checksum = "15d1cfb9e4f68655fa04c01f59edb405b6074a0f7118ea881e5026e4a1cd8593" 522 | dependencies = [ 523 | "bytes", 524 | "futures-channel", 525 | "futures-core", 526 | "futures-util", 527 | "h2", 528 | "http", 529 | "http-body", 530 | "httparse", 531 | "httpdate", 532 | "itoa", 533 | "pin-project-lite", 534 | "socket2", 535 | "tokio", 536 | "tower-service", 537 | "tracing", 538 | "want", 539 | ] 540 | 541 | [[package]] 542 | name = "idna" 543 | version = "0.2.3" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 546 | dependencies = [ 547 | "matches", 548 | "unicode-bidi", 549 | "unicode-normalization", 550 | ] 551 | 552 | [[package]] 553 | name = "indexmap" 554 | version = "1.7.0" 555 | source = "registry+https://github.com/rust-lang/crates.io-index" 556 | checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" 557 | dependencies = [ 558 | "autocfg", 559 | "hashbrown", 560 | ] 561 | 562 | [[package]] 563 | name = "input_buffer" 564 | version = "0.4.0" 565 | source = "registry+https://github.com/rust-lang/crates.io-index" 566 | checksum = "f97967975f448f1a7ddb12b0bc41069d09ed6a1c161a92687e057325db35d413" 567 | dependencies = [ 568 | "bytes", 569 | ] 570 | 571 | [[package]] 572 | name = "instant" 573 | version = "0.1.11" 574 | source = "registry+https://github.com/rust-lang/crates.io-index" 575 | checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd" 576 | dependencies = [ 577 | "cfg-if", 578 | ] 579 | 580 | [[package]] 581 | name = "itoa" 582 | version = "0.4.8" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" 585 | 586 | [[package]] 587 | name = "js-sys" 588 | version = "0.3.55" 589 | source = "registry+https://github.com/rust-lang/crates.io-index" 590 | checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" 591 | dependencies = [ 592 | "wasm-bindgen", 593 | ] 594 | 595 | [[package]] 596 | name = "lazy_static" 597 | version = "1.4.0" 598 | source = "registry+https://github.com/rust-lang/crates.io-index" 599 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 600 | 601 | [[package]] 602 | name = "libc" 603 | version = "0.2.102" 604 | source = "registry+https://github.com/rust-lang/crates.io-index" 605 | checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" 606 | 607 | [[package]] 608 | name = "libp2p-webrtc-star-signaling-server" 609 | version = "0.1.0" 610 | dependencies = [ 611 | "acme-lib", 612 | "anyhow", 613 | "async-tungstenite", 614 | "clap", 615 | "futures", 616 | "parking_lot", 617 | "serde", 618 | "serde_json", 619 | "tokio", 620 | "tokio-rustls", 621 | "tokio-stream", 622 | "tokio-util", 623 | "tracing", 624 | "tracing-subscriber", 625 | "warp", 626 | ] 627 | 628 | [[package]] 629 | name = "lock_api" 630 | version = "0.4.5" 631 | source = "registry+https://github.com/rust-lang/crates.io-index" 632 | checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" 633 | dependencies = [ 634 | "scopeguard", 635 | ] 636 | 637 | [[package]] 638 | name = "log" 639 | version = "0.4.14" 640 | source = "registry+https://github.com/rust-lang/crates.io-index" 641 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 642 | dependencies = [ 643 | "cfg-if", 644 | ] 645 | 646 | [[package]] 647 | name = "matchers" 648 | version = "0.0.1" 649 | source = "registry+https://github.com/rust-lang/crates.io-index" 650 | checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" 651 | dependencies = [ 652 | "regex-automata", 653 | ] 654 | 655 | [[package]] 656 | name = "matches" 657 | version = "0.1.9" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" 660 | 661 | [[package]] 662 | name = "memchr" 663 | version = "2.4.1" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 666 | 667 | [[package]] 668 | name = "mime" 669 | version = "0.3.16" 670 | source = "registry+https://github.com/rust-lang/crates.io-index" 671 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 672 | 673 | [[package]] 674 | name = "mime_guess" 675 | version = "2.0.3" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212" 678 | dependencies = [ 679 | "mime", 680 | "unicase", 681 | ] 682 | 683 | [[package]] 684 | name = "mio" 685 | version = "0.7.13" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" 688 | dependencies = [ 689 | "libc", 690 | "log", 691 | "miow", 692 | "ntapi", 693 | "winapi", 694 | ] 695 | 696 | [[package]] 697 | name = "miow" 698 | version = "0.3.7" 699 | source = "registry+https://github.com/rust-lang/crates.io-index" 700 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 701 | dependencies = [ 702 | "winapi", 703 | ] 704 | 705 | [[package]] 706 | name = "multipart" 707 | version = "0.17.1" 708 | source = "registry+https://github.com/rust-lang/crates.io-index" 709 | checksum = "d050aeedc89243f5347c3e237e3e13dc76fbe4ae3742a57b94dc14f69acf76d4" 710 | dependencies = [ 711 | "buf_redux", 712 | "httparse", 713 | "log", 714 | "mime", 715 | "mime_guess", 716 | "quick-error", 717 | "rand 0.7.3", 718 | "safemem", 719 | "tempfile", 720 | "twoway", 721 | ] 722 | 723 | [[package]] 724 | name = "ntapi" 725 | version = "0.3.6" 726 | source = "registry+https://github.com/rust-lang/crates.io-index" 727 | checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" 728 | dependencies = [ 729 | "winapi", 730 | ] 731 | 732 | [[package]] 733 | name = "num-integer" 734 | version = "0.1.44" 735 | source = "registry+https://github.com/rust-lang/crates.io-index" 736 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 737 | dependencies = [ 738 | "autocfg", 739 | "num-traits", 740 | ] 741 | 742 | [[package]] 743 | name = "num-traits" 744 | version = "0.2.14" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 747 | dependencies = [ 748 | "autocfg", 749 | ] 750 | 751 | [[package]] 752 | name = "num_cpus" 753 | version = "1.13.0" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 756 | dependencies = [ 757 | "hermit-abi", 758 | "libc", 759 | ] 760 | 761 | [[package]] 762 | name = "once_cell" 763 | version = "1.8.0" 764 | source = "registry+https://github.com/rust-lang/crates.io-index" 765 | checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" 766 | 767 | [[package]] 768 | name = "opaque-debug" 769 | version = "0.3.0" 770 | source = "registry+https://github.com/rust-lang/crates.io-index" 771 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 772 | 773 | [[package]] 774 | name = "openssl" 775 | version = "0.10.36" 776 | source = "registry+https://github.com/rust-lang/crates.io-index" 777 | checksum = "8d9facdb76fec0b73c406f125d44d86fdad818d66fef0531eec9233ca425ff4a" 778 | dependencies = [ 779 | "bitflags", 780 | "cfg-if", 781 | "foreign-types", 782 | "libc", 783 | "once_cell", 784 | "openssl-sys", 785 | ] 786 | 787 | [[package]] 788 | name = "openssl-probe" 789 | version = "0.1.4" 790 | source = "registry+https://github.com/rust-lang/crates.io-index" 791 | checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" 792 | 793 | [[package]] 794 | name = "openssl-sys" 795 | version = "0.9.67" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "69df2d8dfc6ce3aaf44b40dec6f487d5a886516cf6879c49e98e0710f310a058" 798 | dependencies = [ 799 | "autocfg", 800 | "cc", 801 | "libc", 802 | "pkg-config", 803 | "vcpkg", 804 | ] 805 | 806 | [[package]] 807 | name = "os_str_bytes" 808 | version = "3.1.0" 809 | source = "registry+https://github.com/rust-lang/crates.io-index" 810 | checksum = "6acbef58a60fe69ab50510a55bc8cdd4d6cf2283d27ad338f54cb52747a9cf2d" 811 | 812 | [[package]] 813 | name = "parking_lot" 814 | version = "0.11.2" 815 | source = "registry+https://github.com/rust-lang/crates.io-index" 816 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 817 | dependencies = [ 818 | "instant", 819 | "lock_api", 820 | "parking_lot_core", 821 | ] 822 | 823 | [[package]] 824 | name = "parking_lot_core" 825 | version = "0.8.5" 826 | source = "registry+https://github.com/rust-lang/crates.io-index" 827 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 828 | dependencies = [ 829 | "cfg-if", 830 | "instant", 831 | "libc", 832 | "redox_syscall", 833 | "smallvec", 834 | "winapi", 835 | ] 836 | 837 | [[package]] 838 | name = "percent-encoding" 839 | version = "2.1.0" 840 | source = "registry+https://github.com/rust-lang/crates.io-index" 841 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 842 | 843 | [[package]] 844 | name = "pin-project" 845 | version = "1.0.8" 846 | source = "registry+https://github.com/rust-lang/crates.io-index" 847 | checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" 848 | dependencies = [ 849 | "pin-project-internal", 850 | ] 851 | 852 | [[package]] 853 | name = "pin-project-internal" 854 | version = "1.0.8" 855 | source = "registry+https://github.com/rust-lang/crates.io-index" 856 | checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" 857 | dependencies = [ 858 | "proc-macro2", 859 | "quote", 860 | "syn", 861 | ] 862 | 863 | [[package]] 864 | name = "pin-project-lite" 865 | version = "0.2.7" 866 | source = "registry+https://github.com/rust-lang/crates.io-index" 867 | checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" 868 | 869 | [[package]] 870 | name = "pin-utils" 871 | version = "0.1.0" 872 | source = "registry+https://github.com/rust-lang/crates.io-index" 873 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 874 | 875 | [[package]] 876 | name = "pkg-config" 877 | version = "0.3.19" 878 | source = "registry+https://github.com/rust-lang/crates.io-index" 879 | checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" 880 | 881 | [[package]] 882 | name = "ppv-lite86" 883 | version = "0.2.10" 884 | source = "registry+https://github.com/rust-lang/crates.io-index" 885 | checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" 886 | 887 | [[package]] 888 | name = "proc-macro-error" 889 | version = "1.0.4" 890 | source = "registry+https://github.com/rust-lang/crates.io-index" 891 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 892 | dependencies = [ 893 | "proc-macro-error-attr", 894 | "proc-macro2", 895 | "quote", 896 | "syn", 897 | "version_check", 898 | ] 899 | 900 | [[package]] 901 | name = "proc-macro-error-attr" 902 | version = "1.0.4" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 905 | dependencies = [ 906 | "proc-macro2", 907 | "quote", 908 | "version_check", 909 | ] 910 | 911 | [[package]] 912 | name = "proc-macro-hack" 913 | version = "0.5.19" 914 | source = "registry+https://github.com/rust-lang/crates.io-index" 915 | checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" 916 | 917 | [[package]] 918 | name = "proc-macro-nested" 919 | version = "0.1.7" 920 | source = "registry+https://github.com/rust-lang/crates.io-index" 921 | checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" 922 | 923 | [[package]] 924 | name = "proc-macro2" 925 | version = "1.0.29" 926 | source = "registry+https://github.com/rust-lang/crates.io-index" 927 | checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" 928 | dependencies = [ 929 | "unicode-xid", 930 | ] 931 | 932 | [[package]] 933 | name = "publicsuffix" 934 | version = "1.5.6" 935 | source = "registry+https://github.com/rust-lang/crates.io-index" 936 | checksum = "95b4ce31ff0a27d93c8de1849cf58162283752f065a90d508f1105fa6c9a213f" 937 | dependencies = [ 938 | "idna", 939 | "url", 940 | ] 941 | 942 | [[package]] 943 | name = "qstring" 944 | version = "0.7.2" 945 | source = "registry+https://github.com/rust-lang/crates.io-index" 946 | checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" 947 | dependencies = [ 948 | "percent-encoding", 949 | ] 950 | 951 | [[package]] 952 | name = "quick-error" 953 | version = "1.2.3" 954 | source = "registry+https://github.com/rust-lang/crates.io-index" 955 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 956 | 957 | [[package]] 958 | name = "quote" 959 | version = "1.0.9" 960 | source = "registry+https://github.com/rust-lang/crates.io-index" 961 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 962 | dependencies = [ 963 | "proc-macro2", 964 | ] 965 | 966 | [[package]] 967 | name = "rand" 968 | version = "0.7.3" 969 | source = "registry+https://github.com/rust-lang/crates.io-index" 970 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 971 | dependencies = [ 972 | "getrandom 0.1.16", 973 | "libc", 974 | "rand_chacha 0.2.2", 975 | "rand_core 0.5.1", 976 | "rand_hc 0.2.0", 977 | ] 978 | 979 | [[package]] 980 | name = "rand" 981 | version = "0.8.4" 982 | source = "registry+https://github.com/rust-lang/crates.io-index" 983 | checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" 984 | dependencies = [ 985 | "libc", 986 | "rand_chacha 0.3.1", 987 | "rand_core 0.6.3", 988 | "rand_hc 0.3.1", 989 | ] 990 | 991 | [[package]] 992 | name = "rand_chacha" 993 | version = "0.2.2" 994 | source = "registry+https://github.com/rust-lang/crates.io-index" 995 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 996 | dependencies = [ 997 | "ppv-lite86", 998 | "rand_core 0.5.1", 999 | ] 1000 | 1001 | [[package]] 1002 | name = "rand_chacha" 1003 | version = "0.3.1" 1004 | source = "registry+https://github.com/rust-lang/crates.io-index" 1005 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1006 | dependencies = [ 1007 | "ppv-lite86", 1008 | "rand_core 0.6.3", 1009 | ] 1010 | 1011 | [[package]] 1012 | name = "rand_core" 1013 | version = "0.5.1" 1014 | source = "registry+https://github.com/rust-lang/crates.io-index" 1015 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 1016 | dependencies = [ 1017 | "getrandom 0.1.16", 1018 | ] 1019 | 1020 | [[package]] 1021 | name = "rand_core" 1022 | version = "0.6.3" 1023 | source = "registry+https://github.com/rust-lang/crates.io-index" 1024 | checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" 1025 | dependencies = [ 1026 | "getrandom 0.2.3", 1027 | ] 1028 | 1029 | [[package]] 1030 | name = "rand_hc" 1031 | version = "0.2.0" 1032 | source = "registry+https://github.com/rust-lang/crates.io-index" 1033 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 1034 | dependencies = [ 1035 | "rand_core 0.5.1", 1036 | ] 1037 | 1038 | [[package]] 1039 | name = "rand_hc" 1040 | version = "0.3.1" 1041 | source = "registry+https://github.com/rust-lang/crates.io-index" 1042 | checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" 1043 | dependencies = [ 1044 | "rand_core 0.6.3", 1045 | ] 1046 | 1047 | [[package]] 1048 | name = "redox_syscall" 1049 | version = "0.2.10" 1050 | source = "registry+https://github.com/rust-lang/crates.io-index" 1051 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 1052 | dependencies = [ 1053 | "bitflags", 1054 | ] 1055 | 1056 | [[package]] 1057 | name = "regex" 1058 | version = "1.5.4" 1059 | source = "registry+https://github.com/rust-lang/crates.io-index" 1060 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" 1061 | dependencies = [ 1062 | "regex-syntax", 1063 | ] 1064 | 1065 | [[package]] 1066 | name = "regex-automata" 1067 | version = "0.1.10" 1068 | source = "registry+https://github.com/rust-lang/crates.io-index" 1069 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 1070 | dependencies = [ 1071 | "regex-syntax", 1072 | ] 1073 | 1074 | [[package]] 1075 | name = "regex-syntax" 1076 | version = "0.6.25" 1077 | source = "registry+https://github.com/rust-lang/crates.io-index" 1078 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 1079 | 1080 | [[package]] 1081 | name = "remove_dir_all" 1082 | version = "0.5.3" 1083 | source = "registry+https://github.com/rust-lang/crates.io-index" 1084 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 1085 | dependencies = [ 1086 | "winapi", 1087 | ] 1088 | 1089 | [[package]] 1090 | name = "ring" 1091 | version = "0.16.20" 1092 | source = "registry+https://github.com/rust-lang/crates.io-index" 1093 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 1094 | dependencies = [ 1095 | "cc", 1096 | "libc", 1097 | "once_cell", 1098 | "spin", 1099 | "untrusted", 1100 | "web-sys", 1101 | "winapi", 1102 | ] 1103 | 1104 | [[package]] 1105 | name = "rustc_version" 1106 | version = "0.2.3" 1107 | source = "registry+https://github.com/rust-lang/crates.io-index" 1108 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1109 | dependencies = [ 1110 | "semver", 1111 | ] 1112 | 1113 | [[package]] 1114 | name = "rustls" 1115 | version = "0.19.1" 1116 | source = "registry+https://github.com/rust-lang/crates.io-index" 1117 | checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" 1118 | dependencies = [ 1119 | "base64", 1120 | "log", 1121 | "ring", 1122 | "sct", 1123 | "webpki", 1124 | ] 1125 | 1126 | [[package]] 1127 | name = "rustls-native-certs" 1128 | version = "0.5.0" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" 1131 | dependencies = [ 1132 | "openssl-probe", 1133 | "rustls", 1134 | "schannel", 1135 | "security-framework", 1136 | ] 1137 | 1138 | [[package]] 1139 | name = "ryu" 1140 | version = "1.0.5" 1141 | source = "registry+https://github.com/rust-lang/crates.io-index" 1142 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 1143 | 1144 | [[package]] 1145 | name = "safemem" 1146 | version = "0.3.3" 1147 | source = "registry+https://github.com/rust-lang/crates.io-index" 1148 | checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" 1149 | 1150 | [[package]] 1151 | name = "schannel" 1152 | version = "0.1.19" 1153 | source = "registry+https://github.com/rust-lang/crates.io-index" 1154 | checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" 1155 | dependencies = [ 1156 | "lazy_static", 1157 | "winapi", 1158 | ] 1159 | 1160 | [[package]] 1161 | name = "scoped-tls" 1162 | version = "1.0.0" 1163 | source = "registry+https://github.com/rust-lang/crates.io-index" 1164 | checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" 1165 | 1166 | [[package]] 1167 | name = "scopeguard" 1168 | version = "1.1.0" 1169 | source = "registry+https://github.com/rust-lang/crates.io-index" 1170 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1171 | 1172 | [[package]] 1173 | name = "sct" 1174 | version = "0.6.1" 1175 | source = "registry+https://github.com/rust-lang/crates.io-index" 1176 | checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" 1177 | dependencies = [ 1178 | "ring", 1179 | "untrusted", 1180 | ] 1181 | 1182 | [[package]] 1183 | name = "security-framework" 1184 | version = "2.4.2" 1185 | source = "registry+https://github.com/rust-lang/crates.io-index" 1186 | checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" 1187 | dependencies = [ 1188 | "bitflags", 1189 | "core-foundation", 1190 | "core-foundation-sys", 1191 | "libc", 1192 | "security-framework-sys", 1193 | ] 1194 | 1195 | [[package]] 1196 | name = "security-framework-sys" 1197 | version = "2.4.2" 1198 | source = "registry+https://github.com/rust-lang/crates.io-index" 1199 | checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" 1200 | dependencies = [ 1201 | "core-foundation-sys", 1202 | "libc", 1203 | ] 1204 | 1205 | [[package]] 1206 | name = "semver" 1207 | version = "0.9.0" 1208 | source = "registry+https://github.com/rust-lang/crates.io-index" 1209 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 1210 | dependencies = [ 1211 | "semver-parser", 1212 | ] 1213 | 1214 | [[package]] 1215 | name = "semver-parser" 1216 | version = "0.7.0" 1217 | source = "registry+https://github.com/rust-lang/crates.io-index" 1218 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 1219 | 1220 | [[package]] 1221 | name = "serde" 1222 | version = "1.0.130" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" 1225 | dependencies = [ 1226 | "serde_derive", 1227 | ] 1228 | 1229 | [[package]] 1230 | name = "serde_derive" 1231 | version = "1.0.130" 1232 | source = "registry+https://github.com/rust-lang/crates.io-index" 1233 | checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" 1234 | dependencies = [ 1235 | "proc-macro2", 1236 | "quote", 1237 | "syn", 1238 | ] 1239 | 1240 | [[package]] 1241 | name = "serde_json" 1242 | version = "1.0.68" 1243 | source = "registry+https://github.com/rust-lang/crates.io-index" 1244 | checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" 1245 | dependencies = [ 1246 | "itoa", 1247 | "ryu", 1248 | "serde", 1249 | ] 1250 | 1251 | [[package]] 1252 | name = "serde_urlencoded" 1253 | version = "0.7.0" 1254 | source = "registry+https://github.com/rust-lang/crates.io-index" 1255 | checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" 1256 | dependencies = [ 1257 | "form_urlencoded", 1258 | "itoa", 1259 | "ryu", 1260 | "serde", 1261 | ] 1262 | 1263 | [[package]] 1264 | name = "sha-1" 1265 | version = "0.9.8" 1266 | source = "registry+https://github.com/rust-lang/crates.io-index" 1267 | checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" 1268 | dependencies = [ 1269 | "block-buffer", 1270 | "cfg-if", 1271 | "cpufeatures", 1272 | "digest", 1273 | "opaque-debug", 1274 | ] 1275 | 1276 | [[package]] 1277 | name = "sha1" 1278 | version = "0.6.0" 1279 | source = "registry+https://github.com/rust-lang/crates.io-index" 1280 | checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" 1281 | 1282 | [[package]] 1283 | name = "sharded-slab" 1284 | version = "0.1.3" 1285 | source = "registry+https://github.com/rust-lang/crates.io-index" 1286 | checksum = "740223c51853f3145fe7c90360d2d4232f2b62e3449489c207eccde818979982" 1287 | dependencies = [ 1288 | "lazy_static", 1289 | ] 1290 | 1291 | [[package]] 1292 | name = "signal-hook-registry" 1293 | version = "1.4.0" 1294 | source = "registry+https://github.com/rust-lang/crates.io-index" 1295 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 1296 | dependencies = [ 1297 | "libc", 1298 | ] 1299 | 1300 | [[package]] 1301 | name = "slab" 1302 | version = "0.4.4" 1303 | source = "registry+https://github.com/rust-lang/crates.io-index" 1304 | checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" 1305 | 1306 | [[package]] 1307 | name = "smallvec" 1308 | version = "1.6.1" 1309 | source = "registry+https://github.com/rust-lang/crates.io-index" 1310 | checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" 1311 | 1312 | [[package]] 1313 | name = "socket2" 1314 | version = "0.4.2" 1315 | source = "registry+https://github.com/rust-lang/crates.io-index" 1316 | checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" 1317 | dependencies = [ 1318 | "libc", 1319 | "winapi", 1320 | ] 1321 | 1322 | [[package]] 1323 | name = "spin" 1324 | version = "0.5.2" 1325 | source = "registry+https://github.com/rust-lang/crates.io-index" 1326 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 1327 | 1328 | [[package]] 1329 | name = "standback" 1330 | version = "0.2.17" 1331 | source = "registry+https://github.com/rust-lang/crates.io-index" 1332 | checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" 1333 | dependencies = [ 1334 | "version_check", 1335 | ] 1336 | 1337 | [[package]] 1338 | name = "stdweb" 1339 | version = "0.4.20" 1340 | source = "registry+https://github.com/rust-lang/crates.io-index" 1341 | checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" 1342 | dependencies = [ 1343 | "discard", 1344 | "rustc_version", 1345 | "stdweb-derive", 1346 | "stdweb-internal-macros", 1347 | "stdweb-internal-runtime", 1348 | "wasm-bindgen", 1349 | ] 1350 | 1351 | [[package]] 1352 | name = "stdweb-derive" 1353 | version = "0.5.3" 1354 | source = "registry+https://github.com/rust-lang/crates.io-index" 1355 | checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" 1356 | dependencies = [ 1357 | "proc-macro2", 1358 | "quote", 1359 | "serde", 1360 | "serde_derive", 1361 | "syn", 1362 | ] 1363 | 1364 | [[package]] 1365 | name = "stdweb-internal-macros" 1366 | version = "0.2.9" 1367 | source = "registry+https://github.com/rust-lang/crates.io-index" 1368 | checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" 1369 | dependencies = [ 1370 | "base-x", 1371 | "proc-macro2", 1372 | "quote", 1373 | "serde", 1374 | "serde_derive", 1375 | "serde_json", 1376 | "sha1", 1377 | "syn", 1378 | ] 1379 | 1380 | [[package]] 1381 | name = "stdweb-internal-runtime" 1382 | version = "0.1.5" 1383 | source = "registry+https://github.com/rust-lang/crates.io-index" 1384 | checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" 1385 | 1386 | [[package]] 1387 | name = "strsim" 1388 | version = "0.10.0" 1389 | source = "registry+https://github.com/rust-lang/crates.io-index" 1390 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 1391 | 1392 | [[package]] 1393 | name = "syn" 1394 | version = "1.0.77" 1395 | source = "registry+https://github.com/rust-lang/crates.io-index" 1396 | checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0" 1397 | dependencies = [ 1398 | "proc-macro2", 1399 | "quote", 1400 | "unicode-xid", 1401 | ] 1402 | 1403 | [[package]] 1404 | name = "tempfile" 1405 | version = "3.2.0" 1406 | source = "registry+https://github.com/rust-lang/crates.io-index" 1407 | checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" 1408 | dependencies = [ 1409 | "cfg-if", 1410 | "libc", 1411 | "rand 0.8.4", 1412 | "redox_syscall", 1413 | "remove_dir_all", 1414 | "winapi", 1415 | ] 1416 | 1417 | [[package]] 1418 | name = "termcolor" 1419 | version = "1.1.2" 1420 | source = "registry+https://github.com/rust-lang/crates.io-index" 1421 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 1422 | dependencies = [ 1423 | "winapi-util", 1424 | ] 1425 | 1426 | [[package]] 1427 | name = "textwrap" 1428 | version = "0.14.2" 1429 | source = "registry+https://github.com/rust-lang/crates.io-index" 1430 | checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" 1431 | dependencies = [ 1432 | "unicode-width", 1433 | ] 1434 | 1435 | [[package]] 1436 | name = "thiserror" 1437 | version = "1.0.29" 1438 | source = "registry+https://github.com/rust-lang/crates.io-index" 1439 | checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" 1440 | dependencies = [ 1441 | "thiserror-impl", 1442 | ] 1443 | 1444 | [[package]] 1445 | name = "thiserror-impl" 1446 | version = "1.0.29" 1447 | source = "registry+https://github.com/rust-lang/crates.io-index" 1448 | checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" 1449 | dependencies = [ 1450 | "proc-macro2", 1451 | "quote", 1452 | "syn", 1453 | ] 1454 | 1455 | [[package]] 1456 | name = "thread_local" 1457 | version = "1.1.3" 1458 | source = "registry+https://github.com/rust-lang/crates.io-index" 1459 | checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" 1460 | dependencies = [ 1461 | "once_cell", 1462 | ] 1463 | 1464 | [[package]] 1465 | name = "time" 1466 | version = "0.1.43" 1467 | source = "registry+https://github.com/rust-lang/crates.io-index" 1468 | checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" 1469 | dependencies = [ 1470 | "libc", 1471 | "winapi", 1472 | ] 1473 | 1474 | [[package]] 1475 | name = "time" 1476 | version = "0.2.27" 1477 | source = "registry+https://github.com/rust-lang/crates.io-index" 1478 | checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" 1479 | dependencies = [ 1480 | "const_fn", 1481 | "libc", 1482 | "standback", 1483 | "stdweb", 1484 | "time-macros", 1485 | "version_check", 1486 | "winapi", 1487 | ] 1488 | 1489 | [[package]] 1490 | name = "time-macros" 1491 | version = "0.1.1" 1492 | source = "registry+https://github.com/rust-lang/crates.io-index" 1493 | checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" 1494 | dependencies = [ 1495 | "proc-macro-hack", 1496 | "time-macros-impl", 1497 | ] 1498 | 1499 | [[package]] 1500 | name = "time-macros-impl" 1501 | version = "0.1.2" 1502 | source = "registry+https://github.com/rust-lang/crates.io-index" 1503 | checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" 1504 | dependencies = [ 1505 | "proc-macro-hack", 1506 | "proc-macro2", 1507 | "quote", 1508 | "standback", 1509 | "syn", 1510 | ] 1511 | 1512 | [[package]] 1513 | name = "tinyvec" 1514 | version = "1.4.0" 1515 | source = "registry+https://github.com/rust-lang/crates.io-index" 1516 | checksum = "5241dd6f21443a3606b432718b166d3cedc962fd4b8bea54a8bc7f514ebda986" 1517 | dependencies = [ 1518 | "tinyvec_macros", 1519 | ] 1520 | 1521 | [[package]] 1522 | name = "tinyvec_macros" 1523 | version = "0.1.0" 1524 | source = "registry+https://github.com/rust-lang/crates.io-index" 1525 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 1526 | 1527 | [[package]] 1528 | name = "tokio" 1529 | version = "1.12.0" 1530 | source = "registry+https://github.com/rust-lang/crates.io-index" 1531 | checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc" 1532 | dependencies = [ 1533 | "autocfg", 1534 | "bytes", 1535 | "libc", 1536 | "memchr", 1537 | "mio", 1538 | "num_cpus", 1539 | "once_cell", 1540 | "parking_lot", 1541 | "pin-project-lite", 1542 | "signal-hook-registry", 1543 | "tokio-macros", 1544 | "winapi", 1545 | ] 1546 | 1547 | [[package]] 1548 | name = "tokio-macros" 1549 | version = "1.3.0" 1550 | source = "registry+https://github.com/rust-lang/crates.io-index" 1551 | checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110" 1552 | dependencies = [ 1553 | "proc-macro2", 1554 | "quote", 1555 | "syn", 1556 | ] 1557 | 1558 | [[package]] 1559 | name = "tokio-rustls" 1560 | version = "0.22.0" 1561 | source = "registry+https://github.com/rust-lang/crates.io-index" 1562 | checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" 1563 | dependencies = [ 1564 | "rustls", 1565 | "tokio", 1566 | "webpki", 1567 | ] 1568 | 1569 | [[package]] 1570 | name = "tokio-stream" 1571 | version = "0.1.7" 1572 | source = "registry+https://github.com/rust-lang/crates.io-index" 1573 | checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" 1574 | dependencies = [ 1575 | "futures-core", 1576 | "pin-project-lite", 1577 | "tokio", 1578 | ] 1579 | 1580 | [[package]] 1581 | name = "tokio-tungstenite" 1582 | version = "0.13.0" 1583 | source = "registry+https://github.com/rust-lang/crates.io-index" 1584 | checksum = "e1a5f475f1b9d077ea1017ecbc60890fda8e54942d680ca0b1d2b47cfa2d861b" 1585 | dependencies = [ 1586 | "futures-util", 1587 | "log", 1588 | "pin-project", 1589 | "tokio", 1590 | "tungstenite 0.12.0", 1591 | ] 1592 | 1593 | [[package]] 1594 | name = "tokio-util" 1595 | version = "0.6.8" 1596 | source = "registry+https://github.com/rust-lang/crates.io-index" 1597 | checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd" 1598 | dependencies = [ 1599 | "bytes", 1600 | "futures-core", 1601 | "futures-io", 1602 | "futures-sink", 1603 | "log", 1604 | "pin-project-lite", 1605 | "tokio", 1606 | ] 1607 | 1608 | [[package]] 1609 | name = "tower-service" 1610 | version = "0.3.1" 1611 | source = "registry+https://github.com/rust-lang/crates.io-index" 1612 | checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" 1613 | 1614 | [[package]] 1615 | name = "tracing" 1616 | version = "0.1.28" 1617 | source = "registry+https://github.com/rust-lang/crates.io-index" 1618 | checksum = "84f96e095c0c82419687c20ddf5cb3eadb61f4e1405923c9dc8e53a1adacbda8" 1619 | dependencies = [ 1620 | "cfg-if", 1621 | "log", 1622 | "pin-project-lite", 1623 | "tracing-attributes", 1624 | "tracing-core", 1625 | ] 1626 | 1627 | [[package]] 1628 | name = "tracing-attributes" 1629 | version = "0.1.16" 1630 | source = "registry+https://github.com/rust-lang/crates.io-index" 1631 | checksum = "98863d0dd09fa59a1b79c6750ad80dbda6b75f4e71c437a6a1a8cb91a8bcbd77" 1632 | dependencies = [ 1633 | "proc-macro2", 1634 | "quote", 1635 | "syn", 1636 | ] 1637 | 1638 | [[package]] 1639 | name = "tracing-core" 1640 | version = "0.1.20" 1641 | source = "registry+https://github.com/rust-lang/crates.io-index" 1642 | checksum = "46125608c26121c81b0c6d693eab5a420e416da7e43c426d2e8f7df8da8a3acf" 1643 | dependencies = [ 1644 | "lazy_static", 1645 | ] 1646 | 1647 | [[package]] 1648 | name = "tracing-log" 1649 | version = "0.1.2" 1650 | source = "registry+https://github.com/rust-lang/crates.io-index" 1651 | checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" 1652 | dependencies = [ 1653 | "lazy_static", 1654 | "log", 1655 | "tracing-core", 1656 | ] 1657 | 1658 | [[package]] 1659 | name = "tracing-serde" 1660 | version = "0.1.2" 1661 | source = "registry+https://github.com/rust-lang/crates.io-index" 1662 | checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b" 1663 | dependencies = [ 1664 | "serde", 1665 | "tracing-core", 1666 | ] 1667 | 1668 | [[package]] 1669 | name = "tracing-subscriber" 1670 | version = "0.2.24" 1671 | source = "registry+https://github.com/rust-lang/crates.io-index" 1672 | checksum = "fdd0568dbfe3baf7048b7908d2b32bca0d81cd56bec6d2a8f894b01d74f86be3" 1673 | dependencies = [ 1674 | "ansi_term", 1675 | "chrono", 1676 | "lazy_static", 1677 | "matchers", 1678 | "regex", 1679 | "serde", 1680 | "serde_json", 1681 | "sharded-slab", 1682 | "smallvec", 1683 | "thread_local", 1684 | "tracing", 1685 | "tracing-core", 1686 | "tracing-log", 1687 | "tracing-serde", 1688 | ] 1689 | 1690 | [[package]] 1691 | name = "try-lock" 1692 | version = "0.2.3" 1693 | source = "registry+https://github.com/rust-lang/crates.io-index" 1694 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 1695 | 1696 | [[package]] 1697 | name = "tungstenite" 1698 | version = "0.12.0" 1699 | source = "registry+https://github.com/rust-lang/crates.io-index" 1700 | checksum = "8ada8297e8d70872fa9a551d93250a9f407beb9f37ef86494eb20012a2ff7c24" 1701 | dependencies = [ 1702 | "base64", 1703 | "byteorder", 1704 | "bytes", 1705 | "http", 1706 | "httparse", 1707 | "input_buffer", 1708 | "log", 1709 | "rand 0.8.4", 1710 | "sha-1", 1711 | "url", 1712 | "utf-8", 1713 | ] 1714 | 1715 | [[package]] 1716 | name = "tungstenite" 1717 | version = "0.15.0" 1718 | source = "registry+https://github.com/rust-lang/crates.io-index" 1719 | checksum = "983d40747bce878d2fb67d910dcb8bd3eca2b2358540c3cc1b98c027407a3ae3" 1720 | dependencies = [ 1721 | "base64", 1722 | "byteorder", 1723 | "bytes", 1724 | "http", 1725 | "httparse", 1726 | "log", 1727 | "rand 0.8.4", 1728 | "rustls", 1729 | "sha-1", 1730 | "thiserror", 1731 | "url", 1732 | "utf-8", 1733 | "webpki", 1734 | ] 1735 | 1736 | [[package]] 1737 | name = "twoway" 1738 | version = "0.1.8" 1739 | source = "registry+https://github.com/rust-lang/crates.io-index" 1740 | checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" 1741 | dependencies = [ 1742 | "memchr", 1743 | ] 1744 | 1745 | [[package]] 1746 | name = "typenum" 1747 | version = "1.14.0" 1748 | source = "registry+https://github.com/rust-lang/crates.io-index" 1749 | checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" 1750 | 1751 | [[package]] 1752 | name = "unicase" 1753 | version = "2.6.0" 1754 | source = "registry+https://github.com/rust-lang/crates.io-index" 1755 | checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" 1756 | dependencies = [ 1757 | "version_check", 1758 | ] 1759 | 1760 | [[package]] 1761 | name = "unicode-bidi" 1762 | version = "0.3.6" 1763 | source = "registry+https://github.com/rust-lang/crates.io-index" 1764 | checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" 1765 | 1766 | [[package]] 1767 | name = "unicode-normalization" 1768 | version = "0.1.19" 1769 | source = "registry+https://github.com/rust-lang/crates.io-index" 1770 | checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" 1771 | dependencies = [ 1772 | "tinyvec", 1773 | ] 1774 | 1775 | [[package]] 1776 | name = "unicode-segmentation" 1777 | version = "1.8.0" 1778 | source = "registry+https://github.com/rust-lang/crates.io-index" 1779 | checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" 1780 | 1781 | [[package]] 1782 | name = "unicode-width" 1783 | version = "0.1.9" 1784 | source = "registry+https://github.com/rust-lang/crates.io-index" 1785 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 1786 | 1787 | [[package]] 1788 | name = "unicode-xid" 1789 | version = "0.2.2" 1790 | source = "registry+https://github.com/rust-lang/crates.io-index" 1791 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 1792 | 1793 | [[package]] 1794 | name = "untrusted" 1795 | version = "0.7.1" 1796 | source = "registry+https://github.com/rust-lang/crates.io-index" 1797 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 1798 | 1799 | [[package]] 1800 | name = "ureq" 1801 | version = "1.5.5" 1802 | source = "registry+https://github.com/rust-lang/crates.io-index" 1803 | checksum = "2b8b063c2d59218ae09f22b53c42eaad0d53516457905f5235ca4bc9e99daa71" 1804 | dependencies = [ 1805 | "base64", 1806 | "chunked_transfer", 1807 | "cookie", 1808 | "cookie_store", 1809 | "log", 1810 | "once_cell", 1811 | "qstring", 1812 | "rustls", 1813 | "url", 1814 | "webpki", 1815 | "webpki-roots", 1816 | ] 1817 | 1818 | [[package]] 1819 | name = "url" 1820 | version = "2.2.2" 1821 | source = "registry+https://github.com/rust-lang/crates.io-index" 1822 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 1823 | dependencies = [ 1824 | "form_urlencoded", 1825 | "idna", 1826 | "matches", 1827 | "percent-encoding", 1828 | ] 1829 | 1830 | [[package]] 1831 | name = "utf-8" 1832 | version = "0.7.6" 1833 | source = "registry+https://github.com/rust-lang/crates.io-index" 1834 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 1835 | 1836 | [[package]] 1837 | name = "vcpkg" 1838 | version = "0.2.15" 1839 | source = "registry+https://github.com/rust-lang/crates.io-index" 1840 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1841 | 1842 | [[package]] 1843 | name = "vec_map" 1844 | version = "0.8.2" 1845 | source = "registry+https://github.com/rust-lang/crates.io-index" 1846 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 1847 | 1848 | [[package]] 1849 | name = "version_check" 1850 | version = "0.9.3" 1851 | source = "registry+https://github.com/rust-lang/crates.io-index" 1852 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 1853 | 1854 | [[package]] 1855 | name = "want" 1856 | version = "0.3.0" 1857 | source = "registry+https://github.com/rust-lang/crates.io-index" 1858 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 1859 | dependencies = [ 1860 | "log", 1861 | "try-lock", 1862 | ] 1863 | 1864 | [[package]] 1865 | name = "warp" 1866 | version = "0.3.1" 1867 | source = "registry+https://github.com/rust-lang/crates.io-index" 1868 | checksum = "332d47745e9a0c38636dbd454729b147d16bd1ed08ae67b3ab281c4506771054" 1869 | dependencies = [ 1870 | "bytes", 1871 | "futures", 1872 | "headers", 1873 | "http", 1874 | "hyper", 1875 | "log", 1876 | "mime", 1877 | "mime_guess", 1878 | "multipart", 1879 | "percent-encoding", 1880 | "pin-project", 1881 | "scoped-tls", 1882 | "serde", 1883 | "serde_json", 1884 | "serde_urlencoded", 1885 | "tokio", 1886 | "tokio-stream", 1887 | "tokio-tungstenite", 1888 | "tokio-util", 1889 | "tower-service", 1890 | "tracing", 1891 | ] 1892 | 1893 | [[package]] 1894 | name = "wasi" 1895 | version = "0.9.0+wasi-snapshot-preview1" 1896 | source = "registry+https://github.com/rust-lang/crates.io-index" 1897 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 1898 | 1899 | [[package]] 1900 | name = "wasi" 1901 | version = "0.10.2+wasi-snapshot-preview1" 1902 | source = "registry+https://github.com/rust-lang/crates.io-index" 1903 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 1904 | 1905 | [[package]] 1906 | name = "wasm-bindgen" 1907 | version = "0.2.78" 1908 | source = "registry+https://github.com/rust-lang/crates.io-index" 1909 | checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" 1910 | dependencies = [ 1911 | "cfg-if", 1912 | "wasm-bindgen-macro", 1913 | ] 1914 | 1915 | [[package]] 1916 | name = "wasm-bindgen-backend" 1917 | version = "0.2.78" 1918 | source = "registry+https://github.com/rust-lang/crates.io-index" 1919 | checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" 1920 | dependencies = [ 1921 | "bumpalo", 1922 | "lazy_static", 1923 | "log", 1924 | "proc-macro2", 1925 | "quote", 1926 | "syn", 1927 | "wasm-bindgen-shared", 1928 | ] 1929 | 1930 | [[package]] 1931 | name = "wasm-bindgen-macro" 1932 | version = "0.2.78" 1933 | source = "registry+https://github.com/rust-lang/crates.io-index" 1934 | checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" 1935 | dependencies = [ 1936 | "quote", 1937 | "wasm-bindgen-macro-support", 1938 | ] 1939 | 1940 | [[package]] 1941 | name = "wasm-bindgen-macro-support" 1942 | version = "0.2.78" 1943 | source = "registry+https://github.com/rust-lang/crates.io-index" 1944 | checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" 1945 | dependencies = [ 1946 | "proc-macro2", 1947 | "quote", 1948 | "syn", 1949 | "wasm-bindgen-backend", 1950 | "wasm-bindgen-shared", 1951 | ] 1952 | 1953 | [[package]] 1954 | name = "wasm-bindgen-shared" 1955 | version = "0.2.78" 1956 | source = "registry+https://github.com/rust-lang/crates.io-index" 1957 | checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" 1958 | 1959 | [[package]] 1960 | name = "web-sys" 1961 | version = "0.3.55" 1962 | source = "registry+https://github.com/rust-lang/crates.io-index" 1963 | checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" 1964 | dependencies = [ 1965 | "js-sys", 1966 | "wasm-bindgen", 1967 | ] 1968 | 1969 | [[package]] 1970 | name = "webpki" 1971 | version = "0.21.4" 1972 | source = "registry+https://github.com/rust-lang/crates.io-index" 1973 | checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" 1974 | dependencies = [ 1975 | "ring", 1976 | "untrusted", 1977 | ] 1978 | 1979 | [[package]] 1980 | name = "webpki-roots" 1981 | version = "0.21.1" 1982 | source = "registry+https://github.com/rust-lang/crates.io-index" 1983 | checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" 1984 | dependencies = [ 1985 | "webpki", 1986 | ] 1987 | 1988 | [[package]] 1989 | name = "winapi" 1990 | version = "0.3.9" 1991 | source = "registry+https://github.com/rust-lang/crates.io-index" 1992 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1993 | dependencies = [ 1994 | "winapi-i686-pc-windows-gnu", 1995 | "winapi-x86_64-pc-windows-gnu", 1996 | ] 1997 | 1998 | [[package]] 1999 | name = "winapi-i686-pc-windows-gnu" 2000 | version = "0.4.0" 2001 | source = "registry+https://github.com/rust-lang/crates.io-index" 2002 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2003 | 2004 | [[package]] 2005 | name = "winapi-util" 2006 | version = "0.1.5" 2007 | source = "registry+https://github.com/rust-lang/crates.io-index" 2008 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 2009 | dependencies = [ 2010 | "winapi", 2011 | ] 2012 | 2013 | [[package]] 2014 | name = "winapi-x86_64-pc-windows-gnu" 2015 | version = "0.4.0" 2016 | source = "registry+https://github.com/rust-lang/crates.io-index" 2017 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2018 | -------------------------------------------------------------------------------- /signal/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libp2p-webrtc-star-signaling-server" 3 | version = "0.1.0" 4 | edition = "2018" 5 | authors = ["Oliver Wangler "] 6 | description = "WebRTC signaling server" 7 | license = "Apache-2.0 OR MIT" 8 | repository = "https://github.com/wngr/libp2p-webrtc" 9 | homepage = "https://github.com/wngr/libp2p-webrtc" 10 | documentation = "https://docs.rs/libp2p-webrtc" 11 | keywords = ["webrtc", "libp2p", "transport", "signaling"] 12 | readme = "README.md" 13 | 14 | [dependencies] 15 | acme-lib = "0.8.2" 16 | anyhow = "1.0.44" 17 | async-tungstenite = { version = "0.15.0", features = ["tokio", "tokio-rustls-native-certs"] } 18 | clap = "3.0.0-beta.4" 19 | futures = "0.3.17" 20 | parking_lot = "0.11.2" 21 | serde = { version = "1.0.130", features = ["derive"] } 22 | serde_json = "1.0.68" 23 | tokio = { version = "1.12.0", features = ["full"] } 24 | tokio-rustls = "0.22.0" 25 | tokio-stream = "0.1.7" 26 | tokio-util = { version = "0.6.8", features = ["compat"] } 27 | tracing = "0.1.28" 28 | tracing-subscriber = "0.2.24" 29 | warp = "0.3.1" 30 | -------------------------------------------------------------------------------- /signal/README.md: -------------------------------------------------------------------------------- 1 | # libp2p-webrtc-star signaling server 2 | 3 | [![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](https://github.com/wngr/libp2p-webrtc-star-signaling-server) 4 | [![Cargo](https://img.shields.io/crates/v/libp2p-webrtc.svg)](https://crates.io/crates/libp2p-webrtc-star-signaling-server) 5 | [![Documentation](https://docs.rs/libp2p-webrtc/badge.svg)](https://docs.rs/libp2p-webrtc-star-signaling-server) 6 | 7 | WebSocket signaling server to be used with 8 | [libp2p-webrtc](https://crates.io/crates/libp2p-webrtc-star-signaling-server). 9 | Optionally requests TLS certs through the ACME protocol automatically. 10 | 11 | Note, that this crate is currently not interoperable with the respective 12 | js-libp2p and go-libp2p implementations. 13 | 14 | ## License 15 | 16 | Licensed under either of 17 | 18 | * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 19 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 20 | 21 | at your option. 22 | 23 | #### Contribution 24 | 25 | Unless you explicitly state otherwise, any contribution intentionally submitted 26 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 27 | dual licensed as above, without any additional terms or conditions. 28 | -------------------------------------------------------------------------------- /signal/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::HashMap, 3 | fs::File, 4 | io::BufReader, 5 | path::{Path, PathBuf}, 6 | sync::Arc, 7 | }; 8 | 9 | use async_tungstenite::{ 10 | stream::Stream, 11 | tokio::accept_hdr_async, 12 | tungstenite::{ 13 | handshake::server::{ErrorResponse, Request, Response}, 14 | Message, 15 | }, 16 | }; 17 | use clap::{AppSettings, Clap}; 18 | use futures::{channel::oneshot, future, pin_mut, StreamExt}; 19 | use parking_lot::Mutex; 20 | use serde::{Deserialize, Serialize}; 21 | use tokio::{ 22 | net::{TcpListener, TcpStream}, 23 | sync::mpsc, 24 | }; 25 | use tokio_rustls::{ 26 | rustls::{ 27 | internal::pemfile::{certs, pkcs8_private_keys}, 28 | NoClientAuth, ServerConfig, 29 | }, 30 | TlsAcceptor, 31 | }; 32 | use tokio_stream::wrappers::ReceiverStream; 33 | use tokio_util::compat::*; 34 | use tracing::*; 35 | use tracing_subscriber::fmt; 36 | use warp::Filter; 37 | 38 | type Tx = mpsc::Sender; 39 | type ClientsMap = Arc), Tx>>>; 40 | 41 | #[derive(Serialize, Deserialize, Clone, PartialEq, Debug, Eq, Hash)] 42 | pub struct SignalingId { 43 | pub caller: String, 44 | pub counter: usize, 45 | } 46 | 47 | #[derive(Debug, Deserialize, Serialize)] 48 | #[serde(rename_all = "camelCase")] 49 | pub struct SignalingMessage { 50 | pub intent_id: SignalingId, 51 | pub callee: String, 52 | pub signal: serde_json::Value, 53 | } 54 | 55 | async fn handle( 56 | clients: ClientsMap, 57 | stream: TcpStream, 58 | tls_acceptor: Option, 59 | ) -> anyhow::Result<()> { 60 | let stream = if let Some(acceptor) = tls_acceptor { 61 | let stream = acceptor.accept(stream).await?; 62 | Stream::Tls(stream.compat()) 63 | } else { 64 | Stream::Plain(stream.compat()) 65 | } 66 | .compat(); 67 | let mut client_id = None; 68 | let callback = |req: &Request, response: Response| { 69 | let mut tokens = req.uri().path().split('/'); 70 | if let Some(token) = tokens.nth(1) { 71 | let id = tokens.next().and_then(|x| x.parse().ok()); 72 | client_id.replace((token.into(), id)); 73 | Ok(response) 74 | } else { 75 | Err(ErrorResponse::new(Some("Missing client id".to_string()))) 76 | } 77 | }; 78 | 79 | let websocket = accept_hdr_async(stream, callback).await?; 80 | let client_id = client_id.expect("Callback called"); 81 | println!("Client {:?} connected", &client_id); 82 | 83 | let (tx, rx) = mpsc::channel(128); 84 | clients.lock().insert(client_id.clone(), tx); 85 | 86 | let (outgoing, mut incoming) = websocket.split(); 87 | let forward = ReceiverStream::new(rx).map(Ok).forward(outgoing); 88 | let c = clients.clone(); 89 | let client_id_c = client_id.clone(); 90 | let process = async move { 91 | while let Some(Ok(msg)) = incoming.next().await { 92 | let maybe_signal = match &msg { 93 | Message::Text(t) => serde_json::from_str::(t).ok(), 94 | Message::Binary(b) => serde_json::from_slice::(b).ok(), 95 | _ => None, 96 | }; 97 | if let Some(signal) = maybe_signal { 98 | let to = if client_id.0 == signal.callee { 99 | // answer 100 | ( 101 | signal.intent_id.caller.clone(), 102 | Some(signal.intent_id.counter), 103 | ) 104 | } else { 105 | // offer 106 | (signal.callee.clone(), None) 107 | }; 108 | // Can't hold onto mutex across an await point 109 | let maybe_remote = c.lock().get(&to).cloned(); 110 | if let Some(remote) = maybe_remote { 111 | println!("{:?} << {:?}", to, signal); 112 | if let Err(e) = remote.clone().send(msg).await { 113 | println!("Error sending to {:?}: {:?}", to, e); 114 | } 115 | } else { 116 | println!("Received message for \"{:?}\", but client is unknown", to); 117 | } 118 | }; 119 | } 120 | }; 121 | 122 | pin_mut!(process, forward); 123 | future::select(process, forward).await; 124 | 125 | println!("Client {:?} disconnected", &client_id_c); 126 | clients.lock().remove(&client_id_c); 127 | Ok(()) 128 | } 129 | 130 | async fn get_cert( 131 | domain: String, 132 | email: String, 133 | certificate_file: impl AsRef, 134 | private_key_file: impl AsRef, 135 | ) -> anyhow::Result<()> { 136 | let url = acme_lib::DirectoryUrl::LetsEncrypt; 137 | 138 | let persist = acme_lib::persist::FilePersist::new("."); 139 | 140 | // Create a directory entrypoint. 141 | let dir = acme_lib::Directory::from_url(persist, url)?; 142 | 143 | let acc = dir.account(&email)?; 144 | 145 | let mut ord_new = acc.new_order(&domain, &[])?; 146 | let ord_csr = loop { 147 | // are we done? 148 | if let Some(ord_csr) = ord_new.confirm_validations() { 149 | break ord_csr; 150 | } 151 | 152 | let auths = ord_new.authorizations()?; 153 | let chall = auths[0].http_challenge(); 154 | let token = chall.http_token().to_string(); 155 | let proof = chall.http_proof(); 156 | 157 | info!(%token, %proof, "Serving acme-challenge"); 158 | let token = warp::get() 159 | .and(warp::path!(".well-known" / "acme-challenge" / String)) 160 | .map(move |_| { 161 | info!("Challenge served."); 162 | proof.clone() 163 | }); 164 | let (tx80, rx80) = oneshot::channel(); 165 | tokio::spawn( 166 | warp::serve(token) 167 | .bind_with_graceful_shutdown(([0, 0, 0, 0], 80), async { 168 | rx80.await.ok(); 169 | }) 170 | .1, 171 | ); 172 | 173 | chall.validate(5000)?; 174 | info!("Validated!"); 175 | tx80.send(()).unwrap(); 176 | 177 | ord_new.refresh()?; 178 | }; 179 | 180 | let pkey_pri = acme_lib::create_p384_key(); 181 | let ord_cert = ord_csr.finalize_pkey(pkey_pri, 5000)?; 182 | 183 | let cert = ord_cert.download_and_save_cert()?; 184 | info!("Received certificate"); 185 | 186 | std::fs::write(&certificate_file, cert.certificate())?; 187 | std::fs::write(&private_key_file, cert.private_key())?; 188 | info!( 189 | "Stored certificate / private key to {} / {}", 190 | certificate_file.as_ref().display(), 191 | private_key_file.as_ref().display() 192 | ); 193 | Ok(()) 194 | } 195 | 196 | #[derive(Clap)] 197 | #[clap(setting = AppSettings::ColoredHelp)] 198 | struct Opts { 199 | /// Interface to bind to 200 | #[clap(long)] 201 | interface: String, 202 | /// Domain to request a certificate for 203 | #[clap(long)] 204 | domain: Option, 205 | /// Port to bind to 206 | #[clap(long, default_value = "8000")] 207 | port: u16, 208 | #[clap(long)] 209 | /// Email to request a LetsEncrypt cert with 210 | email: Option, 211 | #[clap(long)] 212 | /// Path to a certificate file. Required if `wss` is given. 213 | cert: Option, 214 | #[clap(long)] 215 | /// Path to a private key file. Required if `wss` is given. 216 | private_key: Option, 217 | /// Use TLS 218 | #[clap(long)] 219 | wss: bool, 220 | } 221 | 222 | #[tokio::main] 223 | async fn main() -> anyhow::Result<()> { 224 | let opts: Opts = Opts::parse(); 225 | fmt::init(); 226 | 227 | let acceptor = if opts.wss { 228 | if let (Some(cert), Some(private_key), Some(email), Some(domain)) = 229 | (opts.cert, opts.private_key, opts.email, opts.domain) 230 | { 231 | if !cert.is_file() { 232 | info!("Certificate doesn't exist, requesting one"); 233 | get_cert(domain, email, &cert, &private_key).await?; 234 | } 235 | 236 | let mut config = ServerConfig::new(NoClientAuth::new()); 237 | config.set_single_cert( 238 | certs(&mut BufReader::new(File::open(&cert)?)).unwrap(), 239 | pkcs8_private_keys(&mut BufReader::new(File::open(private_key)?)) 240 | .unwrap() 241 | .remove(0), 242 | )?; 243 | let acceptor = TlsAcceptor::from(Arc::new(config)); 244 | Some(acceptor) 245 | } else { 246 | anyhow::bail!("Please provide `cert,` `private_key`, `domain`, and `email` options"); 247 | } 248 | } else { 249 | None 250 | }; 251 | 252 | let endpoint = format!("{}:{}", opts.interface, opts.port); 253 | let listener = TcpListener::bind(&endpoint).await?; 254 | println!("Listening on {}", endpoint); 255 | let clients = Arc::new(Mutex::new(HashMap::new())); 256 | 257 | while let Ok((stream, peer_addr)) = listener.accept().await { 258 | info!(?peer_addr, "Inbound connection"); 259 | let c = clients.clone(); 260 | let acceptor = acceptor.clone(); 261 | tokio::spawn(async move { 262 | if let Err(e) = handle(c, stream, acceptor).await { 263 | println!("Error handling inbound stream: {:#}", e); 264 | } 265 | }); 266 | } 267 | 268 | Ok(()) 269 | } 270 | --------------------------------------------------------------------------------