Every node in Zhenga network has independent configuration stored in a single file.
1. Configuration file
Configuration is a JSON file with arbitrary name in UTF-8 encoding.
2. Node IDs
Every network node is assigned a unique 8-byte ID. The easiest is to use random bytes for each node ID.
Random bytes can be taken at https://www.random.org/cgi-bin/randbyte?nbytes=8&format=h:
af 59 b9 c1 26 b1 3d ff
Removing all the whitespace gives node id
in hexadecimal format:
{
"id": "af59b9c126b13dff"
}
Known peer nodes are enumerated in the peers
array. Each peer is a separate entity with id
parameter:
{
"id": "af59b9c126b13dff",
"peers":
[
{
"id": "df606b11d84b26fc"
},
{
"id": "6ec39bb261b52d81"
}
]
}
Peers can be given a optional name
:
{
"id": "af59b9c126b13dff",
"peers":
[
{
"name": "Bob",
"id": "df606b11d84b26fc"
},
{
"name": "Carol",
"id": "6ec39bb261b52d81"
}
]
}
3. Secrets
Pre-shared secret
is specified for each peer. It is used for encryption keys generation and should be kept in secret. Configuration file access must be limited accordingly.
{
"id": "af59b9c126b13dff",
"peers":
[
{
"name": "Bob",
"id": "df606b11d84b26fc",
"secret": "jackdaws love my big sphinx of quartz"
},
{
"name": "Carol",
"id": "6ec39bb261b52d81",
"secret": "the quick brown fox jumps over the lazy dog"
}
]
}
4. Listening
Zhenga network is not bound to any specific port and nodes can listen
on any available port:
{
"id": "af59b9c126b13dff",
"listen": 42001,
"peers":
[
{
"name": "Bob",
"id": "df606b11d84b26fc",
"secret": "jackdaws love my big sphinx of quartz"
},
{
"name": "Carol",
"id": "6ec39bb261b52d81",
"secret": "the quick brown fox jumps over the lazy dog"
}
]
}
5. Connections
Peer addresses are specified in the addrs
array in the order of preference. host:port
and ip:port
formats are supported:
{
"id": "af59b9c126b13dff",
"listen": 42001,
"peers":
[
{
"name": "Bob",
"id": "df606b11d84b26fc",
"secret": "jackdaws love my big sphinx of quartz",
"addrs":
[
"localhost:42002",
"bob:42002",
"bob.mydomain.net:54321"
]
},
{
"name": "Carol",
"id": "6ec39bb261b52d81",
"secret": "the quick brown fox jumps over the lazy dog",
"addrs":
[
"localhost:42003"
]
}
]
}
It doesn’t matter who connects and who listens. Any established connection will be used in both directions.
Cross-links are allowed. Zhenga will keep it’s operation to one of the successfull connections.
Port forwarding might be necessary to allow external connections.
Short hostnames may be beneficial when moving between local networks. Devices will keep connecting to each other provided they both are on the same network and hostnames are valid.
6. Shares
Array of shares
is specified for each peer. Paths must be absolute. Windows backslashes must be escaped by adding another backslash: D:\\Path\\Dir
. Names are optional. Default name
is the last directory of the path
. Names must be unique across the node:
{
"id": "af59b9c126b13dff",
"listen": 42001,
"peers":
[
{
"name": "Bob",
"id": "df606b11d84b26fc",
"secret": "jackdaws love my big sphinx of quartz",
"addrs":
[
"localhost:42002",
"bob:42002",
"bob.mydomain.net:54123"
],
"shares":
[
{
"name": "ForBob",
"path": "path/to/for_bob"
}
]
},
{
"name": "Carol",
"id": "6ec39bb261b52d81",
"secret": "the quick brown fox jumps over the lazy dog",
"addrs":
[
"localhost:42003"
],
"shares":
[
{
"name": "ForCarol",
"path": "path/to/for_carol"
}
]
}
]
}
7. Templates
Templates is an array of named shares
:
"templates":
[
]
"templates":
[
{
"name": "ForEveryone",
"shares":
[
{
"name": "One",
"path": "path/to/first"
}
]
}
]
"templates":
[
{
"name": "ForEveryone",
"shares":
[
{
"name": "One",
"path": "path/to/first"
},
{
"name": "Two",
"path": "path/to/second"
}
]
}
]
"templates":
[
{
"name": "ForEveryone",
"shares":
[
{
"name": "One",
"path": "path/to/first"
},
{
"name": "Two",
"path": "path/to/second"
}
]
},
{
"name": "ForFriends",
"shares":
[
{
"name": "ForFriends",
"path": "path/to/for_friends"
}
]
}
]
Templates can include other templates. ForFriends
template includes all shares from ForEveryone
template:
"templates":
[
{
"name": "ForEveryone",
"shares":
[
{
"name": "One",
"path": "path/to/first"
},
{
"name": "Two",
"path": "path/to/second"
}
]
},
{
"name": "ForFriends",
"shares":
[
"ForEveryone",
{
"name": "ForFriends",
"path": "path/to/for_friends"
}
]
}
]
Adding templates to configuration allows peers to include them in shares
:
{
"id": "af59b9c126b13dff",
"listen": 42001,
"templates":
[
{
"name": "ForEveryone",
"shares":
[
{
"name": "One",
"path": "path/to/first"
},
{
"name": "Two",
"path": "path/to/second"
}
]
},
{
"name": "ForFriends",
"shares":
[
"ForEveryone",
{
"name": "ForFriends",
"path": "path/to/for_friends"
}
]
}
],
"peers":
[
{
"name": "Bob",
"id": "df606b11d84b26fc",
"secret": "jackdaws love my big sphinx of quartz",
"addrs":
[
"localhost:42002",
"bob:42002",
"bob.mydomain.net:54123"
],
"shares":
[
"ForFriends",
{
"name": "ForBob",
"path": "path/to/for_bob"
}
]
},
{
"name": "Carol",
"id": "6ec39bb261b52d81",
"secret": "the quick brown fox jumps over the lazy dog",
"addrs":
[
"localhost:42003"
],
"shares":
[
"ForFriends",
{
"name": "ForCarol",
"path": "path/to/for_carol"
}
]
}
]
}
8. Write access
Writable shares are enumerated in the writes
array of each peer:
{
"id": "af59b9c126b13dff",
"listen": 42001,
"templates":
[
{
"name": "ForEveryone",
"shares":
[
{
"name": "One",
"path": "path/to/first"
},
{
"name": "Two",
"path": "path/to/second"
}
]
},
{
"name": "ForFriends",
"shares":
[
"ForEveryone",
{
"name": "ForFriends",
"path": "path/to/for_friends"
}
]
}
],
"peers":
[
{
"name": "Bob",
"id": "df606b11d84b26fc",
"secret": "jackdaws love my big sphinx of quartz",
"addrs":
[
"localhost:42002",
"bob:42002",
"bob.mydomain.net:54123"
],
"shares":
[
"ForFriends",
{
"name": "ForBob",
"path": "path/to/for_bob"
}
],
"writes":
[
"One",
"ForBob"
]
},
{
"name": "Carol",
"id": "6ec39bb261b52d81",
"secret": "the quick brown fox jumps over the lazy dog",
"addrs":
[
"localhost:42003"
],
"shares":
[
"ForFriends",
{
"name": "ForCarol",
"path": "path/to/for_carol"
}
],
"writes":
[
"Two"
]
}
]
}
Shares and templates can be made writable directly:
{
"id": "af59b9c126b13dff",
"listen": 42001,
"templates":
[
{
"name": "ForEveryone",
"shares":
[
{
"name": "One",
"path": "path/to/first"
},
{
"name": "Two",
"path": "path/to/second"
}
]
},
{
"name": "ForFriends",
"shares":
[
"ForEveryone",
{
"name": "ForFriends",
"path": "path/to/for_friends",
"write": true
}
]
}
],
"peers":
[
{
"name": "Bob",
"id": "df606b11d84b26fc",
"secret": "jackdaws love my big sphinx of quartz",
"addrs":
[
"localhost:42002",
"bob:42002",
"bob.mydomain.net:54123"
],
"shares":
[
"ForFriends",
{
"name": "ForBob",
"path": "path/to/for_bob"
}
],
"writes":
[
"One",
"ForBob"
]
},
{
"name": "Carol",
"id": "6ec39bb261b52d81",
"secret": "the quick brown fox jumps over the lazy dog",
"addrs":
[
"localhost:42003"
],
"shares":
[
"ForFriends",
{
"name": "ForCarol",
"path": "path/to/for_carol",
"write": true
}
],
"writes":
[
"Two"
]
}
]
}
Conclusion
The resulting configuration is the alice.cfg
example file that can be found along the downloaded Zhenga binary.