{"id":21406383,"url":"https://github.com/chandler767/golang-chat","last_synced_at":"2026-02-22T02:02:42.436Z","repository":{"id":123048029,"uuid":"137117684","full_name":"chandler767/Golang-Chat","owner":"chandler767","description":"Console chat utility that demonstrates PubNub integration with Golang.","archived":false,"fork":false,"pushed_at":"2019-06-11T19:58:26.000Z","size":1895,"stargazers_count":3,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-14T00:45:22.686Z","etag":null,"topics":["chat","chat-application","concurrency","console","console-application","cui","demo","go","gocui","golang","goroutine","pubnub","pubnub-api","pubnub-chatting","pubnub-messaging","pubnub-sdk","pubnub-sdk-examples","pubsub","pubsubclient","tutorial"],"latest_commit_sha":null,"homepage":"https://go-chat.chandlermayo.com/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chandler767.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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-06-12T19:23:10.000Z","updated_at":"2025-03-14T17:27:35.000Z","dependencies_parsed_at":null,"dependency_job_id":"20cb3bf2-e293-4347-b743-571c8e59e114","html_url":"https://github.com/chandler767/Golang-Chat","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/chandler767/Golang-Chat","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chandler767%2FGolang-Chat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chandler767%2FGolang-Chat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chandler767%2FGolang-Chat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chandler767%2FGolang-Chat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chandler767","download_url":"https://codeload.github.com/chandler767/Golang-Chat/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chandler767%2FGolang-Chat/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29703254,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-21T23:35:04.139Z","status":"online","status_checked_at":"2026-02-22T02:00:08.193Z","response_time":110,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["chat","chat-application","concurrency","console","console-application","cui","demo","go","gocui","golang","goroutine","pubnub","pubnub-api","pubnub-chatting","pubnub-messaging","pubnub-sdk","pubnub-sdk-examples","pubsub","pubsubclient","tutorial"],"created_at":"2024-11-22T16:39:29.940Z","updated_at":"2026-02-22T02:02:42.409Z","avatar_url":"https://github.com/chandler767.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Golang-Chat\nConsole chat utility that demonstrates [PubNub](https://www.pubnub.com/) integration with Golang.\n\n![Image of Go-Chat](https://raw.githubusercontent.com/chandler767/Go-Chat/master/images/chat.png)\n\n## Features \n- Leverages the PubNub Network for chat with [Publish and Subscribe](https://www.pubnub.com/docs/go/data-streams-publish-and-subscribe).\n- Uses [GoCUI](https://github.com/jroimartin/gocui) for a simple console user interface.\n- Username and channel are configurable.\n\n### Quick Start\nDownload the appropriate pre-compiled executable from here: https://github.com/chandler767/Go-Chat/releases\n\n### Video Tutorial and Demo\n[![Go-Chat Tutorial and Demo](https://img.youtube.com/vi/w5Kl1rlb24E/0.jpg)](https://www.youtube.com/watch?v=w5Kl1rlb24E) \n\n### Project Tutorial\nBuild your own chat app with PubNub and Golang.\n\n1. Install the latest version of [Go](https://golang.org/) and setup your $GOPATH.\n2. Use `go get` in your terminal to download the GoCUI package and the PubNub messaging package:\n```bash\ngo get github.com/jroimartin/gocui\ngo get github.com/pubnub/go/messaging\n```\n3. Create a new directory for your project and create a file named `main.go`.\n4. The `main.go` will contain the code for the layout of our chat application using [GoCUI](https://github.com/jroimartin/gocui). GoCUI is a minimalist Go package aimed at creating Console User Interfaces. In this example we create two views (input and ouput) for our chat app, call a manager function that updates our views when the window size changes, and bind the enter key to the text input to submit messages. \n```go\npackage main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nfunc drawchat(channel string, username string) {\n\t// Create a new GUI.\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tpanic(err)\n\t\treturn\n\t}\n\tdefer g.Close()\n\tg.Cursor = true\n\n\t// Update the views when terminal changes size.\n\tg.SetManagerFunc(func(g *gocui.Gui) error {\n\t\ttermwidth, termheight := g.Size()\n\t\t_, err := g.SetView(\"output\", 0, 0, termwidth-1, termheight-4)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t_, err = g.SetView(\"input\", 0, termheight-3, termwidth-1, termheight-1)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n\t// Terminal width and height.\n\ttermwidth, termheight := g.Size()\n\n\t// Output.\n\tov, err := g.SetView(\"output\", 0, 0, termwidth-1, termheight-4)\n\tif err != nil \u0026\u0026 err != gocui.ErrUnknownView {\n\t\tlog.Println(\"Failed to create output view:\", err)\n\t\treturn\n\t}\n\tov.Title = \" Messages  -  \u003c\" + channel + \"\u003e \"\n\tov.FgColor = gocui.ColorRed\n\tov.Autoscroll = true\n\tov.Wrap = true\n\n\t// Send a welcome message.\n\t_, err = fmt.Fprintln(ov, \"\u003cGo-Chat\u003e: Welcome to Go-Chat powered by PubNub!\")\n\tif err != nil {\n\t\tlog.Println(\"Failed to print into output view:\", err)\n\t}\n\t_, err = fmt.Fprintln(ov, \"\u003cGo-Chat\u003e: Press Ctrl-C to quit.\")\n\tif err != nil {\n\t\tlog.Println(\"Failed to print into output view:\", err)\n\t}\n\n\t// Input.\n\tiv, err := g.SetView(\"input\", 0, termheight-3, termwidth-1, termheight-1)\n\tif err != nil \u0026\u0026 err != gocui.ErrUnknownView {\n\t\tlog.Println(\"Failed to create input view:\", err)\n\t\treturn\n\t}\n\tiv.Title = \" New Message  -  \u003c\" + username + \"\u003e \"\n\tiv.FgColor = gocui.ColorWhite\n\tiv.Editable = true\n\terr = iv.SetCursor(0, 0)\n\tif err != nil {\n\t\tlog.Println(\"Failed to set cursor:\", err)\n\t\treturn\n\t}\n\n\t// Bind Ctrl-C so the user can quit.\n\terr = g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error {\n\t\treturn gocui.ErrQuit\n\t})\n\tif err != nil {\n\t\tlog.Println(\"Could not set key binding:\", err)\n\t\treturn\n\t}\n\n\t// Bind enter key to input to send new messages.\n\terr = g.SetKeybinding(\"input\", gocui.KeyEnter, gocui.ModNone, func(g *gocui.Gui, iv *gocui.View) error {\n\t\t// Read buffer from the beginning.\n\t\tiv.Rewind()\n\n\t\t// Get output view and print.\n\t\tov, err := g.View(\"output\")\n\t\tif err != nil {\n\t\t\tlog.Println(\"Cannot get output view:\", err)\n\t\t\treturn err\n\t\t}\n\t\t_, err = fmt.Fprintf(ov, \"\u003c%s\u003e: %s\", username, iv.Buffer())\n\t\tif err != nil {\n\t\t\tlog.Println(\"Cannot print to output view:\", err)\n\t\t}\n\n\t\t// Reset input.\n\t\tiv.Clear()\n\n\t\t// Reset cursor.\n\t\terr = iv.SetCursor(0, 0)\n\t\tif err != nil {\n\t\t\tlog.Println(\"Failed to set cursor:\", err)\n\t\t}\n\t\treturn err\n\t})\n\tif err != nil {\n\t\tlog.Println(\"Cannot bind the enter key:\", err)\n\t}\n\n\t// Set the focus to input.\n\t_, err = g.SetCurrentView(\"input\")\n\tif err != nil {\n\t\tlog.Println(\"Cannot set focus to input view:\", err)\n\t}\n\n\t// Start the main loop.\n\terr = g.MainLoop()\n\tlog.Println(\"Main loop has finished:\", err)\n}\n\nfunc main() {\n\t// Get channel and username.\n\treader := bufio.NewReader(os.Stdin)\n\tfmt.Print(\"Enter Channel Name: \")\n\tchannel, err := reader.ReadString('\\n')\n\tif err != nil {\n\t\tlog.Println(\"Could not set channel:\", err)\n\t}\n\tfmt.Print(\"Enter Desired Username: \")\n\tusername, err := reader.ReadString('\\n')\n\tif err != nil {\n\t\tlog.Println(\"Could not set username:\", err)\n\t}\n\t// Create the GUI.\n\tdrawchat(strings.TrimSuffix(channel, \"\\n\"), strings.TrimSuffix(username, \"\\n\"))\n}\n\n```\n5. Run the application: `go run main.go`. You should be able to enter a channel name, username, and send messages to yourself. \n\n![Image of application GUI](https://raw.githubusercontent.com/chandler767/Go-Chat/master/images/UI.png)\n\n6. Now we need to integrate PubNub to send messages to other users and receive messages.\n7. You need PubNub API Keys. This allows the chat communication over a data stream network. You can fill in the YOUR_PUBLISH_API_KEY and YOUR_SUBSCRIBE_API_KEY placeholder strings with your API keys that you get on the [PubNub website](http://pubnub.com/).\n\n\u003ca href=\"https://dashboard.pubnub.com/signup?devrel_gh=golang-chat\" target=\"_blank\" rel=\"nofollow noopener noreferrer\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/5bc964692f93436566239a5dd506bb55c0ee4171/68747470733a2f2f692e696d6775722e636f6d2f6f673544446a662e706e67\" alt=\"PubNub Signup\" width=\"260\"/\u003e\u003c/a\u003e\n\n8. Import the PubNub messaging package and the encoding/json package.\n```\n\"github.com/pubnub/go/messaging\"\n\"encoding/json\"\n```\n9. Initialize PubNub at the beginning of the function that creates our chat GUI.\n```\n// Initialize PubNub\npubnub := messaging.NewPubnub(\"YOUR_PUBLISH_API_KEY\", \"YOUR_SUBSCRIBE_API_KEY\", \"\", \"\", false, \"\", nil)\n```\n10. Subscribe (listen on) a channel. This is async. We have to refresh the output view when a new message is received. Add this inside the drawchat function before where the main loop is started.\n```go\n// Subscribe (listen on) a channel.\nsuccessChannel := make(chan []byte)\ngo pubnub.Subscribe(channel, \"\", successChannel, false, make(chan []byte))\ngo func() {\n\tfor {\n\t\tselect {\n\t\tcase response := \u003c-successChannel:\n\t\t\tvar msg []interface{}\n\t\t\terr := json.Unmarshal(response, \u0026msg)\n\t\t\tif err != nil {\n\t\t\t\tlog.Println(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tov, err := g.View(\"output\")\n\t\t\tif err != nil {\n\t\t\t\tlog.Println(\"Cannot get output view:\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tswitch m := msg[0].(type) {\n\t\t\tcase []interface{}:\n\t\t\t\t// Get output view and print.\n\t\t\t\t_, err = fmt.Fprintf(ov, \"%s\", m[0])\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Println(\"Cannot print to output view:\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Refresh view\n\t\t\tg.Update(func(g *gocui.Gui) error {\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}\n\t}\n}()\n```\n11. Change your enter key binding function to send messages to PubNub instead of displaying them in the output. The messages will display in the output if they are succesfully sent to PubNub and received by pubnub.Subscribe() function.\n```go\n// Bind enter key to input to send new messages.\nerr = g.SetKeybinding(\"input\", gocui.KeyEnter, gocui.ModNone, func(g *gocui.Gui, iv *gocui.View) error {\n\t// Read buffer from the beginning.\n\tiv.Rewind()\n\n\t// Send message if text was entered.\n\tif len(iv.Buffer()) \u003e= 2 {\n\t\tgo pubnub.Publish(\n\t\t\tchannel,\n\t\t\t\"\u003c\"+username+\"\u003e: \"+iv.Buffer(),\n\t\t\tmake(chan []byte),\n\t\t\tmake(chan []byte),\n\t\t)\n\n\t\t// Reset input.\n\t\tiv.Clear()\n\n\t\t// Reset cursor.\n\t\terr = iv.SetCursor(0, 0)\n\t\tif err != nil {\n\t\t\tlog.Println(\"Failed to set cursor:\", err)\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n})\nif err != nil {\n\tlog.Println(\"Cannot bind the enter key:\", err)\n}\n```\n12. For reference you can print the PubNub version info at the start of our main() function.\n```go\n// Print version info.\nfmt.Println(\"PubNub SDK for go;\", messaging.VersionInfo())\n```\n13. Try it out `go run main.go`.\n\n![Image of Go-Chat startup](https://raw.githubusercontent.com/chandler767/Go-Chat/master/images/startup.png)\n\n![Image of Go-Chat](https://raw.githubusercontent.com/chandler767/Go-Chat/master/images/chat.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchandler767%2Fgolang-chat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchandler767%2Fgolang-chat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchandler767%2Fgolang-chat/lists"}