forked from Lonami/Talaria
Make use of errors in the UDL
This commit is contained in:
parent
004a921299
commit
d11a00d062
|
@ -11,6 +11,7 @@ use log;
|
||||||
use log::{error, info, Level};
|
use log::{error, info, Level};
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::fmt;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||||
|
@ -21,8 +22,6 @@ use tokio::runtime::Runtime;
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/talaria.uniffi.rs"));
|
include!(concat!(env!("OUT_DIR"), "/talaria.uniffi.rs"));
|
||||||
|
|
||||||
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
|
||||||
|
|
||||||
const LOG_MIN_LEVEL: Level = Level::Trace;
|
const LOG_MIN_LEVEL: Level = Level::Trace;
|
||||||
const LOG_TAG: &str = ".native.talari";
|
const LOG_TAG: &str = ".native.talari";
|
||||||
const API_ID: i32 = {
|
const API_ID: i32 = {
|
||||||
|
@ -46,6 +45,25 @@ static RUNTIME: OnceCell<Runtime> = OnceCell::new();
|
||||||
static CLIENT: OnceCell<Client> = OnceCell::new();
|
static CLIENT: OnceCell<Client> = OnceCell::new();
|
||||||
static DATABASE: Mutex<Option<sqlite::Connection>> = Mutex::new(None);
|
static DATABASE: Mutex<Option<sqlite::Connection>> = Mutex::new(None);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum NativeError {
|
||||||
|
Initialization,
|
||||||
|
Database,
|
||||||
|
Network,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for NativeError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Initialization => write!(f, "a resource could not be initialized correctly"),
|
||||||
|
Self::Database => write!(f, "a query to the local database failed"),
|
||||||
|
Self::Network => write!(f, "a network request could not complete successfully"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for NativeError {}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum MessageAck {
|
pub enum MessageAck {
|
||||||
Received,
|
Received,
|
||||||
|
@ -69,6 +87,8 @@ pub struct Dialog {
|
||||||
pinned: bool,
|
pinned: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Result<T> = std::result::Result<T, NativeError>;
|
||||||
|
|
||||||
fn block_on<F: Future>(future: F) -> F::Output {
|
fn block_on<F: Future>(future: F) -> F::Output {
|
||||||
if RUNTIME.get().is_none() {
|
if RUNTIME.get().is_none() {
|
||||||
RUNTIME
|
RUNTIME
|
||||||
|
@ -100,7 +120,8 @@ async fn init_client() -> Result<()> {
|
||||||
let conn = match guard.as_ref() {
|
let conn = match guard.as_ref() {
|
||||||
Some(c) => c,
|
Some(c) => c,
|
||||||
None => {
|
None => {
|
||||||
return Err("Database was not initialized".into());
|
error!("Database was not initialized");
|
||||||
|
return Err(NativeError::Initialization);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -108,7 +129,7 @@ async fn init_client() -> Result<()> {
|
||||||
|
|
||||||
let session = Session::new();
|
let session = Session::new();
|
||||||
|
|
||||||
let sessions = db::get_sessions(conn)?;
|
let sessions = db::get_sessions(conn).map_err(|_| NativeError::Database)?;
|
||||||
if let Some(s) = sessions.get(0) {
|
if let Some(s) = sessions.get(0) {
|
||||||
match (s.user_id, s.dc_id, s.bot) {
|
match (s.user_id, s.dc_id, s.bot) {
|
||||||
(Some(id), Some(dc), Some(bot)) => session.set_user(id, dc, bot),
|
(Some(id), Some(dc), Some(bot)) => session.set_user(id, dc, bot),
|
||||||
|
@ -147,41 +168,51 @@ async fn init_client() -> Result<()> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.await?;
|
.await
|
||||||
|
.map_err(|_| NativeError::Network)?;
|
||||||
|
|
||||||
info!("Connected!");
|
info!("Connected!");
|
||||||
|
|
||||||
CLIENT
|
CLIENT
|
||||||
.set(client)
|
.set(client)
|
||||||
.map_err(|_| "Client was already initialized")?;
|
.map_err(|_| NativeError::Initialization)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn need_login() -> Result<bool> {
|
async fn need_login() -> Result<bool> {
|
||||||
let client = CLIENT.get().ok_or("Client not initialized")?;
|
let client = CLIENT.get().ok_or(NativeError::Initialization)?;
|
||||||
Ok(client.is_authorized().await?)
|
client
|
||||||
|
.is_authorized()
|
||||||
|
.await
|
||||||
|
.map_err(|_| NativeError::Network)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn request_login_code(phone: &str) -> Result<LoginToken> {
|
async fn request_login_code(phone: &str) -> Result<LoginToken> {
|
||||||
let client = CLIENT.get().ok_or("Client not initialized")?;
|
let client = CLIENT.get().ok_or(NativeError::Initialization)?;
|
||||||
let token = client.request_login_code(&phone, API_ID, API_HASH).await?;
|
client
|
||||||
Ok(token)
|
.request_login_code(&phone, API_ID, API_HASH)
|
||||||
|
.await
|
||||||
|
.map_err(|_| NativeError::Network)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn sign_in(token: LoginToken, code: &str) -> Result<()> {
|
async fn sign_in(token: LoginToken, code: &str) -> Result<()> {
|
||||||
let client = CLIENT.get().ok_or("Client not initialized")?;
|
let client = CLIENT.get().ok_or(NativeError::Initialization)?;
|
||||||
client.sign_in(&token, &code).await?;
|
client
|
||||||
|
.sign_in(&token, &code)
|
||||||
|
.await
|
||||||
|
.map_err(|_| NativeError::Network)?;
|
||||||
|
|
||||||
let guard = DATABASE.lock().unwrap();
|
let guard = DATABASE.lock().unwrap();
|
||||||
let conn = match guard.as_ref() {
|
let conn = match guard.as_ref() {
|
||||||
Some(c) => c,
|
Some(c) => c,
|
||||||
None => {
|
None => {
|
||||||
return Err("Database was not initialized".into());
|
error!("Database was not initialized");
|
||||||
|
return Err(NativeError::Initialization);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut session = db::create_session(conn)?;
|
let mut session = db::create_session(conn).map_err(|_| NativeError::Database)?;
|
||||||
let s = client.session();
|
let s = client.session();
|
||||||
if let Some(user) = s.get_user() {
|
if let Some(user) = s.get_user() {
|
||||||
session.user_id = Some(user.id);
|
session.user_id = Some(user.id);
|
||||||
|
@ -211,79 +242,67 @@ async fn sign_in(token: LoginToken, code: &str) -> Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
db::update_session(conn, &session)?;
|
db::update_session(conn, &session).map_err(|_| NativeError::Database)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_dialogs() -> Result<Vec<OgDialog>> {
|
async fn get_dialogs() -> Result<Vec<OgDialog>> {
|
||||||
let client = CLIENT.get().ok_or("Client not initialized")?;
|
let client = CLIENT.get().ok_or(NativeError::Initialization)?;
|
||||||
|
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
let mut dialogs = client.iter_dialogs();
|
let mut dialogs = client.iter_dialogs();
|
||||||
while let Some(dialog) = dialogs.next().await? {
|
while let Some(dialog) = dialogs.next().await.map_err(|_| NativeError::Network)? {
|
||||||
result.push(dialog);
|
result.push(dialog);
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_message(chat: PackedChat, text: &str) -> Result<()> {
|
async fn send_message(chat: PackedChat, text: &str) -> Result<()> {
|
||||||
let client = CLIENT.get().ok_or("Client not initialized")?;
|
let client = CLIENT.get().ok_or(NativeError::Initialization)?;
|
||||||
client.send_message(chat, text).await?;
|
client
|
||||||
|
.send_message(chat, text)
|
||||||
|
.await
|
||||||
|
.map_err(|_| NativeError::Network)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initDatabase(path: String) {
|
pub fn initDatabase(path: String) -> Result<()> {
|
||||||
let mut guard = DATABASE.lock().unwrap();
|
let mut guard = DATABASE.lock().unwrap();
|
||||||
if guard.is_some() {
|
if guard.is_some() {
|
||||||
info!("Database is already initialized");
|
info!("Database is already initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
match db::init_connection(&path) {
|
match db::init_connection(&path) {
|
||||||
Ok(conn) => *guard = Some(conn),
|
Ok(conn) => {
|
||||||
Err(e) => error!("Failed to initialize database: {}", e),
|
*guard = Some(conn);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => Err(NativeError::Database),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initClient() {
|
pub fn initClient() -> Result<()> {
|
||||||
match block_on(init_client()) {
|
block_on(init_client())
|
||||||
Ok(_) => info!("Client initialized"),
|
|
||||||
Err(e) => error!("Failed to initialize client: {}", e),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn needLogin() -> bool {
|
pub fn needLogin() -> Result<bool> {
|
||||||
match block_on(need_login()) {
|
block_on(need_login())
|
||||||
Ok(login) => login.into(),
|
|
||||||
Err(e) => {
|
|
||||||
error!("Failed to check if user is authorized: {}", e);
|
|
||||||
false.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn requestLoginCode(phone: String) -> u64 {
|
pub fn requestLoginCode(phone: String) -> Result<u64> {
|
||||||
match block_on(request_login_code(&phone)) {
|
block_on(request_login_code(&phone)).map(|token| Box::into_raw(Box::new(token)) as u64)
|
||||||
Ok(token) => Box::into_raw(Box::new(token)) as u64,
|
|
||||||
Err(e) => {
|
|
||||||
error!("Failed to request login code: {}", e);
|
|
||||||
0 as u64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn signIn(token_ptr: u64, code: String) {
|
pub fn signIn(token_ptr: u64, code: String) -> Result<()> {
|
||||||
let token = unsafe { *Box::from_raw(token_ptr as *mut LoginToken) };
|
let token = unsafe { *Box::from_raw(token_ptr as *mut LoginToken) };
|
||||||
|
|
||||||
match block_on(sign_in(token, &code)) {
|
block_on(sign_in(token, &code))
|
||||||
Ok(_) => info!("Sign in success"),
|
|
||||||
Err(e) => error!("Failed to sign in: {}", e),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getDialogs() -> Vec<Dialog> {
|
pub fn getDialogs() -> Result<Vec<Dialog>> {
|
||||||
match block_on(get_dialogs()) {
|
block_on(get_dialogs()).map(|dialogs| {
|
||||||
Ok(dialogs) => dialogs
|
dialogs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|d| Dialog {
|
.map(|d| Dialog {
|
||||||
id: d.chat().pack().to_hex(),
|
id: d.chat().pack().to_hex(),
|
||||||
|
@ -316,18 +335,11 @@ pub fn getDialogs() -> Vec<Dialog> {
|
||||||
tl::enums::Dialog::Folder(f) => f.pinned,
|
tl::enums::Dialog::Folder(f) => f.pinned,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect()
|
||||||
Err(e) => {
|
})
|
||||||
error!("Failed to get dialogs: {}", e);
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sendMessage(packed: String, text: String) {
|
pub fn sendMessage(packed: String, text: String) -> Result<()> {
|
||||||
let packed = PackedChat::from_hex(&packed).unwrap();
|
let packed = PackedChat::from_hex(&packed).unwrap();
|
||||||
match block_on(send_message(packed, &text)) {
|
block_on(send_message(packed, &text))
|
||||||
Ok(_) => info!("Message sent"),
|
|
||||||
Err(e) => error!("Failed to send message: {}", e),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
[Error]
|
||||||
|
enum NativeError {
|
||||||
|
"Initialization",
|
||||||
|
"Database",
|
||||||
|
"Network",
|
||||||
|
};
|
||||||
|
|
||||||
enum MessageAck {
|
enum MessageAck {
|
||||||
"Received",
|
"Received",
|
||||||
"Seen",
|
"Seen",
|
||||||
|
@ -19,11 +26,18 @@ dictionary Dialog {
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace talaria {
|
namespace talaria {
|
||||||
|
[Throws=NativeError]
|
||||||
void initDatabase(string path);
|
void initDatabase(string path);
|
||||||
|
[Throws=NativeError]
|
||||||
void initClient();
|
void initClient();
|
||||||
|
[Throws=NativeError]
|
||||||
boolean needLogin();
|
boolean needLogin();
|
||||||
|
[Throws=NativeError]
|
||||||
u64 requestLoginCode(string phone);
|
u64 requestLoginCode(string phone);
|
||||||
|
[Throws=NativeError]
|
||||||
void signIn(u64 tokenPtr, string code);
|
void signIn(u64 tokenPtr, string code);
|
||||||
|
[Throws=NativeError]
|
||||||
sequence<Dialog> getDialogs();
|
sequence<Dialog> getDialogs();
|
||||||
|
[Throws=NativeError]
|
||||||
void sendMessage(string packed, string text);
|
void sendMessage(string packed, string text);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue