{"id":38762497,"url":"https://github.com/holdno/firetower","last_synced_at":"2026-01-17T11:58:27.420Z","repository":{"id":132725160,"uuid":"143743503","full_name":"holdno/firetower","owner":"holdno","description":"firetower 基于golang构建的websocket开发框架 | 推送 | IM | 游戏","archived":false,"fork":false,"pushed_at":"2025-03-19T13:37:07.000Z","size":78949,"stargazers_count":52,"open_issues_count":1,"forks_count":9,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-19T14:33:41.155Z","etag":null,"topics":["golang","im","push","websocket"],"latest_commit_sha":null,"homepage":"http://chat.ojbk.io","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/holdno.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-08-06T14:53:48.000Z","updated_at":"2025-03-19T13:35:01.000Z","dependencies_parsed_at":null,"dependency_job_id":"a14f7bfb-a127-4504-9bfd-37a4dfb4bcdc","html_url":"https://github.com/holdno/firetower","commit_stats":null,"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"purl":"pkg:github/holdno/firetower","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holdno%2Ffiretower","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holdno%2Ffiretower/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holdno%2Ffiretower/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holdno%2Ffiretower/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/holdno","download_url":"https://codeload.github.com/holdno/firetower/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holdno%2Ffiretower/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28508464,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T11:50:55.898Z","status":"ssl_error","status_checked_at":"2026-01-17T11:50:55.569Z","response_time":85,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["golang","im","push","websocket"],"created_at":"2026-01-17T11:58:27.199Z","updated_at":"2026-01-17T11:58:27.364Z","avatar_url":"https://github.com/holdno.png","language":"Go","readme":"\u003cp align=\"center\"\u003e\u003ca href=\"http://chat.ojbk.io\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cimg width=\"200\" src=\"http://img.holdno.com/github/holdno/firetowerlogo.png\" alt=\"firetower logo\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/holdno/beacontower/archive/master.zip\"\u003e\u003cimg src=\"https://img.shields.io/badge/download-fast-brightgreen.svg\" alt=\"Downloads\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://goreportcard.com/report/github.com/holdno/firetower\"\u003e\u003cimg tag=\"github.com/holdno/firetower\" src=\"https://goreportcard.com/badge/github.com/holdno/firetower\"\u003e\u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/build-passing-brightgreen.svg\" alt=\"Build Status\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/package%20utilities-go modules-blue.svg\" alt=\"Package Utilities\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/golang-1.11.0-%23ff69b4.svg\" alt=\"Version\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/license-MIT-brightgreen.svg\" alt=\"license\"\u003e\n\u003c/p\u003e\n\u003ch1 align=\"center\"\u003eFiretower\u003c/h2\u003e\nfiretower是一个用golang开发的分布式推送(IM)服务  \n\n完全基于websocket封装，围绕topic进行sub/pub    \n自身实现订阅管理服务，无需依赖redis  \n聊天室demo体验地址: http://chat.ojbk.io  \n### 可用版本\ngo get github.com/holdno/firetower@v0.4.0  \n### 构成\n\n基本服务由两点构成  \n- topic管理服务  \n\u003e 详见示例 example/topicService  \n\n该服务主要作为集群环境下唯一的topic管理节点  \nfiretower一定要依赖这个管理节点才能正常工作  \n大型项目可以将该服务单独部署在一台独立的服务器上，小项目可以同连接层服务一起部署在一台机器上  \n- 连接层服务(websocket服务)  \n\u003e 详见示例 example/websocketService  \n\nwebsocket服务是用户基于firetower自定义开发的业务逻辑  \n可以通过firetower提供的回调方法来实现自己的业务逻辑  \n（web client 在 example/web 下)  \n### 架构图  \n![beacontower](http://img.holdno.com/github/holdno/firetower_process.png)  \n### 接入姿势  \n``` golang \npackage main\n\nimport (\n    \"fmt\"\n    \"github.com/gorilla/websocket\"\n    \"github.com/holdno/firetower/gateway\"\n    \"github.com/holdno/snowFlakeByGo\" // 这是一个分布式全局唯一id生成器\n    \"net/http\"\n    \"strconv\"\n)\n\nvar upgrader = websocket.Upgrader{\n    CheckOrigin: func(r *http.Request) bool {\n        return true\n    },\n} \n\nvar GlobalIdWorker *snowFlakeByGo.Worker\n\nfunc main() {\n    GlobalIdWorker, _ = snowFlakeByGo.NewWorker(1)\n    // 如果是集群环境  一定一定要给每个服务设置唯一的id\n    // 取值范围 1-1024\n    gateway.ClusterId = 1\n    http.HandleFunc(\"/ws\", Websocket)\n    fmt.Println(\"websocket service start: 0.0.0.0:9999\")\n    http.ListenAndServe(\"0.0.0.0:9999\", nil)\n}\n\nfunc Websocket(w http.ResponseWriter, r *http.Request) {\n    // 做用户身份验证\n    ...\n    // 验证成功才升级连接\n    ws, _ := upgrader.Upgrade(w, r, nil)\n    // 生成一个全局唯一的clientid 正常业务下这个clientid应该由前端传入\n    id := GlobalIdWorker.GetId()\n    tower := gateway.BuildTower(ws, strconv.FormatInt(id, 10)) // 生成一个烽火台\n    tower.Run()\n}\n```\n### 目前支持的回调方法\n- ReadHandler 收到客户端发送的消息时触发\n``` golang\ntower := gateway.BuildTower(ws, strconv.FormatInt(id, 10)) // 创建beacontower实例\ntower.SetReadHandler(func(fire *gateway.FireInfo) bool { // 绑定ReadHandler回调方法\n    // message.Data 为客户端传来的信息\n    // message.Topic 为消息传递的topic\n    // 用户可在此做发送验证\n    // 判断发送方是否有权限向到达方发送内容\n    // 通过 Publish 方法将内容推送到所有订阅 message.Topic 的连接\n    tower.Publish(message)\n    return true\n})\n```\n\n- ReadTimeoutHandler 客户端websocket请求超时处理(生产速度高于消费速度)\n``` golang \ntower.SetReadTimeoutHandler(func(fire *gateway.FireInfo) {\n    fmt.Println(\"read timeout:\", fire.Message.Type, fire.Message.Topic, fire.Message.Data)\n})\n```\n\n- BeforeSubscribeHandler 客户端订阅某些topic时触发(这个时候topic还没有订阅，是before subscribe)\n``` golang\ntower.SetBeforeSubscribeHandler(func(context *gateway.FireLife, topic []string) bool {\n    // 这里用来判断当前用户是否允许订阅该topic\n    return true\n})\n```\n\n- SubscribeHandler 客户端完成某些topic的订阅时触发(topic已经被topicService收录并管理)\n``` golang\ntower.SetSubscribeHandler(func(context *gateway.FireLife, topic []string) bool {\n    // 我们给出的聊天室示例是需要用到这个回调方法\n    // 当某个聊天室(topic)有新的订阅者，则需要通知其他已经在聊天室内的成员当前在线人数+1\n    for _, v := range topic {\n        num := tower.GetConnectNum(v)\n        // 继承订阅消息的context\n        var pushmsg = gateway.NewFireInfo(tower, context)\n        pushmsg.Message.Topic = v\n        pushmsg.Message.Data = []byte(fmt.Sprintf(\"{\\\"type\\\":\\\"onSubscribe\\\",\\\"data\\\":%d}\", num))\n        tower.Publish(pushmsg)\n    }\n    return true\n})\n```\n\n- UnSubscribeHandler 客户端取消订阅某些topic完成时触发 (这个回调方法没有设置before方法，目前没有想到什么场景会使用到before unsubscribe，如果有请issue联系)\n``` golang\ntower.SetUnSubscribeHandler(func(context *gateway.FireLife, topic []string) bool {\n    for _, v := range topic {\n        num := tower.GetConnectNum(v)\n        var pushmsg = gateway.NewFireInfo(tower, context)\n        pushmsg.Message.Topic = v\n        pushmsg.Message.Data = []byte(fmt.Sprintf(\"{\\\"type\\\":\\\"onUnsubscribe\\\",\\\"data\\\":%d}\", num))\n        tower.Publish(pushmsg)\n    }\n    return true\n})\n```\n注意：当客户端断开websocket连接时firetower会将其在线时订阅的所有topic进行退订 会触发UnSubscirbeHandler  \n\n## TODO\n- 运行时web看板  \n- 提供推送相关http及grpc接口\n\n## License  \n[MIT](https://opensource.org/licenses/MIT)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fholdno%2Ffiretower","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fholdno%2Ffiretower","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fholdno%2Ffiretower/lists"}