use crate::external_services::service_interface::{ExternalServiceChannel, RawExternalPacket};
use crate::external_services::JsonWebToken;
use crate::misc::AccountError;
use async_trait::async_trait;
use firebase_rtdb::{AuthResponsePayload, FirebaseRTDB, DEFAULT_EXPIRE_BUFFER_SECS};
use serde::{Deserialize, Serialize};
use std::ops::{Deref, DerefMut};
use std::time::Instant;
#[derive(Serialize, Deserialize, Debug)]
pub struct RtdbClientConfig {
pub url: String,
pub api_key: String,
pub auth_payload: AuthResponsePayload,
#[serde(with = "serde_millis")]
pub expire_time: Instant,
pub jwt: JsonWebToken,
}
impl RtdbClientConfig {
pub fn expired(&self) -> bool {
Instant::now() + DEFAULT_EXPIRE_BUFFER_SECS > self.expire_time
}
}
#[derive(Clone)]
pub struct RtdbInstance {
inner: FirebaseRTDB,
}
impl RtdbInstance {
pub fn new(config: &RtdbClientConfig) -> Result<Self, AccountError> {
FirebaseRTDB::new_from_token(
&config.url,
config.api_key.clone(),
config.jwt.clone(),
config.auth_payload.clone(),
config.expire_time,
)
.map_err(|err| citadel_io::error!(citadel_io::ErrorCode::ExternalService, err.inner))
.map(|r| r.into())
}
pub fn refresh(&mut self) -> Result<(), AccountError> {
let token = self.inner.auth.idToken.clone();
let url = self.inner.base_url.clone();
let auth = self.inner.auth.clone();
let expire_time = self.expire_time;
let api_key = self.api_key.clone();
let _ = std::mem::replace(
&mut self.inner,
FirebaseRTDB::new_from_token(url, api_key, token, auth, expire_time).map_err(
|err| citadel_io::error!(citadel_io::ErrorCode::ExternalService, err.inner),
)?,
);
Ok(())
}
}
impl Deref for RtdbInstance {
type Target = FirebaseRTDB;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for RtdbInstance {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl From<FirebaseRTDB> for RtdbInstance {
fn from(inner: FirebaseRTDB) -> Self {
Self { inner }
}
}
#[async_trait]
impl ExternalServiceChannel for RtdbInstance {
async fn send(
&mut self,
data: RawExternalPacket,
session_cid: u64,
peer_cid: u64,
) -> Result<(), AccountError> {
Ok(self
.root()
.await
.map_err(|err| citadel_io::error!(citadel_io::ErrorCode::ExternalService, err.inner))?
.child("users")
.child(peer_cid.to_string())
.child("peers")
.child(session_cid.to_string())
.final_node("packets")
.post(data)
.await
.map(|_| ())
.map_err(|err| citadel_io::error!(citadel_io::ErrorCode::ExternalService, err.inner))?)
}
}