176 lines
5.3 KiB
Rust
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();
|
|
})
|
|
}))
|
|
}
|