lykin/src/main.rs

176 lines
5.3 KiB
Rust

#![warn(missing_docs)]
//! # lykin
//!
//! _Symbiosis of SSB, key-value store and web server._
//!
//! ## Introduction
//!
//! lykin is a tutorial application funded by a Secure Scuttlebutt (SSB)
//! community grant. It is intended to showcase one way in which an SSB
//! application can be written using the
//! [golgi](http://golgi.mycelial.technology) client library. The application
//! is not intended for widespread or longterm use and will not be maintained
//! as such; it is purely for demonstration purposes. Anyone is free to fork
//! the repository and use it as the basis for their own application.
//!
//! ## Quickstart
//!
//! Prerequisites: a running instance of go-sbot (see the [installation
//! guide](https://github.com/ssbc/go-ssb#installation)).
//!
//! Download, build and run lykin.
//!
//! ```
//! git clone https://git.coopcloud.tech/glyph/lykin.git
//! cd lykin
//! cargo build --release
//! RUST_LOG=lykin=info ./target/release/lykin
//! ```
//!
//! Open `localhost:8000` in your browser.
//!
//! **Note**: by default, lykin attempts to connect to the go-sbot instance on
//! port 8021. Set the `GO_SBOT_PORT` environment variable if you wish to use
//! another port.
//!
//! ## Features
//!
//! lykin presents an email inbox-like UI and functions as a Scuttlebutt reader
//! application. It allows the user to subscribe to peers and read the root
//! posts of those peers. Individual posts can be marked as read or unread.
//!
//! A summary of the features:
//!
//! - Subscribe to a peer (follow)
//! - Unsubscribe from a peer (unfollow)
//! - List subscribed peers
//! - List root posts for each peer
//! - Mark a post as read
//! - Mark a post as unread
//! - Fetch new posts
//!
//! ## Design
//!
//! lykin has been built with the following components:
//!
//! - [tera](https://crates.io/crates/tera) : templating engine
//! - [rocket](https://crates.io/crates/rocket/0.5.0-rc.1) : web server
//! - [golgi](https://crates.io/crates/golgi) : Scuttlebutt client library
//! - [sled](https://crates.io/crates/sled) : transactional embedded database
//! (key-value store)
//! - [sbot](https://github.com/cryptoscope/ssb) : Scuttlebutt server (in our
//! case, go-ssb)
//!
//! ## Documentation
//!
//! This project is documented in the form of code comments and Rust doc
//! comments. In order to generate and read the doc comments in a web browser,
//! run the following command in the lykin repo:
//!
//! `cargo doc --open --no-deps`
//!
//! ## Logging
//!
//! lykin emits logs at three levels: `debug`, `info` and `warn`. The log level
//! can be set using the `RUST_LOG` environment variable.
//!
//! For example, emit only `info` logs:
//!
//! `RUST_LOG=lykin=info ./target/release/lykin`
//!
//! It is also possible to emit logs solely from a single module of lykin.
//!
//! For example, emit only `warn` logs from the `db` module of lykin:
//!
//! `RUST_LOG=lykin::db=warn cargo run`
//!
//! ## Thanks
//!
//! I am grateful to the Butts who voted to fund this work, all contributors to
//! the SSBC and Erick Lavoie in particular - both for partially funding this
//! work and for developing and overseeing the community grant process.
//!
//! ## Contact
//!
//! I can be reached via email:
//! [glyph@mycelial.technology](mailto:glyph@mycelial.technology) or
//! Scuttlebutt: `@HEqy940T6uB+T+d9Jaa58aNfRzLx9eRWqkZljBmnkmk=.ed25519`.
//!
//! ## License
//!
//! MIT.
mod db;
mod routes;
mod sbot;
mod task_loop;
mod utils;
use std::env;
use async_std::channel;
use log::{info, warn};
use rocket::{
fairing::AdHoc,
fs::{relative, FileServer},
launch, routes,
};
use rocket_dyn_templates::Template;
use xdg::BaseDirectories;
use crate::{db::Database, routes::*, task_loop::Task};
#[launch]
async fn rocket() -> _ {
env_logger::init();
// Retrieve and store the public key of the local sbot.
match sbot::whoami().await {
Ok(id) => info!("Public key of the local sbot instance: {}", id),
Err(e) => warn!("Failed to retrieve the public key of the local sbot instance (`whoami` RPC call failed). Please ensure the sbot is running before trying again. Error details: {}", e)
}
// Create the key-value database.
let xdg_dirs = BaseDirectories::with_prefix("lykin").unwrap();
let db_path = xdg_dirs
.place_config_file("database")
.expect("cannot create database directory");
let db = Database::init(&db_path);
let db_clone = db.clone();
// Create a message passing channel.
let (tx, rx) = channel::unbounded();
let tx_clone = tx.clone();
// Spawn the task loop.
info!("Spawning task loop");
task_loop::spawn(db_clone, rx).await;
info!("Launching web server");
rocket::build()
.manage(db)
.manage(tx)
.mount(
"/",
routes![
home,
delete_post,
download_latest_posts,
mark_post_read,
mark_post_unread,
post,
posts,
subscribe_form,
unsubscribe_form,
],
)
.mount("/", FileServer::from(relative!("static")))
.attach(Template::fairing())
.attach(AdHoc::on_shutdown("cancel task loop", |_| {
Box::pin(async move {
tx_clone.send(Task::Cancel).await.unwrap();
})
}))
}