Initial commit
This commit is contained in:
commit
da78c9bbab
|
@ -0,0 +1 @@
|
|||
/target
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,39 @@
|
|||
[package]
|
||||
name = "network"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "network"
|
||||
crate-type = ["staticlib", "cdylib"]
|
||||
|
||||
[dependencies]
|
||||
# uniffi related:
|
||||
uniffi = "0.22.0"
|
||||
uniffi_macros = "0.22.0"
|
||||
|
||||
# actual deps:
|
||||
reqwest = { version = "0.11.13", features = ["json", "blocking"]}
|
||||
chrono = { version = "0.4", features = [ "serde" ] }
|
||||
chrono-tz = { version = "0.8" }
|
||||
thiserror = "1.0.37"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = { version = "1" }
|
||||
bincode = "1.3.3"
|
||||
regex = "1.6.0" # Regular expression utilization
|
||||
|
||||
# net & async:
|
||||
tokio-tungstenite = "0.18.0"
|
||||
tokio = { version = "1.20.1", features = ["full"] }
|
||||
futures = "0.3.25"
|
||||
futures-util = "0.3.26"
|
||||
|
||||
# internal deps
|
||||
err = { git = "https://git.franklinblanco.dev/franklinblanco/err.git" }
|
||||
league-types = { git = "https://git.franklinblanco.dev/franklinblanco/league-types.git" }
|
||||
dev-dtos = { git = "https://git.franklinblanco.dev/franklinblanco/user-svc-dtos-rust.git" }
|
||||
chat-types = { git = "https://git.franklinblanco.dev/franklinblanco/chat-types.git" }
|
||||
chat-communicators = { git = "https://git.franklinblanco.dev/franklinblanco/chat-communicators.git" }
|
||||
|
||||
[build-dependencies]
|
||||
uniffi_build = "0.22.0"
|
|
@ -0,0 +1,4 @@
|
|||
fn main() {
|
||||
//set_var("OUT_DIR", "./");
|
||||
uniffi_build::generate_scaffolding("./src/network.udl").unwrap();
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,49 @@
|
|||
use std::sync::{Arc};
|
||||
|
||||
use dev_dtos::dtos::user::user_dtos::UserForAuthenticationDto;
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
|
||||
use crate::{utils::storage, ForeignError, client::chat::init_client_connection};
|
||||
|
||||
pub enum ClientError {
|
||||
One, Two, Three
|
||||
}
|
||||
|
||||
pub trait WebsocketFfi: Send + Sync + std::fmt::Debug {
|
||||
/// Method that rust will call once a message is recieved from the backend
|
||||
/// Swift just needs to know the message info to actually update it.
|
||||
fn message_recieved(&self, message: chat_types::client_types::chat_message::ChatMessage) -> Result<(), ForeignError>;
|
||||
fn message_sent(&self, ) -> Result<(), ForeignError>;
|
||||
fn message_delivered(&self, message: chat_types::client_types::chat_message::ChatMessage) -> Result<(), ForeignError>;
|
||||
fn message_seen(&self, message: chat_types::client_types::chat_message::ChatMessage) -> Result<(), ForeignError>;
|
||||
fn logged_in(&self) -> Result<(), ForeignError>;
|
||||
fn error(&self, error: String) -> Result<(), ForeignError>;
|
||||
fn client_error(&self, error: ClientError) -> Result<(), ForeignError>;
|
||||
//fn attempt(&self, string_from_rust: String) -> Result<Option<String>, ForeignError>;
|
||||
}
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct WebsocketCaller;
|
||||
|
||||
impl<'a> WebsocketCaller {
|
||||
pub fn new() -> Self {
|
||||
WebsocketCaller::default()
|
||||
}
|
||||
/// Method to be called from swift to initiate websocket connection.
|
||||
/// This method being called assumes the following:
|
||||
/// - Valid UserForAuthentication is stored in device storage
|
||||
pub fn init_ws_connection(&'a self, websocket_ffi: Box<dyn WebsocketFfi>) {
|
||||
let ws_ffi_rwlock = Arc::new(websocket_ffi);
|
||||
|
||||
let user: UserForAuthenticationDto = storage::read("user".into()).unwrap(); //TODO: Remove unwrap
|
||||
//websocket_ffi.message_recieved(ChatMessage { id: 20, from_id: 2, to_id: 1, message: "What the fuck nigga".as_bytes().to_vec(), message_content: MessageContentType::Text, time_sent: 1, time_delivered: vec![], time_seen: vec![] }).unwrap();
|
||||
|
||||
let rt = Runtime::new().unwrap();
|
||||
let _ = rt.block_on(
|
||||
init_client_connection(user, ws_ffi_rwlock)
|
||||
);
|
||||
}
|
||||
pub fn send_message(&self, ) {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
pub mod chat;
|
|
@ -0,0 +1,55 @@
|
|||
use serde::{Serialize, de::DeserializeOwned};
|
||||
|
||||
use crate::{RustError, MessageResource};
|
||||
|
||||
pub fn perform_request_without_client_sync<B: Serialize, R: DeserializeOwned>(
|
||||
base_url: String,
|
||||
method: reqwest::Method,
|
||||
path: String,
|
||||
body: Option<B>,
|
||||
expected_status_code: u16,
|
||||
headers: Vec<(String, String)>,
|
||||
) -> Result<R, RustError> {
|
||||
let client = reqwest::blocking::Client::new();
|
||||
let mut req_incomplete =
|
||||
client.request(method, format!("{url}{path}", url = base_url, path = path));
|
||||
|
||||
for header in headers {
|
||||
req_incomplete = req_incomplete.header(&header.0, &header.1);
|
||||
}
|
||||
|
||||
let req_complete = match body {
|
||||
Some(b) => req_incomplete.json(&b),
|
||||
None => req_incomplete.header("content-length", 0),
|
||||
};
|
||||
println!("{:?}", req_complete);
|
||||
match req_complete.send() {
|
||||
// Error handling here
|
||||
Ok(res) => {
|
||||
// Request sent correctly
|
||||
match res.status().as_u16() == expected_status_code {
|
||||
true => {
|
||||
match res.json::<R>() {
|
||||
Ok(resp_dto) => Ok(resp_dto), // Return correctly deserialized obj
|
||||
Err(err) => Err(RustError::SerdeError{ error: MessageResource { key: "COMMUNICATOR.DESERIALIZE_JSON_FAILED".into(), message: Some(err.to_string()) }, serde_error_str: None }),
|
||||
}
|
||||
}
|
||||
false => {
|
||||
//If status code is any other than expected
|
||||
Err(RustError::UnexpectedStatusCode{
|
||||
expected: expected_status_code,
|
||||
actual: res.status().as_u16(),
|
||||
errors: match res.json::<Vec<MessageResource>>() {
|
||||
Ok(messages) => messages,
|
||||
Err(e) => vec![MessageResource { key: "COMMUNICATOR.NO_ERRORS".into(), message: Some(e.to_string()) }],
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
// Request couldn't be sent
|
||||
Err(RustError::Network{error: MessageResource { key: "COMMUNICATOR.NETWORK".into(), message: Some(e.to_string()) }})
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
use std::sync::{Arc};
|
||||
|
||||
use chat_types::dto::server_out::ServerMessageOut;
|
||||
use tokio_tungstenite::tungstenite::Message;
|
||||
|
||||
use crate::{WebsocketFfi};
|
||||
|
||||
use super::utils::interpret_message;
|
||||
|
||||
|
||||
pub async fn handle_message(message: Message, ws_caller: &Arc<Box<dyn WebsocketFfi>>) -> Result<(), Box<dyn std::error::Error + Send + Sync>>{
|
||||
let server_message_out = interpret_message(message)?;
|
||||
match server_message_out {
|
||||
ServerMessageOut::Acknowledge => {
|
||||
todo!()
|
||||
},
|
||||
ServerMessageOut::LoggedIn => ws_caller.logged_in()?,
|
||||
ServerMessageOut::MessageSent => ws_caller.message_sent()?,
|
||||
ServerMessageOut::MessageRecieved(message) => ws_caller.message_recieved(message.into())?,
|
||||
ServerMessageOut::MessageDelivered(message) => ws_caller.message_delivered(message.into())?,
|
||||
ServerMessageOut::MessageSeen(message) => ws_caller.message_seen(message.into())?,
|
||||
ServerMessageOut::Error(error) => ws_caller.error(error)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
pub mod utils; pub mod handler;
|
||||
|
||||
use std::{sync::{RwLock, Arc}};
|
||||
|
||||
use chat_types::{dto::server_in::ServerMessageIn, domain::error::SocketError};
|
||||
use dev_dtos::dtos::user::user_dtos::UserForAuthenticationDto;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio_tungstenite::{connect_async};
|
||||
use futures_util::{StreamExt};
|
||||
|
||||
use crate::{WebsocketFfi};
|
||||
|
||||
use self::{utils::send_message, handler::handle_message};
|
||||
|
||||
// TODO: Message queue for sending
|
||||
static _MESSAGE_QUEUE: RwLock<Vec<ServerMessageIn>> = RwLock::new(Vec::new());
|
||||
|
||||
pub async fn init_client_connection(user: UserForAuthenticationDto, ws_caller: Arc<Box<dyn WebsocketFfi>>) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let ws_stream = match connect_async("ws://0.0.0.0:3000/websocket").await {
|
||||
Ok((stream, _response)) => {
|
||||
stream
|
||||
}
|
||||
Err(e) => {
|
||||
println!("WebSocket handshake for server failed with {e}!");
|
||||
return Err(SocketError::boxed_error(format!("WebSocket handshake for server failed with {e}!")));
|
||||
}
|
||||
};
|
||||
let (sender, mut receiver) = ws_stream.split();
|
||||
|
||||
//
|
||||
// Login
|
||||
//
|
||||
|
||||
//spawn an async sender to push some more messages into the server
|
||||
let caller = ws_caller.clone();
|
||||
//receiver just prints whatever it gets
|
||||
let mut recv_task = tokio::spawn(async move {
|
||||
while let Some(Ok(msg)) = receiver.next().await {
|
||||
// Never break this loop?
|
||||
let a = handle_message(msg, &caller).await;
|
||||
println!("Something happened {:?}", a);
|
||||
}
|
||||
});
|
||||
let sender_arc = Arc::new(Mutex::new(sender));
|
||||
send_message(sender_arc.clone(), ServerMessageIn::Login(user)).await?;
|
||||
|
||||
//wait for either task to finish and kill the other task
|
||||
tokio::select! {
|
||||
/*_ = (&mut send_task) => {
|
||||
recv_task.abort();
|
||||
},*/
|
||||
_ = (&mut recv_task) => {
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
/*
|
||||
/// Function to handle messages we get (with a slight twist that Frame variant is visible
|
||||
/// since we are working with the underlying tungstenite library directly without axum here).
|
||||
fn process_message(msg: Message) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
match msg {
|
||||
Message::Text(t) => {
|
||||
println!(">>> got str: {:?}", t);
|
||||
}
|
||||
Message::Binary(d) => {
|
||||
println!(">>> got {} bytes: {:?}", d.len(), d);
|
||||
}
|
||||
Message::Close(c) => {
|
||||
if let Some(cf) = c {
|
||||
println!(
|
||||
">>> got close with code {} and reason `{}`",
|
||||
cf.code, cf.reason
|
||||
);
|
||||
} else {
|
||||
println!(">>> somehow got close message without CloseFrame");
|
||||
}
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
|
||||
Message::Pong(v) => {
|
||||
println!(">>> got pong with {:?}", v);
|
||||
}
|
||||
// Just as with axum server, the underlying tungstenite websocket library
|
||||
// will handle Ping for you automagically by replying with Pong and copying the
|
||||
// v according to spec. But if you need the contents of the pings you can see them here.
|
||||
Message::Ping(v) => {
|
||||
println!(">>> got ping with {:?}", v);
|
||||
}
|
||||
|
||||
Message::Frame(_) => {
|
||||
unreachable!("This is never supposed to happen")
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}*/
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use chat_types::{dto::{server_in::{ServerMessageIn, Receivable}, server_out::{ServerMessageOut, Sendable}, message::ClientMessage}, domain::error::SocketError};
|
||||
use futures::{SinkExt};
|
||||
use tokio::sync::Mutex;
|
||||
use tokio_tungstenite::{tungstenite::{Message}};
|
||||
|
||||
|
||||
/// Este es el metodo para enviar mensajes a un cliente a traves de un websocket
|
||||
/// Si le pasas un None en el payload tienes que darle un tipo al metodo, ya que
|
||||
/// El compilador no permite especificarle un metodo default.
|
||||
pub async fn send_message<S>(
|
||||
sender: Arc<Mutex<S>>,
|
||||
message: ServerMessageIn,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> where S: futures_util::Sink<tokio_tungstenite::tungstenite::Message> + Unpin{
|
||||
Ok(
|
||||
match sender
|
||||
.lock()
|
||||
.await
|
||||
.send(Message::Text(serde_json::to_string(
|
||||
&message.into_message()?,
|
||||
)?))
|
||||
.await {
|
||||
Ok(_) => (),
|
||||
Err(_) => return Err(SocketError::boxed_error("Message couldn't be sent for some weird reason...")),
|
||||
})
|
||||
}
|
||||
|
||||
/// use this function to convert a Message::Text() from a client socket connection
|
||||
/// into a ClientMessage<Payload>
|
||||
pub fn interpret_message(
|
||||
message: Message,
|
||||
) -> Result<ServerMessageOut, Box<dyn std::error::Error + Send + Sync>> {
|
||||
if let Message::Text(txt) = message {
|
||||
// txt should be a {"type": "SOMETHING"} or a {"type": "SOMETHING", "payload": {}}
|
||||
let client_message: ClientMessage = serde_json::from_str(txt.as_str())?; //Add error message?
|
||||
Ok(ServerMessageOut::from_message(client_message)?)
|
||||
} else {
|
||||
Err(SocketError::boxed_error(
|
||||
"Recieved client Message is not of type Text...",
|
||||
))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
use dev_dtos::{domain::user::token::Token, dtos::user::user_dtos::{UserForLoginDto, UserForAuthenticationDto}};
|
||||
use league_types::{domain::{sport::Sport, player::Player, league::League, place::Place, league_player::LeaguePlayer, enums::league_player_status::LeaguePlayerStatus, trust::Trust}, dto::{player::{PlayerForCreationDto, PlayerForUpdateDto, PlayerProfileDto}, league::LeagueForCreationDto, league_player::JoinRequest, trust::TrustRequestDto}};
|
||||
|
||||
use reqwest::Method;
|
||||
|
||||
use crate::{client::base::perform_request_without_client_sync as perform_request, RustError};
|
||||
|
||||
pub const BASE_URL: &str = "http://backend.blancoinfante.com/";
|
||||
|
||||
// #############
|
||||
// SPORT ROUTES
|
||||
// #############
|
||||
pub fn get_all_sports() -> Result<Vec<Sport>, RustError> {
|
||||
perform_request::<(), Vec<Sport>>(BASE_URL.to_string(), Method::GET, "league/sport".into(), None, 200, vec![])
|
||||
}
|
||||
|
||||
// #############
|
||||
// PLAYER ROUTES
|
||||
// #############
|
||||
pub fn create_player_profile(player: PlayerForCreationDto) -> Result<Token, RustError> {
|
||||
perform_request::<PlayerForCreationDto, Token>(BASE_URL.to_string(), Method::POST, "league/player".into(), Some(player), 200, vec![])
|
||||
}
|
||||
|
||||
pub fn edit_player_profile(player: PlayerForUpdateDto) -> Result<Player, RustError> {
|
||||
perform_request::<PlayerForUpdateDto, Player>(BASE_URL.to_string(), Method::PUT, "league/player".into(), Some(player), 200, vec![])
|
||||
}
|
||||
|
||||
pub fn login(user: UserForLoginDto) -> Result<Token, RustError> {
|
||||
perform_request::<UserForLoginDto, Token>(BASE_URL.to_string(), Method::POST, "league/player/login".into(), Some(user), 200, vec![])
|
||||
}
|
||||
|
||||
pub fn get_player_profile(player_id: u32) -> Result<PlayerProfileDto, RustError> {
|
||||
perform_request::<(), PlayerProfileDto>(BASE_URL.to_string(), Method::GET, format!("league/player/profile/{}", player_id), None, 200, vec![])
|
||||
}
|
||||
|
||||
pub fn get_player_trusted_list(player_id: u32) -> Result<Vec<Player>, RustError> {
|
||||
perform_request::<(), Vec<Player>>(BASE_URL.to_string(), Method::GET, format!("league/player/trusted_by/{}", player_id), None, 200, vec![])
|
||||
}
|
||||
|
||||
// #############
|
||||
// LEAGUE ROUTES
|
||||
// #############
|
||||
pub fn create_league(league: LeagueForCreationDto) -> Result<League, RustError> {
|
||||
perform_request::<LeagueForCreationDto, League>(BASE_URL.to_string(), Method::POST, "league/league".into(), Some(league), 200, vec![])
|
||||
}
|
||||
|
||||
pub fn get_open_leagues_in_my_area(page: u16, user: UserForAuthenticationDto) -> Result<Vec<League>, RustError> {
|
||||
perform_request::<UserForAuthenticationDto, Vec<League>>(BASE_URL.to_string(), Method::POST, format!("league/league/nearme/{}", page), Some(user), 200, vec![])
|
||||
}
|
||||
|
||||
pub fn get_leagues_in_my_country(country: String, page: u16) -> Result<Vec<League>, RustError> {
|
||||
perform_request::<(), Vec<League>>(BASE_URL.to_string(), Method::GET, format!("league/league/{}/{}", country, page), None, 200, vec![])
|
||||
}
|
||||
|
||||
pub fn get_specific_league(league_id: u32) -> Result<League, RustError> {
|
||||
perform_request::<(), League>(BASE_URL.to_string(), Method::GET, format!("league/league/{}", league_id), None, 200, vec![])
|
||||
}
|
||||
|
||||
pub fn get_leagues_hosted_by_player(user: UserForAuthenticationDto, player_id: u32, page: u16) -> Result<Vec<League>, RustError> {
|
||||
perform_request::<UserForAuthenticationDto, Vec<League>>(BASE_URL.to_string(), Method::POST, format!("league/league/player/{}/{}", player_id, page), Some(user), 200, vec![])
|
||||
}
|
||||
|
||||
pub fn get_leagues_in_place(place_id: u32, page: u16) -> Result<Vec<League>, RustError> {
|
||||
perform_request::<(), Vec<League>>(BASE_URL.to_string(), Method::GET, format!("league/league/place/{}/{}", place_id, page), None, 200, vec![])
|
||||
}
|
||||
|
||||
pub fn get_average_league_age(user: UserForAuthenticationDto, league_id: u32) -> Result<u8, RustError> {
|
||||
perform_request::<UserForAuthenticationDto, u8>(BASE_URL.to_string(), Method::POST, format!("league/league/{}/age", league_id), Some(user), 200, vec![])
|
||||
}
|
||||
|
||||
// #############
|
||||
// PLACE ROUTES
|
||||
// #############
|
||||
pub fn get_places_for_country(country: String, page: u16) -> Result<Vec<Place>, RustError> {
|
||||
perform_request::<(), Vec<Place>>(BASE_URL.to_string(), Method::GET, format!("league/place/country/{}/page/{}", country, page), None, 200, vec![])
|
||||
}
|
||||
|
||||
pub fn get_places_for_sport(sport_id: u32, page: u16) -> Result<Vec<Place>, RustError> {
|
||||
perform_request::<(), Vec<Place>>(BASE_URL.to_string(), Method::GET, format!("league/place/sport/{}/page/{}", sport_id, page), None, 200, vec![])
|
||||
}
|
||||
|
||||
pub fn get_places_in_my_area(user: UserForAuthenticationDto, page: u16) -> Result<Vec<Place>, RustError> {
|
||||
perform_request::<UserForAuthenticationDto, Vec<Place>>(BASE_URL.to_string(), Method::POST, format!("league/place/nearme/{}", page), Some(user), 200, vec![])
|
||||
}
|
||||
|
||||
// ####################
|
||||
// LEAGUE_PLAYER ROUTES
|
||||
// ####################
|
||||
pub fn request_to_join_league(join_req: JoinRequest) -> Result<LeaguePlayer, RustError> {
|
||||
perform_request::<JoinRequest, LeaguePlayer>(BASE_URL.to_string(), Method::POST, "league/league_player/request".into(), Some(join_req), 200, vec![])
|
||||
}
|
||||
|
||||
pub fn get_league_request_status(join_req: JoinRequest) -> Result<LeaguePlayer, RustError> {
|
||||
perform_request::<JoinRequest, LeaguePlayer>(BASE_URL.to_string(), Method::POST, "league/league_player/request/status".into(), Some(join_req), 200, vec![])
|
||||
}
|
||||
|
||||
pub fn change_league_request_status(status: LeaguePlayerStatus, join_req: JoinRequest) -> Result<LeaguePlayer, RustError> {
|
||||
perform_request::<JoinRequest, LeaguePlayer>(BASE_URL.to_string(), Method::PUT, format!("league/league_player/request/{}", status), Some(join_req), 200, vec![])
|
||||
}
|
||||
|
||||
pub fn get_all_leagues_player_has_applied_to(join_req: JoinRequest, page: u16) -> Result<Vec<League>, RustError> {
|
||||
perform_request::<JoinRequest, Vec<League>>(BASE_URL.to_string(), Method::POST, format!("league/league_player/leagues/{}", page), Some(join_req), 200, vec![])
|
||||
}
|
||||
|
||||
pub fn get_all_players_in_league(join_req: JoinRequest) -> Result<Vec<Player>, RustError> {
|
||||
perform_request::<JoinRequest, Vec<Player>>(BASE_URL.to_string(), Method::POST, "league/league_player/players".into(), Some(join_req), 200, vec![])
|
||||
}
|
||||
|
||||
// #############
|
||||
// TRUST ROUTES
|
||||
// #############
|
||||
pub fn add_trusted_player(trust_req: TrustRequestDto) -> Result<Trust, RustError> {
|
||||
perform_request::<TrustRequestDto, Trust>(BASE_URL.to_string(), Method::POST, "league/trust".into(), Some(trust_req), 200, vec![])
|
||||
}
|
||||
|
||||
pub fn remove_trusted_player(trust_req: TrustRequestDto) -> Result<Trust, RustError> {
|
||||
perform_request::<TrustRequestDto, Trust>(BASE_URL.to_string(), Method::DELETE, "league/trust".into(), Some(trust_req), 200, vec![])
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
pub mod league;
|
||||
pub mod base;
|
||||
pub mod chat;
|
|
@ -0,0 +1,34 @@
|
|||
uniffi_macros::include_scaffolding!("network");
|
||||
|
||||
pub mod types;
|
||||
pub mod client;
|
||||
pub mod utils;
|
||||
pub mod callbacks;
|
||||
|
||||
pub use chat_types::client_types::chat_room::ChatRoom;
|
||||
pub use dev_dtos::dtos::user::user_dtos::UserForAuthenticationDto;
|
||||
use utils::storage;
|
||||
pub use utils::storage::*;
|
||||
pub use callbacks::chat::*;
|
||||
|
||||
pub use league_types::domain::sport::Sport;
|
||||
pub use types::error::*;
|
||||
//pub use chat_communicators::client::chat::*;
|
||||
pub use chat_types::client_types::chat_message::*;
|
||||
|
||||
pub fn get_all_sports() -> Result<Vec<Sport>, RustError> {
|
||||
client::league::get_all_sports()
|
||||
}
|
||||
|
||||
pub fn get_me() -> Result<UserForAuthenticationDto, RustError> {
|
||||
storage::read("user".into())
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! unwrap_rust_error {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
Ok(result) => result,
|
||||
Err(error) => return Err(error.into())
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,373 @@
|
|||
// This file was autogenerated by some hot garbage in the `uniffi` crate.
|
||||
// Trust me, you don't want to mess with it!
|
||||
import Foundation
|
||||
|
||||
// Depending on the consumer's build setup, the low-level FFI code
|
||||
// might be in a separate module, or it might be compiled inline into
|
||||
// this module. This is a bit of light hackery to work with both.
|
||||
#if canImport(networkFFI)
|
||||
import networkFFI
|
||||
#endif
|
||||
|
||||
fileprivate extension RustBuffer {
|
||||
// Allocate a new buffer, copying the contents of a `UInt8` array.
|
||||
init(bytes: [UInt8]) {
|
||||
let rbuf = bytes.withUnsafeBufferPointer { ptr in
|
||||
RustBuffer.from(ptr)
|
||||
}
|
||||
self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data)
|
||||
}
|
||||
|
||||
static func from(_ ptr: UnsafeBufferPointer<UInt8>) -> RustBuffer {
|
||||
try! rustCall { ffi_network_a3fa_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) }
|
||||
}
|
||||
|
||||
// Frees the buffer in place.
|
||||
// The buffer must not be used after this is called.
|
||||
func deallocate() {
|
||||
try! rustCall { ffi_network_a3fa_rustbuffer_free(self, $0) }
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension ForeignBytes {
|
||||
init(bufferPointer: UnsafeBufferPointer<UInt8>) {
|
||||
self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress)
|
||||
}
|
||||
}
|
||||
|
||||
// For every type used in the interface, we provide helper methods for conveniently
|
||||
// lifting and lowering that type from C-compatible data, and for reading and writing
|
||||
// values of that type in a buffer.
|
||||
|
||||
// Helper classes/extensions that don't change.
|
||||
// Someday, this will be in a libray of its own.
|
||||
|
||||
fileprivate extension Data {
|
||||
init(rustBuffer: RustBuffer) {
|
||||
// TODO: This copies the buffer. Can we read directly from a
|
||||
// Rust buffer?
|
||||
self.init(bytes: rustBuffer.data!, count: Int(rustBuffer.len))
|
||||
}
|
||||
}
|
||||
|
||||
// A helper class to read values out of a byte buffer.
|
||||
fileprivate class Reader {
|
||||
let data: Data
|
||||
var offset: Data.Index
|
||||
|
||||
init(data: Data) {
|
||||
self.data = data
|
||||
self.offset = 0
|
||||
}
|
||||
|
||||
// Reads an integer at the current offset, in big-endian order, and advances
|
||||
// the offset on success. Throws if reading the integer would move the
|
||||
// offset past the end of the buffer.
|
||||
func readInt<T: FixedWidthInteger>() throws -> T {
|
||||
let range = offset..<offset + MemoryLayout<T>.size
|
||||
guard data.count >= range.upperBound else {
|
||||
throw UniffiInternalError.bufferOverflow
|
||||
}
|
||||
if T.self == UInt8.self {
|
||||
let value = data[offset]
|
||||
offset += 1
|
||||
return value as! T
|
||||
}
|
||||
var value: T = 0
|
||||
let _ = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0, from: range)})
|
||||
offset = range.upperBound
|
||||
return value.bigEndian
|
||||
}
|
||||
|
||||
// Reads an arbitrary number of bytes, to be used to read
|
||||
// raw bytes, this is useful when lifting strings
|
||||
func readBytes(count: Int) throws -> Array<UInt8> {
|
||||
let range = offset..<(offset+count)
|
||||
guard data.count >= range.upperBound else {
|
||||
throw UniffiInternalError.bufferOverflow
|
||||
}
|
||||
var value = [UInt8](repeating: 0, count: count)
|
||||
value.withUnsafeMutableBufferPointer({ buffer in
|
||||
data.copyBytes(to: buffer, from: range)
|
||||
})
|
||||
offset = range.upperBound
|
||||
return value
|
||||
}
|
||||
|
||||
// Reads a float at the current offset.
|
||||
@inlinable
|
||||
func readFloat() throws -> Float {
|
||||
return Float(bitPattern: try readInt())
|
||||
}
|
||||
|
||||
// Reads a float at the current offset.
|
||||
@inlinable
|
||||
func readDouble() throws -> Double {
|
||||
return Double(bitPattern: try readInt())
|
||||
}
|
||||
|
||||
// Indicates if the offset has reached the end of the buffer.
|
||||
@inlinable
|
||||
func hasRemaining() -> Bool {
|
||||
return offset < data.count
|
||||
}
|
||||
}
|
||||
|
||||
// A helper class to write values into a byte buffer.
|
||||
fileprivate class Writer {
|
||||
var bytes: [UInt8]
|
||||
var offset: Array<UInt8>.Index
|
||||
|
||||
init() {
|
||||
self.bytes = []
|
||||
self.offset = 0
|
||||
}
|
||||
|
||||
func writeBytes<S>(_ byteArr: S) where S: Sequence, S.Element == UInt8 {
|
||||
bytes.append(contentsOf: byteArr)
|
||||
}
|
||||
|
||||
// Writes an integer in big-endian order.
|
||||
//
|
||||
// Warning: make sure what you are trying to write
|
||||
// is in the correct type!
|
||||
func writeInt<T: FixedWidthInteger>(_ value: T) {
|
||||
var value = value.bigEndian
|
||||
withUnsafeBytes(of: &value) { bytes.append(contentsOf: $0) }
|
||||
}
|
||||
|
||||
@inlinable
|
||||
func writeFloat(_ value: Float) {
|
||||
writeInt(value.bitPattern)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
func writeDouble(_ value: Double) {
|
||||
writeInt(value.bitPattern)
|
||||
}
|
||||
}
|
||||
|
||||
// Protocol for types that transfer other types across the FFI. This is
|
||||
// analogous go the Rust trait of the same name.
|
||||
fileprivate protocol FfiConverter {
|
||||
associatedtype FfiType
|
||||
associatedtype SwiftType
|
||||
|
||||
static func lift(_ value: FfiType) throws -> SwiftType
|
||||
static func lower(_ value: SwiftType) -> FfiType
|
||||
static func read(from buf: Reader) throws -> SwiftType
|
||||
static func write(_ value: SwiftType, into buf: Writer)
|
||||
}
|
||||
|
||||
// Types conforming to `Primitive` pass themselves directly over the FFI.
|
||||
fileprivate protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType { }
|
||||
|
||||
extension FfiConverterPrimitive {
|
||||
static func lift(_ value: FfiType) throws -> SwiftType {
|
||||
return value
|
||||
}
|
||||
|
||||
static func lower(_ value: SwiftType) -> FfiType {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`.
|
||||
// Used for complex types where it's hard to write a custom lift/lower.
|
||||
fileprivate protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {}
|
||||
|
||||
extension FfiConverterRustBuffer {
|
||||
static func lift(_ buf: RustBuffer) throws -> SwiftType {
|
||||
let reader = Reader(data: Data(rustBuffer: buf))
|
||||
let value = try read(from: reader)
|
||||
if reader.hasRemaining() {
|
||||
throw UniffiInternalError.incompleteData
|
||||
}
|
||||
buf.deallocate()
|
||||
return value
|
||||
}
|
||||
|
||||
static func lower(_ value: SwiftType) -> RustBuffer {
|
||||
let writer = Writer()
|
||||
write(value, into: writer)
|
||||
return RustBuffer(bytes: writer.bytes)
|
||||
}
|
||||
}
|
||||
// An error type for FFI errors. These errors occur at the UniFFI level, not
|
||||
// the library level.
|
||||
fileprivate enum UniffiInternalError: LocalizedError {
|
||||
case bufferOverflow
|
||||
case incompleteData
|
||||
case unexpectedOptionalTag
|
||||
case unexpectedEnumCase
|
||||
case unexpectedNullPointer
|
||||
case unexpectedRustCallStatusCode
|
||||
case unexpectedRustCallError
|
||||
case unexpectedStaleHandle
|
||||
case rustPanic(_ message: String)
|
||||
|
||||
public var errorDescription: String? {
|
||||
switch self {
|
||||
case .bufferOverflow: return "Reading the requested value would read past the end of the buffer"
|
||||
case .incompleteData: return "The buffer still has data after lifting its containing value"
|
||||
case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1"
|
||||
case .unexpectedEnumCase: return "Raw enum value doesn't match any cases"
|
||||
case .unexpectedNullPointer: return "Raw pointer value was null"
|
||||
case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code"
|
||||
case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified"
|
||||
case .unexpectedStaleHandle: return "The object in the handle map has been dropped already"
|
||||
case let .rustPanic(message): return message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate let CALL_SUCCESS: Int8 = 0
|
||||
fileprivate let CALL_ERROR: Int8 = 1
|
||||
fileprivate let CALL_PANIC: Int8 = 2
|
||||
|
||||
fileprivate extension RustCallStatus {
|
||||
init() {
|
||||
self.init(
|
||||
code: CALL_SUCCESS,
|
||||
errorBuf: RustBuffer.init(
|
||||
capacity: 0,
|
||||
len: 0,
|
||||
data: nil
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private func rustCall<T>(_ callback: (UnsafeMutablePointer<RustCallStatus>) -> T) throws -> T {
|
||||
try makeRustCall(callback, errorHandler: {
|
||||
$0.deallocate()
|
||||
return UniffiInternalError.unexpectedRustCallError
|
||||
})
|
||||
}
|
||||
|
||||
private func rustCallWithError<T, F: FfiConverter>
|
||||
(_ errorFfiConverter: F.Type, _ callback: (UnsafeMutablePointer<RustCallStatus>) -> T) throws -> T
|
||||
where F.SwiftType: Error, F.FfiType == RustBuffer
|
||||
{
|
||||
try makeRustCall(callback, errorHandler: { return try errorFfiConverter.lift($0) })
|
||||
}
|
||||
|
||||
private func makeRustCall<T>(_ callback: (UnsafeMutablePointer<RustCallStatus>) -> T, errorHandler: (RustBuffer) throws -> Error) throws -> T {
|
||||
var callStatus = RustCallStatus.init()
|
||||
let returnedVal = callback(&callStatus)
|
||||
switch callStatus.code {
|
||||
case CALL_SUCCESS:
|
||||
return returnedVal
|
||||
|
||||
case CALL_ERROR:
|
||||
throw try errorHandler(callStatus.errorBuf)
|
||||
|
||||
case CALL_PANIC:
|
||||
// When the rust code sees a panic, it tries to construct a RustBuffer
|
||||
// with the message. But if that code panics, then it just sends back
|
||||
// an empty buffer.
|
||||
if callStatus.errorBuf.len > 0 {
|
||||
throw UniffiInternalError.rustPanic(try FfiConverterString.lift(callStatus.errorBuf))
|
||||
} else {
|
||||
callStatus.errorBuf.deallocate()
|
||||
throw UniffiInternalError.rustPanic("Rust panic")
|
||||
}
|
||||
|
||||
default:
|
||||
throw UniffiInternalError.unexpectedRustCallStatusCode
|
||||
}
|
||||
}
|
||||
|
||||
// Public interface members begin here.
|
||||
|
||||
|
||||
fileprivate struct FfiConverterUInt8: FfiConverterPrimitive {
|
||||
typealias FfiType = UInt8
|
||||
typealias SwiftType = UInt8
|
||||
|
||||
static func read(from buf: Reader) throws -> UInt8 {
|
||||
return try lift(buf.readInt())
|
||||
}
|
||||
|
||||
static func write(_ value: UInt8, into buf: Writer) {
|
||||
buf.writeInt(lower(value))
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate struct FfiConverterInt32: FfiConverterPrimitive {
|
||||
typealias FfiType = Int32
|
||||
typealias SwiftType = Int32
|
||||
|
||||
static func read(from buf: Reader) throws -> Int32 {
|
||||
return try lift(buf.readInt())
|
||||
}
|
||||
|
||||
static func write(_ value: Int32, into buf: Writer) {
|
||||
buf.writeInt(lower(value))
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate struct FfiConverterString: FfiConverter {
|
||||
typealias SwiftType = String
|
||||
typealias FfiType = RustBuffer
|
||||
|
||||
static func lift(_ value: RustBuffer) throws -> String {
|
||||
defer {
|
||||
value.deallocate()
|
||||
}
|
||||
if value.data == nil {
|
||||
return String()
|
||||
}
|
||||
let bytes = UnsafeBufferPointer<UInt8>(start: value.data!, count: Int(value.len))
|
||||
return String(bytes: bytes, encoding: String.Encoding.utf8)!
|
||||
}
|
||||
|
||||
static func lower(_ value: String) -> RustBuffer {
|
||||
return value.utf8CString.withUnsafeBufferPointer { ptr in
|
||||
// The swift string gives us int8_t, we want uint8_t.
|
||||
ptr.withMemoryRebound(to: UInt8.self) { ptr in
|
||||
// The swift string gives us a trailing null byte, we don't want it.
|
||||
let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1))
|
||||
return RustBuffer.from(buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func read(from buf: Reader) throws -> String {
|
||||
let len: Int32 = try buf.readInt()
|
||||
return String(bytes: try buf.readBytes(count: Int(len)), encoding: String.Encoding.utf8)!
|
||||
}
|
||||
|
||||
static func write(_ value: String, into buf: Writer) {
|
||||
let len = Int32(value.utf8.count)
|
||||
buf.writeInt(len)
|
||||
buf.writeBytes(value.utf8)
|
||||
}
|
||||
}
|
||||
|
||||
public func `deez`(`ab`: Int32) -> UInt8 {
|
||||
return try! FfiConverterUInt8.lift(
|
||||
try!
|
||||
|
||||
rustCall() {
|
||||
|
||||
network_a3fa_deez(
|
||||
FfiConverterInt32.lower(`ab`), $0)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Top level initializers and tear down methods.
|
||||
*
|
||||
* This is generated by uniffi.
|
||||
*/
|
||||
public enum NetworkLifecycle {
|
||||
/**
|
||||
* Initialize the FFI and Rust library. This should be only called once per application.
|
||||
*/
|
||||
func initialize() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
dictionary MessageResource {
|
||||
string key;
|
||||
string? message;
|
||||
};
|
||||
dictionary Sport {
|
||||
u32 id;
|
||||
string name;
|
||||
u32 category_id;
|
||||
};
|
||||
[Error]
|
||||
enum RustError {
|
||||
"Network",
|
||||
"UnexpectedStatusCode",
|
||||
"SerdeError",
|
||||
"IO",
|
||||
"Uknown",
|
||||
};
|
||||
[Error]
|
||||
enum ForeignError {
|
||||
"FfiCallbackError"
|
||||
};
|
||||
dictionary UserForAuthenticationDto {
|
||||
string app;
|
||||
string id;
|
||||
string token;
|
||||
};
|
||||
|
||||
dictionary TimeSensitiveAction {
|
||||
u32 by;
|
||||
i64 time;
|
||||
};
|
||||
enum MessageContentType {
|
||||
"Text",
|
||||
"Image",
|
||||
"Audio",
|
||||
"Video",
|
||||
};
|
||||
dictionary ChatMessage {
|
||||
u32 id;
|
||||
u32 from_id;
|
||||
u32 to_id;
|
||||
sequence<u8> message;
|
||||
MessageContentType message_content;
|
||||
i64 time_sent;
|
||||
sequence<TimeSensitiveAction> time_delivered;
|
||||
sequence<TimeSensitiveAction> time_seen;
|
||||
};
|
||||
dictionary ChatRoom {
|
||||
u32 id;
|
||||
string title;
|
||||
u32 owner_id;
|
||||
i64 time_created;
|
||||
i64 last_updated;
|
||||
u64 session_messages;
|
||||
};
|
||||
|
||||
enum ClientError {
|
||||
"One",
|
||||
"Two",
|
||||
"Three",
|
||||
};
|
||||
|
||||
callback interface WebsocketFfi {
|
||||
[Throws=ForeignError]
|
||||
void message_recieved(ChatMessage message);
|
||||
[Throws=ForeignError]
|
||||
void logged_in();
|
||||
[Throws=ForeignError]
|
||||
void message_seen(ChatMessage message);
|
||||
[Throws=ForeignError]
|
||||
void message_delivered(ChatMessage message);
|
||||
[Throws=ForeignError]
|
||||
void message_sent();
|
||||
[Throws=ForeignError]
|
||||
void error(string error);
|
||||
[Throws=ForeignError]
|
||||
void client_error(ClientError error);
|
||||
};
|
||||
interface WebsocketCaller {
|
||||
constructor();
|
||||
void init_ws_connection(WebsocketFfi websocket_ffi);
|
||||
};
|
||||
namespace network {
|
||||
[Throws=RustError]
|
||||
UserForAuthenticationDto get_me();
|
||||
[Throws=RustError]
|
||||
sequence<Sport> get_all_sports();
|
||||
void init_storage(string path);
|
||||
};
|
|
@ -0,0 +1,68 @@
|
|||
// This file was autogenerated by some hot garbage in the `uniffi` crate.
|
||||
// Trust me, you don't want to mess with it!
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// The following structs are used to implement the lowest level
|
||||
// of the FFI, and thus useful to multiple uniffied crates.
|
||||
// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H.
|
||||
#ifdef UNIFFI_SHARED_H
|
||||
// We also try to prevent mixing versions of shared uniffi header structs.
|
||||
// If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V4
|
||||
#ifndef UNIFFI_SHARED_HEADER_V4
|
||||
#error Combining helper code from multiple versions of uniffi is not supported
|
||||
#endif // ndef UNIFFI_SHARED_HEADER_V4
|
||||
#else
|
||||
#define UNIFFI_SHARED_H
|
||||
#define UNIFFI_SHARED_HEADER_V4
|
||||
// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️
|
||||
// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️
|
||||
|
||||
typedef struct RustBuffer
|
||||
{
|
||||
int32_t capacity;
|
||||
int32_t len;
|
||||
uint8_t *_Nullable data;
|
||||
} RustBuffer;
|
||||
|
||||
typedef int32_t (*ForeignCallback)(uint64_t, int32_t, RustBuffer, RustBuffer *_Nonnull);
|
||||
|
||||
typedef struct ForeignBytes
|
||||
{
|
||||
int32_t len;
|
||||
const uint8_t *_Nullable data;
|
||||
} ForeignBytes;
|
||||
|
||||
// Error definitions
|
||||
typedef struct RustCallStatus {
|
||||
int8_t code;
|
||||
RustBuffer errorBuf;
|
||||
} RustCallStatus;
|
||||
|
||||
// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️
|
||||
// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️
|
||||
#endif // def UNIFFI_SHARED_H
|
||||
|
||||
uint8_t network_a3fa_deez(
|
||||
int32_t ab,
|
||||
RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
RustBuffer ffi_network_a3fa_rustbuffer_alloc(
|
||||
int32_t size,
|
||||
RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
RustBuffer ffi_network_a3fa_rustbuffer_from_bytes(
|
||||
ForeignBytes bytes,
|
||||
RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
void ffi_network_a3fa_rustbuffer_free(
|
||||
RustBuffer buf,
|
||||
RustCallStatus *_Nonnull out_status
|
||||
);
|
||||
RustBuffer ffi_network_a3fa_rustbuffer_reserve(
|
||||
RustBuffer buf,int32_t additional,
|
||||
RustCallStatus *_Nonnull out_status
|
||||
);
|
|
@ -0,0 +1,6 @@
|
|||
// This file was autogenerated by some hot garbage in the `uniffi` crate.
|
||||
// Trust me, you don't want to mess with it!
|
||||
module networkFFI {
|
||||
header "networkFFI.h"
|
||||
export *
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
use std::fmt::Display;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Debug, thiserror::Error, Serialize, Deserialize, Clone, PartialEq, PartialOrd)]
|
||||
pub struct MessageResource {
|
||||
pub key: String,
|
||||
pub message: Option<String>
|
||||
}
|
||||
impl Display for MessageResource {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "MessageResource: Key: {}, Error: {:?}", self.key, self.message)
|
||||
}
|
||||
}
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum RustError {
|
||||
#[error("Network Error {error}")]
|
||||
Network{error: MessageResource},
|
||||
#[error("UnexpectedStatusCode expected: {expected}, actual: {actual}, errors: {:?}", errors)]
|
||||
UnexpectedStatusCode{expected: u16, actual: u16, errors: Vec<MessageResource>},
|
||||
#[error("SerdeError Error {error}, attempted to SerdeError string: {:?}", serde_error_str)]
|
||||
SerdeError{error: MessageResource, serde_error_str: Option<String>},
|
||||
#[error("IOError Error {error} ")]
|
||||
IO{error: MessageResource},
|
||||
#[error("Uknown error")]
|
||||
Uknown,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum ForeignError {
|
||||
#[error("FFiCallbackError")]
|
||||
FfiCallbackError,
|
||||
|
||||
}
|
||||
|
||||
impl From<err::Error> for RustError {
|
||||
fn from(value: err::Error) -> Self {
|
||||
match value {
|
||||
err::Error::Network(msg) => RustError::Network { error: msg.into() },
|
||||
err::Error::IO(msg) => RustError::IO { error: msg.into() },
|
||||
err::Error::UnexpectedStatusCode(expected, actual, messages) => RustError::UnexpectedStatusCode { expected, actual, errors: messages.into_iter().map(|message| message.into()).collect::<Vec<crate::MessageResource>>() },
|
||||
err::Error::Serde(msg) => RustError::SerdeError { error: msg.into(), serde_error_str: None },
|
||||
_ => RustError::Uknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_error(error: err::Error) -> RustError {
|
||||
error.into()
|
||||
}
|
||||
|
||||
impl From<err::MessageResource> for crate::types::error::MessageResource {
|
||||
fn from(value: err::MessageResource) -> Self {
|
||||
Self { key: match value.key {
|
||||
Some(key) => key,
|
||||
None => "".into(),
|
||||
}, message: Some(value.message) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<uniffi::UnexpectedUniFFICallbackError> for ForeignError {
|
||||
fn from(_value: uniffi::UnexpectedUniFFICallbackError) -> Self {
|
||||
Self::FfiCallbackError
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
pub mod error;
|
|
@ -0,0 +1 @@
|
|||
pub mod storage;
|
|
@ -0,0 +1,41 @@
|
|||
use std::{sync::RwLock, fs};
|
||||
|
||||
use dev_dtos::dtos::user::user_dtos::UserForAuthenticationDto;
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
|
||||
use crate::{RustError, MessageResource};
|
||||
|
||||
static STORAGE_PATH: RwLock<String> = RwLock::new(String::new());
|
||||
|
||||
/// This function MUST BE CALLED on startup or else Storage won't work at all
|
||||
pub fn init_storage(path: String) {
|
||||
let mut write = STORAGE_PATH.write().expect("FATAL ERROR. FAILED TO SECURE A RWLOCK CORRECTLY. STORAGE WON'T WORK NOW.");
|
||||
*write = path;
|
||||
drop(write);
|
||||
// TESTING PURPOSES
|
||||
store(UserForAuthenticationDto{ app: "".into(), id: "3".into(), token: "/2uuNJG3Z2bT9VVd64xBeACPxg64GicloiXtG9uO87as5q5g46TtNu0sAVTACyR8R8uMVXoTBlBP4Q3JhcGB2Q==".to_string() }, "user".into()).unwrap();
|
||||
println!("Wrote shit");
|
||||
}
|
||||
|
||||
// These functions won't be exposed to the clients, just used by the functions they call internally
|
||||
|
||||
pub fn store<T: Serialize>(ty: T, path: String) -> Result<(), RustError>{
|
||||
let serialized_ty = match bincode::serialize(&ty) {
|
||||
Ok(bytes) => bytes,
|
||||
Err(e) => return Err(RustError::SerdeError { error: MessageResource { key: "STORAGE.OBJECT_SERIALIZATION".into(), message: Some(e.to_string()) }, serde_error_str: None }),
|
||||
};
|
||||
match fs::write(format!("{}/{}", STORAGE_PATH.read().unwrap(), path), serialized_ty) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(RustError::IO { error: MessageResource { key:"STORAGE.OBJECT_WRITING".into(), message: Some(e.to_string())} }),
|
||||
}
|
||||
}
|
||||
pub fn read<T: DeserializeOwned>(path: String) -> Result<T, RustError> {
|
||||
let bytes = match fs::read(format!("{}/{}", STORAGE_PATH.read().unwrap(), path)) {
|
||||
Ok(bytes) => bytes,
|
||||
Err(e) => return Err(RustError::IO { error: MessageResource { key:"STORAGE.OBJECT_READING".into(), message: Some(e.to_string())} }),
|
||||
};
|
||||
match bincode::deserialize(&bytes) {
|
||||
Ok(object) => Ok(object),
|
||||
Err(e) => return Err(RustError::SerdeError { error: MessageResource { key: "STORAGE.OBJECT_DESERIALIZATION".into(), message: Some(e.to_string()) }, serde_error_str: None }),
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue