# CabErl
https://nest.pijul.com/cryptix/caberl
A [cable](https://github.com/cabal-club/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](https://nixos.org/) `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.
* [Rebar3](https://rebar3.org/)
* [Erlang (25 or later)](https://www.erlang.org)
* [libsodium](https://doc.libsodium.org)
* [sqlite3](https://sqlite.org)
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](https://www.erlang.org/doc/apps/eunit/chapter.html) 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.
```erlang
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