From b0313b8acb67ff8c75dc3b17f8f473638d52b21a Mon Sep 17 00:00:00 2001 From: Zomatree Date: Thu, 2 Jun 2022 17:02:14 +0100 Subject: [PATCH] feat(revcord): :sparkles: inital revcord commit --- Cargo.lock | 126 ++++++++++++++++ Cargo.toml | 2 +- README.md | 15 +- crates/revcord/README.md | 5 + crates/revcord/api/Cargo.toml | 66 +++++++++ crates/revcord/api/src/main.rs | 74 +++++++++ .../api/src/routes/channels/fetch_channel.rs | 15 ++ crates/revcord/api/src/routes/channels/mod.rs | 10 ++ crates/revcord/api/src/routes/mod.rs | 23 +++ crates/revcord/api/src/version.rs | 1 + crates/revcord/models/Cargo.toml | 58 ++++++++ crates/revcord/models/src/lib.rs | 24 +++ crates/revcord/models/src/models/channel.rs | 136 +++++++++++++++++ crates/revcord/models/src/models/mod.rs | 2 + crates/revcord/models/src/models/user.rs | 140 ++++++++++++++++++ crates/revcord/models/src/variables.rs | 6 + crates/revcord/ws/Cargo.toml | 8 + crates/revcord/ws/src/main.rs | 3 + 18 files changed, 706 insertions(+), 8 deletions(-) create mode 100644 crates/revcord/README.md create mode 100644 crates/revcord/api/Cargo.toml create mode 100644 crates/revcord/api/src/main.rs create mode 100644 crates/revcord/api/src/routes/channels/fetch_channel.rs create mode 100644 crates/revcord/api/src/routes/channels/mod.rs create mode 100644 crates/revcord/api/src/routes/mod.rs create mode 100644 crates/revcord/api/src/version.rs create mode 100644 crates/revcord/models/Cargo.toml create mode 100644 crates/revcord/models/src/lib.rs create mode 100644 crates/revcord/models/src/models/channel.rs create mode 100644 crates/revcord/models/src/models/mod.rs create mode 100644 crates/revcord/models/src/models/user.rs create mode 100644 crates/revcord/models/src/variables.rs create mode 100644 crates/revcord/ws/Cargo.toml create mode 100644 crates/revcord/ws/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 3ed2037a..b6288c53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2244,6 +2244,15 @@ dependencies = [ "syn 0.11.11", ] +[[package]] +name = "ordered-float" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" +dependencies = [ + "num-traits", +] + [[package]] name = "os_info" version = "3.4.0" @@ -2974,6 +2983,88 @@ dependencies = [ "quick-error 1.2.3", ] +[[package]] +name = "revcord-api" +version = "0.1.0" +dependencies = [ + "async-channel", + "async-std", + "bitfield", + "chrono", + "ctrlc", + "dashmap", + "dotenv", + "env_logger", + "futures", + "impl_ops", + "lazy_static", + "lettre", + "linkify 0.6.0", + "log", + "lru", + "mobc", + "mobc-redis", + "mongodb 1.2.5", + "nanoid", + "num_enum", + "once_cell", + "rauth", + "redis 0.21.5", + "regex", + "reqwest", + "revcord-models", + "revolt-quark", + "rocket", + "rocket_cors", + "rocket_okapi", + "schemars", + "serde", + "serde_json", + "ulid 0.4.1", + "url", + "validator", +] + +[[package]] +name = "revcord-models" +version = "0.1.0" +dependencies = [ + "async-recursion", + "async-std", + "async-trait", + "bincode", + "bitfield", + "bson 2.2.0", + "deadqueue", + "dotenv", + "futures", + "impl_ops", + "iso8601-timestamp", + "lazy_static", + "linkify 0.8.1", + "log", + "num_enum", + "okapi", + "optional_struct", + "pretty_env_logger", + "rauth", + "redis-kiss", + "regex", + "revolt-quark", + "rocket", + "rocket_okapi", + "schemars", + "serde", + "serde_json", + "twilight-model", + "ulid 0.5.0", + "validator", +] + +[[package]] +name = "revcord-ws" +version = "0.1.0" + [[package]] name = "revolt-bonfire" version = "1.0.6-patch.2" @@ -3541,6 +3632,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + [[package]] name = "serde_bytes" version = "0.11.6" @@ -3584,6 +3685,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed" +dependencies = [ + "proc-macro2", + "quote 1.0.18", + "syn 1.0.95", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -4419,6 +4531,20 @@ dependencies = [ "utf-8", ] +[[package]] +name = "twilight-model" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c44d87f62a032ea0d8053481672844cab0115330d99d655791be94a31d585256" +dependencies = [ + "bitflags", + "serde", + "serde-value", + "serde_repr", + "time 0.3.9", + "tracing", +] + [[package]] name = "typed-builder" version = "0.4.1" diff --git a/Cargo.toml b/Cargo.toml index c66a4d73..c43f6522 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["crates/*"] +members = ["crates/bonfire", "crates/delta", "crates/quark", "crates/revcord/*"] diff --git a/README.md b/README.md index 7639953f..cb0229fe 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,14 @@ This is a monorepo for the Revolt backend. -| Crate | Description | -| ------------- | --------------------------------- | -| `delta` | REST API server | -| `bonfire` | WebSocket events server | -| `quark` | Models and logic | -| `revcord/api` | Discord REST translation layer | -| `revcord/ws` | Discord gateway translation layer | +| Crate | Description | +| ---------------- | ------------------------------------ | +| `delta` | REST API server | +| `bonfire` | WebSocket events server | +| `quark` | Models and logic | +| `revcord/api` | Discord REST translation layer | +| `revcord/ws` | Discord gateway translation layer | +| `revcord/models` | Discord models and quark translation | Note: `january`, `autumn`, and `vortex` are yet to be moved into this monorepo. diff --git a/crates/revcord/README.md b/crates/revcord/README.md new file mode 100644 index 00000000..f433b2d0 --- /dev/null +++ b/crates/revcord/README.md @@ -0,0 +1,5 @@ +# Revcord + +## Description + +Revcord is a compatibility layer for Discord diff --git a/crates/revcord/api/Cargo.toml b/crates/revcord/api/Cargo.toml new file mode 100644 index 00000000..edc927bd --- /dev/null +++ b/crates/revcord/api/Cargo.toml @@ -0,0 +1,66 @@ +[package] +name = "revcord-api" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +# Utility +lru = "0.7.0" +url = "2.2.2" +log = "0.4.11" +dotenv = "0.15.0" +dashmap = "5.2.0" +linkify = "0.6.0" +once_cell = "1.4.1" +env_logger = "0.7.1" +lazy_static = "1.4.0" +ctrlc = { version = "3.0", features = ["termination"] } + +# Lang. Utilities +regex = "1" +num_enum = "0.5.1" +impl_ops = "0.1.1" +bitfield = "0.13.2" + +# ID / key generation +ulid = "0.4.1" +nanoid = "0.4.0" + +# serde +serde_json = "1.0.57" +serde = { version = "1.0.115", features = ["derive"] } +validator = { version = "0.14", features = ["derive"] } + +# async +futures = "0.3.8" +chrono = "0.4.15" +async-channel = "1.6.1" +reqwest = { version = "0.11.4", features = ["json"] } +async-std = { version = "1.8.0", features = ["tokio1", "tokio02", "attributes"] } + +# internal util +lettre = "0.10.0-alpha.4" +rauth = { git = "https://github.com/insertish/rauth", rev = "001a9698c56cea79e69e4ae71d7bc2cb48aec1a6" } + +# redis +redis = { version = "0.21.2", features = ["async-std-comp"] } +mobc = { version = "0.7.3" } +mobc-redis = { version = "0.7.0", default-features = false, features = ["async-std-comp"] } + +# web +rocket = { version = "0.5.0-rc.1", default-features = false, features = ["json"] } +mongodb = { version = "1.2.2", features = ["async-std-runtime"], default-features = false } +rocket_cors = { git = "https://github.com/lawliet89/rocket_cors", rev = "5843861a88958c16bfaa0b40f0d8910772bcd2f6" } + +# spec generation +schemars = "0.8.8" +# rocket_okapi = "0.8.0-rc.1" +rocket_okapi = { git = "https://github.com/insertish/okapi", rev = "dcf0df115596ee07a587a7a543cddf3d7944645b", features = [ "swagger" ] } + +# quark +revolt-quark = { path = "../../quark" } + +# discord +revcord-models = { path = "../models" } diff --git a/crates/revcord/api/src/main.rs b/crates/revcord/api/src/main.rs new file mode 100644 index 00000000..7dfe2fa0 --- /dev/null +++ b/crates/revcord/api/src/main.rs @@ -0,0 +1,74 @@ +#[macro_use] +extern crate rocket; +#[macro_use] +extern crate rocket_okapi; +extern crate ctrlc; + +pub mod routes; +pub mod version; + +use log::info; +use rauth::{ + config::Config, + logic::Auth, +}; +use revolt_quark::DatabaseInfo; +use rocket_cors::AllowedOrigins; +use std::str::FromStr; + +#[async_std::main] +async fn main() { + let _guard = revolt_quark::setup_logging(); + + info!( + "Starting Revcord server [version {}].", + crate::version::VERSION + ); + + revolt_quark::variables::delta::preflight_checks(); + + #[cfg(debug_assertions)] + ctrlc::set_handler(move || { + // Force ungraceful exit to avoid hang. + std::process::exit(0); + }) + .expect("Error setting Ctrl-C handler"); + + let cors = rocket_cors::CorsOptions { + allowed_origins: AllowedOrigins::All, + allowed_methods: [ + "Get", "Put", "Post", "Delete", "Options", "Head", "Trace", "Connect", "Patch", + ] + .iter() + .map(|s| FromStr::from_str(s).unwrap()) + .collect(), + ..Default::default() + } + .to_cors() + .expect("Failed to create CORS."); + + let db = DatabaseInfo::Auto.connect().await.unwrap(); + + // This is entirely temporary code until rauth is migrated to quark. + // (and / or otherwise gets updated to MongoDB v2 driver) + let mongo_db = mongodb::Client::with_uri_str( + &std::env::var("MONGODB").unwrap_or_else(|_| "mongodb://localhost".to_string()), + ) + .await + .expect("Failed to init db connection."); + + // Launch background task workers. + async_std::task::spawn(revolt_quark::tasks::start_workers(db.clone())); + + let auth = Auth::new(mongo_db.database("revolt"), Config::default()); + let rocket = rocket::build(); + routes::mount(rocket) + .mount("/", rocket_cors::catch_all_options_routes()) + .manage(auth) + .manage(db) + .manage(cors.clone()) + .attach(cors) + .launch() + .await + .unwrap(); +} diff --git a/crates/revcord/api/src/routes/channels/fetch_channel.rs b/crates/revcord/api/src/routes/channels/fetch_channel.rs new file mode 100644 index 00000000..0355c46f --- /dev/null +++ b/crates/revcord/api/src/routes/channels/fetch_channel.rs @@ -0,0 +1,15 @@ +use revolt_quark::{perms, Database, Permission, Ref, Result}; +use revcord_models::{QuarkConversion, channel::Channel, user::User}; +use rocket::{serde::json::Json, State}; + +#[openapi(tag = "Channel Information")] +#[get("/")] +pub async fn req(db: &State, user: User, target: Ref) -> Result> { + let channel = target.as_channel(db).await?; + perms(&user.to_quark().await) + .channel(&channel) + .throw_permission(db, Permission::ViewChannel) + .await?; + + Ok(Json(Channel::from_quark(channel).await)) +} diff --git a/crates/revcord/api/src/routes/channels/mod.rs b/crates/revcord/api/src/routes/channels/mod.rs new file mode 100644 index 00000000..c762536b --- /dev/null +++ b/crates/revcord/api/src/routes/channels/mod.rs @@ -0,0 +1,10 @@ +use rocket::Route; +use rocket_okapi::okapi::openapi3::OpenApi; + +mod fetch_channel; + +pub fn routes() -> (Vec, OpenApi) { + openapi_get_routes_spec![ + fetch_channel::req, + ] +} diff --git a/crates/revcord/api/src/routes/mod.rs b/crates/revcord/api/src/routes/mod.rs new file mode 100644 index 00000000..3407b81a --- /dev/null +++ b/crates/revcord/api/src/routes/mod.rs @@ -0,0 +1,23 @@ +pub use rocket::http::Status; +pub use rocket::response::Redirect; +use rocket::{Build, Rocket}; +use rocket_okapi::{settings::OpenApiSettings, okapi::openapi3::OpenApi}; + +pub mod channels; + +pub fn mount(mut rocket: Rocket) -> Rocket { + let settings = OpenApiSettings::default(); + + mount_endpoints_and_merged_docs! { + rocket, "/".to_owned(), settings, + "/" => (vec![], custom_openapi_spec()), + "/channels" => channels::routes(), + }; + + rocket +} + + +fn custom_openapi_spec() -> OpenApi { + OpenApi::default() +} diff --git a/crates/revcord/api/src/version.rs b/crates/revcord/api/src/version.rs new file mode 100644 index 00000000..f819b416 --- /dev/null +++ b/crates/revcord/api/src/version.rs @@ -0,0 +1 @@ +pub const VERSION: &str = "0.0.1"; diff --git a/crates/revcord/models/Cargo.toml b/crates/revcord/models/Cargo.toml new file mode 100644 index 00000000..5d58cdb5 --- /dev/null +++ b/crates/revcord/models/Cargo.toml @@ -0,0 +1,58 @@ +[package] +name = "revcord-models" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = { version = "1", features = ["derive"] } +validator = { version = "0.14", features = ["derive"] } +iso8601-timestamp = { version = "0.1.8", features = ["schema", "bson"] } +optional_struct = { git = "https://github.com/insertish/OptionalStruct", rev = "e275d2726595474632485934aa0887fa52281f70" } + +# Formats +bincode = "1.3.3" +serde_json = "1.0.78" +bson = { version = "2.1.0", features = ["chrono-0_4"] } + +# Spec Generation +schemars = "0.8.8" +okapi = { git = "https://github.com/insertish/okapi", rev = "dcf0df115596ee07a587a7a543cddf3d7944645b" } +rocket_okapi = { git = "https://github.com/insertish/okapi", rev = "dcf0df115596ee07a587a7a543cddf3d7944645b" } +# okapi = "0.7.0-rc.1" +# rocket_okapi = "0.8.0-rc.1" + +# Databases +redis-kiss = { version = "0.1.3" } + +# Async +futures = "0.3.19" +deadqueue = "0.2.1" +async-trait = "0.1.51" +async-recursion = "1.0.0" +async-std = { version = "1.8.0", features = ["attributes"], optional = true } + +# Logging +log = "0.4.14" +pretty_env_logger = "0.4.0" + +# Util +ulid = "0.5.0" +regex = "1.5.5" +linkify = "0.8.1" +dotenv = "0.15.0" +impl_ops = "0.1.1" +num_enum = "0.5.6" +bitfield = "0.13.2" +lazy_static = "1.4.0" + +# Implementations +revolt-quark = { path = "../../quark" } +rauth = { git = "https://github.com/insertish/rauth", rev = "001a9698c56cea79e69e4ae71d7bc2cb48aec1a6" } + +# Discord +twilight-model = "0.11.0" + +# Web +rocket = { version = "0.5.0-rc.1", features = ["json"] } diff --git a/crates/revcord/models/src/lib.rs b/crates/revcord/models/src/lib.rs new file mode 100644 index 00000000..9d96be9e --- /dev/null +++ b/crates/revcord/models/src/lib.rs @@ -0,0 +1,24 @@ +mod models; + +pub use twilight_model; +pub use models::{channel, user}; + +use async_trait::async_trait; + + + +#[async_trait] +pub trait QuarkConversion: Sized { + type Type; + + async fn to_quark(self) -> Self::Type; + async fn from_quark(data: Self::Type) -> Self; +} + +pub fn to_snowflake(ulid: S) -> twilight_model::id::Id { + todo!() +} + +pub fn to_ulid(snowflake: twilight_model::id::Id) -> String { + todo!() +} diff --git a/crates/revcord/models/src/models/channel.rs b/crates/revcord/models/src/models/channel.rs new file mode 100644 index 00000000..f0d97851 --- /dev/null +++ b/crates/revcord/models/src/models/channel.rs @@ -0,0 +1,136 @@ +use crate::{QuarkConversion, to_snowflake, to_ulid}; +use revolt_quark::models::{Channel as RevoltChannel}; +use twilight_model::channel::{Channel as DiscordChannel, ChannelType}; +use serde::{Serialize, Deserialize}; +use rocket_okapi::{JsonSchema, okapi::schemars::schema::{Schema, SchemaObject}}; +use async_trait::async_trait; +use std::collections::HashMap; + +#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[serde(transparent)] +#[repr(transparent)] +pub struct Channel(DiscordChannel); + +#[async_trait] +impl QuarkConversion for Channel { + type Type = RevoltChannel; + + async fn to_quark(self) -> Self::Type { + let DiscordChannel { guild_id, id, kind, last_message_id, name, nsfw, recipients, topic, owner_id, .. } = self.0; + + match kind { + ChannelType::GuildText => RevoltChannel::TextChannel { + id: to_ulid(id), + server: to_ulid(guild_id.unwrap()), + name: name.unwrap(), + description: topic, + icon: None, + last_message_id: last_message_id.map(to_ulid), + default_permissions: None, // TODO + role_permissions: HashMap::new(), + nsfw: nsfw.unwrap_or_default() + }, + ChannelType::Private => RevoltChannel::DirectMessage { + id: to_ulid(id), + active: false, + recipients: recipients.unwrap_or_default().iter().map(|user| to_ulid(user.id)).collect(), + last_message_id: last_message_id.map(to_ulid) + }, + ChannelType::GuildVoice => RevoltChannel::VoiceChannel { + id: to_ulid(id), + server: to_ulid(guild_id.unwrap()), + name: name.unwrap(), + description: topic, + icon: None, + default_permissions: None, // TODO + role_permissions: HashMap::new(), + nsfw: nsfw.unwrap_or_default() + }, + ChannelType::Group => RevoltChannel::Group { + id: to_ulid(id), + name: name.unwrap(), + owner: to_ulid(owner_id.unwrap()), + description: topic, + recipients: recipients.unwrap_or_default().iter().map(|user| to_ulid(user.id)).collect(), + icon: None, + last_message_id: last_message_id.map(to_ulid), + permissions: None, // TODO + nsfw: nsfw.unwrap_or_default() + }, + _ => todo!() + } + } + + async fn from_quark(data: Self::Type) -> Self { + Self(DiscordChannel { + application_id: None, + bitrate: None, + default_auto_archive_duration: None, + guild_id: match &data { + RevoltChannel::TextChannel { server, ..} => Some(to_snowflake(server.clone())), + RevoltChannel::VoiceChannel { server, .. } => Some(to_snowflake(server.clone())), + _ => None + }, + icon: None, // TODO, + id: to_snowflake(data.id()), + invitable: None, + kind: match &data { + RevoltChannel::SavedMessages { .. } => ChannelType::Private, + RevoltChannel::DirectMessage { .. } => ChannelType::Private, + RevoltChannel::Group { .. } => ChannelType::Group, + RevoltChannel::TextChannel { .. } => ChannelType::GuildText, + RevoltChannel::VoiceChannel { .. } => ChannelType::GuildVoice + }, + last_message_id: match &data { + RevoltChannel::Group { last_message_id, .. } => last_message_id.clone().map(to_snowflake), + RevoltChannel::TextChannel { last_message_id, .. } => last_message_id.clone().map(to_snowflake), + RevoltChannel::DirectMessage { last_message_id, .. } => last_message_id.clone().map(to_snowflake), + _ => None + }, + last_pin_timestamp: None, + member: None, + member_count: None, + message_count: None, + name: match &data { + RevoltChannel::Group { name, .. } => Some(name), + RevoltChannel::TextChannel { name, ..} => Some(name), + RevoltChannel::VoiceChannel { name, .. } => Some(name), + _ => None + }.cloned(), + newly_created: None, + nsfw: match &data { + RevoltChannel::Group { nsfw, .. } => Some(*nsfw), + RevoltChannel::TextChannel { nsfw, .. } => Some(*nsfw), + RevoltChannel::VoiceChannel { nsfw, .. } => Some(*nsfw), + _ => None + }, + owner_id: None, + parent_id: None, + permission_overwrites: None, // TODO, + position: None, // TODO + rate_limit_per_user: None, + recipients: None, + rtc_region: None, + thread_metadata: None, + topic: match &data { + RevoltChannel::Group { description, .. } => description, + RevoltChannel::TextChannel { description, ..} => description, + RevoltChannel::VoiceChannel { description, ..} => description, + _ => &None + }.clone(), + user_limit: None, + video_quality_mode: None + }) + } +} + +impl JsonSchema for Channel { + fn schema_name() -> String { + "Channel".to_string() + } + + fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { + Schema::Object(SchemaObject::default()) + } +} + diff --git a/crates/revcord/models/src/models/mod.rs b/crates/revcord/models/src/models/mod.rs new file mode 100644 index 00000000..d363372a --- /dev/null +++ b/crates/revcord/models/src/models/mod.rs @@ -0,0 +1,2 @@ +pub mod channel; +pub mod user; diff --git a/crates/revcord/models/src/models/user.rs b/crates/revcord/models/src/models/user.rs new file mode 100644 index 00000000..49cb4911 --- /dev/null +++ b/crates/revcord/models/src/models/user.rs @@ -0,0 +1,140 @@ +use crate::{QuarkConversion, to_snowflake, to_ulid}; +use revolt_quark::{models::{User as RevoltUser, user::{BotInformation, UserHint}}, Database}; +use twilight_model::user::{User as DiscordUser}; +use serde::{Serialize, Deserialize}; +use rocket_okapi::{JsonSchema, okapi::{schemars::schema::{Schema, SchemaObject}, openapi3::{SecurityScheme, SecuritySchemeData}}, gen::OpenApiGenerator, request::{OpenApiFromRequest, RequestHeaderInput}}; +use async_trait::async_trait; +use rocket::{Request, request::{self, FromRequest, Outcome}, http::Status}; + +#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[serde(transparent)] +#[repr(transparent)] +pub struct User(DiscordUser); + +impl User { + pub fn into_inner(self) -> DiscordUser { + self.0 + } +} + +#[async_trait] +impl QuarkConversion for User { + type Type = RevoltUser; + + async fn to_quark(self) -> Self::Type { + let DiscordUser { bot, id, name , ..} = self.into_inner(); + + RevoltUser { + id: to_ulid(id), + username: name, + avatar: None, // TODO, + relations: None, + badges: None, // TODO, + status: None, // TODO, + profile: None, // TODO, + flags: None, + privileged: false, + bot: if bot { + Some(BotInformation { + owner: "0".to_string() + }) + } else { + None + }, + relationship: None, + online: None + + } + } + + async fn from_quark(data: Self::Type) -> Self { + Self(DiscordUser { + accent_color: None, + avatar: None, // TODO + bot: data.bot.is_some(), + banner: None, // TODO + discriminator: 1, + email: None, + flags: None, + id: to_snowflake(data.id), + locale: None, + mfa_enabled: None, + name: data.username, + premium_type: None, + public_flags: None, + system: None, + verified: None + }) + } +} + +impl JsonSchema for User { + fn schema_name() -> String { + "User".to_string() + } + + fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { + Schema::Object(SchemaObject::default()) + } +} + + +#[rocket::async_trait] +impl<'r> FromRequest<'r> for User { + type Error = rauth::util::Error; + + async fn from_request(request: &'r Request<'_>) -> request::Outcome { + let user: &Option = request + .local_cache_async(async { + let db = request + .rocket() + .state::() + .expect("Database state not reachable!"); + + let header_token = request + .headers() + .get("Authorization") + .next() + .and_then(|x| x.split(' ').nth(1).map(|s| s.to_string())); + + if let Some(token) = header_token { + if let Ok(user) = RevoltUser::from_token(db, &token, UserHint::Any).await { + return Some(User::from_quark(user).await); + } + } + + None + }) + .await; + + if let Some(user) = user { + Outcome::Success(user.clone()) + } else { + Outcome::Failure((Status::Unauthorized, rauth::util::Error::InvalidSession)) + } + } +} + +impl<'r> OpenApiFromRequest<'r> for User { + fn from_request_input( + _gen: &mut OpenApiGenerator, + _name: String, + _required: bool, + ) -> rocket_okapi::Result { + let mut requirements = schemars::Map::new(); + requirements.insert("Api Key".to_owned(), vec![]); + + Ok(RequestHeaderInput::Security( + "Api Key".to_owned(), + SecurityScheme { + data: SecuritySchemeData::ApiKey { + name: "Authorization".to_owned(), + location: "header".to_owned(), + }, + description: Some("Session Token".to_owned()), + extensions: schemars::Map::new(), + }, + requirements, + )) + } +} diff --git a/crates/revcord/models/src/variables.rs b/crates/revcord/models/src/variables.rs new file mode 100644 index 00000000..778d3d19 --- /dev/null +++ b/crates/revcord/models/src/variables.rs @@ -0,0 +1,6 @@ +use lazy_static::lazy_static; +use std::env; + +lazy_static! { + pub static ref REVCORD_URL: String = env::var("REVCORD_URL").expect("Missing REVCORD_URL environment variable"); +} diff --git a/crates/revcord/ws/Cargo.toml b/crates/revcord/ws/Cargo.toml new file mode 100644 index 00000000..c2d5f732 --- /dev/null +++ b/crates/revcord/ws/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "revcord-ws" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/crates/revcord/ws/src/main.rs b/crates/revcord/ws/src/main.rs new file mode 100644 index 00000000..e7a11a96 --- /dev/null +++ b/crates/revcord/ws/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +}