{"id":13746714,"url":"https://github.com/mroth/sseserver","last_synced_at":"2025-05-01T23:30:23.587Z","repository":{"id":19091317,"uuid":"22319207","full_name":"mroth/sseserver","owner":"mroth","description":":surfer: High-performance Server-Sent Events endpoint for Go","archived":false,"fork":false,"pushed_at":"2024-01-02T20:21:31.000Z","size":144,"stargazers_count":107,"open_issues_count":5,"forks_count":15,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-05-22T18:33:02.879Z","etag":null,"topics":["eventsource","go","golang","server","sse","streaming"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mroth.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2014-07-27T19:03:52.000Z","updated_at":"2024-01-02T07:36:09.000Z","dependencies_parsed_at":"2023-01-14T07:00:39.801Z","dependency_job_id":"941a3bd2-7816-43a6-a348-7a4c89ec890f","html_url":"https://github.com/mroth/sseserver","commit_stats":{"total_commits":59,"total_committers":4,"mean_commits":14.75,"dds":"0.10169491525423724","last_synced_commit":"5fb57b83ef00bfe689133e6ea25e57744aa6e2fe"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mroth%2Fsseserver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mroth%2Fsseserver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mroth%2Fsseserver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mroth%2Fsseserver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mroth","download_url":"https://codeload.github.com/mroth/sseserver/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224280888,"owners_count":17285545,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["eventsource","go","golang","server","sse","streaming"],"created_at":"2024-08-03T06:00:59.513Z","updated_at":"2024-11-12T13:26:30.389Z","avatar_url":"https://github.com/mroth.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# sseserver :surfing_man:\n\n[![PkgGoDev](https://pkg.go.dev/badge/github.com/mroth/sseserver)](https://pkg.go.dev/github.com/mroth/sseserver)\n[![Build Status](https://github.com/mroth/sseserver/workflows/test/badge.svg)](https://github.com/mroth/sseserver/actions)\n[![CodeFactor](https://www.codefactor.io/repository/github/mroth/sseserver/badge)](https://www.codefactor.io/repository/github/mroth/sseserver)\n[![Go Report Card](https://goreportcard.com/badge/github.com/mroth/sseserver)](https://goreportcard.com/report/github.com/mroth/sseserver)\n\n\u003e A high performance and thread-safe Server-Sent Events server for Go with\n_hierarchical namespacing_ support.\n\nThis library has powered the streaming API endpoint for\n:dizzy: [Emojitracker](https://emojitracker.com) in production since 2014, where\nit routinely handles dispatching hundreds of messages per second to thousands of\nsimultaneous clients, on a single Heroku dyno.\n\n## Introduction\n\n### Hierarchical Namespaced Channels*\n\nA client can subscribe to channels reflecting the content they are interested\nin. For example, say you are broadcasting events to the namespaces `/pets/cats`\nand `/pets/dogs`. A client could subscribe to the parent channel `/pets` in the\nhierarchy and receive all messages for either.\n\nIn **sseserver**, channels have infinite depth and are automatically created on\nthe fly with zero setup -- just broadcast and it works.\n\n\u003csmall\u003e(*There's probably a more accurate term for this.  If you know it, let me\nknow.)\u003c/small\u003e\n\n### Performance\n\nDesigned for high throughput as primary performance consideration. In my\npreliminary benchmarking (on `v1.0`, circa 2014) this can handle ~100K/sec\nmessages broadcast across ~1000 open HTTP connections on a 3.4GHz Intel Core i7\n(using a single  core, e.g. with `GOMAXPROCS=1`).  There still remains quite a\nbit of optimization to be done so it should be able to get faster if needed.\n\n### SSE vs Websockets\n\nSSE is the oft-overlooked *uni-directional* cousin of websockets. Being \"just\nHTTP\" it has some benefits:\n\n- Trvially easier to understand, plaintext format.\n  \u003csmall\u003eCan be debugged by a human with `curl`.\u003c/small\u003e\n- Supported in most major browsers for a long time now.\n  \u003csmall\u003eEverything except IE/Edge, but an easy polyfill!\u003c/small\u003e\n- Built-in standard support for automatic reconnection, event binding, etc.\n- Works with HTTP/2.\n\nSee also Smashing Magazine: [\"Using SSE Instead Of WebSockets For Unidirectional\nData Flow Over HTTP/2\"][1].\n\n[1]: https://www.smashingmagazine.com/2018/02/sse-websockets-data-flow-http2/\n\n## Documentation\n\n[![GoDoc](https://godoc.org/github.com/mroth/sseserver?status.svg)](https://godoc.org/github.com/mroth/sseserver)\n\n### Namespaces are URLs\n\nFor clients, no need to think about protocol. To subscribe to one of the above\nnamespaces from the previous example, just connect to `http://$SERVER/pets/dogs`.\nDone.\n\n### Example Usage\n\nA simple Go program utilizing this package:\n\n```go\npackage main\n\nimport (\n    \"time\"\n    \"github.com/mroth/sseserver\"\n)\n\nfunc main() {\n    s := sseserver.NewServer() // create a new server instance\n\n    // broadcast the time every second to the \"/time\" namespace\n    go func() {\n        ticker := time.Tick(time.Duration(1 * time.Second))\n        for {\n            // wait for the ticker to fire\n            t := \u003c-ticker\n            // create the message payload, can be any []byte value\n            data := []byte(t.Format(\"3:04:05 pm (MST)\"))\n            // send a message without an event on the \"/time\" namespace\n            s.Broadcast \u003c- sseserver.SSEMessage{\"\", data, \"/time\"}\n        }\n    }()\n\n    // simulate sending some scoped events on the \"/pets\" namespace\n    go func() {\n        time.Sleep(5 * time.Second)\n        s.Broadcast \u003c- sseserver.SSEMessage{\"new-dog\", []byte(\"Corgi\"), \"/pets/dogs\"}\n        s.Broadcast \u003c- sseserver.SSEMessage{\"new-cat\", []byte(\"Persian\"), \"/pets/cats\"}\n        time.Sleep(1 * time.Second)\n        s.Broadcast \u003c- sseserver.SSEMessage{\"new-dog\", []byte(\"Terrier\"), \"/pets/dogs\"}\n        s.Broadcast \u003c- sseserver.SSEMessage{\"new-dog\", []byte(\"Dauchsand\"), \"/pets/cats\"}\n        time.Sleep(2 * time.Second)\n        s.Broadcast \u003c- sseserver.SSEMessage{\"new-cat\", []byte(\"LOLcat\"), \"/pets/cats\"}\n    }()\n\n    s.Serve(\":8001\") // bind to port and begin serving connections\n}\n```\n\nAll these event namespaces are exposed via HTTP endpoint in the\n`/subscribe/:namespace` route.\n\nOn the client, we can easily connect to those endpoints using built-in functions in JS:\n```js\n// connect to an event source endpoint and print results\nvar es1 = new EventSource(\"http://localhost:8001/subscribe/time\");\nes1.onmessage = function(event) {\n    console.log(\"TICK! The time is currently: \" + event.data);\n};\n\n// connect to a different event source endpoint and register event handlers\n// note that by subscribing to the \"parent\" namespace, we get all events\n// contained within the pets hierarchy.\nvar es2 = new EventSource(\"http://localhost:8001/subscribe/pets\")\nes2.addEventListener(\"new-dog\", function(event) {\n    console.log(\"WOOF! Hello \" + event.data);\n}, false);\n\nes2.addEventListener(\"new-cat\", function(event) {\n    console.log(\"MEOW! Hello \" + event.data);\n}, false);\n```\n\nWhich when connecting to the server would yield results:\n\n    TICK! The time is currently: 6:07:17 pm (EDT)\n    TICK! The time is currently: 6:07:18 pm (EDT)\n    TICK! The time is currently: 6:07:19 pm (EDT)\n    TICK! The time is currently: 6:07:20 pm (EDT)\n    WOOF! Hello Corgi\n    MEOW! Hello Persian\n    TICK! The time is currently: 6:07:21 pm (EDT)\n    WOOF! Hello Terrier\n    WOOF! Hello Dauchsand\n    TICK! The time is currently: 6:07:22 pm (EDT)\n    TICK! The time is currently: 6:07:23 pm (EDT)\n    MEOW! Hello LOLcat\n    TICK! The time is currently: 6:07:24 pm (EDT)\n\n\nOf course you could easily send JSON objects in the data payload instead, and\nmost likely will be doing this often.\n\nAnother advantage of the SSE protocol is that the wire-format is so simple.\nUnlike WebSockets, we can connect with `curl` to an endpoint directly and just\nread what's going on:\n\n```bash\n$ curl http://localhost:8001/subscribe/pets\nevent:new-dog\ndata:Corgi\n\nevent:new-cat\ndata:Persian\n\nevent:new-dog\ndata:Terrier\n\nevent:new-dog\ndata:Dauchsand\n\nevent:new-cat\ndata:LOLcat\n```\n\nYep, it's that simple.\n\n### Keep-Alives\n\nAll connections will send periodic `:keepalive` messages as recommended in the\nWHATWG spec (by default, every 15 seconds). Any library adhering to the\nEventSource standard should already automatically ignore and filter out these\nmessages for you.\n\n### Admin Page\nBy default, an admin status page is available for easy monitoring.\n\n![screenshot](http://f.cl.ly/items/1v2X1k342K3p0K1O2x0B/ssestreamer-admin.png)\n\nIt's powered by a simple JSON API endpoint, which you can also use to build your\nown reporting.  These endpoints can be disabled in the settings (see `Server.Options`).\n\n### HTTP Middleware\n\n`sseserver.Server` implements the standard Go `http.Handler` interface, so you\ncan easily integrate it with most existing HTTP middleware, and easily plug it\ninto whatever you are using for your current routing, etc.\n\n## License\n\n[AGPL-3.0](https://opensource.org/licenses/AGPL-3.0). Dual commercial licensing\navailable upon request.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmroth%2Fsseserver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmroth%2Fsseserver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmroth%2Fsseserver/lists"}