Okay, so the “guts” are well under way and I’m super happy with the progress. Lots of iteration even since the last update.

I decided to take a break for a second to show what a SUPER basic CLI app might look like for someone building with the Rust client.

I’m actually thinking this might be the most perfect way to start delivering the experience. Then offer text and UI/UX clients as we iterate. MVP the shit out of everything.

Here’s the code:

use client::{
    init_client,
    rpcs::{
        auth::{signin, signup},
        message::{delete_message, get_messages_from_pod, put_message_to_pod},
        user::{delete_self, get_user, update_self},
    },
};
use rocksdb::{Options, DB};
use std::env;

#[macro_use]
extern crate lazy_static;

lazy_static! {
    pub(crate) static ref ROCKSDB_CONNECTION: DB = {
        let mut opts = Options::default();
        opts.create_if_missing(true);

        DB::open(&opts, "database").unwrap()
    };
}

fn kv_set(key: String, val: Vec<u8>) {
    ROCKSDB_CONNECTION.put(key, val).unwrap();
}

fn kv_get(key: String, cb: Box<dyn Fn(Vec<u8>)>) {
    if let Ok(Some(val)) = ROCKSDB_CONNECTION.get(key) {
        cb(val);
    };
}

fn log_info(val: String) {
    println!("{}", val);
}
fn log_warn(val: String) {
    println!("{}", val);
}
fn log_error(val: String) {
    eprintln!("{}", val);
}

fn main() {
    let mut args: Vec<String> = env::args().collect();
    args.remove(0);

    let mut command = "".to_string();
    let passcode = &mut [0u8; 32];
    let mut username = "".to_string();
    let mut password = "".to_string();
    let mut signing_key = [0u8; 32];
    let mut pod_id = "".to_string();
    let mut max_count: u32 = 0;
    let mut start: u64 = 0;
    let mut end: u64 = 0;
    let mut id = "".to_string();

    let mut content: Vec<u8> = vec![];

    for arg in args {
        if command == "".to_string() {
            command = arg;
            continue;
        }

        let split_arg: Vec<&str> = arg.split("=").collect();

        println!("{:?}", split_arg);

        let key = split_arg[0];
        let val = split_arg[1];

        match key {
            "--passcode" => crypto::passcode_to_key(val.to_string(), passcode),
            "--username" => username = val.to_string(),
            "--password" => password = val.to_string(),
            "--signing_key" => {
                signing_key = crypto::get_signing_key_from_string(val.to_string())
            }
            "--pod_id" => pod_id = val.to_string(),
            "--max_count" => max_count = val.parse::<u32>().unwrap(),
            "--start" => start = val.parse::<u64>().unwrap(),
            "--end" => end = val.parse::<u64>().unwrap(),
            "--id" => id = val.to_string(),

            // "--content" => content = val, // content comes in formatted like a javascript object (or maybe json) and we convert to protobuf message
            _ => (),
        }
    }

    init_client(*passcode, kv_set, kv_get, log_info, log_warn, log_error);

    match command.as_str() {
        "signup" => signup(&username, &password),
        "signing" => signin(&username, &password, signing_key),

        "get_user" => get_user(username),
        "update_self" => update_self(content),
        "delete_self" => delete_self(username, password),

        "get_messages_from_pod" => {
            get_messages_from_pod(pod_id, max_count, start, end);
        }
        "put_message_to_pod" => put_message_to_pod(pod_id, content),
        "delete_message" => delete_message(id),
        _ => panic!("invalid command"),
    }
}

I wrote everything super manually here and sorry if that’s ugly. Just works so I’ll “fix it” (make it faster and cleaner) later.

Conclusion

This is what each RPC looks like from the publicly distributed, package interface. I’m honestly a little to out of it to remember what RPC I’m missing but I know there’s like one major one that I’ll remember later and add back in.