Basic template

This commit is contained in:
Evie Viau-Chow-Stuart 2023-03-14 23:49:12 -07:00
commit f3d4da17e5
Signed by: evie
GPG key ID: 928652CDFCEC8099
16 changed files with 3305 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
/target
/certs
Caddyfile

8
.idea/.gitignore generated vendored Normal file
View file

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

11
.idea/matrixdiscord.iml generated Normal file
View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="CPP_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml generated Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/matrixdiscord.iml" filepath="$PROJECT_DIR$/.idea/matrixdiscord.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

3036
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

25
Cargo.toml Normal file
View file

@ -0,0 +1,25 @@
[package]
name = "matrixdiscord"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
## Core
tokio = { version = "1.26.0", features = ["full"] }
## Web
axum = "^0.6"
tower-http = { version = "*", features = ["cors"] }
## json citrus
serde = { version = "1.0.156", features = ["derive"] }
serde_derive = "1.0.156"
serde_json = "1.0.94"
serde_with = "2.3.1"
## Misc
tracing = "0.1.37"
tracing-subscriber = "0.3.16"
matrix-sdk = "0.6.2"

1
src/gateway/mod.rs Normal file
View file

@ -0,0 +1 @@
mod routes;

View file

@ -0,0 +1 @@

1
src/http/mod.rs Normal file
View file

@ -0,0 +1 @@
pub mod v9;

111
src/http/v9/errors.rs Normal file
View file

@ -0,0 +1,111 @@
use axum::http::StatusCode;
use axum::Json;
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr};
pub async fn throw_http_error(
error: APIErrorCode,
error_messages: Vec<APIErrorField>,
) -> Json<APIError> {
// I really don't like doing this, maybe play around with serde_as more
let mut error_messages_vec = Vec::<(String, APIErrorField)>::new();
for i in error_messages {
error_messages_vec.push((String::from(i.clone()), i));
}
Json(APIError {
code: u16::from(error),
message: String::from(error),
errors: error_messages_vec,
})
}
#[serde_as]
#[derive(Serialize, Deserialize, Clone)]
pub struct APIError {
code: u16,
message: String,
#[serde_as(as = "HashMap<DisplayFromStr, _>")]
errors: Vec<(String, APIErrorField)>,
}
#[derive(Serialize, Deserialize, Eq, PartialEq, Hash, Clone)]
#[serde(untagged)]
pub enum APIErrorField {
#[serde(alias = "password")]
Password { _errors: Vec<APIErrorMessage> },
#[serde(alias = "username")]
Username { _errors: Vec<APIErrorMessage> },
#[serde(alias = "login")]
Login { _errors: Vec<APIErrorMessage> },
#[serde(alias = "email")]
Email { _errors: Vec<APIErrorMessage> },
#[serde(alias = "date_of_birth")]
DateOfBirth { _errors: Vec<APIErrorMessage> },
}
impl From<APIErrorField> for String {
fn from(field: APIErrorField) -> String {
match field {
APIErrorField::Password { .. } => "password",
APIErrorField::Username { .. } => "username",
APIErrorField::Login { .. } => "login",
APIErrorField::Email { .. } => "email",
APIErrorField::DateOfBirth { .. } => "date_of_birth",
}
.parse()
.unwrap()
}
}
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
pub struct APIErrorMessage {
pub(crate) code: String,
pub(crate) message: String,
}
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum APIErrorCode {
UnknownAccount,
Unauthorized,
InvalidFormBody,
}
impl From<APIErrorCode> for u16 {
fn from(code: APIErrorCode) -> u16 {
match code {
APIErrorCode::UnknownAccount => 10001,
APIErrorCode::Unauthorized => 40001,
APIErrorCode::InvalidFormBody => 50035,
}
}
}
impl From<APIErrorCode> for String {
fn from(code: APIErrorCode) -> String {
match code {
APIErrorCode::UnknownAccount => "Unknown Account".to_string(),
APIErrorCode::Unauthorized => "Unauthorized".to_string(),
APIErrorCode::InvalidFormBody => "Unknown Form Body".to_string(),
}
}
}
impl From<APIErrorCode> for StatusCode {
fn from(code: APIErrorCode) -> StatusCode {
match code {
APIErrorCode::UnknownAccount => StatusCode::BAD_REQUEST,
APIErrorCode::Unauthorized => StatusCode::UNAUTHORIZED,
APIErrorCode::InvalidFormBody => StatusCode::BAD_REQUEST,
}
}
}
impl<'t> From<&'t APIErrorCode> for u16 {
fn from(code: &'t APIErrorCode) -> u16 {
(*code).into()
}
}

2
src/http/v9/mod.rs Normal file
View file

@ -0,0 +1,2 @@
pub mod errors;
pub mod routes;

View file

@ -0,0 +1,17 @@
use axum::Json;
use serde::{Serialize, Deserialize};
#[derive(Deserialize)]
pub struct LoginReq {
pub login: String,
pub password: String
}
#[derive(Serialize)]
pub struct LoginRes {
pub token: String
}
pub async fn login(Json(payload): Json<LoginReq>) -> Json<LoginRes> {
Json(LoginRes { token: "".to_string() })
}

20
src/http/v9/routes/mod.rs Normal file
View file

@ -0,0 +1,20 @@
use axum::{Router, routing::{get, post}};
use crate::http::v9::routes::auth::login;
use crate::http::v9::routes::tracking::*;
pub mod auth;
pub mod tracking;
pub fn assemble_routes() -> Router {
let auth = Router::new()
.route("/login", post(login));
Router::new()
.nest("/auth", auth)
.route("/experiments", get(experiments))
.route("/science", post(science))
.route("/track", post(science))
}

View file

@ -0,0 +1,16 @@
use axum::Json;
use serde::Serialize;
#[derive(Serialize)]
pub struct Experiments {
pub fingerprint: String,
pub assignments: Vec<[i32; 5]>
}
pub async fn experiments() -> Json<Experiments> {
Json(Experiments { fingerprint: "big balls".to_string(), assignments: vec![] })
}
pub async fn science() -> &'static str {
"yummy i love user data"
}

38
src/main.rs Normal file
View file

@ -0,0 +1,38 @@
use axum::{Router};
use std::net::SocketAddr;
use axum::http::Method;
use axum::routing::get;
use tower_http::cors::{Any, CorsLayer};
mod gateway;
mod http;
#[tokio::main]
async fn main() {
tracing_subscriber::fmt::init();
tracing::info!("Starting matrixdiscord");
// CORS
let cors = CorsLayer::new()
.allow_origin(Any)
.allow_methods([Method::GET, Method::POST, Method::PATCH, Method::OPTIONS])
.allow_headers(Any);
let api = Router::new()
.nest("/v9", http::v9::routes::assemble_routes());
let app = Router::new()
.nest("/api", api)
.layer(cors)
.route("/", get(|| async { "?" }));
let addr = SocketAddr::from(([127, 0, 0, 1], 4200));
tracing::info!("Listening on {}", addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.expect("Waaa");
}