diff --git a/Cargo.lock b/Cargo.lock index 7dbd04d..96b0f5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,6 +39,12 @@ dependencies = [ ] [[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -131,6 +137,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "futures-sink" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -149,6 +166,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-core", + "futures-macro", "futures-sink", "futures-task", "pin-project-lite", @@ -187,10 +205,21 @@ checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" name = "giterated-daemon" version = "0.1.0" dependencies = [ + "futures-util", + "serde", + "serde_json", + "tokio", "tokio-tungstenite", + "tracing", ] [[package]] +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + +[[package]] name = "http" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -230,6 +259,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -262,6 +301,16 @@ dependencies = [ ] [[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] name = "object" version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -271,6 +320,35 @@ dependencies = [ ] [[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] name = "percent-encoding" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -343,12 +421,64 @@ dependencies = [ ] [[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + +[[package]] name = "rustc-demangle" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f5db24220c009de9bd45e69fb2938f4b6d2df856aa9304ce377b3180f83b7c1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ad697f7e0b65af4983a4ce8f56ed5b357e8d3c36651bf6a7e13639c17b8e670" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] name = "sha1" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -360,6 +490,15 @@ dependencies = [ ] [[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -369,6 +508,12 @@ dependencies = [ ] [[package]] +name = "smallvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] name = "socket2" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -434,12 +579,27 @@ dependencies = [ "bytes", "libc", "mio", + "num_cpus", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2", + "tokio-macros", "windows-sys", ] [[package]] +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "tokio-tungstenite" version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -452,6 +612,38 @@ dependencies = [ ] [[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +dependencies = [ + "once_cell", +] + +[[package]] name = "tungstenite" version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml index 1e6e1c8..f5cf2ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -tokio-tungstenite = "*" \ No newline at end of file +tokio-tungstenite = "*" +tokio = { version = "1.32.0", features = ["full"] } +tracing = "*" +futures-util = "*" +serde = { version = "1", features = ["derive"]} +serde_json = "1.0" \ No newline at end of file diff --git a/src/command/issues.rs b/src/command/issues.rs index be04ff4..b4a9c3a 100644 --- a/src/command/issues.rs +++ b/src/command/issues.rs @@ -1,13 +1,18 @@ +use serde::{Deserialize, Serialize}; + use crate::model::repository::Repository; +#[derive(Clone)] pub struct IssuesCountCommand { pub respository: Repository, } +#[derive(Clone, Serialize, Deserialize)] pub struct IssuesCountResponse { pub count: u64, } +#[derive(Clone)] pub struct IssuesLabelsCommand { pub repository: Repository, } diff --git a/src/command/mod.rs b/src/command/mod.rs index ae73fc2..685145a 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -1,2 +1,14 @@ +use serde::{Deserialize, Serialize}; + +use crate::handshake::HandshakeMessage; + +use self::repository::RepositoryMessage; + pub mod issues; pub mod repository; + +#[derive(Clone, Serialize, Deserialize)] +pub enum MessageKind { + Handshake(HandshakeMessage), + Repository(RepositoryMessage), +} diff --git a/src/command/repository.rs b/src/command/repository.rs index 60b609d..27b3aae 100644 --- a/src/command/repository.rs +++ b/src/command/repository.rs @@ -1,14 +1,26 @@ +use serde::{Deserialize, Serialize}; + use crate::model::{ repository::{CommitMetadata, Repository, RepositoryFile, RepositoryView}, user::User, }; -pub struct RepositoryCommand { +use super::issues::IssuesCountResponse; + +#[derive(Clone, Serialize, Deserialize)] +pub struct RepositoryMessage { pub target: Repository, - pub command: RepositoryCommandKind, + pub command: RepositoryMessageKind, +} + +#[derive(Clone, Serialize, Deserialize)] +pub enum RepositoryMessageKind { + Request(RepositoryRequest), + Response(RepositoryResponse), } -pub enum RepositoryCommandKind { +#[derive(Clone, Serialize, Deserialize)] +pub enum RepositoryRequest { CreateRepository(CreateRepositoryCommand), RepositoryFileInspection(RepositoryFileInspectionCommand), RepositoryInfo(RepositoryInfoRequest), @@ -17,6 +29,17 @@ pub enum RepositoryCommandKind { Issues(RepositoryIssuesRequest), } +#[derive(Clone, Serialize, Deserialize)] +pub enum RepositoryResponse { + CreateRepository(CreateRepositoryResponse), + RepositoryFileInspection(RepositoryFileInspectionResponse), + RepositoryInfo(RepositoryView), + IssuesCount(IssuesCountResponse), + IssueLabels(RepositoryIssueLabelsResponse), + Issues(RepositoryIssuesResponse), +} + +#[derive(Clone, Serialize, Deserialize)] pub struct CreateRepositoryCommand { pub name: String, pub description: String, @@ -24,15 +47,18 @@ pub struct CreateRepositoryCommand { pub owner: User, } +#[derive(Clone, Serialize, Deserialize)] pub enum CreateRepositoryResponse { Created, Failed, } +#[derive(Clone, Serialize, Deserialize)] pub struct RepositoryFileInspectionCommand { pub path: RepositoryFile, } +#[derive(Clone, Serialize, Deserialize)] pub enum RepositoryFileInspectionResponse { File { commit_metadata: CommitMetadata, @@ -46,29 +72,37 @@ pub enum RepositoryFileInspectionResponse { }, } +#[derive(Clone, Serialize, Deserialize)] pub struct RepositoryIssuesCountRequest; +#[derive(Clone, Serialize, Deserialize)] pub struct RepositoryIssuesCountResponse { pub count: u64, } +#[derive(Clone, Serialize, Deserialize)] pub struct RepositoryIssueLabelsRequest; +#[derive(Clone, Serialize, Deserialize)] pub struct RepositoryIssueLabelsResponse { - pub labels: IssueLabel, + pub labels: Vec, } +#[derive(Clone, Serialize, Deserialize)] pub struct IssueLabel { pub name: String, pub color: String, } +#[derive(Clone, Serialize, Deserialize)] pub struct RepositoryIssuesRequest; +#[derive(Clone, Serialize, Deserialize)] pub struct RepositoryIssuesResponse { pub issues: Vec, } +#[derive(Clone, Serialize, Deserialize)] pub struct RepositoryIssue { pub author: User, pub id: u64, @@ -77,6 +111,7 @@ pub struct RepositoryIssue { pub labels: Vec, } +#[derive(Clone, Serialize, Deserialize)] pub struct RepositoryInfoRequest { pub info: RepositoryView, } diff --git a/src/connection.rs b/src/connection.rs index 29405d1..b4341b8 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -1,5 +1,288 @@ -use crate::model::instance::InstanceMeta; +use std::{collections::HashMap, net::SocketAddr, sync::Arc}; -pub struct Connection { - pub instance: InstanceMeta -} \ No newline at end of file +use futures_util::{stream::StreamExt, SinkExt, TryStreamExt}; +use tokio::{ + io::{AsyncRead, AsyncWrite}, + net::TcpStream, + sync::{ + broadcast::{Receiver, Sender}, + Mutex, + }, + task::JoinHandle, +}; +use tokio_tungstenite::{tungstenite::Message, WebSocketStream}; + +use crate::{ + command::{ + issues::IssuesCountResponse, + repository::{ + RepositoryFileInspectionResponse, RepositoryIssueLabelsResponse, + RepositoryIssuesResponse, RepositoryMessage, RepositoryMessageKind, RepositoryRequest, + RepositoryResponse, + }, + MessageKind, + }, + handshake::{HandshakeFinalize, HandshakeMessage, HandshakeResponse, InitiateHandshake}, + listener::Listeners, + model::{ + instance::{Instance, InstanceMeta}, + repository::{CommitMetadata, RepositoryView}, + }, +}; + +pub struct RawConnection { + pub task: JoinHandle<()>, +} + +pub struct InstanceConnection { + pub instance: InstanceMeta, + pub sender: Sender, + pub task: JoinHandle<()>, +} + +/// Represents a connection which hasn't finished the handshake. +pub struct UnestablishedConnection { + pub socket: WebSocketStream, +} + +#[derive(Default)] +pub struct Connections { + pub connections: Vec, + pub instance_connections: HashMap, +} + +pub async fn connection_worker( + mut socket: WebSocketStream, + listeners: Arc>, + mut connections: Arc>, + addr: SocketAddr, +) { + let mut handshaked = false; + let this_instance = Instance { + url: String::from("FOO"), + }; + + while let Some(message) = socket.next().await { + let message = match message { + Ok(message) => message, + Err(err) => { + error!("Error reading message: {:?}", err); + continue; + } + }; + + let payload = match message { + Message::Text(text) => text.into_bytes(), + Message::Binary(bytes) => bytes, + Message::Ping(_) => continue, + Message::Pong(_) => continue, + Message::Close(_) => { + info!("Closing connection with {}.", addr); + + return; + } + _ => unreachable!(), + }; + + let message = match serde_json::from_slice::(&payload) { + Ok(message) => message, + Err(err) => { + error!("Error deserializing message from {}: {:?}", addr, err); + continue; + } + }; + + if let MessageKind::Handshake(handshake) = message { + match handshake { + HandshakeMessage::Initiate(_) => { + // Send HandshakeMessage::Response + let message = HandshakeResponse { + identity: Instance { + url: String::from("foo.com"), + }, + version: String::from("0.1.0"), + }; + + socket + .send(Message::Binary( + serde_json::to_vec(&HandshakeMessage::Response(message)).unwrap(), + )) + .await + .unwrap(); + + continue; + } + HandshakeMessage::Response(_) => { + // Send HandshakeMessage::Finalize + let message = HandshakeFinalize { success: true }; + + socket + .send(Message::Binary( + serde_json::to_vec(&HandshakeMessage::Finalize(message)).unwrap(), + )) + .await + .unwrap(); + + continue; + } + HandshakeMessage::Finalize(_) => { + handshaked = true; + + continue; + } + } + } + + if !handshaked { + continue; + } + + if let MessageKind::Repository(repository) = &message { + if repository.target.instance != this_instance { + // We need to send this command to a different instance + + let mut listener = send_and_get_listener(message, &listeners, &connections).await; + + // Wait for response + while let Ok(message) = listener.recv().await { + if let MessageKind::Repository(RepositoryMessage { + command: RepositoryMessageKind::Response(_), + .. + }) = message + { + socket + .send(Message::Binary(serde_json::to_vec(&message).unwrap())) + .await + .unwrap(); + } + } + } else { + // This message is targeting this instance + match &repository.command { + RepositoryMessageKind::Request(request) => match request { + RepositoryRequest::CreateRepository(_) => todo!(), + RepositoryRequest::RepositoryFileInspection(_) => { + let response = RepositoryFileInspectionResponse::File { + commit_metadata: CommitMetadata::default(), + }; + } + RepositoryRequest::RepositoryInfo(_) => { + let response = RepositoryView { + name: String::from("Nederland"), + description: String::from("ik hou van het nederland"), + default_branch: String::from("nederland"), + latest_commit: CommitMetadata::default(), + files: vec![], + }; + + socket + .send(Message::Binary( + serde_json::to_vec(&MessageKind::Repository( + RepositoryMessage { + target: repository.target.clone(), + command: RepositoryMessageKind::Response( + RepositoryResponse::RepositoryInfo(response), + ), + }, + )) + .unwrap(), + )) + .await + .unwrap(); + } + RepositoryRequest::IssuesCount(_) => { + let response: IssuesCountResponse = IssuesCountResponse { count: 727420 }; + + socket + .send(Message::Binary( + serde_json::to_vec(&MessageKind::Repository( + RepositoryMessage { + target: repository.target.clone(), + command: RepositoryMessageKind::Response( + RepositoryResponse::IssuesCount(response), + ), + }, + )) + .unwrap(), + )) + .await + .unwrap(); + } + RepositoryRequest::IssueLabels(_) => { + let response = RepositoryIssueLabelsResponse { labels: vec![] }; + + socket + .send(Message::Binary( + serde_json::to_vec(&MessageKind::Repository( + RepositoryMessage { + target: repository.target.clone(), + command: RepositoryMessageKind::Response( + RepositoryResponse::IssueLabels(response), + ), + }, + )) + .unwrap(), + )) + .await + .unwrap(); + } + RepositoryRequest::Issues(_) => { + let response = RepositoryIssuesResponse { issues: vec![] }; + + socket + .send(Message::Binary( + serde_json::to_vec(&MessageKind::Repository( + RepositoryMessage { + target: repository.target.clone(), + command: RepositoryMessageKind::Response( + RepositoryResponse::Issues(response), + ), + }, + )) + .unwrap(), + )) + .await + .unwrap(); + } + }, + RepositoryMessageKind::Response(response) => { + unreachable!() + } + } + } + } + } +} + +async fn send_and_get_listener( + message: MessageKind, + listeners: &Arc>, + mut connections: &Arc>, +) -> Receiver { + let (instance, user, repository) = match &message { + MessageKind::Handshake(_) => { + todo!() + } + MessageKind::Repository(repository) => (None, None, Some(repository.target.clone())), + }; + + let target = todo!(); + + let mut listeners = listeners.lock().await; + let mut listener = listeners.add(instance, user, repository); + drop(listeners); + + let connections = connections.lock().await; + + if let Some(connection) = connections.instance_connections.get(&target) { + connection.sender.send(message); + } else { + error!("Unable to message {}, this is a bug.", target.url); + + panic!(); + } + + drop(connections); + + listener +} diff --git a/src/handshake.rs b/src/handshake.rs new file mode 100644 index 0000000..357960f --- /dev/null +++ b/src/handshake.rs @@ -0,0 +1,29 @@ +use serde::{Deserialize, Serialize}; + +use crate::model::instance::Instance; + +/// Sent by the initiator of a new inter-daemon connection. +#[derive(Clone, Serialize, Deserialize)] +pub struct InitiateHandshake { + pub identity: Instance, + pub version: String, +} + +/// Sent in response to [`InitiateHandshake`] +#[derive(Clone, Serialize, Deserialize)] +pub struct HandshakeResponse { + pub identity: Instance, + pub version: String, +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct HandshakeFinalize { + pub success: bool, +} + +#[derive(Clone, Serialize, Deserialize)] +pub enum HandshakeMessage { + Initiate(InitiateHandshake), + Response(HandshakeResponse), + Finalize(HandshakeFinalize), +} diff --git a/src/listener.rs b/src/listener.rs new file mode 100644 index 0000000..1c93005 --- /dev/null +++ b/src/listener.rs @@ -0,0 +1,31 @@ +use std::collections::HashMap; + +use tokio::sync::broadcast::{Receiver, Sender}; + +use crate::{ + command::{repository::RepositoryMessage, MessageKind}, + model::{instance::Instance, repository::Repository, user::User}, +}; + +#[derive(Default)] +pub struct Listeners { + listeners: HashMap, Receiver)>, +} + +impl Listeners { + pub fn add( + &mut self, + instance: Option, + user: Option, + repository: Option, + ) -> Receiver { + todo!() + } +} + +#[derive(Hash)] +pub struct ListenerTarget { + pub instance: Option, + pub user: Option, + pub repository: Option, +} diff --git a/src/main.rs b/src/main.rs index e5c8acd..e66020d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,78 @@ +use std::{error::Error, net::SocketAddr, sync::Arc}; + +use connection::{connection_worker, Connections, RawConnection, UnestablishedConnection}; +use listener::Listeners; +use tokio::{ + io::{AsyncRead, AsyncWrite}, + net::{TcpListener, TcpStream}, + sync::Mutex, +}; +use tokio_tungstenite::{accept_async, WebSocketStream}; + pub mod command; -pub mod model; pub mod connection; +pub mod handshake; +pub mod listener; +pub mod model; + +#[macro_use] +extern crate tracing; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let mut listener = TcpListener::bind("127.0.0.1:8080").await?; + let mut connections: Arc> = Arc::default(); + let mut listeners: Arc> = Arc::default(); + + loop { + let stream = accept_stream(&mut listener).await; + + let (stream, address) = match stream { + Ok(stream) => stream, + Err(err) => { + error!("Failed to accept connection. {:?}", err); + continue; + } + }; + + let connection = accept_websocket_connection(stream).await; + + let connection = match connection { + Ok(connection) => connection, + Err(err) => { + error!( + "Failed to initiate Websocket connection from {}. {:?}", + address, err + ); + continue; + } + }; + + let connection = RawConnection { + task: tokio::spawn(connection_worker( + connection, + listeners.clone(), + connections.clone(), + address, + )), + }; + + connections.lock().await.connections.push(connection); + } +} + +async fn accept_stream( + listener: &mut TcpListener, +) -> Result<(TcpStream, SocketAddr), Box> { + let stream = listener.accept().await?; + + Ok(stream) +} + +async fn accept_websocket_connection( + stream: S, +) -> Result, Box> { + let connection = accept_async(stream).await?; -fn main() { - println!("Hello, world!"); + Ok(connection) } diff --git a/src/model/instance.rs b/src/model/instance.rs index 871ef9d..3d7e80f 100644 --- a/src/model/instance.rs +++ b/src/model/instance.rs @@ -1,4 +1,11 @@ +use serde::{Deserialize, Serialize}; + pub struct InstanceMeta { pub url: String, pub public_key: String, } + +#[derive(Clone, Hash, Eq, PartialEq, Serialize, Deserialize)] +pub struct Instance { + pub url: String, +} diff --git a/src/model/repository.rs b/src/model/repository.rs index b7c0b53..9ca976e 100644 --- a/src/model/repository.rs +++ b/src/model/repository.rs @@ -1,10 +1,16 @@ use std::time::Instant; +use serde::{Deserialize, Serialize}; + +use super::instance::Instance; + +#[derive(Hash, Clone, Serialize, Deserialize)] pub struct Repository { pub name: String, - pub instance: String, + pub instance: Instance, } +#[derive(Clone, Serialize, Deserialize)] pub struct RepositoryView { pub name: String, pub description: String, @@ -13,19 +19,22 @@ pub struct RepositoryView { pub files: Vec, } +#[derive(Clone, Serialize, Deserialize)] pub enum RepositoryFile { Directory(String), File(String), } +#[derive(Clone, Serialize, Deserialize)] pub struct RepositoryFileWithCommitMetadata { pub file: RepositoryFile, pub commit_metadata: CommitMetadata, } +#[derive(Clone, Serialize, Deserialize, Default)] pub struct CommitMetadata { pub author: String, pub message: String, pub hash: String, - pub time: Instant, + pub time: (), } diff --git a/src/model/user.rs b/src/model/user.rs index eb496dd..69d55bd 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -1,3 +1,6 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Hash, Serialize, Deserialize)] pub struct User { pub username: String, pub instance: String,