a cabal implementation in erlang
README.md

CabErl

https://nest.pijul.com/cryptix/caberl

A cable implementation in Erlang!

DISCLAIMER This is my project to learn the language. Don't expect too much of plus it might not be fully idiomatic either.

Done

  • fairly complete peer api
    • read & write channels, set_nick, set_topic, join & leave
  • de- and encoding of messages and posts
  • server listener, decode loop and request responses
  • request channel state and posts for the last day
  • request posts for hash replies

TODO

  • UTF-8 handling seems to be a bit gnarly
    • make sure all string fields (channels, text, topic, etc.) handle unicode codepoints properly
    • See https://www.erlang.org/doc/apps/stdlib/unicode_usage.html
  • complete channel and connection state
    • new messages for open requests should be forwarded, etc. (TTL feature)
    • implement rate limiting based on bytes transmitted per peer
  • complete tests for full remote peer lifecycle
    • cleanup peer socket linkage
  • flesh out db:read with time windows
  • add request for remote channel listings
  • only fetch posts for hashes we actually asked for
  • add supervisor tree for db and listener
  • add more tests for links/heads tracking
  • keep track of requests limits and time windows

Building and testing

This project uses rebar3 to build the erlang code and it's dependencies.

If you don't want to use the supplied Nix flake.nix/shell.nix to get a development environment you need to install the following tools and libraries with your package manager of choice such that rebar can pick them up.

If you are using archlinux, take a look at the .build.yaml for a list of package names.

To check if everything fetches and compiles you can use rebar3 compile, which should show something like this and exit cleanly:

===> Verifying dependencies...
===> Analyzing applications...
===> Compiling cable

Testing

The rebar3 eunit is a helper to run the EUnit suites in the test/ folder. This will spawn various peers and makes them comminicate in various ways.

Headless peer in a shell

rebar3 shell starts an erlang shell with all dependencies loaded. You can use it to spawn one or more peers.

1> {ok, Pid} = peer:start_link([]).
[Cable] Public Key: 75D98E54FE09B959EB7797D7F0F4FFE2E4F63EA735AADD1957FC00B2E3DCBA2B
[Transport] Loaded existing Curve25519 keypair
[DB] Path: "/home/cryptix/.caberl/sqlite.db"
[DB] schema.sql applied
[Peer] Event Loop: <0.404.0>
[Transport] Starting encrypted server on port 3113 (pid: <0.405.0>)
[Transport] Accept loop started (pid: <0.407.0>)
[Transport] Waiting for encrypted connections (listener: <0.406.0>, transport: <0.405.0>)
[Peer] Listening on {127,0,0,1}:3113
{ok,<0.400.0>}
2> Chan = "default".
2> peer:join(Pid, Chan).
ok
3> peer:write(Pid, Chan, "sup?").
[Wrote] #"welcome": "sup?"
ok
4> peer:dial(Pid, "some.ho.st:1234").
... communication logs
5> peer:stop(Pid).

To change the address and port for incoming connections, replace the [] in the start_link([]) with [{listener, ["1.2.3.4", 12345]}].

If you've never seen erlang before, a few tips:

  • Statements need to be terminated with a .
  • Variables need to be capitalized and can only be assigned once
  • think of lower-case strings (like ok or error) like constants
  • Exiting the shell is not very intutive. Press ctrl+g to get in the User switch command mode. Here you can exit it by entering the letter q.

Links

  • Cabal website: https://cabal.chat/
  • More Code https://github.com/cabal-club/

License

Lesser GPL 2