{"id":24173255,"url":"https://github.com/zyxar/socketio","last_synced_at":"2025-09-20T17:32:58.560Z","repository":{"id":57489053,"uuid":"139448503","full_name":"zyxar/socketio","owner":"zyxar","description":"socket.io/engine.io implementation in Go","archived":false,"fork":false,"pushed_at":"2020-08-25T15:10:42.000Z","size":183,"stargazers_count":19,"open_issues_count":2,"forks_count":8,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-11-15T04:10:08.269Z","etag":null,"topics":["engine-io","engine-io-server","engineio","go-socket-io","go-socketio","socket-io","socket-io-server","socketio"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zyxar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-07-02T13:36:59.000Z","updated_at":"2023-07-24T17:16:56.000Z","dependencies_parsed_at":"2022-08-29T20:31:18.879Z","dependency_job_id":null,"html_url":"https://github.com/zyxar/socketio","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zyxar%2Fsocketio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zyxar%2Fsocketio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zyxar%2Fsocketio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zyxar%2Fsocketio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zyxar","download_url":"https://codeload.github.com/zyxar/socketio/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233678687,"owners_count":18712984,"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":["engine-io","engine-io-server","engineio","go-socket-io","go-socketio","socket-io","socket-io-server","socketio"],"created_at":"2025-01-13T01:15:31.231Z","updated_at":"2025-09-20T17:32:53.272Z","avatar_url":"https://github.com/zyxar.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# socketio\n\n[socket.io](https://socket.io/)/[engine.io](https://github.com/socketio/engine.io) implementation in Go\n\n[![GoDoc](https://godoc.org/github.com/zyxar/socketio?status.svg)](https://godoc.org/github.com/zyxar/socketio)\n[![Go Report Card](https://goreportcard.com/badge/github.com/zyxar/socketio)](https://goreportcard.com/report/github.com/zyxar/socketio)\n[![license](https://img.shields.io/badge/license-New%20BSD-ff69b4.svg)](https://github.com/zyxar/socketio/blob/master/LICENSE)\n[![Build Status](https://travis-ci.org/zyxar/socketio.svg?branch=master)](https://travis-ci.org/zyxar/socketio)\n\n\n## Install\n\n```shell\ngo get -v -u github.com/zyxar/socketio\n```\n\n## Features\n\n- compatible with official nodejs implementation (w/o room);\n- `socket.io` server;\n- `socket.io` client (`websocket` only);\n- `engine.io` server;\n- `engine.io` client (`websocket` only);\n- binary data;\n- namespace support;\n- [socket.io-msgpack-parser](https://github.com/darrachequesne/socket.io-msgpack-parser) support;\n\n\n## Example\n\nServer:\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/zyxar/socketio\"\n)\n\nfunc main() {\n\tserver, _ := socketio.NewServer(time.Second*25, time.Second*5, socketio.DefaultParser)\n\tserver.Namespace(\"/\").\n\t\tOnConnect(func(so socketio.Socket) {\n\t\t\tlog.Println(\"connected:\", so.RemoteAddr(), so.Sid(), so.Namespace())\n\t\t}).\n\t\tOnDisconnect(func(so socketio.Socket) {\n\t\t\tlog.Printf(\"%v %v %q disconnected\", so.Sid(), so.RemoteAddr(), so.Namespace())\n\t\t}).\n\t\tOnError(func(so socketio.Socket, err ...interface{}) {\n\t\t\tlog.Println(\"socket\", so.Sid(), so.RemoteAddr(), so.Namespace(), \"error:\", err)\n\t\t}).\n\t\tOnEvent(\"message\", func(so socketio.Socket, data string) {\n\t\t\tlog.Println(data)\n\t\t})\n\n\thttp.ListenAndServe(\":8081\", server)\n}\n```\nClient:\n```js\nconst io = require('socket.io-client');\nconst socket = io('http://localhost:8081');\nvar id;\n\nsocket.on('connect', function() {\n  console.log('connected');\n  if (id === undefined) {\n    id = setInterval(function() {\n      socket.emit('message', 'hello there!')\n    }, 2000);\n  }\n});\nsocket.on('event', console.log);\nsocket.on('disconnect', function() {\n  console.log('disconnected');\n  if (id) {\n    clearInterval(id);\n    id = undefined;\n  }\n});\n```\n\n### With Acknowledgements\n\n- Server -\u003e Client\n\nServer:\n```go\n\tso.Emit(\"ack\", \"foo\", func(msg string) {\n\t\tlog.Println(msg)\n\t})\n```\nClient:\n```js\n  socket.on('ack', function(name, fn) {\n    console.log(name);\n    fn('bar');\n  })\n```\n\n- Client -\u003e Server\n\nServer:\n```go\n\tserver.Namespace(\"/\").OnEvent(\"foobar\", func(data string) (string, string) {\n\t\tlog.Println(\"foobar:\", data)\n\t\treturn \"foo\", \"bar\"\n\t})\n```\n\nClient:\n```js\n  socket.emit('foobar', '-wow-', function (foo, bar) {\n    console.log('foobar:', foo, bar);\n  });\n```\n\n### With Binary Data\n\nServer:\n```go\n\tserver.Namespace(\"/\").\n\t\tOnEvent(\"binary\", func(data interface{}, b *socketio.Bytes) {\n\t\t\tlog.Println(data)\n\t\t\tbb, _ := b.MarshalBinary()\n\t\t\tlog.Printf(\"%x\", bb)\n\t\t}).\n\t\tOnConnect(func(so socketio.Socket) {\n\t\t\tgo func() {\n\t\t\t\tfor {\n\t\t\t\t\tselect {\n\t\t\t\t\tcase \u003c-time.After(time.Second * 2):\n\t\t\t\t\t\tif err := so.Emit(\"event\", \"check it out!\", time.Now()); err != nil {\n\t\t\t\t\t\t\tlog.Println(err)\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}()\n\t\t})\n```\n\nClient:\n```js\n  var ab = new ArrayBuffer(4);\n  var a = new Uint8Array(ab);\n  a.set([1,2,3,4]);\n\n  id = setInterval(function() {\n    socket.emit('binary', 'buf:', ab);\n  }, 2000);\n\n  socket.on('event', console.log);\n```\n\n#### Binary Helper for `protobuf`\n\n```go\nimport (\n\t\"github.com/golang/protobuf/proto\"\n)\n\ntype ProtoMessage struct {\n\tproto.Message\n}\n\nfunc (p ProtoMessage) MarshalBinary() ([]byte, error) {\n\treturn proto.Marshal(p.Message)\n}\n\nfunc (p *ProtoMessage) UnmarshalBinary(b []byte) error {\n\treturn proto.Unmarshal(b, p.Message)\n}\n```\n\n#### Binary Helper for `MessagePack`\n\n```go\nimport (\n\t\"github.com/tinylib/msgp/msgp\"\n)\n\ntype MessagePack struct {\n\tMessage interface {\n\t\tmsgp.MarshalSizer\n\t\tmsgp.Unmarshaler\n\t}\n}\n\nfunc (m MessagePack) MarshalBinary() ([]byte, error) {\n\treturn m.Message.MarshalMsg(nil)\n}\n\nfunc (m *MessagePack) UnmarshalBinary(b []byte) error {\n\t_, err := m.Message.UnmarshalMsg(b)\n\treturn err\n}\n```\n\n\n### Customized Namespace\n\nServer:\n```go\n\tserver.Namespace(\"/ditto\").OnEvent(\"disguise\", func(msg interface{}, b socketio.Bytes) {\n\t\tbb, _ := b.MarshalBinary()\n\t\tlog.Printf(\"%v: %x\", msg, bb)\n\t})\n```\n\nClient:\n```js\nlet ditto = io('http://localhost:8081/ditto');\nditto.emit('disguise', 'pidgey', new ArrayBuffer(8));\n```\n\n## Parser\n\nThe `encoder` and `decoder` provided by `socketio.DefaultParser` is compatible with [`socket.io-parser`](https://github.com/socketio/socket.io-parser/), complying with revision 4 of [socket.io-protocol](https://github.com/socketio/socket.io-protocol).\n\nAn `Event` or `Ack` Packet with any data satisfying `socketio.Binary` interface (e.g. `socketio.Bytes`) would be encoded as `BinaryEvent` or `BinaryAck` Packet respectively.\n\n`socketio.MsgpackParser`, compatible with [socket.io-msgpack-parser](https://github.com/darrachequesne/socket.io-msgpack-parser), is an alternative custom parser.\n\n\n## nginx as Reverse Proxy (or TLS Terminator)\n\n```\nupstream socketio {\n    ip_hash;\n    server localhost:8080;\n}\n\nserver {\n\n    # ...\n\n    location /socket.io/ {\n        if ($request_method = OPTIONS) {\n                add_header Content-Length 0;\n                add_header Content-Type text/plain;\n                add_header Access-Control-Allow-Origin \"$http_origin\" always;\n                add_header Access-Control-Allow-Credentials 'true' always;\n                add_header Access-Control-Allow-Methods \"POST,GET,OPTIONS\";\n                add_header Access-Control-Allow-Headers \"content-type\";\n                return 204;\n        }\n        proxy_pass http://socketio;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection \"upgrade\";\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header Host $host;\n        add_header Access-Control-Allow-Origin \"$http_origin\" always;\n        add_header Access-Control-Allow-Credentials 'true' always;\n    }\n}\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzyxar%2Fsocketio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzyxar%2Fsocketio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzyxar%2Fsocketio/lists"}