{"id":13413617,"url":"https://github.com/fanux/lhttp","last_synced_at":"2025-04-04T19:09:58.962Z","repository":{"id":40329690,"uuid":"48720086","full_name":"fanux/lhttp","owner":"fanux","description":"go websocket, a better way to buid your IM server","archived":false,"fork":false,"pushed_at":"2018-04-08T08:06:09.000Z","size":13672,"stargazers_count":691,"open_issues_count":6,"forks_count":141,"subscribers_count":59,"default_branch":"master","last_synced_at":"2024-10-14T15:56:18.144Z","etag":null,"topics":["chat-room","golang","im","websocket","websockets"],"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/fanux.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":"2015-12-29T01:13:36.000Z","updated_at":"2024-09-26T07:42:50.000Z","dependencies_parsed_at":"2022-08-18T00:55:45.368Z","dependency_job_id":null,"html_url":"https://github.com/fanux/lhttp","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fanux%2Flhttp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fanux%2Flhttp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fanux%2Flhttp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fanux%2Flhttp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fanux","download_url":"https://codeload.github.com/fanux/lhttp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247234921,"owners_count":20905854,"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":["chat-room","golang","im","websocket","websockets"],"created_at":"2024-07-30T20:01:44.652Z","updated_at":"2025-04-04T19:09:58.941Z","avatar_url":"https://github.com/fanux.png","language":"Go","readme":"# Your star is my power!! :rocket: :star: :star: :star: :star: :star:\n\n[![License MIT](https://img.shields.io/npm/l/express.svg)](http://opensource.org/licenses/MIT)\n[![Go Report Card](https://goreportcard.com/badge/github.com/fanux/lhttp)](https://goreportcard.com/report/github.com/fanux/lhttp) [![GoDoc](https://godoc.org/github.com/fanux/lhttp?status.svg)](http://godoc.org/github.com/fanux/lhttp) \n[![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/avelino/awesome-go/blob/master/README.md#networking) \n\n### Discribe\nlhttp is a http like protocol using websocket to provide long live, \nbuild your IM service quickly scalable without XMPP! \n\nEverything is customizable.\n\n### [简体中文](https://github.com/fanux/lhttp/blob/master/doc/README_zh.md)\n\n### Features\n*   simple easy but powerful!\n*   fast, publish 10000 messages using 0.04s(single-core CPU,1G memory).\n*   support cluster.\n*   easy to customize and expansion.\n*   work well with HTTP. So LHTTP can work with others language like PHP java python etc,.\n\n### A simple [chat room demo](https://github.com/fanux/lhttp-web-demo)\n![chat-demo](https://github.com/fanux/lhttp-web-demo/blob/master/web-demo.gif)\nwith [lhttp javascript sdk](https://github.com/fanux/lhttp-javascript-sdk) we complete a simple chat room within 40 lines code!!\n\n### SDKs \n- [x] [javascript SDK](https://github.com/fanux/lhttp-javascript-sdk) webapp or website.\n- [ ] [c SDK](https://github.com/fanux/lhttp-c-sdk) ARM application or some c/c++ application.\n\n### [Header filter development](https://github.com/fanux/lhttp/blob/master/doc/DEVELOP.md)\n\n#### Protocol stack:\n```go\n+--------------------+\n|       lhttp        |\n+--------------------+\n|     websocket      |\n+--------------------+\n|        TCP         |\n+--------------------+\n```\n\n#### Architecture\n```go\n        +---------------------------------------+\n        |    message center cluster (gnatsd)    |\n        +---------------------------------------+\n ........|.................|...............|..................\n| +-------------+   +-------------+   +-------------+        | \n| |lhttp server |   |lhttp server |   |lhttp server |   ...  |  lhttp server cluster\n| +-------------+   +-------------+   +-------------+        | \n .....|..........._____|  |___.............|  |_________......\n      |          |            |            |            |       \u003c----using websocket link\n +--------+  +--------+   +--------+   +--------+   +--------+   \n | client |  | client |   | client |   | client |   | client |   \n +--------+  +--------+   +--------+   +--------+   +--------+  \n```\n\n#### Quick start\n```bash\ngo get github.com/nats-io/nats\ngo get github.com/fanux/lhttp\n```\nWe need run gnatsd first:\n```bash\ncd bin\n./gnatsd \u0026\n./lhttpd \n```\nOpen anohter bash run lhttpClient, then input your command:\n```bash\ncd bin\n./lhttpClient\n```\n\n### Ship on docker\n```\n$ docker build -t lhttp:latest .\n$ docker run -p 9090:9090 -p 8081:8081 lhttp:latest\n```\nOpen two windows in your browser, enter `http://localhost:9090`.\n\nLhttp server port is 8081, your own websocket client can connect to `ws://localhost:8081`\n\nEnjoy the chat...\n\nAlternative, pull image from docker hub.\n```\n$ docker run -p 9090:9090 -p 8081:8081 fanux/lhttp:latest\n```\n\n### Protocol\n```go\nLHTTP/1.0 Command\\r\\n                --------start line, define command, and protocol [protocol/version] [command]\\r\\n\nHeader1:value\\r\\n                    --------headers\nHeader2:value\\r\\n\n\\r\\n\nbody                                 --------message body\n```\nfor example:\n```go\nLHTTP/1.0 chat\\r\\n\ncontent-type:json\\r\\n\npublish:channel_jack\\r\\n\n\\r\\n\n{\n    to:jack,\n    from:mike,\n    message:hello jack,\n    time:1990-1210 5:30:48\n}\n```\n### Usage\n \u003e define your processor, you need combine ```BaseProcessor```\n \n```go\ntype ChatProcessor struct {\n    *lhttp.BaseProcessor\n}\n```\nif you don't like ```BaseProcessor```, define your struct witch must has ```OnOpen(*WsHandler)``` \n```OnClose(*WsHandler)``` method\nlike this:(don't recommand)\n```go\ntype ChatProcessor struct {\n}\nfunc (p ChatProcessor)OnOpen(h *WsHandler) {\n    //your logic\n}\nfunc (p ChatProcessor)OnClose(h *WsHandler) {\n    //your logic\n}\nfunc (p ChatProcessor)OnMessage(h *WsHandler) {\n    //your logic\n}\n```\n\n\u003e regist your processor\n\n```go\nlhttp.Regist(\"chat\",\u0026ChatProcessor{\u0026lhttp.BaseProcessor{}})\n```\n**then if command is \"chat\" ChatProcessor will handle it** \n\n\u003e define your onmessage handle\n\n```go\nfunc (p *ChatProcessor)OnMessage(h *WsHandler) {\n    h.Send(h.GetBody())\n}\n```\n### Start websocket server\n```go\nhttp.Handler(\"/echo\",lhttp.Handler(lhttp.StartServer))\nhttp.ListenAndServe(\":8081\")\n```\n### Example , echo\n```go\ntype ChatProcessor struct {\n    *lhttp.BaseProcessor\n}\n\nfunc (p *ChatProcessor) OnMessage (h *lhttp.WsHandler) {\n    log.Print(\"on message :\", h.GetBody())\n    h.Send(h.GetBody())\n}\n\nfunc main(){\n    lhttp.Regist(\"chat\", \u0026ChatProcessor{\u0026lhttp.BaseProcessor{}})\n\n    http.Handle(\"/echo\",lhttp.Handler(lhttp.StartServer))\n    http.ListenAndServe(\":8081\",nil)\n}\n```\n***\n\n### Test\nopen  websocketServer and run:\n```bash\ncd websocketServer\ngo run test.go\n```\nas we can see, both of the new headers are added and new command is set by the server. \nIf we don't set a header or command ,then they will return the same result as they \nrequested. \n\nopen an other bash, and run client in websocketClient\n```bash\ncd websocketClient\ngo run test.go\n```\n### Subscribe/Publish\nclient1:\n```go\nLHTTP/1.0 command\\r\\n\nsubscribe:channelID\\r\\n\n\\r\\n\nbody optional\n```\nclient2:\n```go\nLHTTP/1.0 command\\r\\n\npublish:channelID\\r\\n\n\\r\\n\nbody require\n```\nclient1:\n```go\nLHTTP/1.0 command\\r\\n\nunsubscribe:channelID\\r\\n\n\\r\\n\nbody optional\n```\nclient2 publish a message by channelID, client1 subscribe it, so client 1 will receive the message.\nif client1 send unsubscribe channelID, he will not receive message any more in channelID\n\nsupport multiple channelID:\n```go\nLHTTP/1.0 chat\\r\\n\nsubscribe:channelID1 channelID2 channelID3\\r\\n\n\\r\\n\n```\n#### Using HTTP publish message! \nlhttp support publish message by standard HTTP. \nURL: /publish . \nmethod: POST . \nbody: use lhttp publishes message as HTTP body.\nfor example I want send a message to who subscribe channel_test by HTTP.\n```go\n    resp,err := http.POST(\"https://www.yourserver.com/publish\", \"text/plain\",\n    \"LHTTP/1.0 chat\\r\\npublish:channel_test\\r\\n\\r\\nhello channel_test guys!\")\n```\nwhen lhttp server receive this message, will publish whole body to channel_test.\n\nyour can use ```Publish``` function in tools.go\n```go\n//func Publish(channelID []string, command string, header map[string]string, body string) (err error) {\n//}\n//send message to who subscribe mike.\n\nPublish(\"mike\", \"yourCommand\", nil, \"hello mike!\")\n```\n\n\n### Upstream\nwe can use lhttp as a proxy:\n```go\nLHTTP/1.0 command\\r\\n\nupstream:POST http://www.xxx.com\\r\\n\n\\r\\n\nbody\n```\nlhttp will use hole message as http body, post to http://www.xxx.com\nif method is GET, lhttp  send http GET request **ignore lhttp message body**:\n\n```go\nLHTTP/1.0 command\\r\\n\nupstream:GET http://www.xxx.com?user=user_a\u0026age=26\\r\\n\n\\r\\n\nbody\n```\n\n#### This case will show you about upstream proxy:\njack use lhttp chat with mike, lhttp is third part module, we can't modify lhttp server but\nwe want to save the chat record, how can we do?\n\n```\n        +----+                  +----+\n        |jack|                  |mike|\n        +----+                  +----+\n         |_____________    _______|\n                       |  |\n                   +------------+\n                   |lhttp server|\n                   +------------+\n                         |(http request with chat record)\n                         V\n                   +------------+\n                   | http server|  upstream server(http://www.xxx.com/record)\n                   +------------+\n                   (save chat record)\n    \n```\njack:\n`MESSAGE_UPSTREAM`\n```go\nLHTTP/1.0 chat\\r\\n\nupstream:POST http://www.xxx.com/record\\r\\n\npublish:channel_mike\\r\\n\n\\r\\n\nhello mike,I am jack\n```\nmike:\n```go\nLHTTP/1.0 chat\\r\\n\nsubscribe:channel_mike\\r\\n\n\\r\\n\n```\nwhen jack send publish message, not only mike will receive the message, the http server will\nalso receive it. witch http body is:```MESSAGE_UPSTREAM```, so http server can do anything about\nmessage include save the record\n\n### Multipart data\nfor example a file upload message, the multipart header record the offset of each data part, \neach part can have it own headers\n```go\nLHTTP/1.0 upload\\r\\n\nmultipart:0 56\\r\\n\n\\r\\n\ncontent-type:text/json\\r\\n\n\\r\\n\n{filename:file.txt,fileLen:5}\ncontent-type:text/plain\\r\\n\n\\r\\n\nhello\n```\n```go\ncontent-type:text/json\\r\\n\\r\\n{filename:file.txt,fileLen:5}content-type:text/plain\\r\\n\\r\\nhello\n^                                                          ^\n|\u003c---------------------first part-------------------------\u003e|\u003c---------second part------------\u003e|\n0                                                          56                           \n```\nwhy not boundary but use offset? if use boundary lhttp need ergodic hole message, that behaviour \nis poor efficiency. instead we use offset to cut message \n\n#### How to get multipart data\nfor example this is client message.\n```go\nLHTTP/1.0 upload\\r\\nmultipart:0 14\\r\\n\\r\\nk1:v1\\r\\n\\r\\nbody1k2:v2\\r\\n\\r\\nbody2\n```\nserver code:\n```go\ntype UploadProcessor struct {\n\t*lhttp.BaseProcessor\n}\n\nfunc (*UploadProcessor) OnMessage(ws *lhttp.WsHandler) {\n\tfor m := ws.GetMultipart(); m != nil; m = m.GetNext() {\n\t\tlog.Print(\"multibody:\", m.GetBody(), \" headers:\", m.GetHeaders())\n\t}\n}\n\n//don't forget to regist your command processor\n\nlhttp.Regist(\"upload\", \u0026UploadProcessor{\u0026lhttp.BaseProcessor{}})\n```\n\n## Partners\n[![](https://yunbi.com/logos/logo.svg)](https://yunbi.com)\n","funding_links":[],"categories":["网络相关库","Networking","网络","Go","網絡","Relational Databases","\u003cspan id=\"网络-networking\"\u003e网络 Networking\u003c/span\u003e"],"sub_categories":["暂未分类","Transliteration","Strings","Uncategorized","交流","高級控制台界面","音译","Advanced Console UIs","暂未分类这些库被放在这里是因为其他类别似乎都不适合。","\u003cspan id=\"高级控制台用户界面-advanced-console-uis\"\u003e高级控制台用户界面 Advanced Console UIs\u003c/span\u003e","高级控制台界面"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffanux%2Flhttp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffanux%2Flhttp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffanux%2Flhttp/lists"}