{"id":17125359,"url":"https://github.com/danielblagy/hurlean","last_synced_at":"2025-06-15T08:35:02.353Z","repository":{"id":57615043,"uuid":"374443217","full_name":"danielblagy/hurlean","owner":"danielblagy","description":"A networking library.","archived":false,"fork":false,"pushed_at":"2021-07-28T13:46:51.000Z","size":85,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-29T09:45:06.277Z","etag":null,"topics":["client-server","go","golang","golang-framework","golang-network","networking"],"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/danielblagy.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":"2021-06-06T19:10:18.000Z","updated_at":"2022-09-25T08:01:06.000Z","dependencies_parsed_at":"2022-09-10T23:31:42.307Z","dependency_job_id":null,"html_url":"https://github.com/danielblagy/hurlean","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielblagy%2Fhurlean","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielblagy%2Fhurlean/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielblagy%2Fhurlean/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielblagy%2Fhurlean/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danielblagy","download_url":"https://codeload.github.com/danielblagy/hurlean/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245204960,"owners_count":20577450,"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-server","go","golang","golang-framework","golang-network","networking"],"created_at":"2024-10-14T18:44:45.532Z","updated_at":"2025-03-24T03:32:30.819Z","avatar_url":"https://github.com/danielblagy.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# hurlean\n\n## TCP Networking Framework\n\n## Installing\n\n```\n$ go get github.com/danielblagy/hurlean\n```\n\n## Import\n\n```golang\nimport(\n\t\"github.com/danielblagy/hurlean\"\n\t//...\n)\n```\n\n## Console Chat Example\n\n[Chat Server Application](test_app_server/main.go)\\\n[Chat Client Application](test_app_client/main.go)\n\n## How To Use\n\nLet's create a simple server and client apps.\nThe client app will be able to query the server for current time.\n\n### Example Server App\n\nLet's start by creating **the server program**\n\nFirst we import packages that we'll need\n\n```golang\npackage main\n\nimport (\n\t\"github.com/danielblagy/hurlean\"\n\t\"fmt\"\n\t\"time\"\n\t\"bufio\"\n\t\"os\"\n)\n```\n\nThen we implement `hurlean.ServerFunctionalityProvider` interface.\\\nWith this interface we define the behavior of our server application.\\\n\nFirst we define the struct of our interface implementation. Here we can put our client application state.\\\nIn this simple example we won't need much, only a *bufio.Scanner variable to store the initialized console scanner.\nWe the scanner we can get console input from the user of our server application. We'll provide two commands: 'exit',\nwhich will stop the server, and 'disconnect' which will force-disconnect all the currently connected users.\n\n```golang\ntype ExampleClientHandler struct{}\n\ntype ExampleServerFunctionalityProvider struct{\n\t// here we can store application-specific data\n\tscanner *bufio.Scanner\n}\n```\n\nNext we implement functions that define the behavior of our server in the case of any client activity.\n\n```golang\n// executed once for each client\nfunc (fp ExampleServerFunctionalityProvider) OnClientConnect(si *hurlean.ServerInstance, id uint32) {\n\t\n\tfmt.Printf(\"Client %v has connected to the server\\n\", id)\n}\n\n// executed once for each client\nfunc (fp ExampleServerFunctionalityProvider) OnClientDisconnect(si *hurlean.ServerInstance, id uint32) {\n\t\n\tfmt.Printf(\"Client %v has disconnected from the server\\n\", id)\n}\n\n// executed each time the server gets a message from a client\nfunc (fp ExampleServerFunctionalityProvider) OnClientMessage(si *hurlean.ServerInstance, id uint32, message hurlean.Message) {\n\t\n\tfmt.Printf(\"Message from %v: %v\\n\", id, message)\n\t\n\tif message.Type == \"get current time\" {\n\t\tcurrentTimeMessage := hurlean.Message{\n\t\t\tType: \"time\",\n\t\t\tBody: time.Now().Format(\"Mon Jan 2 15:04:05 -0700 MST 2006\"),\t// current time\n\t\t}\n\t\tsi.Send(id, currentTimeMessage)\n\t\t\n\t\tfmt.Printf(\"Current time has been sent to %v\\n\", id)\n\t} else {\n\t\tfmt.Printf(\"Unknown message type '%v'\\n\", message.Type)\n\t}\n}\n```\n\nNow let's implement the functions that define the logic of our server program.\n\n```golang\n// executed once when the server instance is initialized\nfunc (fp ExampleServerFunctionalityProvider) OnServerInit(serverInstance *hurlean.ServerInstance) {\n\t// empty for this simple example\n}\n\n// executed continuously in a loop when the server is running\nfunc (fp ExampleServerFunctionalityProvider) OnServerUpdate(serverInstance *hurlean.ServerInstance) {\n\t\n\t// get console input from the server administrator (the app user)\n\tif fp.scanner.Scan() {\n\t\tswitch (fp.scanner.Text()) {\n\t\tcase \"exit\":\n\t\t\tserverInstance.Stop()\n\t\t\t\n\t\tcase \"disconnect\":\n\t\t\tserverInstance.DisconnectAll()\n\t\t}\n\t}\n}\n```\n\nNow, to the main function. Here we start the server on port 4545 and provide interfaces implementations and the state.\\\nIn the case of failure to start the server, error will be returned.\n\n```golang\nfunc main() {\n\t\n\t// init server state\n\texampleServerFunctionalityProvider := ExampleServerFunctionalityProvider{\n\t\tscanner: bufio.NewScanner(os.Stdin),\n\t}\n\t\n\tif err := hurlean.StartServer(\"4545\", exampleServerFunctionalityProvider); err != nil {\n\t\tfmt.Println(err)\n\t}\n}\n```\n\n[Full source](#example-server-app-full-source)\n\n### Example Client App\n\nImport packages first\n\n```golang\npackage main\n\nimport (\n\t\"github.com/danielblagy/hurlean\"\n\t\"fmt\"\n\t\"bufio\"\n\t\"os\"\n)\n```\n\nThen we need to implement `hurlean.ClientFunctionalityProvider` interface.\\\nMuch like with server state, we're going to define client state as well.\n\n```golang\ntype ExampleClientFunctionalityProvider struct{\n\t// here we can store application-specific data\n\tscanner *bufio.Scanner\n}\n```\n\nWe proceed by implementing the interface functions.\\\nHere we define how we should respond to the messages coming from the server.\n\n```golang\n// executed each time the client gets a message from the server\nfunc (fp ExampleClientFunctionalityProvider) OnServerMessage(clientInstance *hurlean.ClientInstance, message hurlean.Message) {\n\t\n\tif message.Type == \"time\" {\n\t\tfmt.Printf(\"Current time: %v\\n\\n\", message.Body)\n\t} else {\n\t\tfmt.Printf(\"Unknown message type '%v'\", message.Type)\n\t}\n}\n```\n\nNow we need to implement functions that define the client application behavior.\n\n```golang\n// executed once when the client instance is initialized\nfunc (fp ExampleClientFunctionalityProvider) OnClientInit(clientInstance *hurlean.ClientInstance) {\n\t// empty for this simple example\n}\n\n// executed continuously in a loop when the client is running\nfunc (fp ExampleClientFunctionalityProvider) OnClientUpdate(clientInstance *hurlean.ClientInstance) {\n\t\n\t// get console input from the user\n\tif fp.scanner.Scan() {\n\t\tswitch (fp.scanner.Text()) {\n\t\tcase \"time\":\n\t\t\tgetTimeMessage := hurlean.Message{\n\t\t\t\tType: \"get current time\",\n\t\t\t\tBody: \"\",\n\t\t\t}\n\t\t\tclientInstance.Send(getTimeMessage)\n\t\t\t\n\t\tcase \"disconnect\":\n\t\t\tclientInstance.Disconnect()\n\t\t}\n\t}\n}\n```\n\nAnd finally, the main function where we start the client application.\\\nIn the case of failure to connect to the server, error will be returned.\n\n``` golang\nfunc main() {\n\t\n\t// init client state\n\texampleClientFunctionalityProvider := ExampleClientFunctionalityProvider{\n\t\tscanner: bufio.NewScanner(os.Stdin),\n\t}\n\t\n\tif err := hurlean.ConnectToServer(\n\t\t\"localhost\", \"4545\", exampleClientFunctionalityProvider); err != nil {\n\t\tfmt.Println(err)\n\t}\n}\n```\n\n[Full source](#example-client-app-full-source)\n\n\n### Example Server App Full Source\n\n```golang\npackage main\n\n\nimport (\n\t\"github.com/danielblagy/hurlean\"\n\t\"fmt\"\n\t\"time\"\n\t\"bufio\"\n\t\"os\"\n)\n\n\ntype ExampleServerFunctionalityProvider struct{\n\t// here we can store application-specific data\n\tscanner *bufio.Scanner\n}\n\n// executed once for each client\nfunc (fp ExampleServerFunctionalityProvider) OnClientConnect(si *hurlean.ServerInstance, id uint32) {\n\t\n\tfmt.Printf(\"Client %v has connected to the server\\n\", id)\n}\n\n// executed once for each client\nfunc (fp ExampleServerFunctionalityProvider) OnClientDisconnect(si *hurlean.ServerInstance, id uint32) {\n\t\n\tfmt.Printf(\"Client %v has disconnected from the server\\n\", id)\n}\n\n// executed each time the server gets a message from a client\nfunc (fp ExampleServerFunctionalityProvider) OnClientMessage(si *hurlean.ServerInstance, id uint32, message hurlean.Message) {\n\t\n\tfmt.Printf(\"Message from %v: %v\\n\", id, message)\n\t\n\tif message.Type == \"get current time\" {\n\t\tcurrentTimeMessage := hurlean.Message{\n\t\t\tType: \"time\",\n\t\t\tBody: time.Now().Format(\"Mon Jan 2 15:04:05 -0700 MST 2006\"),\t// current time\n\t\t}\n\t\tsi.Send(id, currentTimeMessage)\n\t\t\n\t\tfmt.Printf(\"Current time has been sent to %v\\n\", id)\n\t} else {\n\t\tfmt.Printf(\"Unknown message type '%v'\\n\", message.Type)\n\t}\n}\n\n// executed once when the server instance is initialized\nfunc (fp ExampleServerFunctionalityProvider) OnServerInit(serverInstance *hurlean.ServerInstance) {\n\t// empty for this simple example\n}\n\n// executed continuously in a loop when the server is running\nfunc (fp ExampleServerFunctionalityProvider) OnServerUpdate(serverInstance *hurlean.ServerInstance) {\n\t\n\t// get console input from the server administrator (the app user)\n\tif fp.scanner.Scan() {\n\t\tswitch (fp.scanner.Text()) {\n\t\tcase \"exit\":\n\t\t\tserverInstance.Stop()\n\t\t\t\n\t\tcase \"disconnect\":\n\t\t\tserverInstance.DisconnectAll()\n\t\t}\n\t}\n}\n\n\nfunc main() {\n\t\n\t// init server state\n\texampleServerFunctionalityProvider := ExampleServerFunctionalityProvider{\n\t\tscanner: bufio.NewScanner(os.Stdin),\n\t}\n\t\n\tif err := hurlean.StartServer(\"4545\", exampleServerFunctionalityProvider); err != nil {\n\t\tfmt.Println(err)\n\t}\n}\n```\n\n### Example Client App Full Source\n\n```golang\npackage main\n\n\nimport (\n\t\"github.com/danielblagy/hurlean\"\n\t\"fmt\"\n\t\"bufio\"\n\t\"os\"\n)\n\n\ntype ExampleClientFunctionalityProvider struct{\n\t// here we can store application-specific data\n\tscanner *bufio.Scanner\n}\n\n// executed each time the client gets a message from the server\nfunc (fp ExampleClientFunctionalityProvider) OnServerMessage(clientInstance *hurlean.ClientInstance, message hurlean.Message) {\n\t\n\tif message.Type == \"time\" {\n\t\tfmt.Printf(\"Current time: %v\\n\\n\", message.Body)\n\t} else {\n\t\tfmt.Printf(\"Unknown message type '%v'\", message.Type)\n\t}\n}\n\n// executed once when the client instance is initialized\nfunc (fp ExampleClientFunctionalityProvider) OnClientInit(clientInstance *hurlean.ClientInstance) {\n\t// empty for this simple example\n}\n\n// executed continuously in a loop when the client is running\nfunc (fp ExampleClientFunctionalityProvider) OnClientUpdate(clientInstance *hurlean.ClientInstance) {\n\t\n\t// get console input from the user\n\tif fp.scanner.Scan() {\n\t\tswitch (fp.scanner.Text()) {\n\t\tcase \"time\":\n\t\t\tgetTimeMessage := hurlean.Message{\n\t\t\t\tType: \"get current time\",\n\t\t\t\tBody: \"\",\n\t\t\t}\n\t\t\tclientInstance.Send(getTimeMessage)\n\t\t\t\n\t\tcase \"disconnect\":\n\t\t\tclientInstance.Disconnect()\n\t\t}\n\t}\n}\n\n\nfunc main() {\n\t\n\t// init client state\n\texampleClientFunctionalityProvider := ExampleClientFunctionalityProvider{\n\t\tscanner: bufio.NewScanner(os.Stdin),\n\t}\n\t\n\tif err := hurlean.ConnectToServer(\n\t\t\"localhost\", \"4545\", exampleClientFunctionalityProvider); err != nil {\n\t\tfmt.Println(err)\n\t}\n}\n```\n\n\nFor more complex example check out [the console chat example](#console-chat-example)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielblagy%2Fhurlean","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanielblagy%2Fhurlean","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielblagy%2Fhurlean/lists"}