some quick documentation
This commit is contained in:
parent
8d297920fb
commit
87cfccb4f7
@ -1,3 +1,5 @@
|
|||||||
|
//! Koreader Progress Sync API.
|
||||||
|
|
||||||
use poem::{
|
use poem::{
|
||||||
error::ResponseError,
|
error::ResponseError,
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
@ -19,17 +21,20 @@ use crate::{
|
|||||||
error_response,
|
error_response,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Data for registering a new user.
|
||||||
#[derive(Object, Deserialize)]
|
#[derive(Object, Deserialize)]
|
||||||
struct RegisterRequest {
|
struct RegisterRequest {
|
||||||
username: String,
|
username: String,
|
||||||
password: String,
|
password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Answer after registering a new user.
|
||||||
#[derive(Object, Serialize)]
|
#[derive(Object, Serialize)]
|
||||||
struct UserCreated {
|
struct UserCreated {
|
||||||
username: String,
|
username: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Datafor pushing progress.
|
||||||
#[derive(Debug, Clone, Object, Deserialize)]
|
#[derive(Debug, Clone, Object, Deserialize)]
|
||||||
pub struct DocumentUpdate {
|
pub struct DocumentUpdate {
|
||||||
pub device: String,
|
pub device: String,
|
||||||
@ -39,6 +44,7 @@ pub struct DocumentUpdate {
|
|||||||
pub progress: String,
|
pub progress: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Answer when pulling progress.
|
||||||
#[derive(Debug, Clone, Object, Deserialize)]
|
#[derive(Debug, Clone, Object, Deserialize)]
|
||||||
pub struct DocumentProgress {
|
pub struct DocumentProgress {
|
||||||
pub device: String,
|
pub device: String,
|
||||||
@ -70,6 +76,9 @@ pub struct Api;
|
|||||||
|
|
||||||
#[OpenApi]
|
#[OpenApi]
|
||||||
impl Api {
|
impl Api {
|
||||||
|
/// Register a new user.
|
||||||
|
///
|
||||||
|
/// If a user of that id already exist, return a conflict.
|
||||||
#[oai(path = "/users/create", method = "post")]
|
#[oai(path = "/users/create", method = "post")]
|
||||||
async fn register(
|
async fn register(
|
||||||
&self,
|
&self,
|
||||||
@ -88,11 +97,13 @@ impl Api {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return OK if a user authenticated successfully.
|
||||||
#[oai(path = "/users/auth", method = "get", transform = "authorize")]
|
#[oai(path = "/users/auth", method = "get", transform = "authorize")]
|
||||||
async fn login(&self) -> Result<payload::Response<()>> {
|
async fn login(&self) -> Result<payload::Response<()>> {
|
||||||
Ok(payload::Response::new(()).status(StatusCode::OK))
|
Ok(payload::Response::new(()).status(StatusCode::OK))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Push new progress.
|
||||||
#[oai(path = "/syncs/progress", method = "put", transform = "authorize")]
|
#[oai(path = "/syncs/progress", method = "put", transform = "authorize")]
|
||||||
async fn push_progress(
|
async fn push_progress(
|
||||||
&self,
|
&self,
|
||||||
@ -108,6 +119,7 @@ impl Api {
|
|||||||
Ok(payload::Response::new(()).status(StatusCode::OK))
|
Ok(payload::Response::new(()).status(StatusCode::OK))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pull progress for document with id `doc_id`.
|
||||||
#[oai(
|
#[oai(
|
||||||
path = "/syncs/progress/:doc_id",
|
path = "/syncs/progress/:doc_id",
|
||||||
method = "get",
|
method = "get",
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
|
//! Global application state.
|
||||||
|
|
||||||
use crate::{cli::Config, db::Db};
|
use crate::{cli::Config, db::Db};
|
||||||
|
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
|
/// Application configuration.
|
||||||
pub config: Config,
|
pub config: Config,
|
||||||
|
/// Database connection.
|
||||||
pub db: Db,
|
pub db: Db,
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
//! Poem middleware for koreader progress sync authentication.
|
||||||
|
//!
|
||||||
|
//! Authentication works with two headers:
|
||||||
|
//! - x-auth-user: username
|
||||||
|
//! - x-auth-key: md5 hashed password
|
||||||
|
|
||||||
use poem::{
|
use poem::{
|
||||||
error::ResponseError, http::StatusCode, Endpoint, EndpointExt, Error, Middleware, Request,
|
error::ResponseError, http::StatusCode, Endpoint, EndpointExt, Error, Middleware, Request,
|
||||||
Result,
|
Result,
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! Data access and persistence.
|
||||||
|
|
||||||
use ::entity::{document, user};
|
use ::entity::{document, user};
|
||||||
use migration::{Migrator, MigratorTrait};
|
use migration::{Migrator, MigratorTrait};
|
||||||
use sea_orm::{
|
use sea_orm::{
|
||||||
@ -16,6 +18,7 @@ pub enum DataStoreError {
|
|||||||
DatabaseError(#[from] DbErr),
|
DatabaseError(#[from] DbErr),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Document progress to insert/update.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DocumentInsert {
|
pub struct DocumentInsert {
|
||||||
id: String,
|
id: String,
|
||||||
@ -44,6 +47,7 @@ pub struct Db {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Db {
|
impl Db {
|
||||||
|
/// Add a new user and return an error if one with `id` already exists.
|
||||||
pub async fn add_user(&self, id: &str, key: &str) -> Result<user::Model, DataStoreError> {
|
pub async fn add_user(&self, id: &str, key: &str) -> Result<user::Model, DataStoreError> {
|
||||||
let user = user::ActiveModel {
|
let user = user::ActiveModel {
|
||||||
id: Set(id.to_owned()),
|
id: Set(id.to_owned()),
|
||||||
@ -53,10 +57,13 @@ impl Db {
|
|||||||
Ok(user.insert(&self.connection).await?)
|
Ok(user.insert(&self.connection).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get user with id `id` or None if they do not exist.
|
||||||
pub async fn get_user(&self, id: &str) -> Result<Option<user::Model>, DataStoreError> {
|
pub async fn get_user(&self, id: &str) -> Result<Option<user::Model>, DataStoreError> {
|
||||||
Ok(user::Entity::find_by_id(id).one(&self.connection).await?)
|
Ok(user::Entity::find_by_id(id).one(&self.connection).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the progress for document with id `doc_id` from user with id `user_id` or None if that
|
||||||
|
/// combination does not exist.
|
||||||
pub async fn get_position(
|
pub async fn get_position(
|
||||||
&self,
|
&self,
|
||||||
user_id: &str,
|
user_id: &str,
|
||||||
@ -69,6 +76,9 @@ impl Db {
|
|||||||
.await?)
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update progress for document with id `doc_id` from user with id `user_id`.
|
||||||
|
///
|
||||||
|
/// Set the progress timestamp to now.
|
||||||
pub async fn update_position(&self, doc: &DocumentInsert) -> Result<(), DataStoreError> {
|
pub async fn update_position(&self, doc: &DocumentInsert) -> Result<(), DataStoreError> {
|
||||||
let now = OffsetDateTime::now_utc();
|
let now = OffsetDateTime::now_utc();
|
||||||
let now = PrimitiveDateTime::new(now.date(), now.time());
|
let now = PrimitiveDateTime::new(now.date(), now.time());
|
||||||
@ -93,6 +103,7 @@ impl Db {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Connect to the database and return the opened connectoin pool.
|
||||||
pub async fn connect(connection_string: &str) -> Result<Db, DataStoreError> {
|
pub async fn connect(connection_string: &str) -> Result<Db, DataStoreError> {
|
||||||
let connection: DatabaseConnection = Database::connect(connection_string).await?;
|
let connection: DatabaseConnection = Database::connect(connection_string).await?;
|
||||||
Migrator::up(&connection, None).await?;
|
Migrator::up(&connection, None).await?;
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! Error handling for the sync service.
|
||||||
|
|
||||||
use poem::{http::StatusCode, Body, Response};
|
use poem::{http::StatusCode, Body, Response};
|
||||||
use poem_openapi::Object;
|
use poem_openapi::Object;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
@ -11,6 +13,8 @@ struct ErrorResponse {
|
|||||||
message: String,
|
message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Log `error` on the server side with a generated id and send back a sanitized error message with
|
||||||
|
/// the same id.
|
||||||
pub fn create_and_log<F>(error: impl Error, cb: F) -> Response
|
pub fn create_and_log<F>(error: impl Error, cb: F) -> Response
|
||||||
where
|
where
|
||||||
F: Fn() -> (String, StatusCode),
|
F: Fn() -> (String, StatusCode),
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! Implementation of a koreader progress sync server.
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use api::Api;
|
use api::Api;
|
||||||
use app_state::AppState;
|
use app_state::AppState;
|
||||||
@ -18,6 +20,7 @@ pub mod cli;
|
|||||||
pub mod db;
|
pub mod db;
|
||||||
pub mod error_response;
|
pub mod error_response;
|
||||||
|
|
||||||
|
/// Run the progress sync server.
|
||||||
pub async fn run(args: &Config, db_url: &str) -> Result<()> {
|
pub async fn run(args: &Config, db_url: &str) -> Result<()> {
|
||||||
let db = db::connect(db_url).await?;
|
let db = db::connect(db_url).await?;
|
||||||
let app_state = Arc::new(AppState {
|
let app_state = Arc::new(AppState {
|
||||||
|
Loading…
Reference in New Issue
Block a user