1
0
mirror of https://git.ngram.ca/OpenJam/rc-servers synced 2026-08-23 23:08:52 +00:00

Improve intercom and reduce meaningless error logging

This commit is contained in:
NG (Graham)
2026-08-09 18:02:45 -04:00
parent 961190a467
commit 52dc0519fb
7 changed files with 222 additions and 56 deletions

View File

@@ -1,7 +1,121 @@
use serde::{Serialize, Deserialize};
pub struct IntercomListener<D> {
websocket: reqwest_websocket::WebSocket,
_d: std::marker::PhantomData<D>,
}
impl <D> IntercomListener<D> {
pub(super) fn new(websocket: reqwest_websocket::WebSocket) -> Self {
Self {
websocket,
_d: Default::default(),
}
}
/*pub async fn close(self, reason: &str) {
if let Err(e) = self.websocket.close(reqwest_websocket::CloseCode::Normal, Some(reason)).await {
log::error!("Failed to close intercom websocket with reason {}: {}", reason, e);
}
}*/
}
impl <D: serde::de::DeserializeOwned + 'static> IntercomListener<D> {
pub async fn listen(self) -> impl futures::Stream<Item=Result<D, reqwest_websocket::Error>> + Unpin {
use futures::StreamExt;
//self.websocket.map(|msg_res| msg_res.and_then(|msg| msg.json()))
let (sink, stream) = self.websocket.split();
let sink = std::sync::Arc::new(tokio::sync::Mutex::new(sink));
stream.filter_map(move |msg_res| {
let sink = sink.clone();
Box::pin(async move {
let res = match msg_res.ok() {
None => None,
/*reqwest_websocket::Message::Text(s) => {
(serde_json::from_str(&s).map_err(reqwest_websocket::Error::Json), None)
},*/
Some(reqwest_websocket::Message::Ping(p)) => {
use futures::SinkExt;
log::debug!("Received {}B intercom websocket ping: {}", p.len(), String::from_utf8_lossy(&p));
let mut sink_lock = sink.lock().await;
if let Err(e) = sink_lock.send(reqwest_websocket::Message::Pong(p)).await {
log::warn!("Failed to send intercom websocket pong: {}", e);
}
None
},
Some(reqwest_websocket::Message::Pong(p)) => {
log::debug!("Received {}B intercom websocket pong: {}", p.len(), String::from_utf8_lossy(&p));
None
},
Some(msg) => Some(msg.json())
};
res
}
)})
}
}
impl <D: serde::ser::Serialize> IntercomListener<D> {
pub async fn send(self) -> impl futures::Sink<D> {
use futures::SinkExt;
self.websocket.with::<D, _, _, reqwest_websocket::Error>(|d| {
async move {
serde_json::to_string(&d)
.map_err(reqwest_websocket::Error::Json)
.map(reqwest_websocket::Message::Text)
}
})
}
}
impl <D: serde::ser::Serialize + serde::de::DeserializeOwned + 'static> IntercomListener<D> {
pub async fn split(self) -> (impl futures::Sink<D>, impl futures::Stream<Item=Result<D, reqwest_websocket::Error>> + Unpin) {
use futures::SinkExt;
use futures::StreamExt;
let (sink, stream) = self.websocket.split();
let sink = std::sync::Arc::new(tokio::sync::Mutex::new(sink));
let sink_impl_instance = sink.clone();
let sink_impl = futures::sink::unfold(sink_impl_instance, |sink_instance, d| async move {
let msg = serde_json::to_string(&d)
.map_err(reqwest_websocket::Error::Json)
.map(reqwest_websocket::Message::Text)?;
let mut lock = sink_instance.lock().await;
lock.send(msg).await?;
drop(lock);
Ok::<_, reqwest_websocket::Error>(sink_instance)
});
let stream_impl = stream.filter_map(move |msg_res| {
let sink = sink.clone();
Box::pin(async move {
let res = match msg_res.ok() {
None => None,
/*reqwest_websocket::Message::Text(s) => {
(serde_json::from_str(&s).map_err(reqwest_websocket::Error::Json), None)
},*/
Some(reqwest_websocket::Message::Ping(p)) => {
use futures::SinkExt;
log::debug!("Received {}B intercom websocket ping: {}", p.len(), String::from_utf8_lossy(&p));
let mut sink_lock = sink.lock().await;
if let Err(e) = sink_lock.send(reqwest_websocket::Message::Pong(p)).await {
log::warn!("Failed to send intercom websocket pong: {}", e);
}
None
},
Some(reqwest_websocket::Message::Pong(p)) => {
log::debug!("Received {}B intercom websocket pong: {}", p.len(), String::from_utf8_lossy(&p));
None
},
Some(msg) => Some(msg.json())
};
res
}
)});
(sink_impl, stream_impl)
}
}
impl super::account_json::UserData {
async fn listen_on_websocket<D: serde::de::DeserializeOwned>(&self, server_name: &str) -> Result<super::IntercomListener<D>, reqwest_websocket::Error> {
async fn listen_on_websocket<D: serde::de::DeserializeOwned>(&self, server_name: &str) -> Result<IntercomListener<D>, reqwest_websocket::Error> {
use reqwest_websocket::Upgrade;
let url_encoded_pub_id = urlencoding::encode(&self.account.public_id);
let token = generate_token(format!("{}/{}", server_name, url_encoded_pub_id).as_bytes(), &self.secret);
@@ -15,10 +129,7 @@ impl super::account_json::UserData {
.await?
.into_websocket()
.await?;
Ok(super::IntercomListener {
websocket,
_d: Default::default(),
})
Ok(IntercomListener::new(websocket))
}
async fn post_to_intercom<D: serde::Serialize>(&self, data: &D, server_name: &str, operation: &str) -> Result<(), reqwest::Error> {
@@ -86,7 +197,7 @@ impl super::IntercomUser for super::account_json::UserData {
Ok(())
}
async fn webservice_listener(&self) -> Result<super::IntercomListener<IntercomWebServiceUserMessage>, polariton_server::operations::SimpleOpError> {
async fn webservice_listener(&self) -> Result<IntercomListener<IntercomWebServiceUserMessage>, polariton_server::operations::SimpleOpError> {
self.listen_on_websocket(".oj_services").await
.map_err(|e| polariton_server::operations::SimpleOpError::with_message(
crate::data::error_codes::WebServicesError::PlatformFeatureNotAvailable as i16,

View File

@@ -11,10 +11,11 @@ mod inventory;
pub use inventory::{UnlockedParts, UnlockOverride};
mod traits;
pub use traits::{UserProvider, User, UserToken, UserSlots, UserSlotData, VehicleData, UserAuthInfo, FederatedAuthInfo, UserLoginInfo, UserAuthenticator, FederatedAuthenticator, NewSlotData, UserId, RegistrationInfo, VehicleUploadData, ChatUser, AvatarInfo, GetAvatarInfo, ControlData, ControlType, CustomisationData, GetCustomisationData, SetSanction, SanctionType, LobbyUser, GameDescriptor, PlayerLobbyDescriptor, MultiplayerUser, PlayerScore, MultiplayerError, MultiplayerErrorCode, PlayerDescriptor, GameEventSetter, CurrentGameEvent, AuthError, IntercomUser, FakePlayers, ResolvedVehicle, CommonUser, IntercomListener, UserRole, SocialUser, SocialUserC, CurrencyType, CurrencyOp, MatchRewards, SingleplayerUser, PurchaseResult, FactoryUser, FriendInviteReturn, FriendData, FriendInviteStatus, SocialInfo, ClanData, ClanMember, ClanMemberRank, ClanType, ClanSearchQuery, ClanInviteData, Userless, GameOverrides, WebUser, GarageWebInfo, GarageWebStats, SanctionWebStats, AccountWebStats, SocialWebStats, FederationWebData, FederationWebDetails};
pub use traits::{UserProvider, User, UserToken, UserSlots, UserSlotData, VehicleData, UserAuthInfo, FederatedAuthInfo, UserLoginInfo, UserAuthenticator, FederatedAuthenticator, NewSlotData, UserId, RegistrationInfo, VehicleUploadData, ChatUser, AvatarInfo, GetAvatarInfo, ControlData, ControlType, CustomisationData, GetCustomisationData, SetSanction, SanctionType, LobbyUser, GameDescriptor, PlayerLobbyDescriptor, MultiplayerUser, PlayerScore, MultiplayerError, MultiplayerErrorCode, PlayerDescriptor, GameEventSetter, CurrentGameEvent, AuthError, IntercomUser, FakePlayers, ResolvedVehicle, CommonUser, UserRole, SocialUser, SocialUserC, CurrencyType, CurrencyOp, MatchRewards, SingleplayerUser, PurchaseResult, FactoryUser, FriendInviteReturn, FriendData, FriendInviteStatus, SocialInfo, ClanData, ClanMember, ClanMemberRank, ClanType, ClanSearchQuery, ClanInviteData, Userless, GameOverrides, WebUser, GarageWebInfo, GarageWebStats, SanctionWebStats, AccountWebStats, SocialWebStats, FederationWebData, FederationWebDetails};
pub mod intercom;
pub use intercom::generate_token as generate_intercom_token;
pub use intercom::IntercomListener;
mod multiplayer;
mod lobby;

View File

@@ -431,7 +431,7 @@ pub struct PlayerScore {
pub trait IntercomUser: CommonUser {
async fn save_custom_avatar(&self, image: Vec<u8>) -> Result<(), polariton_server::operations::SimpleOpError>;
async fn save_factory_thumbnail(&self, factory_id: i32, image: Vec<u8>) -> Result<(), polariton_server::operations::SimpleOpError>;
async fn webservice_listener(&self) -> Result<IntercomListener<super::intercom::IntercomWebServiceUserMessage>, polariton_server::operations::SimpleOpError>;
async fn webservice_listener(&self) -> Result<super::IntercomListener<super::intercom::IntercomWebServiceUserMessage>, polariton_server::operations::SimpleOpError>;
async fn show_dev_message(&self, msg: super::intercom::IntercomDevMessage, to: Vec<String>);
async fn enter_maintenance(&self, msg: super::intercom::IntercomMaintenanceMessage, to: Vec<String>);
async fn trigger_workaround(&self, msg: super::intercom::IntercomWorkaroundMessage, to: Vec<String>);
@@ -439,21 +439,6 @@ pub trait IntercomUser: CommonUser {
async fn update_status(&self, server_name: &str, msg: oj_serdes::ServerStatus);
}
pub struct IntercomListener<D: serde::de::DeserializeOwned> {
pub(super) websocket: reqwest_websocket::WebSocket,
pub(super) _d: std::marker::PhantomData<D>,
}
impl <D: serde::de::DeserializeOwned> IntercomListener<D> {
pub async fn listen(self) -> impl futures::Stream<Item=Result<D, Box<reqwest_websocket::Error>>> + Unpin {
use futures::StreamExt;
self.websocket.map(|msg|
msg.map_err(Box::new)
.and_then(|msg| msg.json().map_err(Box::new))
)
}
}
pub struct ResolvedVehicle {
pub mastery: i32,
pub tier: i32,

View File

@@ -14,10 +14,7 @@ impl super::AccountProvider {
.await?
.into_websocket()
.await?;
Ok(super::IntercomListener {
websocket,
_d: Default::default(),
})
Ok(super::IntercomListener::new(websocket))
}
}