diff --git a/Cargo.lock b/Cargo.lock index d1063f4..e04b255 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -263,6 +263,113 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn 1.0.107", +] + +[[package]] +name = "async-channel" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17adb73da160dfb475c183343c8cccd80721ea5a605d3eb57125f0a7b7a92d0b" +dependencies = [ + "async-lock", + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" +dependencies = [ + "async-channel", + "async-executor", + "async-io", + "async-lock", + "blocking", + "futures-lite", + "once_cell", + "tokio", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite", + "log", + "parking", + "polling", + "rustix 0.37.3", + "slab", + "socket2", + "waker-fn", +] + +[[package]] +name = "async-lock" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-attributes", + "async-channel", + "async-global-executor", + "async-io", + "async-lock", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + [[package]] name = "async-stream" version = "0.3.4" @@ -285,6 +392,12 @@ dependencies = [ "syn 1.0.107", ] +[[package]] +name = "async-task" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" + [[package]] name = "async-trait" version = "0.1.68" @@ -305,6 +418,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "atomic-waker" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "debc29dde2e69f9e47506b525f639ed42300fc014a3e007832592448fa8e4599" + [[package]] name = "atty" version = "0.2.14" @@ -389,6 +508,20 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blocking" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c67b173a56acffd6d2326fb7ab938ba0b00a71480e14902b2591c87bc5741e8" +dependencies = [ + "async-channel", + "async-lock", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", +] + [[package]] name = "borsh" version = "0.10.3" @@ -535,6 +668,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "clap" +version = "3.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" +dependencies = [ + "bitflags", + "clap_derive 3.2.18", + "clap_lex 0.2.4", + "indexmap", + "once_cell", + "textwrap", +] + [[package]] name = "clap" version = "4.1.10" @@ -542,14 +689,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce38afc168d8665cfc75c7b1dd9672e50716a137f433f070991619744a67342a" dependencies = [ "bitflags", - "clap_derive", - "clap_lex", + "clap_derive 4.1.9", + "clap_lex 0.3.3", "is-terminal", "once_cell", "strsim", "termcolor", ] +[[package]] +name = "clap_derive" +version = "3.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" +dependencies = [ + "heck 0.4.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.107", +] + [[package]] name = "clap_derive" version = "4.1.9" @@ -563,6 +723,15 @@ dependencies = [ "syn 1.0.107", ] +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "clap_lex" version = "0.3.3" @@ -593,6 +762,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "concurrent-queue" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c278839b831783b70278b14df4d45e1beb1aad306c07bb796637de9a0e323e8e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "const-oid" version = "0.9.1" @@ -679,6 +857,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "ctor" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" +dependencies = [ + "quote", + "syn 1.0.107", +] + [[package]] name = "ctrlc" version = "3.2.5" @@ -920,6 +1108,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "errno" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.45.0", +] + [[package]] name = "errno-dragonfly" version = "0.1.2" @@ -1050,6 +1249,21 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" +[[package]] +name = "futures-lite" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + [[package]] name = "futures-sink" version = "0.3.26" @@ -1111,6 +1325,18 @@ dependencies = [ "wasi 0.11.0+wasi-snapshot-preview1", ] +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "h2" version = "0.3.15" @@ -1366,7 +1592,7 @@ checksum = "8687c819457e979cc940d09cb16e42a1bf70aa6b60a549de6d3a62a0ee90c69e" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", - "rustix", + "rustix 0.36.10", "windows-sys 0.45.0", ] @@ -1403,6 +1629,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + [[package]] name = "language-tags" version = "0.3.2" @@ -1442,6 +1677,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +[[package]] +name = "linux-raw-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" + [[package]] name = "local-channel" version = "0.1.3" @@ -1477,6 +1718,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", + "value-bag", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata", ] [[package]] @@ -1716,6 +1967,12 @@ dependencies = [ "libm", ] +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + [[package]] name = "parking_lot" version = "0.11.2" @@ -1819,6 +2076,22 @@ version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" +[[package]] +name = "polling" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e1f879b2998099c2d69ab9605d145d5b661195627eccc680002c4918a7fb6fa" +dependencies = [ + "autocfg", + "bitflags", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.45.0", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1975,6 +2248,15 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] + [[package]] name = "regex-syntax" version = "0.6.28" @@ -2101,10 +2383,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fe885c3a125aa45213b68cc1472a49880cb5923dc23f522ad2791b882228778" dependencies = [ "bitflags", - "errno", + "errno 0.2.8", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.1.4", + "windows-sys 0.45.0", +] + +[[package]] +name = "rustix" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b24138615de35e32031d041a09032ef3487a616d901ca4db224e7d557efae2" +dependencies = [ + "bitflags", + "errno 0.3.0", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.1", "windows-sys 0.45.0", ] @@ -2200,6 +2496,22 @@ dependencies = [ "uuid", ] +[[package]] +name = "sea-orm-cli" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ead9f7dac975f10447f17d08edbb2046daa087b5e0b50bbf8211f303459078c" +dependencies = [ + "chrono", + "clap 3.2.23", + "dotenvy", + "regex", + "sea-schema", + "tracing", + "tracing-subscriber", + "url", +] + [[package]] name = "sea-orm-macros" version = "0.11.2" @@ -2213,6 +2525,23 @@ dependencies = [ "syn 1.0.107", ] +[[package]] +name = "sea-orm-migration" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7a6123c1035b0530deb713820688f0234431ab6c1893b14dce493ade76af" +dependencies = [ + "async-trait", + "clap 3.2.23", + "dotenvy", + "futures", + "sea-orm", + "sea-orm-cli", + "sea-schema", + "tracing", + "tracing-subscriber", +] + [[package]] name = "sea-query" version = "0.28.3" @@ -2257,6 +2586,29 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sea-schema" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeb2940bb5a10bc6cd05b450ce6cd3993e27fddd7eface2becb97fc5af3a040e" +dependencies = [ + "futures", + "sea-query", + "sea-schema-derive", +] + +[[package]] +name = "sea-schema-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56821b7076f5096b8f726e2791ad255a99c82498e08ec477a65a96c461ff1927" +dependencies = [ + "heck 0.3.3", + "proc-macro2", + "quote", + "syn 1.0.107", +] + [[package]] name = "sea-strum" version = "0.23.0" @@ -2410,6 +2762,15 @@ dependencies = [ "digest 0.10.6", ] +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -2676,7 +3037,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall", - "rustix", + "rustix 0.36.10", "windows-sys 0.42.0", ] @@ -2689,6 +3050,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + [[package]] name = "tfclient" version = "0.1.5" @@ -2696,7 +3063,7 @@ dependencies = [ "base64 0.21.0", "base64-serde", "chrono", - "clap", + "clap 4.1.10", "ctrlc", "dirs 5.0.0", "dnapi-rs", @@ -2738,6 +3105,16 @@ dependencies = [ "syn 1.0.107", ] +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "time" version = "0.1.45" @@ -2940,6 +3317,21 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tracing-subscriber" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +dependencies = [ + "matchers", + "once_cell", + "regex", + "sharded-slab", + "thread_local", + "tracing", + "tracing-core", +] + [[package]] name = "trifid-api" version = "0.1.0" @@ -2953,6 +3345,8 @@ dependencies = [ "serde", "simple_logger", "toml 0.7.3", + "trifid_api_entities", + "trifid_api_migration", ] [[package]] @@ -2971,6 +3365,22 @@ dependencies = [ "x25519-dalek", ] +[[package]] +name = "trifid_api_entities" +version = "0.1.0" +dependencies = [ + "sea-orm", +] + +[[package]] +name = "trifid_api_migration" +version = "0.1.0" +dependencies = [ + "async-std", + "async-trait", + "sea-orm-migration", +] + [[package]] name = "try-lock" version = "0.2.4" @@ -3060,6 +3470,16 @@ dependencies = [ "serde", ] +[[package]] +name = "value-bag" +version = "1.0.0-alpha.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" +dependencies = [ + "ctor", + "version_check", +] + [[package]] name = "vcpkg" version = "0.2.15" @@ -3072,6 +3492,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + [[package]] name = "want" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index 31bce56..9b3de10 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,8 @@ [workspace] members = [ "trifid-api", + "trifid-api/trifid_api_migration", + "trifid-api/trifid_api_entities", "tfclient", "trifid-pki", "dnapi-rs" diff --git a/trifid-api/Cargo.toml b/trifid-api/Cargo.toml index b9cfbd1..c351acc 100644 --- a/trifid-api/Cargo.toml +++ b/trifid-api/Cargo.toml @@ -17,6 +17,8 @@ log = "0.4" # Logging simple_logger = "4" # Logging sea-orm = { version = "^0", features = [ "sqlx-postgres", "runtime-actix-rustls", "macros" ]} # Database +trifid_api_migration = { version = "0.1.0", path = "trifid_api_migration" } # Database +trifid_api_entities = { version = "0.1.0", path = "trifid_api_entities" } # Database rand = "0.8" # Misc. hex = "0.4" # Misc. \ No newline at end of file diff --git a/trifid-api/src/config.rs b/trifid-api/src/config.rs index 6abdc18..fdb00c5 100644 --- a/trifid-api/src/config.rs +++ b/trifid-api/src/config.rs @@ -1,4 +1,5 @@ use std::fs; +use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use log::error; use once_cell::sync::Lazy; use serde::{Serialize, Deserialize}; @@ -23,7 +24,8 @@ pub static CONFIG: Lazy = Lazy::new(|| { #[derive(Serialize, Debug, Deserialize)] pub struct TrifidConfig { - pub database: TrifidConfigDatabase + pub database: TrifidConfigDatabase, + pub server: TrifidConfigServer } #[derive(Serialize, Deserialize, Debug)] @@ -45,7 +47,14 @@ pub struct TrifidConfigDatabase { pub sqlx_logging: bool } +#[derive(Serialize, Deserialize, Debug)] +pub struct TrifidConfigServer { + #[serde(default = "socketaddr_8080")] + pub bind: SocketAddr +} + fn max_connections_default() -> u32 { 100 } fn min_connections_default() -> u32 { 5 } fn time_defaults() -> u64 { 8 } -fn sqlx_logging_default() -> bool { true } \ No newline at end of file +fn sqlx_logging_default() -> bool { true } +fn socketaddr_8080() -> SocketAddr { SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from([0, 0, 0, 0]), 8080)) } \ No newline at end of file diff --git a/trifid-api/src/error.rs b/trifid-api/src/error.rs new file mode 100644 index 0000000..4659084 --- /dev/null +++ b/trifid-api/src/error.rs @@ -0,0 +1,128 @@ +use actix_web::error::{JsonPayloadError, PayloadError}; +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct APIErrorsResponse { + pub errors: Vec +} +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct APIError { + pub code: String, + pub message: String, + #[serde(skip_serializing_if = "is_none")] + #[serde(default)] + pub path: Option +} + +fn is_none(o: &Option) -> bool { o.is_none() } + +impl From<&JsonPayloadError> for APIError { + fn from(value: &JsonPayloadError) -> Self { + match value { + JsonPayloadError::OverflowKnownLength { length, limit } => { + APIError { + code: "ERR_PAYLOAD_OVERFLOW_KNOWN_LENGTH".to_string(), + message: format!("Payload size is bigger than allowed & content length header set. (length: {}, limit: {})", length, limit), + path: None + } + }, + JsonPayloadError::Overflow { limit } => { + APIError { + code: "ERR_PAYLOAD_OVERFLOW".to_string(), + message: format!("Payload size is bigger than allowed but no content-length header is set. (limit: {})", limit), + path: None + } + }, + JsonPayloadError::ContentType => { + APIError { + code: "ERR_NOT_JSON".to_string(), + message: "Content-Type header not set to expected application/json".to_string(), + path: None, + } + }, + JsonPayloadError::Deserialize(e) => { + APIError { + code: "ERR_JSON_DESERIALIZE".to_string(), + message: format!("Error deserializing JSON: {}", e), + path: None, + } + }, + JsonPayloadError::Serialize(e) => { + APIError { + code: "ERR_JSON_SERIALIZE".to_string(), + message: format!("Error serializing JSON: {}", e), + path: None, + } + }, + JsonPayloadError::Payload(e) => { + e.into() + }, + _ => { + APIError { + code: "ERR_UNKNOWN_ERROR".to_string(), + message: "An unknown error has occured".to_string(), + path: None, + } + } + } + } +} + +impl From<&PayloadError> for APIError { + fn from(value: &PayloadError) -> Self { + match value { + PayloadError::Incomplete(e) => { + APIError { + code: "ERR_UNEXPECTED_EOF".to_string(), + message: match e { + None => "Payload reached EOF but was incomplete".to_string(), + Some(e) => format!("Payload reached EOF but was incomplete: {}", e) + }, + path: None, + } + } + PayloadError::EncodingCorrupted => { + APIError { + code: "ERR_CORRUPTED_PAYLOAD".to_string(), + message: "Payload content encoding corrupted".to_string(), + path: None, + } + } + PayloadError::Overflow => { + APIError { + code: "ERR_PAYLOAD_OVERFLOW".to_string(), + message: "Payload reached size limit".to_string(), + path: None, + } + } + PayloadError::UnknownLength => { + APIError { + code: "ERR_PAYLOAD_UNKNOWN_LENGTH".to_string(), + message: "Unable to determine payload length".to_string(), + path: None, + } + } + PayloadError::Http2Payload(e) => { + APIError { + code: "ERR_HTTP2_ERROR".to_string(), + message: format!("HTTP/2 error: {}", e), + path: None, + } + } + PayloadError::Io(e) => { + APIError { + code: "ERR_IO_ERROR".to_string(), + message: format!("I/O error: {}", e), + path: None, + } + } + _ => { + APIError { + code: "ERR_UNKNOWN_ERROR".to_string(), + message: "An unknown error has occured".to_string(), + path: None, + } + } + } + } +} \ No newline at end of file diff --git a/trifid-api/src/main.rs b/trifid-api/src/main.rs index 0ef408b..388d5f2 100644 --- a/trifid-api/src/main.rs +++ b/trifid-api/src/main.rs @@ -4,10 +4,13 @@ use actix_web::{App, HttpResponse, HttpServer, post, web::{Data, Json, JsonConfi use log::{error, info, Level}; use sea_orm::{ConnectOptions, Database, DatabaseConnection}; use serde::{Serialize, Deserialize}; +use trifid_api_migration::{Migrator, MigratorTrait}; use crate::config::CONFIG; - +use crate::error::{APIError, APIErrorsResponse}; pub mod config; +pub mod routes; +pub mod error; #[actix_web::main] async fn main() -> Result<(), Box> { @@ -27,9 +30,26 @@ async fn main() -> Result<(), Box> { let db = Database::connect(opt).await?; + info!("Performing database migration..."); + Migrator::up(&db, None).await?; + let data = Data::new(db); - + HttpServer::new(move || { + App::new() + .app_data(data.clone()) + .app_data(JsonConfig::default().error_handler(|err, _req| { + let api_error: APIError = (&err).into(); + actix_web::error::InternalError::from_response( + err, + HttpResponse::BadRequest().json(APIErrorsResponse { + errors: vec![ + api_error + ], + }) + ).into() + })) + }).bind(CONFIG.server.bind)?.run().await?; Ok(()) } diff --git a/trifid-api/src/routes/mod.rs b/trifid-api/src/routes/mod.rs new file mode 100644 index 0000000..e69de29 diff --git a/trifid-api/trifid_api_entities/Cargo.toml b/trifid-api/trifid_api_entities/Cargo.toml new file mode 100644 index 0000000..73b20f4 --- /dev/null +++ b/trifid-api/trifid_api_entities/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "trifid_api_entities" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +sea-orm = { version = "^0" } \ No newline at end of file diff --git a/trifid-api/trifid_api_entities/src/lib.rs b/trifid-api/trifid_api_entities/src/lib.rs new file mode 100644 index 0000000..35e436f --- /dev/null +++ b/trifid-api/trifid_api_entities/src/lib.rs @@ -0,0 +1,5 @@ +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.2 + +pub mod prelude; + +pub mod user; diff --git a/trifid-api/trifid_api_entities/src/prelude.rs b/trifid-api/trifid_api_entities/src/prelude.rs new file mode 100644 index 0000000..5a361f5 --- /dev/null +++ b/trifid-api/trifid_api_entities/src/prelude.rs @@ -0,0 +1,3 @@ +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.2 + +pub use super::user::Entity as User; diff --git a/trifid-api/trifid_api_entities/src/user.rs b/trifid-api/trifid_api_entities/src/user.rs new file mode 100644 index 0000000..ab703b3 --- /dev/null +++ b/trifid-api/trifid_api_entities/src/user.rs @@ -0,0 +1,17 @@ +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.2 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "user")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: String, + pub email: String, + pub password_hash: String, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/trifid-api/trifid_api_migration/Cargo.toml b/trifid-api/trifid_api_migration/Cargo.toml new file mode 100644 index 0000000..f090efb --- /dev/null +++ b/trifid-api/trifid_api_migration/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "trifid_api_migration" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +name = "trifid_api_migration" +path = "src/lib.rs" + +[dependencies] +async-std = { version = "1", features = ["attributes", "tokio1"] } +async-trait = "0.1.68" + +[dependencies.sea-orm-migration] +version = "0.11.0" +features = [ + # Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run trifid_api_migration via CLI. + # View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime. + # e.g. + # "runtime-tokio-rustls", # `ASYNC_RUNTIME` feature + # "sqlx-postgres", # `DATABASE_DRIVER` feature + "sqlx-postgres", + "runtime-actix-rustls" +] diff --git a/trifid-api/trifid_api_migration/README.md b/trifid-api/trifid_api_migration/README.md new file mode 100644 index 0000000..b3ea53e --- /dev/null +++ b/trifid-api/trifid_api_migration/README.md @@ -0,0 +1,41 @@ +# Running Migrator CLI + +- Generate a new migration file + ```sh + cargo run -- migrate generate MIGRATION_NAME + ``` +- Apply all pending migrations + ```sh + cargo run + ``` + ```sh + cargo run -- up + ``` +- Apply first 10 pending migrations + ```sh + cargo run -- up -n 10 + ``` +- Rollback last applied migrations + ```sh + cargo run -- down + ``` +- Rollback last 10 applied migrations + ```sh + cargo run -- down -n 10 + ``` +- Drop all tables from the database, then reapply all migrations + ```sh + cargo run -- fresh + ``` +- Rollback all applied migrations, then reapply all migrations + ```sh + cargo run -- refresh + ``` +- Rollback all applied migrations + ```sh + cargo run -- reset + ``` +- Check the status of all migrations + ```sh + cargo run -- status + ``` diff --git a/trifid-api/trifid_api_migration/src/lib.rs b/trifid-api/trifid_api_migration/src/lib.rs new file mode 100644 index 0000000..372443b --- /dev/null +++ b/trifid-api/trifid_api_migration/src/lib.rs @@ -0,0 +1,14 @@ +pub use sea_orm_migration::prelude::*; + +pub struct Migrator; + +pub mod m20230402_162601_create_table_users; + +#[async_trait::async_trait] +impl MigratorTrait for Migrator { + fn migrations() -> Vec> { + vec![ + Box::new(m20230402_162601_create_table_users::Migration) + ] + } +} diff --git a/trifid-api/trifid_api_migration/src/m20230402_162601_create_table_users.rs b/trifid-api/trifid_api_migration/src/m20230402_162601_create_table_users.rs new file mode 100644 index 0000000..ce6457d --- /dev/null +++ b/trifid-api/trifid_api_migration/src/m20230402_162601_create_table_users.rs @@ -0,0 +1,33 @@ +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(User::Table) + .if_not_exists() + .col(ColumnDef::new(User::Id).string().not_null().primary_key()) + .col(ColumnDef::new(User::Email).string().not_null()) + .col(ColumnDef::new(User::PasswordHash).string().not_null()) + .to_owned() + ).await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager.drop_table(Table::drop().table(User::Table).to_owned()).await + } +} + +/// Learn more at https://docs.rs/sea-query#iden +#[derive(Iden)] +enum User { + Table, + Id, + Email, + PasswordHash, +} diff --git a/trifid-api/trifid_api_migration/src/main.rs b/trifid-api/trifid_api_migration/src/main.rs new file mode 100644 index 0000000..84ac5bc --- /dev/null +++ b/trifid-api/trifid_api_migration/src/main.rs @@ -0,0 +1,6 @@ +use sea_orm_migration::prelude::*; + +#[async_std::main] +async fn main() { + cli::run_cli(trifid_api_migration::Migrator).await; +}