{"id":15198346,"url":"https://github.com/txix-open/etp","last_synced_at":"2025-10-28T08:31:49.672Z","repository":{"id":57516351,"uuid":"212786742","full_name":"txix-open/etp","owner":"txix-open","description":"Event transport protocol - alternative to socket.io","archived":false,"fork":false,"pushed_at":"2024-11-01T12:32:58.000Z","size":109,"stargazers_count":9,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-01T13:02:22.145Z","etag":null,"topics":["client","etp","event-transport-protocol","go","golang","server","socket-io","websocket"],"latest_commit_sha":null,"homepage":"","language":"Go","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/txix-open.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-10-04T10:09:09.000Z","updated_at":"2024-11-01T12:33:02.000Z","dependencies_parsed_at":"2024-04-18T11:09:26.093Z","dependency_job_id":"a8412d22-70f5-4b39-8297-6834a6fc95b7","html_url":"https://github.com/txix-open/etp","commit_stats":{"total_commits":29,"total_committers":5,"mean_commits":5.8,"dds":0.4137931034482759,"last_synced_commit":"b72fc78c81b5b88774c8df9cce0b749dc2714c4a"},"previous_names":["txix-open/isp-etp-go","txix-open/etp","integration-system/isp-etp-go"],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/txix-open%2Fetp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/txix-open%2Fetp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/txix-open%2Fetp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/txix-open%2Fetp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/txix-open","download_url":"https://codeload.github.com/txix-open/etp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238623158,"owners_count":19502990,"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":["client","etp","event-transport-protocol","go","golang","server","socket-io","websocket"],"created_at":"2024-09-28T01:03:17.673Z","updated_at":"2025-10-28T08:31:49.353Z","avatar_url":"https://github.com/txix-open.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# etp\n\n[![GoDoc](https://godoc.org/github.com/txix-open/etp/v4?status.svg)](https://godoc.org/github.com/txix-open/etp/v4)\n![Build and test](https://github.com/txix-open/etp/actions/workflows/main.yml/badge.svg)\n[![codecov](https://codecov.io/gh/txix-open/etp/branch/master/graph/badge.svg?token=JMTTJ5O6WB)](https://codecov.io/gh/txix-open/etp)\n[![Go Report Card](https://goreportcard.com/badge/github.com/txix-open/etp/v4)](https://goreportcard.com/report/github.com/txix-open/etp/v4)\n\nETP - event transport protocol on WebSocket, simple and powerful.\n\nHighly inspired by [socket.io](https://socket.io/). But there is no good implementation in Go, that is why `etp` exists.\n\nThe package based on [github.com/nhooyr/websocket](https://github.com/nhooyr/websocket).\n\n## Install\n\n```bash\ngo get -u github.com/txix-open/etp/v4\n```\n\n## Features:\n- Rooms for server\n- [Javascript client](https://github.com/txix-open/isp-etp-js-client)\n- Concurrent event emitting\n- Context based API\n- Event acknowledgment (for sync communication)\n\n## Internals\n- WebSocket message\n    - `websocket.MessageText` (not binary)\n    - `\u003ceventName\u003e||\u003cackId\u003e||\u003ceventData\u003e`\n- Each event is handled concurrently in separated goroutine\n- Message limit is `1MB` by default\n\n## Complete example\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/txix-open/etp/v4\"\n\t\"github.com/txix-open/etp/v4/msg\"\n)\n\nfunc main() {\n\tsrv := etp.NewServer(etp.WithServerAcceptOptions(\u0026etp.AcceptOptions{\n\t\tInsecureSkipVerify: true, //completely ignore CORS checks, enable only for dev purposes\n\t}))\n\n\t//callback to handle new connection\n\tsrv.OnConnect(func(conn *etp.Conn) {\n\t\t//you have access to original HTTP request\n\t\tfmt.Printf(\"id: %d, url: %s, connected\\n\", conn.Id(), conn.HttpRequest().URL)\n\t\tsrv.Rooms().Join(conn, \"goodClients\") //leave automatically then disconnected\n\n\t\tconn.Data().Set(\"key\", \"value\") //put any data associative with connection\n\t})\n\n\t//callback to handle disconnection\n\tsrv.OnDisconnect(func(conn *etp.Conn, err error) {\n\t\tfmt.Println(\"disconnected\", conn.Id(), err, etp.IsNormalClose(err))\n\t})\n\n\t//callback to handle any error during serving\n\tsrv.OnError(func(conn *etp.Conn, err error) {\n\t\tconnId := uint64(0)\n\t\t// be careful, conn can be nil on upgrading protocol error (before success WebSocket connection)\n\t\tif conn != nil {\n\t\t\tconnId = conn.Id()\n\t\t}\n\t\tfmt.Println(\"error\", connId, err)\n\t})\n\n\t//your business event handler\n\t//each event is handled in separated goroutine\n\tsrv.On(\"hello\", etp.HandlerFunc(func(ctx context.Context, conn *etp.Conn, event msg.Event) []byte {\n\t\tfmt.Printf(\"hello event received: %s, %s\\n\", event.Name, event.Data)\n\t\treturn []byte(\"hello handled\")\n\t}))\n\n\t//fallback handler\n\tsrv.OnUnknownEvent(etp.HandlerFunc(func(ctx context.Context, conn *etp.Conn, event msg.Event) []byte {\n\t\tfmt.Printf(\"unknown event received, %s, %s\\n\", event.Name, event.Data)\n\t\t_ = conn.Close() //you may close a connection whenever you want\n\t\treturn nil\n\t}))\n\n\tmux := http.NewServeMux()\n\tmux.Handle(\"GET /ws\", srv)\n\tgo func() {\n\t\terr := http.ListenAndServe(\":8080\", mux)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}()\n\ttime.Sleep(1 * time.Second)\n\n\tcli := etp.NewClient().\n\t\tOnDisconnect(func(conn *etp.Conn, err error) { //basically you have all handlers like a server here\n\t\t\tfmt.Println(\"client disconnected\", conn.Id(), err)\n\t\t})\n\terr := cli.Dial(context.Background(), \"ws://localhost:8080/ws\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\t//to check connection is still alive\n\terr = cli.Ping(context.Background())\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\t//simply emit event\n\terr = cli.Emit(context.Background(), \"hello\", []byte(\"fire and forget\"))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\t//emit event and wait server response\n\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) //highly recommended to set up timeout for waiting acknowledgment\n\tdefer cancel()\n\tresp, err := cli.EmitWithAck(ctx, \"hello\", []byte(\"wait acknowledgment\"))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Printf(\"hello resposne: '%s'\\n\", resp)\n\n\t//data can be empty\n\terr = cli.Emit(ctx, \"unknown event\", nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\ttime.Sleep(15 * time.Second)\n\n\t//call to disconnect all clients\n\tsrv.Shutdown()\n}\n```\n\n## V3 Migration\n\n* Internal message format is the same as `v2`\n* Each event now is handled in separated goroutine (completely async)\n* Significantly reduce code base, removed redundant interfaces\n* Fixed some memory leaks and potential deadlocks\n* Main package `github.com/txix-open/isp-etp-go/v2` -\u003e `github.com/txix-open/etp/v4`\n* `OnDefault` -\u003e `OnUnknownEvent`\n* `On*` API are the same either `etp.Client` and `etp.Server`\n* WAS\n\n```go\nsrv.On(\"event\", func (conn etp.Conn, data []byte) {\n    log.Println(\"Received \" + testEvent + \":\" + string(data))\n}).\n```\n\n* BECOME\n\n```go\nsrv.On(\"hello\", etp.HandlerFunc(func(ctx context.Context, conn *etp.Conn, event msg.Event) []byte {\n    fmt.Printf(\"hello event received: %s, %s\\n\", event.Name, event.Data)\n    return []byte(\"hello handled\")\n}))\n```\n\nThe second param now is a interface.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftxix-open%2Fetp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftxix-open%2Fetp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftxix-open%2Fetp/lists"}