├── .editorconfig ├── .gitattributes ├── .gitignore ├── .vscode ├── extensions.json └── settings.json ├── README.md ├── browser ├── index.html └── index.js ├── c++ ├── CMakeLists.txt ├── beast.cpp └── qt.cpp ├── c ├── CMakeLists.txt ├── lws.c └── mg.c ├── csharp ├── Program.cs ├── aisStream.SimpleExample.csproj └── aisStream.SimpleExample.sln ├── dart ├── .gitignore ├── CHANGELOG.md ├── README.md ├── analysis_options.yaml ├── bin │ ├── ais_stream_websocket_client.dart │ └── app.dart ├── example.iml ├── pubspec.lock └── pubspec.yaml ├── golang ├── go.mod ├── go.sum ├── main.go └── main_filter_mmsi_and_messages.go ├── java ├── example-app │ ├── dependency-reduced-pom.xml │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── aisstream │ │ │ └── example-app │ │ │ ├── AisStreamWebsocketClient.java │ │ │ └── App.java │ │ └── test │ │ └── java │ │ └── io │ │ └── aisstream │ │ └── example-app │ │ └── AppTest.java └── readme.md ├── javascript ├── index.js ├── package-lock.json └── package.json ├── python ├── README.md ├── main.py ├── main_mmsi_message_filter.py ├── main_ssl_disabled.py └── setup.py ├── rust ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md └── src │ └── main.rs └── typescript ├── client.ts ├── package-lock.json ├── package.json └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | indent_style = space 9 | indent_size = 4 10 | max_line_length = 120 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | # Source code 4 | *.bash text eol=lf 5 | *.bat text eol=crlf 6 | *.c text diff=cpp 7 | *.cc text diff=cpp 8 | *.cmd text eol=crlf 9 | *.coffee text 10 | *.cpi text diff=cpp 11 | *.cpp text diff=cpp 12 | *.css text diff=css 13 | *.cxx text diff=cpp 14 | *.c++ text diff=cpp 15 | *.h text diff=cpp 16 | *.hh text diff=cpp 17 | *.hpp text diff=cpp 18 | *.htm text diff=html 19 | *.html text diff=html 20 | *.h++ text diff=cpp 21 | *.inc text 22 | *.ini text 23 | *.js text 24 | *.json text 25 | *.jsx text 26 | *.less text 27 | *.ls text 28 | *.map text -diff 29 | *.od text 30 | *.onlydata text 31 | *.php text diff=php 32 | *.pl text 33 | *.ps1 text eol=crlf 34 | *.py text diff=python 35 | *.rb text diff=ruby 36 | *.rs text diff=rust 37 | *.sass text 38 | *.scm text 39 | *.scss text diff=css 40 | *.sh text eol=lf 41 | *.sql text 42 | *.styl text 43 | *.tag text 44 | *.ts text 45 | *.tsx text 46 | *.xml text 47 | *.xhtml text diff=html 48 | 49 | # Compiled Object files 50 | *.slo binary 51 | *.lo binary 52 | *.o binary 53 | *.obj binary 54 | 55 | # Precompiled Headers 56 | *.gch binary 57 | *.pch binary 58 | 59 | # Compiled Dynamic libraries 60 | *.so binary 61 | *.dylib binary 62 | *.dll binary 63 | 64 | # Compiled Static libraries 65 | *.lai binary 66 | *.la binary 67 | *.a binary 68 | *.lib binary 69 | 70 | # Docker 71 | Dockerfile text 72 | 73 | # Documentation 74 | *.ipynb text 75 | *.markdown text diff=markdown 76 | *.md text diff=markdown 77 | *.mdwn text diff=markdown 78 | *.mdown text diff=markdown 79 | *.mkd text diff=markdown 80 | *.mkdn text diff=markdown 81 | *.mdtxt text 82 | *.mdtext text 83 | *.txt text 84 | AUTHORS text 85 | CHANGELOG text 86 | CHANGES text 87 | CONTRIBUTING text 88 | COPYING text 89 | copyright text 90 | *COPYRIGHT* text 91 | INSTALL text 92 | license text 93 | LICENSE text 94 | NEWS text 95 | readme text 96 | *README* text 97 | TODO text 98 | 99 | # Templates 100 | *.dot text 101 | *.ejs text 102 | *.erb text 103 | *.haml text 104 | *.handlebars text 105 | *.hbs text 106 | *.hbt text 107 | *.jade text 108 | *.latte text 109 | *.mustache text 110 | *.njk text 111 | *.phtml text 112 | *.svelte text 113 | *.tmpl text 114 | *.tpl text 115 | *.twig text 116 | *.vue text 117 | 118 | # Configs 119 | Cargo.lock text 120 | *.cnf text 121 | *.conf text 122 | *.config text 123 | .editorconfig text 124 | .env text 125 | .gitattributes text 126 | .gitconfig text 127 | .htaccess text 128 | *.lock text -diff 129 | package.json text eol=lf 130 | package-lock.json text -diff 131 | pnpm-lock.yaml text eol=lf -diff 132 | .prettierrc text 133 | yarn.lock text -diff 134 | *.toml text diff=toml 135 | *.yaml text 136 | *.yml text 137 | browserslist text 138 | Makefile text 139 | makefile text 140 | 141 | # Heroku 142 | Procfile text 143 | 144 | # Graphics 145 | *.ai binary 146 | *.bmp binary 147 | *.eps binary 148 | *.gif binary 149 | *.gifv binary 150 | *.ico binary 151 | *.jng binary 152 | *.jp2 binary 153 | *.jpg binary 154 | *.jpeg binary 155 | *.jpx binary 156 | *.jxr binary 157 | *.pdf binary 158 | *.png binary 159 | *.psb binary 160 | *.psd binary 161 | *.svg text 162 | *.svgz binary 163 | *.tif binary 164 | *.tiff binary 165 | *.wbmp binary 166 | *.webp binary 167 | 168 | # Audio 169 | *.kar binary 170 | *.m4a binary 171 | *.mid binary 172 | *.midi binary 173 | *.mp3 binary 174 | *.ogg binary 175 | *.ra binary 176 | 177 | # Video 178 | *.3gpp binary 179 | *.3gp binary 180 | *.as binary 181 | *.asf binary 182 | *.asx binary 183 | *.avi binary 184 | *.fla binary 185 | *.flv binary 186 | *.m4v binary 187 | *.mng binary 188 | *.mov binary 189 | *.mp4 binary 190 | *.mpeg binary 191 | *.mpg binary 192 | *.ogv binary 193 | *.swc binary 194 | *.swf binary 195 | *.webm binary 196 | 197 | # Archives 198 | *.7z binary 199 | *.gz binary 200 | *.jar binary 201 | *.rar binary 202 | *.tar binary 203 | *.zip binary 204 | 205 | # Fonts 206 | *.ttf binary 207 | *.eot binary 208 | *.otf binary 209 | *.woff binary 210 | *.woff2 binary 211 | 212 | # Executables 213 | *.exe binary 214 | *.out binary 215 | *.app binary 216 | 217 | # RC files 218 | *.*rc text 219 | 220 | # Ignore files 221 | *.*ignore text 222 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node 2 | **/node_modules/ 3 | npm-debug.log 4 | yarn-error.log 5 | 6 | # IDEs and editors 7 | .idea/ 8 | .project 9 | .classpath 10 | .c9/ 11 | *.launch 12 | .settings/ 13 | *.sublime-workspace 14 | 15 | # Visual Studio Code 16 | .vscode/* 17 | !.vscode/extensions.json 18 | !.vscode/launch.json 19 | !.vscode/settings.json 20 | !.vscode/tasks.json 21 | .history/* 22 | 23 | # System files 24 | .DS_Store 25 | Thumbs.db 26 | 27 | # Log 28 | *.log 29 | 30 | # Environment files 31 | .env 32 | .env.* 33 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "EditorConfig.EditorConfig", 4 | "rust-lang.rust-analyzer", 5 | "serayuzgur.crates", 6 | "tamasfe.even-better-toml", 7 | "usernamehw.errorlens", 8 | "vadimcn.vscode-lldb" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "rust-analyzer.check.command": "clippy", 4 | "rust-analyzer.linkedProjects": ["./rust/Cargo.toml"], 5 | "[rust]": { 6 | "editor.defaultFormatter": "rust-lang.rust-analyzer" 7 | }, 8 | "[markdown]": { 9 | "editor.wordWrap": "off" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | This repository contains examples of using the AISStream API in Golang, Python, JavaScript and many more languages. 4 | 5 | ## Prerequisites 6 | 7 | Before you can use these examples, you will need to sign up for an AISStream API key at [aisstream.io](https://aisstream.io/authenticate). 8 | 9 | ### Golang Example 10 | 11 | To run the Golang example, you will need to have Go installed on your system. 12 | 13 | Clone the repository: `git clone https://github.com/aisstream/example`. Navigate to the golang directory: `cd example/golang`. Install the dependencies: `go get -d`. Replace `""` in the `main.go` file with your AISStream API key. Run the example: `go run main.go`. 14 | 15 | ### Python Example 16 | 17 | To run the Python example, you will need to have Python 3 installed on your system. 18 | 19 | Clone the repository: `git clone https://github.com/aisstream/example`. Navigate to the python directory: `cd example/python`. Install the dependencies: `python setup.py install`. Replace `""` in the `main.py` file with your AISStream API key. Run the example: python main.py. 20 | 21 | ### JavaScript Example 22 | 23 | To run the JavaScript example, you will need to have Node.js installed on your system. 24 | 25 | Clone the repository: `git clone https://github.com/aisstream/example`. 26 | Navigate to the javascript directory: `cd example/javascript`. 27 | Install the dependencies: `npm install`. 28 | To run the Javascript example, define the environment variable `AISSTREAM_API_KEY` with your AISStream API key. 29 | Run the example: `node main.js`. 30 | 31 | ### C# Example 32 | 33 | To run the C# example, you will need to have .NET 8 installed on your system. 34 | 35 | ### C Example 36 | 37 | To build the C examples, you will need to have [CMake 3.20+](https://cmake.org) and OpenSSL installed on your system. In addition, one example (`lws.c`) requires [libwebsocket](https://libwebsockets.org/) with OpenSSL. To run the C examples, replace `""` in the `lws.c` and `mg.c` files with your AISStream API key. 38 | 39 | ### C++ Examples 40 | 41 | To build the C++ examples, you will need to have [CMake 3.20+](https://cmake.org) and OpenSSL installed on your system. Two C++ examples are available. One with [Boost.Beast](https://www.boost.org/doc/libs/1_84_0/libs/beast/doc/html/index.html) and one with [Qt](https://www.qt.io/download-open-source). 42 | 43 | ### Rust Example 44 | 45 | To build the Rust example, you will need to have [Rust 1.77.2+](https://www.rust-lang.org). 46 | To run the Rust example, define the environment variable `AISSTREAM_API_KEY` with your AISStream API key. 47 | 48 | ### Additional Resources 49 | 50 | For more information on the AISStream API, visit the [AISStream documentation](https://aisstream.io/documentation). 51 | -------------------------------------------------------------------------------- /browser/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 |
7 | 8 | 9 | -------------------------------------------------------------------------------- /browser/index.js: -------------------------------------------------------------------------------- 1 | const container = document.getElementById("position-data"); 2 | 3 | const socket = new WebSocket("ws://localhost:3333/v0/stream"); 4 | 5 | socket.onopen = function (event) { 6 | console.log("socket is open", event); 7 | const subscriptionMessage = { 8 | Apikey: "e606bdfbb09fb210b4a2b3c4a02c29b61c6b70b1", 9 | BoundingBoxes: [ 10 | [ 11 | [-180, -90], 12 | [180, 90], 13 | ], 14 | ], 15 | }; 16 | socket.send(JSON.stringify(subscriptionMessage)); 17 | }; 18 | 19 | socket.onmessage = function (event) { 20 | console.log(event.data) 21 | const aisMessage = JSON.parse(event.data); 22 | if (aisMessage["MessageType"] === "PositionReport") { 23 | let positionReport = aisMessage["Message"]["PositionReport"]; 24 | const positionMessage = `ShipId: ${positionReport["UserID"]} Latitude: ${positionReport["Latitude"]} Longitude: ${positionReport["Longitude"]}`; 25 | console.log(positionMessage); 26 | const span = document.createElement("span"); 27 | span.innerText = positionMessage; 28 | container.appendChild(span); 29 | } 30 | }; 31 | 32 | socket.onclose = function (event) { 33 | console.log("socket is closed", event); 34 | }; 35 | 36 | console.log("created socket", socket); 37 | -------------------------------------------------------------------------------- /c++/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | 3 | project(AisStream 4 | VERSION 1.0.0 5 | LANGUAGES C CXX 6 | HOMEPAGE_URL "https://aisstream.io/" 7 | ) 8 | 9 | set(CMAKE_CXX_STANDARD 17) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | set(CMAKE_DEBUG_POSTFIX d) 12 | set(CMAKE_AUTOMOC ON) 13 | if(MSVC) 14 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") 15 | endif() 16 | 17 | # Example with beast 18 | find_package(Boost) 19 | find_package(OpenSSL COMPONENTS Crypto SSL) 20 | if(OPENSSL_FOUND AND Boost_FOUND) 21 | add_executable(example_beast beast.cpp) 22 | target_link_libraries(example_beast PUBLIC OpenSSL::SSL) 23 | target_include_directories(example_beast PUBLIC ${Boost_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}/..) 24 | target_link_libraries(example_beast ${Boost_LIBRARIES}) 25 | set_target_properties(example_beast PROPERTIES AUTOMOC OFF) 26 | if(MSVC) 27 | target_compile_options(example_beast PRIVATE /bigobj) 28 | endif() 29 | endif() 30 | 31 | # Example with Qt 32 | find_package(Qt6 COMPONENTS Core WebSockets) 33 | if(Qt6_FOUND) 34 | qt_add_executable(example_qt qt.cpp) 35 | set_target_properties(example_qt PROPERTIES WIN32_EXECUTABLE FALSE MACOSX_BUNDLE FALSE) 36 | target_link_libraries(example_qt PUBLIC Qt6::WebSockets) 37 | endif() 38 | -------------------------------------------------------------------------------- /c++/beast.cpp: -------------------------------------------------------------------------------- 1 | #ifdef _WIN32 2 | #include 3 | #endif 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // Sends a WebSocket message and prints the response 16 | class session : public std::enable_shared_from_this 17 | { 18 | private: 19 | boost::asio::ip::tcp::resolver m_resolver; 20 | boost::beast::websocket::stream> m_ws; 21 | boost::beast::flat_buffer m_buffer; 22 | std::string m_host; 23 | std::string m_text; 24 | 25 | private: 26 | // Report a failure 27 | void fail(boost::beast::error_code ec, char const* what) 28 | { 29 | std::cerr << what << ": " << ec.message() << "\n"; 30 | } 31 | 32 | public: 33 | // Resolver and socket require an io_context 34 | explicit session(boost::asio::io_context& ioc, boost::asio::ssl::context& ctx) 35 | : m_resolver(boost::asio::make_strand(ioc)) 36 | , m_ws(boost::asio::make_strand(ioc), ctx) 37 | , m_host("stream.aisstream.io") 38 | , m_text("{ \"APIKey\": \"\", \"BoundingBoxes\": [[[-11.0, 178.0], [30.0, 74.0]]]}") 39 | { 40 | } 41 | 42 | // Start the asynchronous operation 43 | void run() 44 | { 45 | // Look up the domain name 46 | m_resolver.async_resolve(m_host, "443", boost::beast::bind_front_handler(&session::on_resolve, shared_from_this())); 47 | } 48 | 49 | void on_resolve(boost::beast::error_code ec, boost::asio::ip::tcp::resolver::results_type results) 50 | { 51 | if (ec) 52 | return fail(ec, "resolve"); 53 | 54 | // Set a timeout on the operation 55 | boost::beast::get_lowest_layer(m_ws).expires_after(std::chrono::seconds(30)); 56 | 57 | // Make the connection on the IP address we get from a lookup 58 | boost::beast::get_lowest_layer(m_ws).async_connect(results, boost::beast::bind_front_handler(&session::on_connect, shared_from_this())); 59 | } 60 | 61 | void on_connect(boost::beast::error_code ec, boost::asio::ip::tcp::resolver::results_type::endpoint_type ep) 62 | { 63 | if (ec) 64 | return fail(ec, "connect"); 65 | 66 | // Set a timeout on the operation 67 | boost::beast::get_lowest_layer(m_ws).expires_after(std::chrono::seconds(30)); 68 | 69 | // Set SNI Hostname (many hosts need this to handshake successfully) 70 | if (!SSL_set_tlsext_host_name(m_ws.next_layer().native_handle(), m_host.c_str())) 71 | { 72 | ec = boost::beast::error_code(static_cast(::ERR_get_error()), boost::asio::error::get_ssl_category()); 73 | return fail(ec, "connect"); 74 | } 75 | 76 | // Update the host_ string. This will provide the value of the 77 | // Host HTTP header during the WebSocket handshake. 78 | // See https://tools.ietf.org/html/rfc7230#section-5.4 79 | m_host += ':' + std::to_string(ep.port()); 80 | 81 | // Perform the SSL handshake 82 | m_ws.next_layer().async_handshake(boost::asio::ssl::stream_base::client, boost::beast::bind_front_handler(&session::on_ssl_handshake, shared_from_this())); 83 | } 84 | 85 | void on_ssl_handshake(boost::beast::error_code ec) 86 | { 87 | if (ec) 88 | return fail(ec, "ssl_handshake"); 89 | 90 | // Turn off the timeout on the tcp_stream, because 91 | // the websocket stream has its own timeout system. 92 | boost::beast::get_lowest_layer(m_ws).expires_never(); 93 | 94 | // Set suggested timeout settings for the websocket 95 | m_ws.set_option(boost::beast::websocket::stream_base::timeout::suggested(boost::beast::role_type::client)); 96 | 97 | // Set a decorator to change the User-Agent of the handshake 98 | m_ws.set_option(boost::beast::websocket::stream_base::decorator([](boost::beast::websocket::request_type& req) 99 | { 100 | req.set(boost::beast::http::field::user_agent, std::string(BOOST_BEAST_VERSION_STRING) + " websocket-client-async-ssl"); 101 | })); 102 | 103 | // Perform the websocket handshake 104 | m_ws.async_handshake(m_host, "/v0/stream", boost::beast::bind_front_handler(&session::on_handshake,shared_from_this())); 105 | } 106 | 107 | void on_handshake(boost::beast::error_code ec) 108 | { 109 | if (ec) 110 | return fail(ec, "handshake"); 111 | 112 | // Send the message 113 | m_ws.async_write(boost::asio::buffer(m_text), boost::beast::bind_front_handler(&session::on_write, shared_from_this())); 114 | } 115 | 116 | void on_write(boost::beast::error_code ec, std::size_t bytes_transferred) 117 | { 118 | boost::ignore_unused(bytes_transferred); 119 | 120 | if (ec) 121 | return fail(ec, "write"); 122 | 123 | // Read a message into our buffer 124 | m_ws.async_read(m_buffer, boost::beast::bind_front_handler(&session::on_read, shared_from_this())); 125 | } 126 | 127 | void on_read(boost::beast::error_code ec, std::size_t bytes_transferred) 128 | { 129 | boost::ignore_unused(bytes_transferred); 130 | 131 | if (ec) 132 | { 133 | fail(ec, "read"); 134 | 135 | // Close the WebSocket connection 136 | m_ws.async_close(boost::beast::websocket::close_code::normal, boost::beast::bind_front_handler(&session::on_close, shared_from_this())); 137 | } 138 | else 139 | { 140 | // The make_printable() function helps print a ConstBufferSequence 141 | std::cout << boost::beast::make_printable(m_buffer.data()) << std::endl; 142 | 143 | m_buffer.clear(); 144 | m_ws.async_read(m_buffer, boost::beast::bind_front_handler(&session::on_read, shared_from_this())); 145 | } 146 | } 147 | 148 | void on_close(boost::beast::error_code ec) 149 | { 150 | if (ec) 151 | return fail(ec, "close"); 152 | 153 | // If we get here then the connection is closed gracefully 154 | } 155 | }; 156 | 157 | //------------------------------------------------------------------------------ 158 | 159 | int main(int argc, char** argv) 160 | { 161 | // The io_context is required for all I/O 162 | boost::asio::io_context ioc; 163 | 164 | // The SSL context is required, and holds certificates 165 | boost::asio::ssl::context ctx{ boost::asio::ssl::context::tlsv12_client }; 166 | 167 | // Launch the asynchronous operation 168 | std::make_shared(ioc, ctx)->run(); 169 | 170 | // Run the I/O service. The call will return when 171 | // the socket is closed. 172 | ioc.run(); 173 | 174 | return EXIT_SUCCESS; 175 | } 176 | -------------------------------------------------------------------------------- /c++/qt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | class AisStreamClient : public QObject 8 | { 9 | Q_OBJECT 10 | public: 11 | explicit AisStreamClient(QObject* parent = nullptr); 12 | 13 | private Q_SLOTS: 14 | void onConnected(); 15 | void onTextMessageReceived(QString message); 16 | void onBinaryMessageReceived(const QByteArray& message); 17 | void onSslErrors(const QList& errors); 18 | 19 | private: 20 | QWebSocket m_webSocket; 21 | }; 22 | 23 | #include "qt.moc" 24 | 25 | AisStreamClient::AisStreamClient(QObject* parent) 26 | : QObject(parent) 27 | { 28 | connect(&m_webSocket, &QWebSocket::connected, this, &AisStreamClient::onConnected); 29 | connect(&m_webSocket, QOverload&>::of(&QWebSocket::sslErrors), this, &AisStreamClient::onSslErrors); 30 | QSslConfiguration sslConfiguration; 31 | m_webSocket.setSslConfiguration(sslConfiguration); 32 | m_webSocket.open(QUrl("wss://stream.aisstream.io/v0/stream")); 33 | } 34 | 35 | void AisStreamClient::onConnected() 36 | { 37 | qDebug() << "WebSocket connected"; 38 | connect(&m_webSocket, &QWebSocket::textMessageReceived, this, &AisStreamClient::onTextMessageReceived); 39 | connect(&m_webSocket, &QWebSocket::binaryMessageReceived, this, &AisStreamClient::onBinaryMessageReceived); 40 | m_webSocket.sendTextMessage(QStringLiteral("{ \"APIKey\": \"\", \"BoundingBoxes\": [[[-11.0, 178.0], [30.0, 74.0]]]}")); 41 | } 42 | 43 | void AisStreamClient::onTextMessageReceived(QString message) 44 | { 45 | qDebug() << "Message received:" << message; 46 | } 47 | 48 | void AisStreamClient::onBinaryMessageReceived(const QByteArray& message) 49 | { 50 | onTextMessageReceived(QString(message)); 51 | } 52 | 53 | void AisStreamClient::onSslErrors(const QList& errors) 54 | { 55 | qWarning() << "SSL errors:" << errors; 56 | qApp->quit(); 57 | } 58 | 59 | int main(int argc, char* argv[]) 60 | { 61 | QCoreApplication a(argc, argv); 62 | 63 | AisStreamClient client; 64 | Q_UNUSED(client); 65 | 66 | return a.exec(); 67 | } 68 | -------------------------------------------------------------------------------- /c/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | 3 | project(AisStream 4 | VERSION 1.0.0 5 | LANGUAGES C 6 | HOMEPAGE_URL "https://aisstream.io/" 7 | ) 8 | 9 | set(CMAKE_C_STANDARD 17) 10 | set(CMAKE_C_STANDARD_REQUIRED ON) 11 | set(CMAKE_DEBUG_POSTFIX d) 12 | if(MSVC) 13 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP") 14 | endif() 15 | 16 | # Example with mongoose 17 | find_package(OpenSSL QUIET COMPONENTS Crypto SSL) 18 | if(OPENSSL_FOUND) 19 | if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/mongoose.c) 20 | file(DOWNLOAD https://raw.githubusercontent.com/cesanta/mongoose/master/mongoose.c ${CMAKE_CURRENT_BINARY_DIR}/mongoose.c) 21 | endif() 22 | if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/mongoose.h) 23 | file(DOWNLOAD https://raw.githubusercontent.com/cesanta/mongoose/master/mongoose.h ${CMAKE_CURRENT_BINARY_DIR}/mongoose.h) 24 | endif() 25 | add_executable(example_mg mg.c ${CMAKE_CURRENT_BINARY_DIR}/mongoose.c ${CMAKE_CURRENT_BINARY_DIR}/mongoose.h) 26 | target_include_directories(example_mg PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) 27 | target_link_libraries(example_mg PUBLIC OpenSSL::SSL) 28 | target_compile_definitions(example_mg PRIVATE MG_TLS=MG_TLS_OPENSSL) 29 | endif() 30 | 31 | # Example with libwebsockets 32 | find_package(libwebsockets QUIET) 33 | if(libwebsockets_FOUND) 34 | include(LwsCheckRequirements) 35 | set(requirements 1) 36 | require_lws_config(LWS_ROLE_WS 1 requirements) 37 | require_lws_config(LWS_WITH_CLIENT 1 requirements) 38 | 39 | if (requirements) 40 | add_executable(example_lws lws.c) 41 | target_link_libraries(example_lws PUBLIC websockets) 42 | endif() 43 | endif() 44 | -------------------------------------------------------------------------------- /c/lws.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static struct lws_context* context; 6 | static int interrupted = 0; 7 | static const char* msg = "{ \"APIKey\": \"\", \"BoundingBoxes\": [[[-11.0, 178.0], [30.0, 74.0]]]}"; 8 | 9 | static int connect_client() 10 | { 11 | struct lws_client_connect_info i; 12 | 13 | memset(&i, 0, sizeof(i)); 14 | 15 | i.context = context; 16 | i.port = 443; 17 | i.address = "stream.aisstream.io"; 18 | i.path = "/v0/stream"; 19 | i.host = i.address; 20 | i.origin = i.address; 21 | i.ssl_connection = LCCSCF_USE_SSL | LCCSCF_ALLOW_SELFSIGNED | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK; 22 | i.protocol = "lws-minimal"; 23 | i.local_protocol_name = i.protocol; 24 | 25 | lwsl_notice("%s: connection %s:%d\n", __func__, i.address, i.port); 26 | if (!lws_client_connect_via_info(&i)) return 1; 27 | 28 | return 0; 29 | } 30 | 31 | static int callback(struct lws* wsi, enum lws_callback_reasons reason, void* user, void* in, size_t len) 32 | { 33 | int m = 0, n = 0; 34 | short r; 35 | 36 | switch (reason) { 37 | 38 | case LWS_CALLBACK_PROTOCOL_INIT: 39 | connect_client(); 40 | break; 41 | 42 | case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: 43 | lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", in ? (char*)in : "(null)"); 44 | interrupted = 1; 45 | break; 46 | 47 | /* --- client callbacks --- */ 48 | 49 | case LWS_CALLBACK_CLIENT_ESTABLISHED: 50 | lws_callback_on_writable(wsi); 51 | lwsl_user("%s: established connection, wsi = %p\n", __func__, wsi); 52 | break; 53 | 54 | case LWS_CALLBACK_CLIENT_CLOSED: 55 | lwsl_user("%s: CLOSED\n", __func__); 56 | interrupted = 1; 57 | break; 58 | 59 | case LWS_CALLBACK_CLIENT_WRITEABLE: 60 | n = (int)strlen(msg); 61 | m = lws_write(wsi, (unsigned char*)msg, n, LWS_WRITE_TEXT); 62 | if (m < n) 63 | { 64 | lwsl_err("sending message failed: %d < %d\n", m, n); 65 | return -1; 66 | } 67 | break; 68 | 69 | case LWS_CALLBACK_CLIENT_RECEIVE: 70 | lwsl_user("RX: %s\n", (const char*)in); 71 | break; 72 | 73 | case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: 74 | lwsl_notice("server initiated connection close: len = %lu, in = %s\n", (unsigned long)len, (char*)in); 75 | return 0; 76 | 77 | default: 78 | break; 79 | } 80 | 81 | return lws_callback_http_dummy(wsi, reason, user, in, len); 82 | } 83 | 84 | static const struct lws_protocols protocols[] = { 85 | { "rx-tx", callback, 4096, 4096, 0, NULL, 0 }, 86 | LWS_PROTOCOL_LIST_TERM 87 | }; 88 | 89 | static void sigint_handler(int sig) 90 | { 91 | interrupted = 1; 92 | } 93 | 94 | int main(int argc, const char** argv) 95 | { 96 | struct lws_context_creation_info info; 97 | int n = 0; 98 | 99 | signal(SIGINT, sigint_handler); 100 | 101 | lws_set_log_level(LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE, NULL); 102 | 103 | memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ 104 | info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; 105 | info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */ 106 | info.protocols = protocols; 107 | #if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL) 108 | /* 109 | * OpenSSL uses the system trust store. mbedTLS has to be told which 110 | * CA to trust explicitly. 111 | */ 112 | info.client_ssl_ca_filepath = "./stream.aisstream.io.cer"; 113 | #endif 114 | info.fd_limit_per_thread = (unsigned int)3; 115 | 116 | context = lws_create_context(&info); 117 | if (!context) 118 | { 119 | lwsl_err("lws init failed\n"); 120 | return 1; 121 | } 122 | 123 | while (n >= 0 && !interrupted) 124 | n = lws_service(context, 0); 125 | 126 | lwsl_notice("%s: exiting service loop. n = %d, interrupted = %d\n", __func__, n, interrupted); 127 | 128 | lws_context_destroy(context); 129 | 130 | return 0; 131 | } 132 | -------------------------------------------------------------------------------- /c/mg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static bool interrupted = false; 6 | static const char* msg = "{ \"APIKey\": \"\", \"BoundingBoxes\": [[[-11.0, 178.0], [30.0, 74.0]]]}"; 7 | static const char* url = "wss://stream.aisstream.io/v0/stream"; 8 | 9 | static void callback(struct mg_connection* c, int ev, void* ev_data, void* fn_data) 10 | { 11 | if (ev == MG_EV_OPEN) 12 | { 13 | c->is_hexdumping = 1; 14 | } 15 | else if (ev == MG_EV_CONNECT) 16 | { 17 | struct mg_tls_opts opts; 18 | memset(&opts, 0, sizeof(struct mg_tls_opts)); 19 | mg_tls_init(c, &opts); 20 | } 21 | else if (ev == MG_EV_ERROR) 22 | { 23 | MG_ERROR(("%p %s", c->fd, (char*)ev_data)); 24 | interrupted = true; 25 | } 26 | else if (ev == MG_EV_WS_OPEN) 27 | { 28 | mg_ws_send(c, msg, strlen(msg), WEBSOCKET_OP_TEXT); 29 | } 30 | else if (ev == MG_EV_WS_MSG) 31 | { 32 | // When we get response, print it 33 | struct mg_ws_message* wm = (struct mg_ws_message*)ev_data; 34 | printf("RX: [%.*s]\n", (int)wm->data.len, wm->data.ptr); 35 | } 36 | else if (ev == MG_EV_ERROR || ev == MG_EV_CLOSE) 37 | { 38 | interrupted = true; 39 | } 40 | else 41 | { 42 | } 43 | } 44 | 45 | static void sigint_handler(int sig) 46 | { 47 | interrupted = true; 48 | } 49 | 50 | int main(int argc, const char** argv) 51 | { 52 | signal(SIGINT, sigint_handler); 53 | 54 | struct mg_mgr mgr; // Event manager 55 | struct mg_connection* c; // Client connection 56 | mg_mgr_init(&mgr); // Initialise event manager 57 | mg_log_set(MG_LL_INFO); // Set log level 58 | c = mg_ws_connect(&mgr, url, callback, NULL, NULL); // Create client 59 | while (c && interrupted == false) mg_mgr_poll(&mgr, 100); // Wait for echo 60 | mg_mgr_free(&mgr); // Deallocate resources 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /csharp/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.WebSockets; 3 | using System.Text; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace aisStream.SimpleExample 8 | { 9 | internal class Program 10 | { 11 | public static async Task Main(string[] args) 12 | { 13 | CancellationTokenSource source = new CancellationTokenSource(); 14 | CancellationToken token = source.Token; 15 | using (var ws = new ClientWebSocket()) 16 | { 17 | await ws.ConnectAsync(new Uri("wss://stream.aisstream.io/v0/stream"), token); 18 | await ws.SendAsync(new ArraySegment(Encoding.UTF8.GetBytes("{ \"APIKey\": \"\", \"BoundingBoxes\": [[[-11.0, 178.0], [30.0, 74.0]]]}")), WebSocketMessageType.Text, true, token); 19 | byte[] buffer = new byte[4096]; 20 | while (ws.State == WebSocketState.Open) 21 | { 22 | var result = await ws.ReceiveAsync(new ArraySegment(buffer), token); 23 | if (result.MessageType == WebSocketMessageType.Close) 24 | { 25 | await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, token); 26 | } 27 | else 28 | { 29 | Console.WriteLine($"Received {Encoding.Default.GetString(buffer, 0, result.Count)}"); 30 | } 31 | } 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /csharp/aisStream.SimpleExample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /csharp/aisStream.SimpleExample.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.8.34330.188 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "aisStream.SimpleExample", "aisStream.SimpleExample.csproj", "{823345A8-ED41-4A61-9ACF-7BBB7B3192DC}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {823345A8-ED41-4A61-9ACF-7BBB7B3192DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {823345A8-ED41-4A61-9ACF-7BBB7B3192DC}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {823345A8-ED41-4A61-9ACF-7BBB7B3192DC}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {823345A8-ED41-4A61-9ACF-7BBB7B3192DC}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {EB1DC92E-A23A-4370-8EB2-E18453902F99} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /dart/.gitignore: -------------------------------------------------------------------------------- 1 | # https://dart.dev/guides/libraries/private-files 2 | # Created by `dart pub` 3 | .dart_tool/ 4 | -------------------------------------------------------------------------------- /dart/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.0 2 | 3 | - Initial version. 4 | -------------------------------------------------------------------------------- /dart/README.md: -------------------------------------------------------------------------------- 1 | A sample AISStream command line tool in `bin/`. 2 | -------------------------------------------------------------------------------- /dart/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the static analysis results for your project (errors, 2 | # warnings, and lints). 3 | # 4 | # This enables the 'recommended' set of lints from `package:lints`. 5 | # This set helps identify many issues that may lead to problems when running 6 | # or consuming Dart code, and enforces writing Dart using a single, idiomatic 7 | # style and format. 8 | # 9 | # If you want a smaller set of lints you can change this to specify 10 | # 'package:lints/core.yaml'. These are just the most critical lints 11 | # (the recommended set includes the core lints). 12 | # The core lints are also what is used by pub.dev for scoring packages. 13 | 14 | include: package:lints/recommended.yaml 15 | 16 | # Uncomment the following section to specify additional rules. 17 | 18 | # linter: 19 | # rules: 20 | # - camel_case_types 21 | 22 | # analyzer: 23 | # exclude: 24 | # - path/to/excluded/files/** 25 | 26 | # For more information about the core and recommended set of lints, see 27 | # https://dart.dev/go/core-lints 28 | 29 | # For additional information about configuring this file, see 30 | # https://dart.dev/guides/language/analysis-options 31 | -------------------------------------------------------------------------------- /dart/bin/ais_stream_websocket_client.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:web_socket_channel/web_socket_channel.dart'; 4 | 5 | class AISStreamWebsocketClient { 6 | final String _serverUri; 7 | 8 | AISStreamWebsocketClient(this._serverUri); 9 | 10 | void connect() async { 11 | final channel = WebSocketChannel.connect( 12 | Uri.parse(_serverUri), 13 | ); 14 | await channel.ready; 15 | channel.stream.listen(onMessage); 16 | channel.sink.add( 17 | '{"APIKey":"","BoundingBoxes":[[[-90,-180],[90,180]]]}', 18 | ); 19 | } 20 | 21 | void onMessage(dynamic message) { 22 | final jsonString = utf8.decode(message); 23 | print(jsonString); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /dart/bin/app.dart: -------------------------------------------------------------------------------- 1 | import 'ais_stream_websocket_client.dart'; 2 | 3 | void main() { 4 | final aissstream = AISStreamWebsocketClient( 5 | 'wss://stream.aisstream.io/v0/stream', 6 | ); 7 | aissstream.connect(); 8 | } 9 | -------------------------------------------------------------------------------- /dart/example.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /dart/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | _fe_analyzer_shared: 5 | dependency: transitive 6 | description: 7 | name: _fe_analyzer_shared 8 | sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "67.0.0" 12 | analyzer: 13 | dependency: transitive 14 | description: 15 | name: analyzer 16 | sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "6.4.1" 20 | args: 21 | dependency: transitive 22 | description: 23 | name: args 24 | sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "2.4.2" 28 | async: 29 | dependency: transitive 30 | description: 31 | name: async 32 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "2.11.0" 36 | boolean_selector: 37 | dependency: transitive 38 | description: 39 | name: boolean_selector 40 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "2.1.1" 44 | collection: 45 | dependency: transitive 46 | description: 47 | name: collection 48 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.18.0" 52 | convert: 53 | dependency: transitive 54 | description: 55 | name: convert 56 | sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "3.1.1" 60 | coverage: 61 | dependency: transitive 62 | description: 63 | name: coverage 64 | sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76" 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "1.7.2" 68 | crypto: 69 | dependency: transitive 70 | description: 71 | name: crypto 72 | sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab 73 | url: "https://pub.dev" 74 | source: hosted 75 | version: "3.0.3" 76 | file: 77 | dependency: transitive 78 | description: 79 | name: file 80 | sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" 81 | url: "https://pub.dev" 82 | source: hosted 83 | version: "7.0.0" 84 | frontend_server_client: 85 | dependency: transitive 86 | description: 87 | name: frontend_server_client 88 | sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 89 | url: "https://pub.dev" 90 | source: hosted 91 | version: "4.0.0" 92 | glob: 93 | dependency: transitive 94 | description: 95 | name: glob 96 | sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" 97 | url: "https://pub.dev" 98 | source: hosted 99 | version: "2.1.2" 100 | http_multi_server: 101 | dependency: transitive 102 | description: 103 | name: http_multi_server 104 | sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" 105 | url: "https://pub.dev" 106 | source: hosted 107 | version: "3.2.1" 108 | http_parser: 109 | dependency: transitive 110 | description: 111 | name: http_parser 112 | sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" 113 | url: "https://pub.dev" 114 | source: hosted 115 | version: "4.0.2" 116 | io: 117 | dependency: transitive 118 | description: 119 | name: io 120 | sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" 121 | url: "https://pub.dev" 122 | source: hosted 123 | version: "1.0.4" 124 | js: 125 | dependency: transitive 126 | description: 127 | name: js 128 | sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf 129 | url: "https://pub.dev" 130 | source: hosted 131 | version: "0.7.1" 132 | lints: 133 | dependency: "direct dev" 134 | description: 135 | name: lints 136 | sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 137 | url: "https://pub.dev" 138 | source: hosted 139 | version: "3.0.0" 140 | logging: 141 | dependency: transitive 142 | description: 143 | name: logging 144 | sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" 145 | url: "https://pub.dev" 146 | source: hosted 147 | version: "1.2.0" 148 | matcher: 149 | dependency: transitive 150 | description: 151 | name: matcher 152 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb 153 | url: "https://pub.dev" 154 | source: hosted 155 | version: "0.12.16+1" 156 | meta: 157 | dependency: transitive 158 | description: 159 | name: meta 160 | sha256: "25dfcaf170a0190f47ca6355bdd4552cb8924b430512ff0cafb8db9bd41fe33b" 161 | url: "https://pub.dev" 162 | source: hosted 163 | version: "1.14.0" 164 | mime: 165 | dependency: transitive 166 | description: 167 | name: mime 168 | sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e 169 | url: "https://pub.dev" 170 | source: hosted 171 | version: "1.0.4" 172 | node_preamble: 173 | dependency: transitive 174 | description: 175 | name: node_preamble 176 | sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" 177 | url: "https://pub.dev" 178 | source: hosted 179 | version: "2.0.2" 180 | package_config: 181 | dependency: transitive 182 | description: 183 | name: package_config 184 | sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" 185 | url: "https://pub.dev" 186 | source: hosted 187 | version: "2.1.0" 188 | path: 189 | dependency: transitive 190 | description: 191 | name: path 192 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" 193 | url: "https://pub.dev" 194 | source: hosted 195 | version: "1.9.0" 196 | pool: 197 | dependency: transitive 198 | description: 199 | name: pool 200 | sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" 201 | url: "https://pub.dev" 202 | source: hosted 203 | version: "1.5.1" 204 | pub_semver: 205 | dependency: transitive 206 | description: 207 | name: pub_semver 208 | sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" 209 | url: "https://pub.dev" 210 | source: hosted 211 | version: "2.1.4" 212 | shelf: 213 | dependency: transitive 214 | description: 215 | name: shelf 216 | sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 217 | url: "https://pub.dev" 218 | source: hosted 219 | version: "1.4.1" 220 | shelf_packages_handler: 221 | dependency: transitive 222 | description: 223 | name: shelf_packages_handler 224 | sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" 225 | url: "https://pub.dev" 226 | source: hosted 227 | version: "3.0.2" 228 | shelf_static: 229 | dependency: transitive 230 | description: 231 | name: shelf_static 232 | sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e 233 | url: "https://pub.dev" 234 | source: hosted 235 | version: "1.1.2" 236 | shelf_web_socket: 237 | dependency: transitive 238 | description: 239 | name: shelf_web_socket 240 | sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" 241 | url: "https://pub.dev" 242 | source: hosted 243 | version: "1.0.4" 244 | source_map_stack_trace: 245 | dependency: transitive 246 | description: 247 | name: source_map_stack_trace 248 | sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" 249 | url: "https://pub.dev" 250 | source: hosted 251 | version: "2.1.1" 252 | source_maps: 253 | dependency: transitive 254 | description: 255 | name: source_maps 256 | sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" 257 | url: "https://pub.dev" 258 | source: hosted 259 | version: "0.10.12" 260 | source_span: 261 | dependency: transitive 262 | description: 263 | name: source_span 264 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 265 | url: "https://pub.dev" 266 | source: hosted 267 | version: "1.10.0" 268 | stack_trace: 269 | dependency: transitive 270 | description: 271 | name: stack_trace 272 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" 273 | url: "https://pub.dev" 274 | source: hosted 275 | version: "1.11.1" 276 | stream_channel: 277 | dependency: transitive 278 | description: 279 | name: stream_channel 280 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 281 | url: "https://pub.dev" 282 | source: hosted 283 | version: "2.1.2" 284 | string_scanner: 285 | dependency: transitive 286 | description: 287 | name: string_scanner 288 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 289 | url: "https://pub.dev" 290 | source: hosted 291 | version: "1.2.0" 292 | term_glyph: 293 | dependency: transitive 294 | description: 295 | name: term_glyph 296 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 297 | url: "https://pub.dev" 298 | source: hosted 299 | version: "1.2.1" 300 | test: 301 | dependency: "direct dev" 302 | description: 303 | name: test 304 | sha256: d87214d19fb311997d8128ec501a980f77cb240ac4e7e219accf452813ff473c 305 | url: "https://pub.dev" 306 | source: hosted 307 | version: "1.25.3" 308 | test_api: 309 | dependency: transitive 310 | description: 311 | name: test_api 312 | sha256: "2419f20b0c8677b2d67c8ac4d1ac7372d862dc6c460cdbb052b40155408cd794" 313 | url: "https://pub.dev" 314 | source: hosted 315 | version: "0.7.1" 316 | test_core: 317 | dependency: transitive 318 | description: 319 | name: test_core 320 | sha256: "2236f70be1e5ab405c675e88c36935a87dad9e05a506b57dd5c0f617f5aebcb2" 321 | url: "https://pub.dev" 322 | source: hosted 323 | version: "0.6.1" 324 | typed_data: 325 | dependency: transitive 326 | description: 327 | name: typed_data 328 | sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c 329 | url: "https://pub.dev" 330 | source: hosted 331 | version: "1.3.2" 332 | vm_service: 333 | dependency: transitive 334 | description: 335 | name: vm_service 336 | sha256: a2662fb1f114f4296cf3f5a50786a2d888268d7776cf681aa17d660ffa23b246 337 | url: "https://pub.dev" 338 | source: hosted 339 | version: "14.0.0" 340 | watcher: 341 | dependency: transitive 342 | description: 343 | name: watcher 344 | sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" 345 | url: "https://pub.dev" 346 | source: hosted 347 | version: "1.1.0" 348 | web_socket_channel: 349 | dependency: "direct main" 350 | description: 351 | name: web_socket_channel 352 | sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b 353 | url: "https://pub.dev" 354 | source: hosted 355 | version: "2.4.0" 356 | webkit_inspection_protocol: 357 | dependency: transitive 358 | description: 359 | name: webkit_inspection_protocol 360 | sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" 361 | url: "https://pub.dev" 362 | source: hosted 363 | version: "1.2.1" 364 | yaml: 365 | dependency: transitive 366 | description: 367 | name: yaml 368 | sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" 369 | url: "https://pub.dev" 370 | source: hosted 371 | version: "3.1.2" 372 | sdks: 373 | dart: ">=3.1.5 <4.0.0" 374 | -------------------------------------------------------------------------------- /dart/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: aisstream 2 | description: A sample AISStream command line tool. 3 | version: 1.0.0 4 | 5 | environment: 6 | sdk: ^3.1.5 7 | 8 | # Add regular dependencies here. 9 | dependencies: 10 | web_socket_channel: ^2.4.0 11 | 12 | dev_dependencies: 13 | lints: ^3.0.0 14 | test: ^1.24.0 15 | -------------------------------------------------------------------------------- /golang/go.mod: -------------------------------------------------------------------------------- 1 | module ais-stream/examples/sample_apps/golang 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/aisstream/ais-message-models/golang/aisStream v0.0.0-20230628154343-8650fc5bf8c3 7 | github.com/gorilla/websocket v1.5.0 8 | ) 9 | -------------------------------------------------------------------------------- /golang/go.sum: -------------------------------------------------------------------------------- 1 | github.com/aisstream/ais-message-models/golang/aisStream v0.0.0-20221228192545-6a6efb6f4595 h1:c5h60IYOGQclYsKPsIurt+ZRBcwnIvUpsWf5y5aduJ8= 2 | github.com/aisstream/ais-message-models/golang/aisStream v0.0.0-20221228192545-6a6efb6f4595/go.mod h1:xrb7t7b2Het1o1/ompfiTuIqU6iQ/nh+LOiAouJjgi4= 3 | github.com/aisstream/ais-message-models/golang/aisStream v0.0.0-20230628154343-8650fc5bf8c3 h1:3S9MdCwywvI9ojUosWFm7RL6018nWVn7CZJylIE5sg0= 4 | github.com/aisstream/ais-message-models/golang/aisStream v0.0.0-20230628154343-8650fc5bf8c3/go.mod h1:xrb7t7b2Het1o1/ompfiTuIqU6iQ/nh+LOiAouJjgi4= 5 | github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= 6 | github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 7 | -------------------------------------------------------------------------------- /golang/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | aisstream "github.com/aisstream/ais-message-models/golang/aisStream" 7 | "github.com/gorilla/websocket" 8 | "log" 9 | ) 10 | 11 | func main() { 12 | 13 | url := "wss://stream.aisstream.io/v0/stream" 14 | ws, _, err := websocket.DefaultDialer.Dial(url, nil) 15 | if err != nil { 16 | log.Fatalln(err) 17 | } 18 | defer ws.Close() 19 | 20 | subMsg := aisstream.SubscriptionMessage{ 21 | APIKey: "", 22 | BoundingBoxes: [][][]float64{{{-90.0, -180.0}, {90.0, 180.0}}}, // bounding box for the entire world 23 | } 24 | 25 | subMsgBytes, _ := json.Marshal(subMsg) 26 | if err := ws.WriteMessage(websocket.TextMessage, subMsgBytes); err != nil { 27 | log.Fatalln(err) 28 | } 29 | 30 | for { 31 | _, p, err := ws.ReadMessage() 32 | if err != nil { 33 | log.Fatalln(err) 34 | } 35 | var packet aisstream.AisStreamMessage 36 | 37 | err = json.Unmarshal(p, &packet) 38 | if err != nil { 39 | log.Fatalln(err) 40 | } 41 | 42 | var shipName string 43 | // field may or may not be populated 44 | if packetShipName, ok := packet.MetaData["ShipName"]; ok { 45 | shipName = packetShipName.(string) 46 | } 47 | 48 | switch packet.MessageType { 49 | case aisstream.POSITION_REPORT: 50 | var positionReport aisstream.PositionReport 51 | positionReport = *packet.Message.PositionReport 52 | fmt.Printf("MMSI: %d Ship Name: %s Latitude: %f Longitude: %f\n", 53 | positionReport.UserID, shipName, positionReport.Latitude, positionReport.Longitude) 54 | } 55 | 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /golang/main_filter_mmsi_and_messages.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | aisstream "github.com/aisstream/ais-message-models/golang/aisStream" 7 | "github.com/gorilla/websocket" 8 | "log" 9 | ) 10 | 11 | func main() { 12 | 13 | url := "wss://stream.aisstream.io/v0/stream" 14 | ws, http, err := websocket.DefaultDialer.Dial(url, nil) 15 | if err != nil { 16 | log.Fatalln(err) 17 | } 18 | _ = http 19 | defer ws.Close() 20 | 21 | subMsg := aisstream.SubscriptionMessage{ 22 | APIKey: "", 23 | BoundingBoxes: [][][]float64{{{-90.0, -180.0}, {90.0, 180.0}}}, // bounding box for the entire world 24 | } 25 | 26 | subMsgBytes, _ := json.Marshal(subMsg) 27 | if err := ws.WriteMessage(websocket.TextMessage, subMsgBytes); err != nil { 28 | log.Fatalln(err) 29 | } 30 | 31 | for { 32 | _, p, err := ws.ReadMessage() 33 | if err != nil { 34 | log.Fatalln(err) 35 | } 36 | var packet aisstream.AisStreamMessage 37 | 38 | err = json.Unmarshal(p, &packet) 39 | if err != nil { 40 | log.Fatalln(err) 41 | } 42 | 43 | var shipName string 44 | // field may or may not be populated 45 | if packetShipName, ok := packet.MetaData["ShipName"]; ok { 46 | shipName = packetShipName.(string) 47 | } 48 | 49 | switch packet.MessageType { 50 | case aisstream.POSITION_REPORT: 51 | var positionReport aisstream.PositionReport 52 | positionReport = *packet.Message.PositionReport 53 | fmt.Printf("MMSI: %d Ship Name: %s Latitude: %f Longitude: %f\n", 54 | positionReport.UserID, shipName, positionReport.Latitude, positionReport.Longitude) 55 | } 56 | 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /java/example-app/dependency-reduced-pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | io.aisstream.example_app 5 | example-app 6 | example-app 7 | 1.0-SNAPSHOT 8 | aisstream.io 9 | 10 | 11 | 12 | maven-shade-plugin 13 | 3.4.1 14 | 15 | 16 | package 17 | 18 | shade 19 | 20 | 21 | 22 | 23 | 24 | maven-clean-plugin 25 | 3.1.0 26 | 27 | 28 | maven-resources-plugin 29 | 3.0.2 30 | 31 | 32 | maven-compiler-plugin 33 | 3.8.0 34 | 35 | 36 | maven-surefire-plugin 37 | 2.22.1 38 | 39 | 40 | maven-jar-plugin 41 | 3.0.2 42 | 43 | 44 | maven-install-plugin 45 | 2.5.2 46 | 47 | 48 | maven-deploy-plugin 49 | 2.8.2 50 | 51 | 52 | maven-site-plugin 53 | 3.7.1 54 | 55 | 56 | maven-project-info-reports-plugin 57 | 3.0.0 58 | 59 | 60 | 61 | 62 | 63 | junit 64 | junit 65 | 4.11 66 | test 67 | 68 | 69 | hamcrest-core 70 | org.hamcrest 71 | 72 | 73 | 74 | 75 | 76 | 1.7 77 | 1.7 78 | UTF-8 79 | 80 | 81 | -------------------------------------------------------------------------------- /java/example-app/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 4.0.0 6 | 7 | io.aisstream.example_app 8 | example-app 9 | 1.0-SNAPSHOT 10 | 11 | example-app 12 | 13 | aisstream.io 14 | 15 | 16 | UTF-8 17 | 1.7 18 | 1.7 19 | 20 | 21 | 22 | 23 | org.java-websocket 24 | Java-WebSocket 25 | 1.5.3 26 | 27 | 28 | junit 29 | junit 30 | 4.11 31 | test 32 | 33 | 34 | org.slf4j 35 | slf4j-api 36 | 1.6.1 37 | 38 | 39 | org.slf4j 40 | slf4j-simple 41 | 1.6.1 42 | 43 | 44 | 45 | 46 | 47 | 48 | org.apache.maven.plugins 49 | maven-shade-plugin 50 | 3.4.1 51 | 52 | 53 | package 54 | 55 | shade 56 | 57 | 58 | 59 | 60 | 61 | 62 | maven-clean-plugin 63 | 3.1.0 64 | 65 | 66 | 67 | maven-resources-plugin 68 | 3.0.2 69 | 70 | 71 | maven-compiler-plugin 72 | 3.8.0 73 | 74 | 75 | maven-surefire-plugin 76 | 2.22.1 77 | 78 | 79 | maven-jar-plugin 80 | 3.0.2 81 | 82 | 83 | maven-install-plugin 84 | 2.5.2 85 | 86 | 87 | maven-deploy-plugin 88 | 2.8.2 89 | 90 | 91 | 92 | maven-site-plugin 93 | 3.7.1 94 | 95 | 96 | maven-project-info-reports-plugin 97 | 3.0.0 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /java/example-app/src/main/java/io/aisstream/example-app/AisStreamWebsocketClient.java: -------------------------------------------------------------------------------- 1 | package io.aisstream.example_app; 2 | 3 | import java.net.URI; 4 | import java.net.URISyntaxException; 5 | import java.util.Map; 6 | import java.nio.ByteBuffer; 7 | import java.nio.charset.StandardCharsets; 8 | import org.java_websocket.client.WebSocketClient; 9 | import org.java_websocket.drafts.Draft; 10 | import org.java_websocket.handshake.ServerHandshake; 11 | 12 | /** 13 | * This example demonstrates how to create a websocket connection to a server. Only the most 14 | * important callbacks are overloaded. 15 | */ 16 | public class AisStreamWebsocketClient extends WebSocketClient { 17 | 18 | public AisStreamWebsocketClient(URI serverURI) { 19 | super(serverURI); 20 | } 21 | 22 | @Override 23 | public void onOpen(ServerHandshake handshakedata) { 24 | // send subscription message upon connection 25 | send("{\"APIKey\":\"\",\"BoundingBoxes\":[[[-90,-180],[90,180]]]}"); 26 | } 27 | 28 | 29 | @Override 30 | public void onMessage(ByteBuffer message) { 31 | String jsonString = StandardCharsets.UTF_8.decode(message).toString(); 32 | System.out.println(jsonString); 33 | } 34 | 35 | @Override 36 | public void onMessage(String message) { 37 | // unused as aisstream.io returns messages as byte buffers 38 | } 39 | 40 | @Override 41 | public void onClose(int code, String reason, boolean remote) { 42 | // The close codes are documented in class org.java_websocket.framing.CloseFrame 43 | System.out.println( 44 | "Connection closed by " + (remote ? "remote peer" : "us") + " Code: " + code + " Reason: " 45 | + reason); 46 | } 47 | 48 | @Override 49 | public void onError(Exception ex) { 50 | ex.printStackTrace(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /java/example-app/src/main/java/io/aisstream/example-app/App.java: -------------------------------------------------------------------------------- 1 | package io.aisstream.example_app; 2 | 3 | import java.net.URI; 4 | import java.net.URISyntaxException; 5 | import java.util.Map; 6 | 7 | // example connecting to aisstream.io using the popular websocket library from http://github.com/TooTallNate/Java-WebSocket 8 | public class App { 9 | public static void main(String[] args) throws URISyntaxException{ 10 | System.out.println("starting"); 11 | AisStreamWebsocketClient client = new AisStreamWebsocketClient(new URI( 12 | "wss://stream.aisstream.io/v0/stream")); 13 | client.connect(); 14 | } 15 | } -------------------------------------------------------------------------------- /java/example-app/src/test/java/io/aisstream/example-app/AppTest.java: -------------------------------------------------------------------------------- 1 | package io.aisstream.example_app; 2 | 3 | import static org.junit.Assert.assertTrue; 4 | 5 | import org.junit.Test; 6 | 7 | /** 8 | * Unit test for simple App. 9 | */ 10 | public class AppTest 11 | { 12 | /** 13 | * Rigorous Test :-) 14 | */ 15 | @Test 16 | public void shouldAnswerWithTrue() 17 | { 18 | assertTrue( true ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /java/readme.md: -------------------------------------------------------------------------------- 1 | ## Instructions 2 | 3 | To run the following java example clone this repo preform the following actions. 4 | 5 | 1. Install maven via the instructions [here](https://maven.apache.org/install.html) 6 | 2. `mvn package` 7 | 3. `java -cp target/example-app-1.0-SNAPSHOT.jar io.aisstream.example_app.App` -------------------------------------------------------------------------------- /javascript/index.js: -------------------------------------------------------------------------------- 1 | import WebSocket from "ws"; // npm install ws 2 | const socket = new WebSocket("wss://stream.aisstream.io/v0/stream"); 3 | const API_KEY = process.env.AISSTREAM_API_KEY; // Would need to be established first 4 | socket.addEventListener("open", (_) => { 5 | const subscriptionMessage = { 6 | APIkey: API_KEY, 7 | BoundingBoxes: [ 8 | [ 9 | [-180, -90], 10 | [180, 90], 11 | ], 12 | ], 13 | }; 14 | console.log(JSON.stringify(subscriptionMessage)); 15 | socket.send(JSON.stringify(subscriptionMessage)); 16 | }); 17 | 18 | socket.addEventListener("error", (event) => { 19 | console.log(event); 20 | }); 21 | 22 | socket.addEventListener("message", (event) => { 23 | let aisMessage = JSON.parse(event.data); 24 | if (aisMessage["MessageType"] === "PositionReport") { 25 | let positionReport = aisMessage["Message"]["PositionReport"]; 26 | console.log( 27 | `ShipId: ${positionReport["UserID"]} Latitude: ${positionReport["Latitude"]} Longitude: ${positionReport["Longitude"]}` 28 | ); 29 | } 30 | }); 31 | -------------------------------------------------------------------------------- /javascript/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "javascript", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "javascript", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "websocket": "^1.0.34", 13 | "ws": "^8.11.0" 14 | } 15 | }, 16 | "node_modules/bufferutil": { 17 | "version": "4.0.7", 18 | "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz", 19 | "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==", 20 | "hasInstallScript": true, 21 | "dependencies": { 22 | "node-gyp-build": "^4.3.0" 23 | }, 24 | "engines": { 25 | "node": ">=6.14.2" 26 | } 27 | }, 28 | "node_modules/d": { 29 | "version": "1.0.1", 30 | "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", 31 | "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", 32 | "dependencies": { 33 | "es5-ext": "^0.10.50", 34 | "type": "^1.0.1" 35 | } 36 | }, 37 | "node_modules/debug": { 38 | "version": "2.6.9", 39 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 40 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 41 | "dependencies": { 42 | "ms": "2.0.0" 43 | } 44 | }, 45 | "node_modules/es5-ext": { 46 | "version": "0.10.62", 47 | "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", 48 | "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", 49 | "hasInstallScript": true, 50 | "dependencies": { 51 | "es6-iterator": "^2.0.3", 52 | "es6-symbol": "^3.1.3", 53 | "next-tick": "^1.1.0" 54 | }, 55 | "engines": { 56 | "node": ">=0.10" 57 | } 58 | }, 59 | "node_modules/es6-iterator": { 60 | "version": "2.0.3", 61 | "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", 62 | "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", 63 | "dependencies": { 64 | "d": "1", 65 | "es5-ext": "^0.10.35", 66 | "es6-symbol": "^3.1.1" 67 | } 68 | }, 69 | "node_modules/es6-symbol": { 70 | "version": "3.1.3", 71 | "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", 72 | "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", 73 | "dependencies": { 74 | "d": "^1.0.1", 75 | "ext": "^1.1.2" 76 | } 77 | }, 78 | "node_modules/ext": { 79 | "version": "1.7.0", 80 | "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", 81 | "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", 82 | "dependencies": { 83 | "type": "^2.7.2" 84 | } 85 | }, 86 | "node_modules/ext/node_modules/type": { 87 | "version": "2.7.2", 88 | "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", 89 | "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" 90 | }, 91 | "node_modules/is-typedarray": { 92 | "version": "1.0.0", 93 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 94 | "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" 95 | }, 96 | "node_modules/ms": { 97 | "version": "2.0.0", 98 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 99 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 100 | }, 101 | "node_modules/next-tick": { 102 | "version": "1.1.0", 103 | "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", 104 | "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" 105 | }, 106 | "node_modules/node-gyp-build": { 107 | "version": "4.5.0", 108 | "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", 109 | "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==", 110 | "bin": { 111 | "node-gyp-build": "bin.js", 112 | "node-gyp-build-optional": "optional.js", 113 | "node-gyp-build-test": "build-test.js" 114 | } 115 | }, 116 | "node_modules/type": { 117 | "version": "1.2.0", 118 | "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", 119 | "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" 120 | }, 121 | "node_modules/typedarray-to-buffer": { 122 | "version": "3.1.5", 123 | "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", 124 | "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", 125 | "dependencies": { 126 | "is-typedarray": "^1.0.0" 127 | } 128 | }, 129 | "node_modules/utf-8-validate": { 130 | "version": "5.0.10", 131 | "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", 132 | "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", 133 | "hasInstallScript": true, 134 | "dependencies": { 135 | "node-gyp-build": "^4.3.0" 136 | }, 137 | "engines": { 138 | "node": ">=6.14.2" 139 | } 140 | }, 141 | "node_modules/websocket": { 142 | "version": "1.0.34", 143 | "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", 144 | "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", 145 | "dependencies": { 146 | "bufferutil": "^4.0.1", 147 | "debug": "^2.2.0", 148 | "es5-ext": "^0.10.50", 149 | "typedarray-to-buffer": "^3.1.5", 150 | "utf-8-validate": "^5.0.2", 151 | "yaeti": "^0.0.6" 152 | }, 153 | "engines": { 154 | "node": ">=4.0.0" 155 | } 156 | }, 157 | "node_modules/ws": { 158 | "version": "8.11.0", 159 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", 160 | "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", 161 | "engines": { 162 | "node": ">=10.0.0" 163 | }, 164 | "peerDependencies": { 165 | "bufferutil": "^4.0.1", 166 | "utf-8-validate": "^5.0.2" 167 | }, 168 | "peerDependenciesMeta": { 169 | "bufferutil": { 170 | "optional": true 171 | }, 172 | "utf-8-validate": { 173 | "optional": true 174 | } 175 | } 176 | }, 177 | "node_modules/yaeti": { 178 | "version": "0.0.6", 179 | "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", 180 | "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", 181 | "engines": { 182 | "node": ">=0.10.32" 183 | } 184 | } 185 | }, 186 | "dependencies": { 187 | "bufferutil": { 188 | "version": "4.0.7", 189 | "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz", 190 | "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==", 191 | "requires": { 192 | "node-gyp-build": "^4.3.0" 193 | } 194 | }, 195 | "d": { 196 | "version": "1.0.1", 197 | "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", 198 | "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", 199 | "requires": { 200 | "es5-ext": "^0.10.50", 201 | "type": "^1.0.1" 202 | } 203 | }, 204 | "debug": { 205 | "version": "2.6.9", 206 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 207 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 208 | "requires": { 209 | "ms": "2.0.0" 210 | } 211 | }, 212 | "es5-ext": { 213 | "version": "0.10.62", 214 | "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", 215 | "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", 216 | "requires": { 217 | "es6-iterator": "^2.0.3", 218 | "es6-symbol": "^3.1.3", 219 | "next-tick": "^1.1.0" 220 | } 221 | }, 222 | "es6-iterator": { 223 | "version": "2.0.3", 224 | "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", 225 | "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", 226 | "requires": { 227 | "d": "1", 228 | "es5-ext": "^0.10.35", 229 | "es6-symbol": "^3.1.1" 230 | } 231 | }, 232 | "es6-symbol": { 233 | "version": "3.1.3", 234 | "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", 235 | "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", 236 | "requires": { 237 | "d": "^1.0.1", 238 | "ext": "^1.1.2" 239 | } 240 | }, 241 | "ext": { 242 | "version": "1.7.0", 243 | "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", 244 | "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", 245 | "requires": { 246 | "type": "^2.7.2" 247 | }, 248 | "dependencies": { 249 | "type": { 250 | "version": "2.7.2", 251 | "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", 252 | "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" 253 | } 254 | } 255 | }, 256 | "is-typedarray": { 257 | "version": "1.0.0", 258 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 259 | "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" 260 | }, 261 | "ms": { 262 | "version": "2.0.0", 263 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 264 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 265 | }, 266 | "next-tick": { 267 | "version": "1.1.0", 268 | "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", 269 | "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" 270 | }, 271 | "node-gyp-build": { 272 | "version": "4.5.0", 273 | "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", 274 | "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==" 275 | }, 276 | "type": { 277 | "version": "1.2.0", 278 | "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", 279 | "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" 280 | }, 281 | "typedarray-to-buffer": { 282 | "version": "3.1.5", 283 | "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", 284 | "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", 285 | "requires": { 286 | "is-typedarray": "^1.0.0" 287 | } 288 | }, 289 | "utf-8-validate": { 290 | "version": "5.0.10", 291 | "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", 292 | "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", 293 | "requires": { 294 | "node-gyp-build": "^4.3.0" 295 | } 296 | }, 297 | "websocket": { 298 | "version": "1.0.34", 299 | "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", 300 | "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", 301 | "requires": { 302 | "bufferutil": "^4.0.1", 303 | "debug": "^2.2.0", 304 | "es5-ext": "^0.10.50", 305 | "typedarray-to-buffer": "^3.1.5", 306 | "utf-8-validate": "^5.0.2", 307 | "yaeti": "^0.0.6" 308 | } 309 | }, 310 | "ws": { 311 | "version": "8.11.0", 312 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", 313 | "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", 314 | "requires": {} 315 | }, 316 | "yaeti": { 317 | "version": "0.0.6", 318 | "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", 319 | "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==" 320 | } 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /javascript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "javascript", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "ws": "^8.11.0" 13 | }, 14 | "type":"module" 15 | } 16 | -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aisstream/example/9a2bba8706e04f85aa341e144ef2c4d1c7d1f81f/python/README.md -------------------------------------------------------------------------------- /python/main.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import websockets 3 | import json 4 | from datetime import datetime, timezone 5 | 6 | async def connect_ais_stream(): 7 | 8 | async with websockets.connect("wss://stream.aisstream.io/v0/stream") as websocket: 9 | subscribe_message = {"APIKey": "", "BoundingBoxes": [[[-11, 178], [30, 74]]]} 10 | 11 | subscribe_message_json = json.dumps(subscribe_message) 12 | await websocket.send(subscribe_message_json) 13 | 14 | async for message_json in websocket: 15 | message = json.loads(message_json) 16 | message_type = message["MessageType"] 17 | 18 | if message_type == "PositionReport": 19 | # the message parameter contains a key of the message type which contains the message itself 20 | ais_message = message['Message']['PositionReport'] 21 | print(f"[{datetime.now(timezone.utc)}] ShipId: {ais_message['UserID']} Latitude: {ais_message['Latitude']} Longitude: {ais_message['Longitude']}") 22 | 23 | if __name__ == "__main__": 24 | asyncio.run(connect_ais_stream()) 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /python/main_mmsi_message_filter.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import websockets 3 | import json 4 | from datetime import datetime, timezone 5 | 6 | async def connect_ais_stream(): 7 | 8 | async with websockets.connect("wss://stream.aisstream.io/v0/stream") as websocket: 9 | subscribe_message = {"APIKey": "", "BoundingBoxes": [[[-11, -178], [30, 74]]], "FiltersShipMMSI": ["538007480", "636015988", "316003701"], "FilterMessageTypes": ["PositionReport"]} 10 | 11 | subscribe_message_json = json.dumps(subscribe_message) 12 | await websocket.send(subscribe_message_json) 13 | 14 | async for message_json in websocket: 15 | message = json.loads(message_json) 16 | ais_message = message['Message']['PositionReport'] 17 | print(f"[{datetime.now(timezone.utc)}] ShipId: {ais_message['UserID']} Latitude: {ais_message['Latitude']} Longitude: {ais_message['Longitude']}") 18 | 19 | if __name__ == "__main__": 20 | asyncio.run(connect_ais_stream()) 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /python/main_ssl_disabled.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import websockets 3 | import json 4 | import ssl 5 | import pathlib 6 | from datetime import datetime, timezone 7 | 8 | ## unsecure ssl approach - TESTING ONLY 9 | ssl_context = ssl.SSLContext() 10 | ssl_context.check_hostname = False 11 | ssl_context.verify_mode = ssl.CERT_NONE 12 | 13 | async def connect_ais_stream(): 14 | 15 | async with websockets.connect("wss://stream.aisstream.io/v0/stream",ssl=ssl_context) as websocket: 16 | subscribe_message = {"APIKey": '', "BoundingBoxes": [[[-180, -90], [180, 90]]]} 17 | 18 | subscribe_message_json = json.dumps(subscribe_message) 19 | await websocket.send(subscribe_message_json) 20 | 21 | async for message_json in websocket: 22 | message = json.loads(message_json) 23 | message_type = message["MessageType"] 24 | 25 | if message_type == "PositionReport": 26 | # the message parameter contains a key of the message type which contains the message itself 27 | ais_message = message['Message']['PositionReport'] 28 | print(f"[{datetime.now(timezone.utc)}] ShipId: {ais_message['UserID']} Latitude: {ais_message['Latitude']} Longitude: {ais_message['Longitude']}") 29 | 30 | if __name__ == "__main__": 31 | asyncio.run(connect_ais_stream()) 32 | -------------------------------------------------------------------------------- /python/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | setup( 3 | name='aisstream.io-example-simple', 4 | author='aisstream.io', 5 | version='0.1', 6 | install_requires=[ 7 | 'websockets', 8 | 'asyncio' 9 | ], 10 | ) -------------------------------------------------------------------------------- /rust/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /debug/ 4 | /target/ 5 | 6 | # These are backup files generated by rustfmt 7 | **/*.rs.bk 8 | 9 | # MSVC Windows builds of rustc generate these, which store debugging information 10 | *.pdb 11 | -------------------------------------------------------------------------------- /rust/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 = "bitflags" 7 | version = "1.3.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 10 | 11 | [[package]] 12 | name = "bitflags" 13 | version = "2.5.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" 16 | 17 | [[package]] 18 | name = "block-buffer" 19 | version = "0.10.4" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 22 | dependencies = [ 23 | "generic-array", 24 | ] 25 | 26 | [[package]] 27 | name = "byteorder" 28 | version = "1.5.0" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 31 | 32 | [[package]] 33 | name = "bytes" 34 | version = "1.6.0" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" 37 | 38 | [[package]] 39 | name = "cc" 40 | version = "1.0.94" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7" 43 | 44 | [[package]] 45 | name = "cfg-if" 46 | version = "1.0.0" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 49 | 50 | [[package]] 51 | name = "core-foundation" 52 | version = "0.9.4" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 55 | dependencies = [ 56 | "core-foundation-sys", 57 | "libc", 58 | ] 59 | 60 | [[package]] 61 | name = "core-foundation-sys" 62 | version = "0.8.6" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" 65 | 66 | [[package]] 67 | name = "cpufeatures" 68 | version = "0.2.12" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" 71 | dependencies = [ 72 | "libc", 73 | ] 74 | 75 | [[package]] 76 | name = "crypto-common" 77 | version = "0.1.6" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 80 | dependencies = [ 81 | "generic-array", 82 | "typenum", 83 | ] 84 | 85 | [[package]] 86 | name = "data-encoding" 87 | version = "2.5.0" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" 90 | 91 | [[package]] 92 | name = "digest" 93 | version = "0.10.7" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 96 | dependencies = [ 97 | "block-buffer", 98 | "crypto-common", 99 | ] 100 | 101 | [[package]] 102 | name = "errno" 103 | version = "0.3.8" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" 106 | dependencies = [ 107 | "libc", 108 | "windows-sys", 109 | ] 110 | 111 | [[package]] 112 | name = "fastrand" 113 | version = "2.0.2" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" 116 | 117 | [[package]] 118 | name = "fnv" 119 | version = "1.0.7" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 122 | 123 | [[package]] 124 | name = "foreign-types" 125 | version = "0.3.2" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 128 | dependencies = [ 129 | "foreign-types-shared", 130 | ] 131 | 132 | [[package]] 133 | name = "foreign-types-shared" 134 | version = "0.1.1" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 137 | 138 | [[package]] 139 | name = "form_urlencoded" 140 | version = "1.2.1" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 143 | dependencies = [ 144 | "percent-encoding", 145 | ] 146 | 147 | [[package]] 148 | name = "generic-array" 149 | version = "0.14.7" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 152 | dependencies = [ 153 | "typenum", 154 | "version_check", 155 | ] 156 | 157 | [[package]] 158 | name = "getrandom" 159 | version = "0.2.14" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" 162 | dependencies = [ 163 | "cfg-if", 164 | "libc", 165 | "wasi", 166 | ] 167 | 168 | [[package]] 169 | name = "http" 170 | version = "1.1.0" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" 173 | dependencies = [ 174 | "bytes", 175 | "fnv", 176 | "itoa", 177 | ] 178 | 179 | [[package]] 180 | name = "httparse" 181 | version = "1.8.0" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 184 | 185 | [[package]] 186 | name = "idna" 187 | version = "0.5.0" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 190 | dependencies = [ 191 | "unicode-bidi", 192 | "unicode-normalization", 193 | ] 194 | 195 | [[package]] 196 | name = "itoa" 197 | version = "1.0.11" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 200 | 201 | [[package]] 202 | name = "lazy_static" 203 | version = "1.4.0" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 206 | 207 | [[package]] 208 | name = "libc" 209 | version = "0.2.153" 210 | source = "registry+https://github.com/rust-lang/crates.io-index" 211 | checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" 212 | 213 | [[package]] 214 | name = "linux-raw-sys" 215 | version = "0.4.13" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" 218 | 219 | [[package]] 220 | name = "log" 221 | version = "0.4.21" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" 224 | 225 | [[package]] 226 | name = "native-tls" 227 | version = "0.2.11" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" 230 | dependencies = [ 231 | "lazy_static", 232 | "libc", 233 | "log", 234 | "openssl", 235 | "openssl-probe", 236 | "openssl-sys", 237 | "schannel", 238 | "security-framework", 239 | "security-framework-sys", 240 | "tempfile", 241 | ] 242 | 243 | [[package]] 244 | name = "once_cell" 245 | version = "1.19.0" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 248 | 249 | [[package]] 250 | name = "openssl" 251 | version = "0.10.64" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" 254 | dependencies = [ 255 | "bitflags 2.5.0", 256 | "cfg-if", 257 | "foreign-types", 258 | "libc", 259 | "once_cell", 260 | "openssl-macros", 261 | "openssl-sys", 262 | ] 263 | 264 | [[package]] 265 | name = "openssl-macros" 266 | version = "0.1.1" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 269 | dependencies = [ 270 | "proc-macro2", 271 | "quote", 272 | "syn", 273 | ] 274 | 275 | [[package]] 276 | name = "openssl-probe" 277 | version = "0.1.5" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 280 | 281 | [[package]] 282 | name = "openssl-sys" 283 | version = "0.9.102" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" 286 | dependencies = [ 287 | "cc", 288 | "libc", 289 | "pkg-config", 290 | "vcpkg", 291 | ] 292 | 293 | [[package]] 294 | name = "percent-encoding" 295 | version = "2.3.1" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 298 | 299 | [[package]] 300 | name = "pkg-config" 301 | version = "0.3.30" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 304 | 305 | [[package]] 306 | name = "ppv-lite86" 307 | version = "0.2.17" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 310 | 311 | [[package]] 312 | name = "proc-macro2" 313 | version = "1.0.81" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" 316 | dependencies = [ 317 | "unicode-ident", 318 | ] 319 | 320 | [[package]] 321 | name = "quote" 322 | version = "1.0.36" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 325 | dependencies = [ 326 | "proc-macro2", 327 | ] 328 | 329 | [[package]] 330 | name = "rand" 331 | version = "0.8.5" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 334 | dependencies = [ 335 | "libc", 336 | "rand_chacha", 337 | "rand_core", 338 | ] 339 | 340 | [[package]] 341 | name = "rand_chacha" 342 | version = "0.3.1" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 345 | dependencies = [ 346 | "ppv-lite86", 347 | "rand_core", 348 | ] 349 | 350 | [[package]] 351 | name = "rand_core" 352 | version = "0.6.4" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 355 | dependencies = [ 356 | "getrandom", 357 | ] 358 | 359 | [[package]] 360 | name = "rust" 361 | version = "1.0.0" 362 | dependencies = [ 363 | "serde", 364 | "serde_json", 365 | "tungstenite", 366 | "url", 367 | ] 368 | 369 | [[package]] 370 | name = "rustix" 371 | version = "0.38.32" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" 374 | dependencies = [ 375 | "bitflags 2.5.0", 376 | "errno", 377 | "libc", 378 | "linux-raw-sys", 379 | "windows-sys", 380 | ] 381 | 382 | [[package]] 383 | name = "ryu" 384 | version = "1.0.17" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" 387 | 388 | [[package]] 389 | name = "schannel" 390 | version = "0.1.23" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" 393 | dependencies = [ 394 | "windows-sys", 395 | ] 396 | 397 | [[package]] 398 | name = "security-framework" 399 | version = "2.10.0" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" 402 | dependencies = [ 403 | "bitflags 1.3.2", 404 | "core-foundation", 405 | "core-foundation-sys", 406 | "libc", 407 | "security-framework-sys", 408 | ] 409 | 410 | [[package]] 411 | name = "security-framework-sys" 412 | version = "2.10.0" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" 415 | dependencies = [ 416 | "core-foundation-sys", 417 | "libc", 418 | ] 419 | 420 | [[package]] 421 | name = "serde" 422 | version = "1.0.198" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" 425 | dependencies = [ 426 | "serde_derive", 427 | ] 428 | 429 | [[package]] 430 | name = "serde_derive" 431 | version = "1.0.198" 432 | source = "registry+https://github.com/rust-lang/crates.io-index" 433 | checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" 434 | dependencies = [ 435 | "proc-macro2", 436 | "quote", 437 | "syn", 438 | ] 439 | 440 | [[package]] 441 | name = "serde_json" 442 | version = "1.0.116" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" 445 | dependencies = [ 446 | "itoa", 447 | "ryu", 448 | "serde", 449 | ] 450 | 451 | [[package]] 452 | name = "sha1" 453 | version = "0.10.6" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 456 | dependencies = [ 457 | "cfg-if", 458 | "cpufeatures", 459 | "digest", 460 | ] 461 | 462 | [[package]] 463 | name = "syn" 464 | version = "2.0.60" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" 467 | dependencies = [ 468 | "proc-macro2", 469 | "quote", 470 | "unicode-ident", 471 | ] 472 | 473 | [[package]] 474 | name = "tempfile" 475 | version = "3.10.1" 476 | source = "registry+https://github.com/rust-lang/crates.io-index" 477 | checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" 478 | dependencies = [ 479 | "cfg-if", 480 | "fastrand", 481 | "rustix", 482 | "windows-sys", 483 | ] 484 | 485 | [[package]] 486 | name = "thiserror" 487 | version = "1.0.58" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" 490 | dependencies = [ 491 | "thiserror-impl", 492 | ] 493 | 494 | [[package]] 495 | name = "thiserror-impl" 496 | version = "1.0.58" 497 | source = "registry+https://github.com/rust-lang/crates.io-index" 498 | checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" 499 | dependencies = [ 500 | "proc-macro2", 501 | "quote", 502 | "syn", 503 | ] 504 | 505 | [[package]] 506 | name = "tinyvec" 507 | version = "1.6.0" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 510 | dependencies = [ 511 | "tinyvec_macros", 512 | ] 513 | 514 | [[package]] 515 | name = "tinyvec_macros" 516 | version = "0.1.1" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 519 | 520 | [[package]] 521 | name = "tungstenite" 522 | version = "0.21.0" 523 | source = "registry+https://github.com/rust-lang/crates.io-index" 524 | checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" 525 | dependencies = [ 526 | "byteorder", 527 | "bytes", 528 | "data-encoding", 529 | "http", 530 | "httparse", 531 | "log", 532 | "native-tls", 533 | "rand", 534 | "sha1", 535 | "thiserror", 536 | "url", 537 | "utf-8", 538 | ] 539 | 540 | [[package]] 541 | name = "typenum" 542 | version = "1.17.0" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 545 | 546 | [[package]] 547 | name = "unicode-bidi" 548 | version = "0.3.15" 549 | source = "registry+https://github.com/rust-lang/crates.io-index" 550 | checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" 551 | 552 | [[package]] 553 | name = "unicode-ident" 554 | version = "1.0.12" 555 | source = "registry+https://github.com/rust-lang/crates.io-index" 556 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 557 | 558 | [[package]] 559 | name = "unicode-normalization" 560 | version = "0.1.23" 561 | source = "registry+https://github.com/rust-lang/crates.io-index" 562 | checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" 563 | dependencies = [ 564 | "tinyvec", 565 | ] 566 | 567 | [[package]] 568 | name = "url" 569 | version = "2.5.0" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" 572 | dependencies = [ 573 | "form_urlencoded", 574 | "idna", 575 | "percent-encoding", 576 | ] 577 | 578 | [[package]] 579 | name = "utf-8" 580 | version = "0.7.6" 581 | source = "registry+https://github.com/rust-lang/crates.io-index" 582 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 583 | 584 | [[package]] 585 | name = "vcpkg" 586 | version = "0.2.15" 587 | source = "registry+https://github.com/rust-lang/crates.io-index" 588 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 589 | 590 | [[package]] 591 | name = "version_check" 592 | version = "0.9.4" 593 | source = "registry+https://github.com/rust-lang/crates.io-index" 594 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 595 | 596 | [[package]] 597 | name = "wasi" 598 | version = "0.11.0+wasi-snapshot-preview1" 599 | source = "registry+https://github.com/rust-lang/crates.io-index" 600 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 601 | 602 | [[package]] 603 | name = "windows-sys" 604 | version = "0.52.0" 605 | source = "registry+https://github.com/rust-lang/crates.io-index" 606 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 607 | dependencies = [ 608 | "windows-targets", 609 | ] 610 | 611 | [[package]] 612 | name = "windows-targets" 613 | version = "0.52.5" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" 616 | dependencies = [ 617 | "windows_aarch64_gnullvm", 618 | "windows_aarch64_msvc", 619 | "windows_i686_gnu", 620 | "windows_i686_gnullvm", 621 | "windows_i686_msvc", 622 | "windows_x86_64_gnu", 623 | "windows_x86_64_gnullvm", 624 | "windows_x86_64_msvc", 625 | ] 626 | 627 | [[package]] 628 | name = "windows_aarch64_gnullvm" 629 | version = "0.52.5" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" 632 | 633 | [[package]] 634 | name = "windows_aarch64_msvc" 635 | version = "0.52.5" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" 638 | 639 | [[package]] 640 | name = "windows_i686_gnu" 641 | version = "0.52.5" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" 644 | 645 | [[package]] 646 | name = "windows_i686_gnullvm" 647 | version = "0.52.5" 648 | source = "registry+https://github.com/rust-lang/crates.io-index" 649 | checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" 650 | 651 | [[package]] 652 | name = "windows_i686_msvc" 653 | version = "0.52.5" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" 656 | 657 | [[package]] 658 | name = "windows_x86_64_gnu" 659 | version = "0.52.5" 660 | source = "registry+https://github.com/rust-lang/crates.io-index" 661 | checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" 662 | 663 | [[package]] 664 | name = "windows_x86_64_gnullvm" 665 | version = "0.52.5" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" 668 | 669 | [[package]] 670 | name = "windows_x86_64_msvc" 671 | version = "0.52.5" 672 | source = "registry+https://github.com/rust-lang/crates.io-index" 673 | checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" 674 | -------------------------------------------------------------------------------- /rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust" 3 | version = "1.0.0" 4 | edition = "2021" 5 | rust-version = "1.77.2" 6 | publish = false 7 | resolver = "2" 8 | 9 | [dependencies] 10 | serde = { version = "1.0.198", features = ["derive"] } 11 | serde_json = "1.0.116" 12 | tungstenite = { version = "0.21.0", features = ["native-tls"] } 13 | url = "2.5.0" 14 | 15 | [profile.dev.build-override] 16 | debug = true 17 | 18 | [profile.release] 19 | panic = "unwind" 20 | codegen-units = 1 21 | lto = true 22 | strip = true 23 | 24 | [lints.rust] 25 | unsafe_code = "forbid" 26 | 27 | [lints.clippy] 28 | all = { level = "deny", priority = -1 } 29 | pedantic = { level = "deny", priority = -1 } 30 | cargo = { level = "deny", priority = -1 } 31 | cargo_common_metadata = "allow" 32 | multiple-crate-versions = "allow" 33 | module_name_repetitions = "allow" 34 | -------------------------------------------------------------------------------- /rust/README.md: -------------------------------------------------------------------------------- 1 | # Rust 2 | 3 | ```sh 4 | cargo run 5 | ``` 6 | -------------------------------------------------------------------------------- /rust/src/main.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::error::Error; 3 | use url::Url; 4 | 5 | type Message = serde_json::Value; 6 | 7 | fn main() -> Result<(), Box> { 8 | // Aisstream 9 | let aisstream_api_url: Url = Url::parse("wss://stream.aisstream.io/v0/stream")?; 10 | let aisstream_api_key: String = std::env::var("AISSTREAM_API_KEY")?; 11 | 12 | // WebSocket 13 | println!("Connecting `{aisstream_api_url}`"); 14 | let (mut socket, _) = tungstenite::connect(aisstream_api_url)?; 15 | 16 | // Authentication 17 | println!("Authenticating..."); 18 | socket.send(tungstenite::Message::Text( 19 | serde_json::json!({ 20 | "APIKey": aisstream_api_key, 21 | "BoundingBoxes": [[[-180, -90], [180, 90]]] 22 | }) 23 | .to_string(), 24 | ))?; 25 | let message = match socket.read()? { 26 | tungstenite::Message::Binary(message) => { 27 | match serde_json::from_slice::(&message)? { 28 | AuthMessage::AuthError(message) => { 29 | return Err(format!("Authentication error: {message:?}").into()); 30 | } 31 | AuthMessage::Message(message) => Some(message), 32 | } 33 | } 34 | _ => None, 35 | }; 36 | println!("Successfully authenticated"); 37 | if let Some(message) = message { 38 | print_message(&message); 39 | } 40 | 41 | // Loop 42 | loop { 43 | let message = match socket.read()? { 44 | tungstenite::Message::Binary(message) => serde_json::from_slice::(&message)?, 45 | tungstenite::Message::Close(message) => { 46 | return Err(format!("Connection closed: {message:?}").into()); 47 | } 48 | _ => continue, 49 | }; 50 | print_message(&message); 51 | } 52 | } 53 | 54 | fn print_message(message: &Message) { 55 | println!("Message: {message}"); 56 | } 57 | 58 | #[derive(Serialize, Deserialize, Clone, Debug)] 59 | #[serde(untagged)] 60 | pub enum AuthMessage { 61 | AuthError(AuthError), 62 | Message(Message), 63 | } 64 | 65 | #[derive(Serialize, Deserialize, Clone, Debug)] 66 | pub struct AuthError { 67 | pub error: String, 68 | } 69 | -------------------------------------------------------------------------------- /typescript/client.ts: -------------------------------------------------------------------------------- 1 | import WebSocket from "ws"; 2 | 3 | 4 | const socket = new WebSocket("wss://stream.aisstream.io/v0/stream") 5 | 6 | socket.onopen = function (_) { 7 | let subscriptionMessage = { 8 | Apikey: "YOUR API KEY", 9 | BoundingBoxes: [[[-180, -90], [180, 90]]] 10 | } 11 | socket.send(JSON.stringify(subscriptionMessage)); 12 | }; 13 | 14 | socket.onmessage = function (event) { 15 | (); 16 | }; 17 | -------------------------------------------------------------------------------- /typescript/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aisstream-example-1", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "aisstream-example-1", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "ws": "^8.11.0" 13 | } 14 | }, 15 | "node_modules/ws": { 16 | "version": "8.11.0", 17 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", 18 | "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", 19 | "engines": { 20 | "node": ">=10.0.0" 21 | }, 22 | "peerDependencies": { 23 | "bufferutil": "^4.0.1", 24 | "utf-8-validate": "^5.0.2" 25 | }, 26 | "peerDependenciesMeta": { 27 | "bufferutil": { 28 | "optional": true 29 | }, 30 | "utf-8-validate": { 31 | "optional": true 32 | } 33 | } 34 | } 35 | }, 36 | "dependencies": { 37 | "ws": { 38 | "version": "8.11.0", 39 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", 40 | "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", 41 | "requires": {} 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aisstream-example-1", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "client.ts", 6 | "type": "module", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "ws": "^8.11.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | /* Projects */ 5 | // "incremental": true, /* Enable incremental compilation */ 6 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 7 | // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ 8 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ 9 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 10 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 11 | 12 | /* Language and Environment */ 13 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 14 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 15 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 16 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 17 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 18 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ 19 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 20 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ 21 | // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ 22 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 23 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 24 | 25 | /* Modules */ 26 | "module": "commonjs", /* Specify what module code is generated. */ 27 | // "rootDir": "./", /* Specify the root folder within your source files. */ 28 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 29 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 30 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 31 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 32 | // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ 33 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 34 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 35 | // "resolveJsonModule": true, /* Enable importing .json files */ 36 | // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ 37 | 38 | /* JavaScript Support */ 39 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ 40 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 41 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ 42 | 43 | /* Emit */ 44 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 45 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 46 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 47 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 48 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ 49 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 50 | // "removeComments": true, /* Disable emitting comments. */ 51 | // "noEmit": true, /* Disable emitting files from a compilation. */ 52 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 53 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ 54 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 55 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 56 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 57 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 58 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 59 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 60 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 61 | // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ 62 | // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ 63 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 64 | // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ 65 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 66 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 67 | 68 | /* Interop Constraints */ 69 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 70 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 71 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ 72 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 73 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 74 | 75 | /* Type Checking */ 76 | "strict": true, /* Enable all strict type-checking options. */ 77 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ 78 | // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ 79 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 80 | // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ 81 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 82 | // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ 83 | // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ 84 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 85 | // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ 86 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ 87 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 88 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 89 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 90 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 91 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 92 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ 93 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 94 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 95 | 96 | /* Completeness */ 97 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 98 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 99 | } 100 | } 101 | --------------------------------------------------------------------------------