{"id":33179925,"url":"https://github.com/JuliaWeb/WebSockets.jl","last_synced_at":"2025-11-20T21:02:05.972Z","repository":{"id":7783702,"uuid":"9153575","full_name":"JuliaWeb/WebSockets.jl","owner":"JuliaWeb","description":"A WebSockets library for Julia","archived":false,"fork":false,"pushed_at":"2022-11-29T13:00:00.000Z","size":622,"stargazers_count":162,"open_issues_count":9,"forks_count":58,"subscribers_count":20,"default_branch":"master","last_synced_at":"2025-11-10T00:21:36.075Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Julia","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JuliaWeb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-04-01T18:53:59.000Z","updated_at":"2025-11-05T03:54:19.000Z","dependencies_parsed_at":"2022-07-12T15:03:09.317Z","dependency_job_id":null,"html_url":"https://github.com/JuliaWeb/WebSockets.jl","commit_stats":null,"previous_names":[],"tags_count":37,"template":false,"template_full_name":null,"purl":"pkg:github/JuliaWeb/WebSockets.jl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaWeb%2FWebSockets.jl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaWeb%2FWebSockets.jl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaWeb%2FWebSockets.jl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaWeb%2FWebSockets.jl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JuliaWeb","download_url":"https://codeload.github.com/JuliaWeb/WebSockets.jl/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JuliaWeb%2FWebSockets.jl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":285511776,"owners_count":27184237,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-20T02:00:05.334Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-11-16T03:00:37.818Z","updated_at":"2025-11-20T21:02:05.966Z","avatar_url":"https://github.com/JuliaWeb.png","language":"Julia","funding_links":[],"categories":["Network Security","Tools per Language"],"sub_categories":["Protocol Libraries","Julia"],"readme":"# WebSockets.jl\n\n[![Coverage Status](https://img.shields.io/coveralls/JuliaWeb/WebSockets.jl.svg)](https://coveralls.io/r/JuliaWeb/WebSockets.jl)\n[![Appveyor](https://ci.appveyor.com/api/projects/status/github/JuliaWeb/WebSockets.jl?svg=true\u0026logo=appveyor)](https://ci.appveyor.com/project/shashi/WebSockets-jl/branch/master)\n\n\nServer and client side [Websockets](https://tools.ietf.org/html/rfc6455) protocol in Julia. WebSockets is a small overhead message protocol layered over [TCP](https://tools.ietf.org/html/rfc793). It uses HTTP(S) for establishing the connections.\n\n## Upgrading to v. 1.6\nJulia 1.8.2 or higher is now required due to some instabilities. \n\nThere are minor 'public API' changes in v. 1.6. We advise 'using' each function like below, except when experimenting.\n\nThis example tries typical 'old' code, shows errors, and shows replacement code. \n\n```julia\njulia\u003e using WebSockets: serve, writeguarded, readguarded, @wslog, open, \n                  HTTP, Response, ServerWS, with_logger, WebSocketLogger\njulia\u003e begin\n           function handler(req)\n               @wslog \"Somebody wants a http response\"\n               Response(200)\n           end\n           function wshandler(ws_server)\n               @wslog \"A client opened this websocket connection\"\n               writeguarded(ws_server, \"Hello\")\n               readguarded(ws_server)\n           end\n           serverWS = ServerWS(handler, wshandler)\n           servetask = @async with_logger(WebSocketLogger()) do\n               serve(serverWS, port = 8000)\n               \"Task ended\"\n           end\n       end\n[ Info: Listening on: 127.0.0.1:8000\nTask (runnable) @0x000001921cbd2ca0\n```\n\nThe above would work on earlier versions. But now test in a browser: [http://127.0.0.1:8000](http://127.0.0.1:8000). The browser would show: `Server never wrote a response`, and the REPL would show:\n\n```julia\njulia\u003e [ Wslog 11:08:09.957: Somebody wants a http response\n[ Wslog 11:08:10.078: Somebody wants a http response\n```\n\nWe had two requests from the browser - one was for the 'favicon' of our site. But something went wrong here. If you like long stacktraces, also try ```HTTP.get(\"http://127.0.0.1:8000\");```\n\n__Let's revise the http handler to match the new requirements:__\n```julia\njulia\u003e function handler(req)\n               @wslog \"HTTP.jl v1.0+ requires more of a response\"\n               Response(200, \"Nothing to see here!\")\n       end\n```\n\nReload the browser page to verify the server is updated and working!\n\nLet us test the websockets!\n```julia\njulia\u003e open(\"ws://127.0.0.1:8000\") do ws_client\n                  data, success = readguarded(ws_client)\n                  if success\n                      println(stderr, ws_client, \" received: \", String(data))\n                  end\n              end;\n[ LogLevel(50): A client opened this websocket connection\nWebSocket(client, CONNECTED) received: Hello\n```\n\nThat's it, we have upgraded by simply modifing the Response constructors. The websocket was closed at exiting the handler, and to close the running server:\n```julia\njulia\u003e put!(serverWS.in, \"close!\")\n[ Info: Server on 127.0.0.1:8000 closing\n\"close!\"\n\njulia\u003e servetask\nTask (done) @0x000001d6457a1180\n```\n\nAccess inline documentation and have a look at the examples folder! The testing files also demonstrate a variety of uses. Benchmarks show examples of websockets and servers running on separate processes, as oposed to asyncronous tasks.\n\n### About this package\nOriginally from 2013 and Julia 0.2, the WebSockets API has remained largely unchanged. It now depends on [HTTP.jl](https://github.com/JuliaWeb/HTTP.jl) for establishing the http connections. That package is in ambitious development, and most functionality of this package is already implemented directly in HTTP.jl.\n\nThis more downstream package may lag behind the latest version of HTTP.jl, and in so doing perhaps avoid some borderline bugs. This is why the examples and tests do not import HTTP methods directly, but rely on the methods imported in this package. E.g. by using `WebSockets.HTTP.listen` instead of `HTTP.listen` you may possibly be using the previous release of package HTTP. The imported HTTP version is capped so as to avoid possible issues when new versions of HTTP are released.\n\nWe aim to replace code with similar code in HTTP when possible, reducing this package to a wrapper. Ideally, all top-level tests will continue to pass without change.\n\n## What can you do with it?\n- read and write between entities you can program or know about\n- serve an svg file to the web browser, containing javascript for connecting back through a websocket, adding two-way interaction with graphics\n- enjoy very low latency and high speed with a minimum of edge case coding\n- implement your own 'if X send this, Y do that' subprotocols. Typically,\n  one subprotocol for sensor input, another for graphics or text to a display.\n- use registered [websocket subprotocols](https://www.iana.org/assignments/websocket/websocket.xml#version-number) for e.g. remote controlled hardware\n- relay user interaction to backend simulations\n- build a network including browser clients and long-running relay servers\n- use convenience functions for gatekeeping\n\nWebSockets are well suited for user interactions via a browser or [cross-platform applications](https://electronjs.org/) like electron. Workload and development time can be moved off Julia resources, error checking code can be reduced. Preferably use websockets for passing arguments, not code, between compiled functions on both sides; it has both speed and security advantages over passing code for evaluation.\n\n## Other tips\n- Putting http handlers and websocket coroutines ('handlers') in the same process can be a security advantage. It is good practice to modify web page responses to include time-limited tokens in the address, the wsuri.\n- Since `read` and `readguared` are blocking functions, you can easily end up reading indefinitely from any side of the connection. See the `close` function code for an example of non-blocking read with a timeout.\n- Compression is not currenlty implemented, but easily adaptable. On local connections, there's probably not much to gain.\n- If you worry about milliseconds, TCP quirks like 'warm-up' time with low transmission speed after a pause can be avoided with heartbeats. High-performance examples are missing.\n- Garbage collection increases message latency at semi-random intervals, as is visible in  benchmark plots. Benchmarks should include non-memory-allocating examples.\n- Time prefixes in e.g. `@wslog` are not accurate. To accurately track sequences of logging messages, include the time in your logging message, e.g. using 'time_ns()'\n\n##### Debugging with WebSockets.ServeWS servers\nError messages from run-time are directed to a .out channel. See inline docs: ?Websockets.serve.\nWhen using `readguarded` or `writeguarded`, errors are logged with `@debug` statements. Set the logging level of the logger you use to 'Debug', as in 'examples/count_with_logger.jl'.\n\n##### Debugging with WebSockets.HTTP.listen servers\nIf you prefer to write your own server coroutine with this approach, error messages may be sent as messages to the client. This may not be good practice if you're serving pages to the internet, but very nice while developing locally. There are some inline comments in the source code which may be of help.\n\n## Development, new features, comments\nThe issues section is used for planning development: Contributions are welcome.\n\n- Version 1.6 makes necessary changes to use HTTP 1.1.0 and limits the Julia versions to 1.8.2+.\n- Version 1.5 shows the current number of connections on ServerWS. ServerWS in itself is immutable.\n- Version 1.4 removes a ratelimiter function.\n- Version 1.3 integrates `WebSocketLogger`. It closely resembles `ConsoleLogger` from the Julia standard library. Additional features: see inline docs and 'examples/count_with_logger.jl'. With this closer integration with Julia's core logging functionality, we also introduce `@debug` statements in `readguarded` and `writeguarded` (as well as when receiving 'ping' or 'pong'). The functions still return a boolean to indicate failure, but return no reason except the logger messages.\n- The /benchmark folder contain some code that is not currently working, pending logging facilities.\n- Alternative Julia packages: [DandelionWebSockets](https://github.com/dandeliondeathray/DandelionWebSockets.jl) and the direct implementation in [HTTP.jl](https://github.com/JuliaWeb/HTTP.jl).\n\n## Errors after updating?\n### To version 1.6\nUpdated to use HTTP 1.1.0-1.5 as a dependency.\n\nIn your code: Response(200) -\u003e Response(200, \"OK\")\nAlso see the example at the top.\n\n### To version 1.5.6\nUpdated to use HTTP 0.9 as a dependency.\n\n### To version 1.5.2/3\nJulia 0.7 is dropped from testing, but the compatibility as stated in 'Project.toml' is kept, since HTTP is also claiming to be 0.7 compatible and we do not want to put too many restraints on the compatibility graph. The non-compatibility is that @wslog will not quite work.\n\n### To version 1.5.2\nWebSockets.DEFAULTOPTIONS has changed to WebSockets.default_options()\nThe previous behaviour is considered a bug, and might result in\n   close(s1::ServerWS) or put!(s1::ServerWS.in, \"close\")\nalso closing s2::ServerWS.\n\n### To version 1.5.0\n\n#### If you don't call serve(::ServerWS, etc,) but write your own code including 'listen':\nThe 'listen... do' syntax example is removed. You now need to wrap the handler function:\n    handler(req) = WebSockets.Response(200)\n    handler_wrap = WebSockets.RequestHandlerFunction(handler)\n\nThe function that accepts RequestHandlerFunction is called `handle`. It replaces `handle_request`, which was more accepting.\n\nConsider taking keyword option values from the new function WebSockets.default_options()\n\n#### If you call WebSockets.serve(::ServerWS, etc,):\n\nThere are no changes if you're using syntax like examples/minimal_server.jl.\n\nKeywords 'cert' and 'key' are no longer accepted. Instead, make sure you're using the same version of MbedTLS as WebSockets.HTTP this way:\n```\nsslconf = WebSockets.SSLConfig(cert, key)\nServerWS(h,w, sslconfig = sslconf)\n```\n\nThe upgrade to using HTTP 0.8 changes the bevaviour of server options. Try not passing any options to ServerWS. If you do, they will overrule the list of options in WebSockets.DEFAULTOPTIONS.\n\nType ServerOptions is removed and the corresponding fields now reside in  ServerWS.\n\nThe optional function 'tcpisvalid' used to take two arguments; it should now take only one.\n\nRatelimiting is now performed outside of optional user functions, if you pass keyword rate_limit ≠ nothing.\n\nKeyword logger is no longer supported. For redirecting logs, use Logging.with_logger\n\n### To version 1.4.0\nWe removed the default ratelimit! function, since the way it worked was counter-intuitive and slowed down most use cases. If you have not provided any ratelimit to SererOptions in the past, you may be able to notice a very tiny performance improvement. See issue #124 and the inline documentation.  \n\n### To version 1.3.0\nWebSockets additionaly exports WebSocketLogger, @wslog, Wslog.\n\n### To version 1.1.0\nThis version is driven by large restructuring in HTTP.jl. We import more functions and types into WebSockets, e.g., WebSockets.Request. The main interface does not, intentionally, change, except for 'origin', which should now be qualified as WebSockets.origin.\n\n### To version 0.5.0\nThe introduction of client side websockets to this package in version 0.5.0 may require changes in your code:\n- The `WebSocket.id` field is no longer supported. You can generate unique counters by code similar to 'bencmark/functions_open_browsers.jl' COUNTBROWSER.\n- You may want to modify you error handling code. Examine WebSocketsClosedError.message.\n- You may want to use `readguarded` and `writeguarded` to save on error handling code.\n- `Server` -\u003e `WebSockets.WSServer`\n- `WebSocketHandler` -\u003e `WebSockets.WebsocketHandler` (or just pass a function without wrapper)\n- `HttpHandler`-\u003e `HTTP.HandlerFunction` (or just pass a function without wrapper)\n- `run` -\u003e `serve`\n- `Response` -\u003e `HTTP.Response`\n- `Request` -\u003e `HTTP.Response`\n\n You may also want to consider using `target`, `orgin`and `subprotocol`, which\n are compatible with both of the types above.\n\n\n~~~~\n::::::::::::::::\n::            ::\n::  Made at   ::\n::            ::\n::::::::::::::::\n       ::\n Recurse Center\n::::::::::::::::\n~~~~\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJuliaWeb%2FWebSockets.jl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FJuliaWeb%2FWebSockets.jl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJuliaWeb%2FWebSockets.jl/lists"}