A whispernet written in Go.
Based on: https://code.google.com/p/whispering-gophers/
If you have not worked in GO before (i.e., don't have a GOPATH), then start here:
mkdir ~/somedir
cd somedir
export GOPATH=~/somedir
git clone https://github.com/pdxgo/whispering-gophers.git
go get github.com/pdxgo/whispering-gophers
cd whispering-gophers
go build
For the first peer:
go run main.go -nick phil
Next peers:
go run main.go -peer $IP_OF_PEER:55555 -nick goldy
Where $IP_OF_PEER
is the IP address printed by a running peer.
Peers are long running programs which accept user input and display messages from other peers. At the minimum a well participating peer must:
- Manually connect to at least 1 peer
- Bind to an address and accept connections from any peer
Messages should be of the form:
{
"ID": "<globally unique string>",
"Addr": "<IP:Port the sender is listening on>",
"Body": "<the actual message to display>"
}
Peers should follow the following behavior with regard to messages:
- Display messages (
Body
key) from other peers - Disconnect peers which send malformed messages
- Accept user input as
Body
content - Send messages to all known peers.
- When sending messages
Addr
must be theIP:Port
combination the peer is listening on. - Connect to new peers seen in
Addr
fields of received messages - Broadcast all messages to all peers (except
Addr
); store list of Seen messages by ID to avoid rebroadcasting - Payloads without a
Body
and/or with unknown keys should be silently ignored to support extensions - Messages are not delimited or framed. Multiple messages may be sent across a single connection. Peers recieving messages must detect the end of the JSON object to know when one message ends and another may begin.
Connections are unidirectional. In a healthy whispernet each peer will have 1 outgoing connection to send messages to every other peer, as well as 1 incoming connection from each peer for receiving messages.
Roughly ordered based on difficulty.
Pretty display messagesDone!Nicks!Done!- Forget old message IDs (the basic daemon slowly uses all memory) - may use Timestamp field - see below
- Base ID on hash of Addr + Body + Timestamp - see below
- Discover based on UDP broadcasts See below - Partially done
- Build web interface into daemon
- Simple input form (textbox + submit button)
- Chat output (refreshed on a timer or using websockets if you're really fancy)
- Peer connection controls (connect to a new host, disconnect from a host)
- File transfers - see below
- Send backlog to newly connected peers - see backlog below
- Flood control: Disconnect and blacklist peers whose activity exceeds a threshold
- PKI all the things
- Scalable routing
UDP Broadcast Protocol
Broadcasts should be of the form: "IP:PORT" (same as Addr
) and may be sent on
behalf of any peers.
Timestamp field
To support various features, messages should include an optional Timestamp field of the format milliseconds since UNIX epoch as a number. For example:
{
"ID": "abc123",
"Addr": "192.168.1.53:2345",
"Body": "Hello world!",
"Timestamp": 1382050782085
}
Hashed ID field
To 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:
{
"ID": "hash:sha256:<hash>",
...
}
Where each string starts with "hash:" followed by the name of the hash function used, followed by a colon and the hex encoded hash.
Unknown hash functions should cause the reader to revert to the basic random-string-ID behavior.
Peers should drop messages whose hashes don't match the current message payload.
File transfers
Two new keys: "FileType" and "FileContents"
- FileType should be the MIME type like: "image/gif"
- FileContents should be the Base64 encoded file contents
Backlog
Upon 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.