Start working on Rust impl of identity-api
This commit is contained in:
parent
864521787f
commit
1d131e790c
13 changed files with 520 additions and 0 deletions
0
identity-api-rs/.database/.gitkeep
Normal file
0
identity-api-rs/.database/.gitkeep
Normal file
9
identity-api-rs/.gitignore
vendored
Normal file
9
identity-api-rs/.gitignore
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/target
|
||||||
|
Cargo.lock
|
||||||
|
|
||||||
|
.database/*
|
||||||
|
!.database/.gitkeep
|
||||||
|
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
11
identity-api-rs/Cargo.toml
Normal file
11
identity-api-rs/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "identity-api"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
axum = { version = "0.7" }
|
||||||
|
chrono = "0.4"
|
||||||
|
diesel = { version = "2.2", features = ["sqlite", "returning_clauses_for_sqlite_3_35", "chrono"] }
|
||||||
|
dotenvy = "0.15"
|
||||||
|
tokio = { version = "1", features = ["full"] }
|
9
identity-api-rs/diesel.toml
Normal file
9
identity-api-rs/diesel.toml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# For documentation on how to configure this file,
|
||||||
|
# see https://diesel.rs/guides/configuring-diesel-cli
|
||||||
|
|
||||||
|
[print_schema]
|
||||||
|
file = "src/database/schema.rs"
|
||||||
|
custom_type_derives = ["diesel::query_builder::QueryId", "Clone"]
|
||||||
|
|
||||||
|
[migrations_directory]
|
||||||
|
dir = "migrations"
|
0
identity-api-rs/migrations/.gitkeep
Normal file
0
identity-api-rs/migrations/.gitkeep
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
DROP TABLE IF EXISTS date_entries;
|
||||||
|
DROP TABLE IF EXISTS location_entries;
|
||||||
|
DROP TABLE IF EXISTS music_entries;
|
||||||
|
DROP TABLE IF EXISTS entries;
|
||||||
|
DROP TABLE IF EXISTS heirs;
|
||||||
|
DROP TABLE IF EXISTS session_keys;
|
||||||
|
DROP TABLE IF EXISTS users;
|
||||||
|
DROP TABLE IF EXISTS limits;
|
|
@ -0,0 +1,69 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS limits (
|
||||||
|
id varchar PRIMARY KEY NOT NULL,
|
||||||
|
current_asset_count integer NOT NULL,
|
||||||
|
max_asset_count integer NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id varchar PRIMARY KEY NOT NULL,
|
||||||
|
created_at timestamp NOT NULL,
|
||||||
|
last_connected_at timestamp NOT NULL,
|
||||||
|
email varchar NOT NULL,
|
||||||
|
password varchar NOT NULL,
|
||||||
|
name varchar NOT NULL,
|
||||||
|
limits varchar NOT NULL,
|
||||||
|
assets varchar NOT NULL,
|
||||||
|
FOREIGN KEY (limits) REFERENCES limits (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS session_keys (
|
||||||
|
key varchar PRIMARY KEY NOT NULL,
|
||||||
|
user_id varchar NOT NULL,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS heirs (
|
||||||
|
id varchar PRIMARY KEY NOT NULL,
|
||||||
|
user_id varchar NOT NULL,
|
||||||
|
created_at timestamp NOT NULL,
|
||||||
|
name varchar NOT NULL,
|
||||||
|
email varchar,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS entries (
|
||||||
|
id varchar PRIMARY KEY NOT NULL,
|
||||||
|
user_id varchar NOT NULL,
|
||||||
|
created_at timestamp NOT NULL,
|
||||||
|
feelings text NOT NULL,
|
||||||
|
assets text NOT NULL,
|
||||||
|
title text,
|
||||||
|
description text,
|
||||||
|
kind varchar NOT NULL,
|
||||||
|
music_entry varchar,
|
||||||
|
location_entry varchar,
|
||||||
|
date_entry varchar,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users (id),
|
||||||
|
FOREIGN KEY (music_entry) REFERENCES music_entries (id),
|
||||||
|
FOREIGN KEY (location_entry) REFERENCES location_entries (id),
|
||||||
|
FOREIGN KEY (date_entry) REFERENCES date_entries (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS music_entries (
|
||||||
|
id varchar PRIMARY KEY NOT NULL,
|
||||||
|
artist varchar NOT NULL,
|
||||||
|
title varchar NOT NULL,
|
||||||
|
links text NOT NULL,
|
||||||
|
universal_ids text NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS location_entries (
|
||||||
|
id varchar PRIMARY KEY NOT NULL,
|
||||||
|
location_text text,
|
||||||
|
location_coordinates varchar
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS date_entries (
|
||||||
|
id varchar PRIMARY KEY NOT NULL,
|
||||||
|
referenced_date timestamp NOT NULL
|
||||||
|
);
|
28
identity-api-rs/src/database/mod.rs
Normal file
28
identity-api-rs/src/database/mod.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// Identity. Store your memories and mental belongings
|
||||||
|
// Copyright (C) 2024 Sofía Aritz
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use diesel::{Connection, SqliteConnection};
|
||||||
|
|
||||||
|
use crate::env::database_url;
|
||||||
|
|
||||||
|
pub mod models;
|
||||||
|
pub mod schema;
|
||||||
|
pub mod types;
|
||||||
|
|
||||||
|
pub fn establish_connection() -> SqliteConnection {
|
||||||
|
let url = database_url();
|
||||||
|
SqliteConnection::establish(url).unwrap_or_else(|_| panic!("failed to connect to {}", url))
|
||||||
|
}
|
46
identity-api-rs/src/database/models.rs
Normal file
46
identity-api-rs/src/database/models.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// Identity. Store your memories and mental belongings
|
||||||
|
// Copyright (C) 2024 Sofía Aritz
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use chrono::NaiveDateTime;
|
||||||
|
use diesel::prelude::*;
|
||||||
|
|
||||||
|
use crate::database::schema;
|
||||||
|
use crate::database::types::List;
|
||||||
|
|
||||||
|
#[derive(Queryable, Selectable)]
|
||||||
|
#[diesel(table_name = schema::date_entries)]
|
||||||
|
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||||
|
pub struct DateEntry {
|
||||||
|
id: String,
|
||||||
|
referenced_date: NaiveDateTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Queryable, Selectable)]
|
||||||
|
#[diesel(table_name = schema::entries)]
|
||||||
|
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||||
|
pub struct Entry {
|
||||||
|
id: String,
|
||||||
|
user_id: String,
|
||||||
|
created_at: NaiveDateTime,
|
||||||
|
feelings: List<String>,
|
||||||
|
assets: List<String>,
|
||||||
|
title: Option<String>,
|
||||||
|
description: Option<String>,
|
||||||
|
kind: String,
|
||||||
|
music_entry: Option<String>,
|
||||||
|
location_entry: Option<String>,
|
||||||
|
date_entry: Option<String>,
|
||||||
|
}
|
99
identity-api-rs/src/database/schema.rs
Normal file
99
identity-api-rs/src/database/schema.rs
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
// @generated automatically by Diesel CLI.
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
date_entries (id) {
|
||||||
|
id -> Text,
|
||||||
|
referenced_date -> Timestamp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
entries (id) {
|
||||||
|
id -> Text,
|
||||||
|
user_id -> Text,
|
||||||
|
created_at -> Timestamp,
|
||||||
|
feelings -> Text,
|
||||||
|
assets -> Text,
|
||||||
|
title -> Nullable<Text>,
|
||||||
|
description -> Nullable<Text>,
|
||||||
|
kind -> Text,
|
||||||
|
music_entry -> Nullable<Text>,
|
||||||
|
location_entry -> Nullable<Text>,
|
||||||
|
date_entry -> Nullable<Text>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
heirs (id) {
|
||||||
|
id -> Text,
|
||||||
|
user_id -> Text,
|
||||||
|
created_at -> Timestamp,
|
||||||
|
name -> Text,
|
||||||
|
email -> Nullable<Text>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
limits (id) {
|
||||||
|
id -> Text,
|
||||||
|
current_asset_count -> Integer,
|
||||||
|
max_asset_count -> Integer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
location_entries (id) {
|
||||||
|
id -> Text,
|
||||||
|
location_text -> Nullable<Text>,
|
||||||
|
location_coordinates -> Nullable<Text>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
music_entries (id) {
|
||||||
|
id -> Text,
|
||||||
|
artist -> Text,
|
||||||
|
title -> Text,
|
||||||
|
links -> Text,
|
||||||
|
universal_ids -> Text,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
session_keys (key) {
|
||||||
|
key -> Text,
|
||||||
|
user_id -> Text,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
users (id) {
|
||||||
|
id -> Text,
|
||||||
|
created_at -> Timestamp,
|
||||||
|
last_connected_at -> Timestamp,
|
||||||
|
email -> Text,
|
||||||
|
password -> Text,
|
||||||
|
name -> Text,
|
||||||
|
limits -> Text,
|
||||||
|
assets -> Text,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diesel::joinable!(entries -> date_entries (date_entry));
|
||||||
|
diesel::joinable!(entries -> location_entries (location_entry));
|
||||||
|
diesel::joinable!(entries -> music_entries (music_entry));
|
||||||
|
diesel::joinable!(entries -> users (user_id));
|
||||||
|
diesel::joinable!(heirs -> users (user_id));
|
||||||
|
diesel::joinable!(session_keys -> users (user_id));
|
||||||
|
diesel::joinable!(users -> limits (limits));
|
||||||
|
|
||||||
|
diesel::allow_tables_to_appear_in_same_query!(
|
||||||
|
date_entries,
|
||||||
|
entries,
|
||||||
|
heirs,
|
||||||
|
limits,
|
||||||
|
location_entries,
|
||||||
|
music_entries,
|
||||||
|
session_keys,
|
||||||
|
users,
|
||||||
|
);
|
83
identity-api-rs/src/database/types.rs
Normal file
83
identity-api-rs/src/database/types.rs
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
use diesel::{
|
||||||
|
backend::Backend, deserialize::{FromSql, FromSqlRow}, serialize::ToSql, sql_types::Text, sqlite::Sqlite
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(FromSqlRow, Debug, Clone)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct List<V: std::fmt::Debug>(pub Vec<V>);
|
||||||
|
|
||||||
|
impl ToString for List<String> {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
"[".to_owned()
|
||||||
|
+ &self
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
|
.map(|v| "\"".to_owned() + &v.replace("\"", "\\\"") + "\"")
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(",")
|
||||||
|
+ "]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for List<String> {
|
||||||
|
fn from(mut value: String) -> Self {
|
||||||
|
if value.starts_with('[') {
|
||||||
|
value.remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.ends_with(']') {
|
||||||
|
value.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
let char_len = value.chars().count();
|
||||||
|
let mut values = Vec::new();
|
||||||
|
let mut current = String::new();
|
||||||
|
let mut writing_str = false;
|
||||||
|
let mut escape_next = false;
|
||||||
|
|
||||||
|
for (i, ch) in value.chars().enumerate() {
|
||||||
|
if i == char_len - 1 {
|
||||||
|
values.push(current);
|
||||||
|
current = String::new();
|
||||||
|
} else if escape_next {
|
||||||
|
current.push(ch);
|
||||||
|
escape_next = false;
|
||||||
|
} else if ch == '\\' {
|
||||||
|
escape_next = true;
|
||||||
|
} else if ch == '\"' {
|
||||||
|
writing_str = !writing_str;
|
||||||
|
} else if ch == ',' && !writing_str {
|
||||||
|
values.push(current);
|
||||||
|
current = String::new();
|
||||||
|
} else if writing_str {
|
||||||
|
current.push(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List(values)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromSql<Text, Sqlite> for List<String>
|
||||||
|
where
|
||||||
|
String: FromSql<Text, Sqlite>,
|
||||||
|
{
|
||||||
|
fn from_sql(bytes: <Sqlite as Backend>::RawValue<'_>) -> diesel::deserialize::Result<Self> {
|
||||||
|
let str = <String as FromSql<Text, Sqlite>>::from_sql(bytes)?;
|
||||||
|
Ok(List::from(str))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToSql<Text, Sqlite> for List<String>
|
||||||
|
where
|
||||||
|
String: ToSql<Text, Sqlite>,
|
||||||
|
{
|
||||||
|
fn to_sql<'b>(
|
||||||
|
&'b self,
|
||||||
|
out: &mut diesel::serialize::Output<'b, '_, Sqlite>,
|
||||||
|
) -> diesel::serialize::Result {
|
||||||
|
let val = self.to_string();
|
||||||
|
out.set_value(val);
|
||||||
|
Ok(diesel::serialize::IsNull::No)
|
||||||
|
}
|
||||||
|
}
|
112
identity-api-rs/src/env.rs
Normal file
112
identity-api-rs/src/env.rs
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
// Identity. Store your memories and mental belongings
|
||||||
|
// Copyright (C) 2024 Sofía Aritz
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
const REQUIRED_ENV_VARIABLES: [&'static str; 4] = [
|
||||||
|
"IDENTITY_API_JWT_SECRET",
|
||||||
|
"IDENTITY_API_ASSET_API_ENDPOINT",
|
||||||
|
"IDENTITY_API_JWT_ALG",
|
||||||
|
"DATABASE_URL",
|
||||||
|
];
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum LoadEnvError {
|
||||||
|
DotenvyError(dotenvy::Error),
|
||||||
|
MissingVariable(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_env() -> Result<(), LoadEnvError> {
|
||||||
|
dotenvy::dotenv().map_err(|e| LoadEnvError::DotenvyError(e))?;
|
||||||
|
|
||||||
|
for key in REQUIRED_ENV_VARIABLES {
|
||||||
|
if env::var(key).is_err() {
|
||||||
|
return Err(LoadEnvError::MissingVariable(key.into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn landing_message() -> &'static str {
|
||||||
|
static IDENTITY_API_LANDING_MESSAGE: OnceLock<String> = OnceLock::new();
|
||||||
|
IDENTITY_API_LANDING_MESSAGE.get_or_init(|| {
|
||||||
|
env::var("IDENTITY_API_LANDING_MESSAGE").unwrap_or(format!(
|
||||||
|
"{} v{}",
|
||||||
|
env!("CARGO_PKG_NAME"),
|
||||||
|
env!("CARGO_PKG_VERSION")
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn asset_api_m2m_refresh_interval() -> &'static Duration {
|
||||||
|
static IDENTITY_API_ASSET_API_M2M_REFRESH_INTERVAL: OnceLock<Duration> = OnceLock::new();
|
||||||
|
IDENTITY_API_ASSET_API_M2M_REFRESH_INTERVAL.get_or_init(|| {
|
||||||
|
let millis: u64 = env::var("IDENTITY_API_ASSET_API_M2M_REFRESH_INTERVAL_ms")
|
||||||
|
.map(|v|
|
||||||
|
v
|
||||||
|
.parse()
|
||||||
|
.expect("invalid environment variable value: `IDENTITY_API_ASSET_API_M2M_REFRESH_INTERVAL_ms`")
|
||||||
|
)
|
||||||
|
.unwrap_or(60 * 1000);
|
||||||
|
|
||||||
|
Duration::from_millis(millis)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn listen_port() -> &'static u16 {
|
||||||
|
static IDENTITY_API_LISTEN_PORT: OnceLock<u16> = OnceLock::new();
|
||||||
|
IDENTITY_API_LISTEN_PORT.get_or_init(|| {
|
||||||
|
env::var("IDENTITY_API_LISTEN_PORT")
|
||||||
|
.map(|v| {
|
||||||
|
v.parse()
|
||||||
|
.expect("invalid environment variable value: `IDENTITY_API_LISTEN_PORT`")
|
||||||
|
})
|
||||||
|
.unwrap_or(3000)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jwt_secret() -> &'static str {
|
||||||
|
static IDENTITY_API_JWT_SECRET: OnceLock<String> = OnceLock::new();
|
||||||
|
IDENTITY_API_JWT_SECRET.get_or_init(|| {
|
||||||
|
env::var("IDENTITY_API_JWT_SECRET")
|
||||||
|
.expect("environment variables were not loaded correctly")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jwt_alg() -> &'static str {
|
||||||
|
static IDENTITY_API_JWT_ALG: OnceLock<String> = OnceLock::new();
|
||||||
|
IDENTITY_API_JWT_ALG.get_or_init(|| {
|
||||||
|
env::var("IDENTITY_API_JWT_ALG").expect("environment variables were not loaded correctly")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn asset_api_endpoint() -> &'static str {
|
||||||
|
static IDENTITY_API_ASSET_API_ENDPOINT: OnceLock<String> = OnceLock::new();
|
||||||
|
IDENTITY_API_ASSET_API_ENDPOINT.get_or_init(|| {
|
||||||
|
env::var("IDENTITY_API_ASSET_API_ENDPOINT")
|
||||||
|
.expect("environment variables were not loaded correctly")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn database_url() -> &'static str {
|
||||||
|
static DATABASE_URL: OnceLock<String> = OnceLock::new();
|
||||||
|
DATABASE_URL.get_or_init(|| {
|
||||||
|
env::var("DATABASE_URL").expect("environment variables were not loaded correctly")
|
||||||
|
})
|
||||||
|
}
|
46
identity-api-rs/src/main.rs
Normal file
46
identity-api-rs/src/main.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// Identity. Store your memories and mental belongings
|
||||||
|
// Copyright (C) 2024 Sofía Aritz
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use axum::{routing::get, Router};
|
||||||
|
use env::LoadEnvError;
|
||||||
|
|
||||||
|
mod database;
|
||||||
|
mod env;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
let _ = env::load_env().inspect_err(|e| match e {
|
||||||
|
LoadEnvError::DotenvyError(error) => panic!("failed to load .env file: {:?}", error),
|
||||||
|
LoadEnvError::MissingVariable(variable) => {
|
||||||
|
panic!("missing environment variable: `{variable}`")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let app = Router::new().route("/", get(landing));
|
||||||
|
|
||||||
|
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
|
||||||
|
.await
|
||||||
|
.expect("failed to bind");
|
||||||
|
|
||||||
|
println!("listening on http://{}", listener.local_addr().unwrap());
|
||||||
|
axum::serve(listener, app)
|
||||||
|
.await
|
||||||
|
.expect("failed to serve app");
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn landing() -> &'static str {
|
||||||
|
env::landing_message()
|
||||||
|
}
|
Loading…
Reference in a new issue