init
This commit is contained in:
89
.idea/workspace.xml
generated
89
.idea/workspace.xml
generated
@@ -12,56 +12,27 @@
|
|||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="b2b598c9-ef0b-4cbc-8852-cfbc8ce3920e" name="Changes" comment="init">
|
<list default="true" id="b2b598c9-ef0b-4cbc-8852-cfbc8ce3920e" name="Changes" comment="init">
|
||||||
<change afterPath="$PROJECT_DIR$/src/utils/config.rs" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/src/db/mod.rs" afterDir="false" />
|
||||||
<change afterPath="$PROJECT_DIR$/src/utils/logger.rs" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/src/db/models/_channel_user.rs" afterDir="false" />
|
||||||
<change afterPath="$PROJECT_DIR$/src/utils/toolbox.rs" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/src/db/models/_server_user.rs" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/src/db/models/attachment.rs" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/src/db/models/category.rs" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/src/db/models/channel.rs" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/src/db/models/message.rs" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/src/db/models/mod.rs" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/src/db/models/server.rs" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/src/db/models/user.rs" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/src/db/repositories/_server_user_repository.rs" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/src/db/repositories/mod.rs" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/Cargo.lock" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.lock" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/Cargo.lock" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.lock" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/Cargo.toml" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.toml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/Cargo.toml" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.toml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/app/app.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/app/app.rs" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/app/app.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/app/app.rs" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/app/conf.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/app/mod.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/core/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/app/http/mod.rs" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/domain/client.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/domain/event.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/domain/mod.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/domain/models.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/domain/user.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/lib.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/lib.rs" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/lib.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/lib.rs" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/main.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/main.rs" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/network/http/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/network/http/mod.rs" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/network/http.rs" beforeDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/network/http/server.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/network/http/server.rs" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/network/http_routes/channel.rs" beforeDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/network/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/network/mod.rs" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/network/http_routes/master.rs" beforeDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/store/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/db/repositories/_channel_user_repository.rs" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/network/http_routes/message.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/network/http_routes/mod.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/network/http_routes/sub_server.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/network/http_routes/user.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/network/http_routes/websocket.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/network/mod.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/network/protocol.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/network/udp.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/network/udp_back.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/runtime/dispatcher.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/runtime/mod.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/store/migrations/001_init.sqlite.sql" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/store/mod.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/store/models/channel.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/store/models/link_sub_server_user.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/store/models/message.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/store/models/mod.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/store/models/sub_server.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/store/models/user.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/store/repositories/channel_repository.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/store/repositories/link_sub_server_user_repository.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/store/repositories/message_repository.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/store/repositories/mod.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/store/repositories/sub_server_repository.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/store/repositories/user_repository.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/store/session/client.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/store/session/mod.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/store/store_service.rs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/utils/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/utils/mod.rs" afterDir="false" />
|
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
@@ -115,13 +86,15 @@
|
|||||||
"org.rust.cargo.project.model.PROJECT_DISCOVERY": "true",
|
"org.rust.cargo.project.model.PROJECT_DISCOVERY": "true",
|
||||||
"org.rust.cargo.project.model.impl.CargoExternalSystemProjectAware.subscribe.first.balloon": "",
|
"org.rust.cargo.project.model.impl.CargoExternalSystemProjectAware.subscribe.first.balloon": "",
|
||||||
"org.rust.first.attach.projects": "true",
|
"org.rust.first.attach.projects": "true",
|
||||||
"settings.editor.selected.configurable": "ml.llm.LLMConfigurable",
|
"settings.editor.selected.configurable": "preferences.pluginManager",
|
||||||
"to.speed.mode.migration.done": "true",
|
"to.speed.mode.migration.done": "true",
|
||||||
"vue.rearranger.settings.migration": "true"
|
"vue.rearranger.settings.migration": "true"
|
||||||
}
|
}
|
||||||
}</component>
|
}</component>
|
||||||
<component name="RecentsManager">
|
<component name="RecentsManager">
|
||||||
<key name="MoveFile.RECENT_KEYS">
|
<key name="MoveFile.RECENT_KEYS">
|
||||||
|
<recent name="\\wsl.localhost\Debian\home\Nell\linux_dev\ox_speak_server\src" />
|
||||||
|
<recent name="\\wsl.localhost\Debian\home\Nell\linux_dev\ox_speak_server\src\store\db" />
|
||||||
<recent name="\\wsl.localhost\Debian\home\Nell\linux_dev\ox_speak_server\src\app\http" />
|
<recent name="\\wsl.localhost\Debian\home\Nell\linux_dev\ox_speak_server\src\app\http" />
|
||||||
<recent name="\\wsl.localhost\Debian\home\Nell\linux_dev\ox_speak_server\src\network" />
|
<recent name="\\wsl.localhost\Debian\home\Nell\linux_dev\ox_speak_server\src\network" />
|
||||||
</key>
|
</key>
|
||||||
@@ -180,7 +153,11 @@
|
|||||||
<workItem from="1758380522178" duration="7468000" />
|
<workItem from="1758380522178" duration="7468000" />
|
||||||
<workItem from="1758439568539" duration="4787000" />
|
<workItem from="1758439568539" duration="4787000" />
|
||||||
<workItem from="1758951672825" duration="25708000" />
|
<workItem from="1758951672825" duration="25708000" />
|
||||||
<workItem from="1759042700460" duration="11051000" />
|
<workItem from="1759042700460" duration="16518000" />
|
||||||
|
<workItem from="1759562385229" duration="218000" />
|
||||||
|
<workItem from="1759562619209" duration="13323000" />
|
||||||
|
<workItem from="1759649037947" duration="3578000" />
|
||||||
|
<workItem from="1759657715670" duration="10824000" />
|
||||||
</task>
|
</task>
|
||||||
<task id="LOCAL-00001" summary="init">
|
<task id="LOCAL-00001" summary="init">
|
||||||
<option name="closed" value="true" />
|
<option name="closed" value="true" />
|
||||||
@@ -190,7 +167,23 @@
|
|||||||
<option name="project" value="LOCAL" />
|
<option name="project" value="LOCAL" />
|
||||||
<updated>1756218076891</updated>
|
<updated>1756218076891</updated>
|
||||||
</task>
|
</task>
|
||||||
<option name="localTasksCounter" value="2" />
|
<task id="LOCAL-00002" summary="init">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1759077528343</created>
|
||||||
|
<option name="number" value="00002" />
|
||||||
|
<option name="presentableId" value="LOCAL-00002" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1759077528343</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00003" summary="init">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1759077533456</created>
|
||||||
|
<option name="number" value="00003" />
|
||||||
|
<option name="presentableId" value="LOCAL-00003" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1759077533456</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="4" />
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
|
|||||||
740
Cargo.lock
generated
740
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -29,4 +29,6 @@ tower = "0.5"
|
|||||||
tower-http = "0.6"
|
tower-http = "0.6"
|
||||||
hyper = "1.7"
|
hyper = "1.7"
|
||||||
|
|
||||||
sea-orm = { version = "1.1", features = [ "sqlx-sqlite", "runtime-tokio", "macros" ] }
|
sqlx = { version = "0.8", features = ["runtime-tokio", "tls-rustls", "sqlite", "postgres", "mysql", "uuid", "chrono", "migrate"] }
|
||||||
|
uuid = { version = "1.18", features = ["v4", "v7", "serde"] }
|
||||||
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
use crate::app::http::router::configure_routes;
|
||||||
|
use crate::network::http::server::HttpServer;
|
||||||
use crate::network::udp::server::UdpServer;
|
use crate::network::udp::server::UdpServer;
|
||||||
use crate::utils::config::Config;
|
use crate::utils::config::Config;
|
||||||
use crate::utils::logger::ContextLogger;
|
use crate::utils::logger::ContextLogger;
|
||||||
@@ -24,8 +26,16 @@ impl App {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let http_server = match HttpServer::new("127.0.0.1:8080") {
|
||||||
|
Ok(http_server) => http_server,
|
||||||
|
Err(e) => {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, format!("Failed to create HTTP server: {}", e)))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let context = Context {
|
let context = Context {
|
||||||
udp_server
|
udp_server,
|
||||||
|
http_server,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
@@ -34,8 +44,18 @@ impl App {
|
|||||||
logger
|
logger
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn run(self) -> io::Result<()> {
|
||||||
|
self.logger.info("Starting application");
|
||||||
|
self.context.udp_server.run().await?;
|
||||||
|
|
||||||
|
self.context.http_server.run().await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Context {
|
struct Context {
|
||||||
udp_server: UdpServer
|
udp_server: UdpServer,
|
||||||
|
http_server: HttpServer
|
||||||
}
|
}
|
||||||
57
src/db/context.rs
Normal file
57
src/db/context.rs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use sqlx::SqlitePool;
|
||||||
|
use crate::db::{AttachmentRepository, CategoryRepository, ChannelRepository, ChannelUser, ChannelUserRepository, MessageRepository, ServerRepository, ServerUser, ServerUserRepository, UserRepository};
|
||||||
|
use crate::utils::logger::ContextLogger;
|
||||||
|
|
||||||
|
struct Repositories {
|
||||||
|
server_repository: ServerRepository,
|
||||||
|
category_repository: CategoryRepository,
|
||||||
|
channel_repository: ChannelRepository,
|
||||||
|
user_repository: UserRepository,
|
||||||
|
message_repository: MessageRepository,
|
||||||
|
attachment_repository: AttachmentRepository,
|
||||||
|
|
||||||
|
server_user: ServerUserRepository,
|
||||||
|
channel_user: ChannelUserRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DbContext {
|
||||||
|
pool: Arc<SqlitePool>,
|
||||||
|
|
||||||
|
repositories: Arc<Repositories>,
|
||||||
|
|
||||||
|
// logger
|
||||||
|
logger: ContextLogger,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DbContext {
|
||||||
|
pub async fn new(database_url: &str) -> Result<Self, sqlx::Error> {
|
||||||
|
let logger = ContextLogger::new("DB");
|
||||||
|
|
||||||
|
logger.info(&format!("Creating DB context on {}", database_url));
|
||||||
|
let pool = SqlitePool::connect(database_url).await?;
|
||||||
|
logger.info("DB context created");
|
||||||
|
let pool = Arc::new(pool);
|
||||||
|
|
||||||
|
let repositories = Arc::new(Repositories {
|
||||||
|
server_repository: ServerRepository::new(pool.clone()),
|
||||||
|
category_repository: CategoryRepository::new(pool.clone()),
|
||||||
|
channel_repository: ChannelRepository::new(pool.clone()),
|
||||||
|
user_repository: UserRepository::new(pool.clone()),
|
||||||
|
message_repository: MessageRepository::new(pool.clone()),
|
||||||
|
attachment_repository: AttachmentRepository::new(pool.clone()),
|
||||||
|
server_user: ServerUserRepository::new(pool.clone()),
|
||||||
|
channel_user: ChannelUserRepository::new(pool.clone())
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
pool,
|
||||||
|
repositories,
|
||||||
|
logger,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn repositories(&self) -> Arc<Repositories> {
|
||||||
|
self.repositories.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/db/mod.rs
Normal file
6
src/db/mod.rs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
pub mod models;
|
||||||
|
pub mod repositories;
|
||||||
|
mod context;
|
||||||
|
|
||||||
|
pub use models::*;
|
||||||
|
pub use repositories::*;
|
||||||
29
src/db/models/_channel_user.rs
Normal file
29
src/db/models/_channel_user.rs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use sqlx::FromRow;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
|
||||||
|
pub struct ChannelUser {
|
||||||
|
pub id: Uuid,
|
||||||
|
pub channel_id: Uuid,
|
||||||
|
pub user_id: Uuid,
|
||||||
|
pub username: Option<String>,
|
||||||
|
pub joined_at: DateTime<Utc>,
|
||||||
|
pub updated_at: DateTime<Utc>,
|
||||||
|
pub last_read_at: DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChannelUser {
|
||||||
|
pub fn new(channel_id: Uuid, user_id: Uuid) -> Self {
|
||||||
|
Self {
|
||||||
|
id: Uuid::now_v7(),
|
||||||
|
channel_id,
|
||||||
|
user_id,
|
||||||
|
username: None,
|
||||||
|
joined_at: Utc::now(),
|
||||||
|
updated_at: Utc::now(),
|
||||||
|
last_read_at: Utc::now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/db/models/_server_user.rs
Normal file
28
src/db/models/_server_user.rs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use sqlx::FromRow;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
|
||||||
|
pub struct ServerUser {
|
||||||
|
pub id: Uuid,
|
||||||
|
pub server_id: Uuid,
|
||||||
|
pub user_id: Uuid,
|
||||||
|
#[sqlx(default)]
|
||||||
|
pub username: Option<String>,
|
||||||
|
pub joined_at: DateTime<Utc>,
|
||||||
|
pub updated_at: DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServerUser {
|
||||||
|
pub fn new(server_id: Uuid, user_id: Uuid) -> Self {
|
||||||
|
Self {
|
||||||
|
id: Uuid::now_v7(),
|
||||||
|
server_id,
|
||||||
|
user_id,
|
||||||
|
username: None,
|
||||||
|
joined_at: Utc::now(),
|
||||||
|
updated_at: Utc::now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/db/models/attachment.rs
Normal file
27
src/db/models/attachment.rs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use sqlx::FromRow;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
|
||||||
|
pub struct Attachment {
|
||||||
|
pub id: Uuid,
|
||||||
|
pub message_id: Uuid,
|
||||||
|
pub filename: String,
|
||||||
|
pub file_size: i64,
|
||||||
|
pub mime_type: String,
|
||||||
|
pub created_at: DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Attachment {
|
||||||
|
pub fn new(message_id: Uuid, filename: String, file_size: i64, mime_type: String) -> Self {
|
||||||
|
Self {
|
||||||
|
id: Uuid::new_v4(),
|
||||||
|
message_id,
|
||||||
|
filename,
|
||||||
|
file_size,
|
||||||
|
mime_type,
|
||||||
|
created_at: Utc::now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/db/models/category.rs
Normal file
25
src/db/models/category.rs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use sqlx::FromRow;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
|
||||||
|
pub struct Category {
|
||||||
|
pub id: Uuid,
|
||||||
|
pub server_id: Uuid,
|
||||||
|
pub name: String,
|
||||||
|
pub created_at: DateTime<Utc>,
|
||||||
|
pub updated_at: DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Category {
|
||||||
|
pub fn new(server_id: Uuid, name: String) -> Self {
|
||||||
|
Self {
|
||||||
|
id: Uuid::now_v7(),
|
||||||
|
server_id,
|
||||||
|
name,
|
||||||
|
created_at: Utc::now(),
|
||||||
|
updated_at: Utc::now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
56
src/db/models/channel.rs
Normal file
56
src/db/models/channel.rs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, sqlx::FromRow, Serialize, Deserialize)]
|
||||||
|
pub struct Channel {
|
||||||
|
pub id: Uuid, // Blob(16) sqlite
|
||||||
|
#[sqlx(default)]
|
||||||
|
pub server_id: Option<Uuid>,
|
||||||
|
#[sqlx(default)]
|
||||||
|
pub category_id: Option<Uuid>,
|
||||||
|
#[sqlx(default)]
|
||||||
|
pub position: i32,
|
||||||
|
#[sqlx(rename = "type")]
|
||||||
|
pub channel_type: ChannelType,
|
||||||
|
pub name: Option<String>, // Not necessary for DMs
|
||||||
|
pub created_at: DateTime<Utc>,
|
||||||
|
pub updated_at: DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::Type)]
|
||||||
|
#[sqlx(type_name = "text")]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum ChannelType {
|
||||||
|
Text,
|
||||||
|
Voice,
|
||||||
|
Dm
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Channel {
|
||||||
|
pub fn new_server_channel(server_id: Uuid, name: String, channel_type: ChannelType) -> Self {
|
||||||
|
Self {
|
||||||
|
id: Uuid::now_v7(),
|
||||||
|
server_id: Some(server_id),
|
||||||
|
category_id: None,
|
||||||
|
position: 0,
|
||||||
|
channel_type,
|
||||||
|
name: Some(name),
|
||||||
|
created_at: Utc::now(),
|
||||||
|
updated_at: Utc::now()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_dm_channel() -> Self {
|
||||||
|
Self {
|
||||||
|
id: Uuid::now_v7(),
|
||||||
|
server_id: None,
|
||||||
|
category_id: None,
|
||||||
|
channel_type: ChannelType::Dm,
|
||||||
|
name: None,
|
||||||
|
position: 0,
|
||||||
|
created_at: Utc::now(),
|
||||||
|
updated_at: Utc::now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/db/models/message.rs
Normal file
41
src/db/models/message.rs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use sqlx::FromRow;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
|
||||||
|
pub struct Message {
|
||||||
|
pub id: Uuid,
|
||||||
|
pub channel_id: Uuid,
|
||||||
|
pub user_id: Uuid,
|
||||||
|
pub content: String,
|
||||||
|
pub created_at: DateTime<Utc>,
|
||||||
|
pub edited_at: DateTime<Utc>,
|
||||||
|
pub reply_to_id: Option<Uuid>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Message {
|
||||||
|
pub fn new(channel_id: Uuid, user_id: Uuid, content: String) -> Self {
|
||||||
|
Self {
|
||||||
|
id: Uuid::now_v7(),
|
||||||
|
channel_id,
|
||||||
|
user_id,
|
||||||
|
content,
|
||||||
|
created_at: Utc::now(),
|
||||||
|
edited_at: Utc::now(),
|
||||||
|
reply_to_id: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_reply(channel_id: Uuid, user_id: Uuid, content: String, reply_to_id: Uuid) -> Self {
|
||||||
|
Self {
|
||||||
|
id: Uuid::now_v7(),
|
||||||
|
channel_id,
|
||||||
|
user_id,
|
||||||
|
content,
|
||||||
|
created_at: Utc::now(),
|
||||||
|
edited_at: Utc::now(),
|
||||||
|
reply_to_id: Some(reply_to_id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/db/models/mod.rs
Normal file
17
src/db/models/mod.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
mod user;
|
||||||
|
mod server;
|
||||||
|
mod _server_user;
|
||||||
|
mod channel;
|
||||||
|
mod category;
|
||||||
|
mod _channel_user;
|
||||||
|
mod message;
|
||||||
|
mod attachment;
|
||||||
|
|
||||||
|
pub use user::*;
|
||||||
|
pub use server::*;
|
||||||
|
pub use channel::*;
|
||||||
|
pub use category::*;
|
||||||
|
pub use message::*;
|
||||||
|
pub use attachment::*;
|
||||||
|
pub use _server_user::*;
|
||||||
|
pub use _channel_user::*;
|
||||||
25
src/db/models/server.rs
Normal file
25
src/db/models/server.rs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use sqlx::FromRow;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, FromRow, Serialize, Deserialize)]
|
||||||
|
pub struct Server {
|
||||||
|
pub id: Uuid, // Blob(16) sqlite
|
||||||
|
pub username: String,
|
||||||
|
pub password: Option<String>,
|
||||||
|
pub created_at: DateTime<Utc>,
|
||||||
|
pub updated_at: DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Server {
|
||||||
|
pub fn new(username: String, password: Option<String>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: Uuid::now_v7(),
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
created_at: Utc::now(),
|
||||||
|
updated_at: Utc::now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/db/models/user.rs
Normal file
25
src/db/models/user.rs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use sqlx::FromRow;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, FromRow, Serialize, Deserialize)]
|
||||||
|
pub struct User {
|
||||||
|
pub id: Uuid, // Blob(16) sqlite
|
||||||
|
pub username: String,
|
||||||
|
pub pub_key: String, // TEXT
|
||||||
|
pub created_at: DateTime<Utc>,
|
||||||
|
pub updated_at: DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl User {
|
||||||
|
pub fn new(username: String, pub_key: String) -> Self {
|
||||||
|
Self {
|
||||||
|
id: Uuid::now_v7(),
|
||||||
|
username,
|
||||||
|
pub_key,
|
||||||
|
created_at: Utc::now(),
|
||||||
|
updated_at: Utc::now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/db/repositories/_channel_user_repository.rs
Normal file
14
src/db/repositories/_channel_user_repository.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
|
pub struct ChannelUserRepository {
|
||||||
|
pool: Arc<SqlitePool>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChannelUserRepository {
|
||||||
|
pub fn new(pool: Arc<SqlitePool>) -> Self {
|
||||||
|
Self {
|
||||||
|
pool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/db/repositories/_server_user_repository.rs
Normal file
14
src/db/repositories/_server_user_repository.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
|
pub struct ServerUserRepository {
|
||||||
|
pool: Arc<SqlitePool>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServerUserRepository {
|
||||||
|
pub fn new(pool: Arc<SqlitePool>) -> Self {
|
||||||
|
Self {
|
||||||
|
pool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/db/repositories/attachment_repository.rs
Normal file
14
src/db/repositories/attachment_repository.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
|
pub struct AttachmentRepository {
|
||||||
|
pool: Arc<SqlitePool>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AttachmentRepository {
|
||||||
|
pub fn new(pool: Arc<SqlitePool>) -> Self {
|
||||||
|
Self {
|
||||||
|
pool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/db/repositories/category_repository.rs
Normal file
14
src/db/repositories/category_repository.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
|
pub struct CategoryRepository{
|
||||||
|
pool: Arc<SqlitePool>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CategoryRepository {
|
||||||
|
pub fn new(pool: Arc<SqlitePool>) -> Self {
|
||||||
|
Self {
|
||||||
|
pool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/db/repositories/channel_repository.rs
Normal file
15
src/db/repositories/channel_repository.rs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
|
pub struct ChannelRepository {
|
||||||
|
pool: Arc<SqlitePool>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl ChannelRepository {
|
||||||
|
pub fn new(pool: Arc<SqlitePool>) -> Self {
|
||||||
|
Self {
|
||||||
|
pool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/db/repositories/message_repository.rs
Normal file
15
src/db/repositories/message_repository.rs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
|
pub struct MessageRepository{
|
||||||
|
pool: Arc<SqlitePool>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl MessageRepository {
|
||||||
|
pub fn new(pool: Arc<SqlitePool>) -> Self {
|
||||||
|
Self {
|
||||||
|
pool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/db/repositories/mod.rs
Normal file
17
src/db/repositories/mod.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
mod _channel_user_repository;
|
||||||
|
mod _server_user_repository;
|
||||||
|
mod user_repository;
|
||||||
|
mod server_repository;
|
||||||
|
mod channel_repository;
|
||||||
|
mod category_repository;
|
||||||
|
mod message_repository;
|
||||||
|
mod attachment_repository;
|
||||||
|
|
||||||
|
pub use user_repository::*;
|
||||||
|
pub use server_repository::*;
|
||||||
|
pub use channel_repository::*;
|
||||||
|
pub use category_repository::*;
|
||||||
|
pub use message_repository::*;
|
||||||
|
pub use attachment_repository::*;
|
||||||
|
pub use _server_user_repository::*;
|
||||||
|
pub use _channel_user_repository::*;
|
||||||
15
src/db/repositories/server_repository.rs
Normal file
15
src/db/repositories/server_repository.rs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
|
pub struct ServerRepository{
|
||||||
|
pool: Arc<SqlitePool>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl ServerRepository {
|
||||||
|
pub fn new(pool: Arc<SqlitePool>) -> Self {
|
||||||
|
Self{
|
||||||
|
pool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/db/repositories/user_repository.rs
Normal file
14
src/db/repositories/user_repository.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use sqlx::{SqlitePool};
|
||||||
|
|
||||||
|
pub struct UserRepository {
|
||||||
|
pool: Arc<SqlitePool>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserRepository {
|
||||||
|
pub fn new(pool: Arc<SqlitePool>) -> Self {
|
||||||
|
Self {
|
||||||
|
pool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,4 +2,4 @@
|
|||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod network;
|
pub mod network;
|
||||||
pub mod app;
|
pub mod app;
|
||||||
pub mod store;
|
pub mod db;
|
||||||
@@ -1 +1 @@
|
|||||||
mod server;
|
pub mod server;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use axum::{Router, routing::get, http::StatusCode, Json};
|
use axum::{Router};
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use crate::utils::logger::ContextLogger;
|
use crate::utils::logger::ContextLogger;
|
||||||
|
|
||||||
@@ -20,34 +20,13 @@ impl HttpServer {
|
|||||||
Ok(Self { bind_addr, logger })
|
Ok(Self { bind_addr, logger })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(self) -> io::Result<()> {
|
pub async fn run(self, router: Router) -> io::Result<()> {
|
||||||
self.logger.info(&format!("Starting HTTP server on {}", self.bind_addr));
|
self.logger.info(&format!("Starting HTTP server on {}", self.bind_addr));
|
||||||
|
|
||||||
let listener = TcpListener::bind(self.bind_addr).await?;
|
let listener = TcpListener::bind(self.bind_addr).await?;
|
||||||
let app = create_app(self.logger.clone());
|
|
||||||
|
|
||||||
axum::serve(listener, app)
|
axum::serve(listener, router)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
|
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn create_app(logger: ContextLogger) -> Router {
|
|
||||||
Router::new()
|
|
||||||
.route("/", get(|| async { "OX Speak Server - HTTP API" }))
|
|
||||||
.route("/health", get(|| async { StatusCode::OK }))
|
|
||||||
.route("/api/status", get(status_handler))
|
|
||||||
.with_state(logger)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn status_handler(
|
|
||||||
axum::extract::State(logger): axum::extract::State<ContextLogger>
|
|
||||||
) -> Json<serde_json::Value> {
|
|
||||||
logger.info("Status endpoint called");
|
|
||||||
|
|
||||||
Json(serde_json::json!({
|
|
||||||
"status": "ok",
|
|
||||||
"service": "ox-speak-server",
|
|
||||||
"workers": tokio::runtime::Handle::current().metrics().num_workers()
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
pub mod udp;
|
pub mod udp;
|
||||||
mod http;
|
pub mod http;
|
||||||
Reference in New Issue
Block a user