{"id":16930745,"url":"https://github.com/schmichael/whispering-gophers","last_synced_at":"2025-04-11T18:32:12.220Z","repository":{"id":11996246,"uuid":"14573553","full_name":"schmichael/whispering-gophers","owner":"schmichael","description":"A whispernet written in Go. Continued from Google's excellent code lab: https://code.google.com/p/whispering-gophers/","archived":false,"fork":false,"pushed_at":"2015-02-13T04:34:20.000Z","size":246,"stargazers_count":20,"open_issues_count":0,"forks_count":18,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-03-25T14:21:43.516Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/schmichael.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}},"created_at":"2013-11-21T00:38:53.000Z","updated_at":"2023-03-18T19:04:58.000Z","dependencies_parsed_at":"2022-09-01T14:51:46.780Z","dependency_job_id":null,"html_url":"https://github.com/schmichael/whispering-gophers","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/schmichael%2Fwhispering-gophers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schmichael%2Fwhispering-gophers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schmichael%2Fwhispering-gophers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schmichael%2Fwhispering-gophers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/schmichael","download_url":"https://codeload.github.com/schmichael/whispering-gophers/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248458646,"owners_count":21107122,"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":[],"created_at":"2024-10-13T20:42:23.497Z","updated_at":"2025-04-11T18:32:12.196Z","avatar_url":"https://github.com/schmichael.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"Whispering Gophers\n==================\n\nA whispernet written in Go.\n\nBased on: https://code.google.com/p/whispering-gophers/\n\nGetting Started\n---------------\nIf you have not worked in GO before (i.e., don't have a GOPATH), then start here:\n\n```\nmkdir ~/somedir\ncd somedir\nexport GOPATH=~/somedir\ngit clone https://github.com/pdxgo/whispering-gophers.git\ngo get github.com/pdxgo/whispering-gophers\ncd whispering-gophers\ngo build\n```\n\n\nRunning\n-------\n\nFor the first peer:\n\n```sh\ngo run main.go -nick phil\n```\n\nNext peers:\n\n```sh\ngo run main.go -peer $IP_OF_PEER:55555 -nick goldy\n```\n\nWhere ``$IP_OF_PEER`` is the IP address printed by a running peer.\n\nProtocol\n--------\n\n*Peers* are long running programs which accept user input and display messages\nfrom other peers. At the minimum a well participating peer must:\n\n* Manually connect to at least 1 peer\n* Bind to an address and accept connections from any peer\n\n*Messages* should be of the form:\n\n```json\n{\n    \"ID\": \"\u003cglobally unique string\u003e\",\n    \"Addr\": \"\u003cIP:Port the sender is listening on\u003e\",\n    \"Body\": \"\u003cthe actual message to display\u003e\"\n}\n```\n\n*Peers* should follow the following behavior with regard to *messages*:\n\n* Display messages (``Body`` key) from other peers\n* Disconnect peers which send malformed messages\n* Accept user input as ``Body`` content\n* Send messages to all known peers.\n* When sending messages ``Addr`` must be the ``IP:Port`` combination the peer\n  is listening on.\n* Connect to new peers seen in ``Addr`` fields of received messages\n* Broadcast all messages to all peers (except ``Addr``); store list of Seen\n  messages by ID to avoid rebroadcasting\n* Payloads without a ``Body`` and/or with unknown keys should be silently\n  *ignored* to support extensions\n* *Messages are* **not** *delimited or framed.* Multiple messages *may* be sent\n  across a single connection. Peers recieving messages *must* detect the end of\n  the JSON object to know when one message ends and another may begin.\n\nConnections are unidirectional. In a healthy whispernet each peer will have 1\noutgoing connection to send messages to every other peer, as well as 1 incoming\nconnection from each peer for receiving messages.\n\nExtensions\n----------\n\nRoughly ordered based on difficulty.\n\n1. ~~Pretty display messages~~ Done!\n1. ~~Nicks!~~ Done!\n1. Forget old message IDs (the basic daemon slowly uses all memory) - may use\n   *Timestamp* field - see below\n1. Base ID on hash of Addr + Body + Timestamp - see below\n1. Discover based on [UDP\n   broadcasts](https://groups.google.com/d/msg/golang-nuts/nbmYWwHCgPc/ZBw2uH6Bdi4J)\nSee below - *Partially done*\n1. Build web interface into daemon\n 1. Simple input form (textbox + submit button)\n 1. Chat output (refreshed on a timer or using\n    [websockets](http://godoc.org/code.google.com/p/go.net/websocket) if you're\n    really fancy)\n 1. Peer connection controls (connect to a new host, disconnect from a host)\n1. File transfers - see below\n1. Send backlog to newly connected peers - see backlog below\n1. Flood control: Disconnect and blacklist peers whose activity exceeds a\n   threshold\n1. PKI all the things\n1. Scalable routing\n\n**UDP Broadcast Protocol**\n\nBroadcasts should be of the form: \"IP:PORT\" (same as ``Addr``) and may be sent on \nbehalf of any peers.\n\n**Timestamp field**\n\nTo support various features, messages should include an optional Timestamp\nfield of the format milliseconds since UNIX epoch as a number. For example:\n\n```json\n{\n    \"ID\": \"abc123\",\n    \"Addr\": \"192.168.1.53:2345\",\n    \"Body\": \"Hello world!\",\n    \"Timestamp\": 1382050782085\n}\n```\n\n**Hashed ID field**\n\nTo support very rudimentary payload verification, use a hash of the concatenated Addr, Body, and Timestamp fields. To allow backward compatibility with old clients, hashed IDs should be of the form:\n\n```json\n{\n    \"ID\": \"hash:sha256:\u003chash\u003e\",\n    ...\n}\n```\n\nWhere each string starts with \"hash:\" followed by the name of the hash function used, followed by a colon and the hex encoded hash.\n\nUnknown hash functions should cause the reader to revert to the basic random-string-ID behavior.\n\nPeers should drop messages whose hashes don't match the current message payload.\n\n**File transfers**\n\nTwo new keys: \"FileType\" and \"FileContents\"\n\n* *FileType* should be the MIME type like: \"image/gif\"\n* *FileContents* should be the Base64 encoded file contents\n\n**Backlog**\n\nUpon receiving a new connection from a peer, a daemon should replay that peer the last N messages (the actual number shouldn't be important) to the peer.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fschmichael%2Fwhispering-gophers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fschmichael%2Fwhispering-gophers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fschmichael%2Fwhispering-gophers/lists"}