Improve auto updating structs usage (#168)

* Add `GatewayHandle` to `UserMeta`

* Make user::shell async due to gateway add
This commit is contained in:
Flori 2023-07-24 19:13:53 +02:00 committed by GitHub
parent 9ebe72a7dc
commit 07f283a205
7 changed files with 59 additions and 27 deletions

View File

@ -6,9 +6,10 @@ use serde_json::to_string;
use crate::api::LimitType; use crate::api::LimitType;
use crate::errors::ChorusResult; use crate::errors::ChorusResult;
use crate::gateway::Gateway;
use crate::instance::{Instance, UserMeta}; use crate::instance::{Instance, UserMeta};
use crate::ratelimiter::ChorusRequest; use crate::ratelimiter::ChorusRequest;
use crate::types::{LoginResult, LoginSchema}; use crate::types::{GatewayIdentifyPayload, LoginResult, LoginSchema};
impl Instance { impl Instance {
pub async fn login_account(&mut self, login_schema: &LoginSchema) -> ChorusResult<UserMeta> { pub async fn login_account(&mut self, login_schema: &LoginSchema) -> ChorusResult<UserMeta> {
@ -22,7 +23,8 @@ impl Instance {
// We do not have a user yet, and the UserRateLimits will not be affected by a login // We do not have a user yet, and the UserRateLimits will not be affected by a login
// request (since login is an instance wide limit), which is why we are just cloning the // request (since login is an instance wide limit), which is why we are just cloning the
// instances' limits to pass them on as user_rate_limits later. // instances' limits to pass them on as user_rate_limits later.
let mut shell = UserMeta::shell(Rc::new(RefCell::new(self.clone())), "None".to_string()); let mut shell =
UserMeta::shell(Rc::new(RefCell::new(self.clone())), "None".to_string()).await;
let login_result = chorus_request let login_result = chorus_request
.deserialize_response::<LoginResult>(&mut shell) .deserialize_response::<LoginResult>(&mut shell)
.await?; .await?;
@ -30,12 +32,17 @@ impl Instance {
if self.limits_information.is_some() { if self.limits_information.is_some() {
self.limits_information.as_mut().unwrap().ratelimits = shell.limits.clone().unwrap(); self.limits_information.as_mut().unwrap().ratelimits = shell.limits.clone().unwrap();
} }
let mut identify = GatewayIdentifyPayload::common();
let gateway = Gateway::new(self.urls.wss.clone()).await.unwrap();
identify.token = login_result.token.clone();
gateway.send_identify(identify).await;
let user = UserMeta::new( let user = UserMeta::new(
Rc::new(RefCell::new(self.clone())), Rc::new(RefCell::new(self.clone())),
login_result.token, login_result.token,
self.clone_limits_if_some(), self.clone_limits_if_some(),
login_result.settings, login_result.settings,
object, object,
gateway,
); );
Ok(user) Ok(user)
} }

View File

@ -3,6 +3,8 @@ use std::{cell::RefCell, rc::Rc};
use reqwest::Client; use reqwest::Client;
use serde_json::to_string; use serde_json::to_string;
use crate::gateway::Gateway;
use crate::types::GatewayIdentifyPayload;
use crate::{ use crate::{
api::policies::instance::LimitType, api::policies::instance::LimitType,
errors::ChorusResult, errors::ChorusResult,
@ -35,7 +37,8 @@ impl Instance {
// We do not have a user yet, and the UserRateLimits will not be affected by a login // We do not have a user yet, and the UserRateLimits will not be affected by a login
// request (since register is an instance wide limit), which is why we are just cloning // request (since register is an instance wide limit), which is why we are just cloning
// the instances' limits to pass them on as user_rate_limits later. // the instances' limits to pass them on as user_rate_limits later.
let mut shell = UserMeta::shell(Rc::new(RefCell::new(self.clone())), "None".to_string()); let mut shell =
UserMeta::shell(Rc::new(RefCell::new(self.clone())), "None".to_string()).await;
let token = chorus_request let token = chorus_request
.deserialize_response::<Token>(&mut shell) .deserialize_response::<Token>(&mut shell)
.await? .await?
@ -45,12 +48,17 @@ impl Instance {
} }
let user_object = self.get_user(token.clone(), None).await.unwrap(); let user_object = self.get_user(token.clone(), None).await.unwrap();
let settings = UserMeta::get_settings(&token, &self.urls.api.clone(), self).await?; let settings = UserMeta::get_settings(&token, &self.urls.api.clone(), self).await?;
let mut identify = GatewayIdentifyPayload::common();
let gateway = Gateway::new(self.urls.wss.clone()).await.unwrap();
identify.token = token.clone();
gateway.send_identify(identify).await;
let user = UserMeta::new( let user = UserMeta::new(
Rc::new(RefCell::new(self.clone())), Rc::new(RefCell::new(self.clone())),
token.clone(), token.clone(),
self.clone_limits_if_some(), self.clone_limits_if_some(),
settings, settings,
user_object, user_object,
gateway,
); );
Ok(user) Ok(user)
} }

View File

@ -122,7 +122,8 @@ impl User {
let request: reqwest::RequestBuilder = Client::new() let request: reqwest::RequestBuilder = Client::new()
.get(format!("{}/users/@me/settings/", url_api)) .get(format!("{}/users/@me/settings/", url_api))
.bearer_auth(token); .bearer_auth(token);
let mut user = UserMeta::shell(Rc::new(RefCell::new(instance.clone())), token.clone()); let mut user =
UserMeta::shell(Rc::new(RefCell::new(instance.clone())), token.clone()).await;
let chorus_request = ChorusRequest { let chorus_request = ChorusRequest {
request, request,
limit_type: LimitType::Global, limit_type: LimitType::Global,
@ -151,7 +152,7 @@ impl Instance {
This function is a wrapper around [`User::get`]. This function is a wrapper around [`User::get`].
*/ */
pub async fn get_user(&mut self, token: String, id: Option<&String>) -> ChorusResult<User> { pub async fn get_user(&mut self, token: String, id: Option<&String>) -> ChorusResult<User> {
let mut user = UserMeta::shell(Rc::new(RefCell::new(self.clone())), token); let mut user = UserMeta::shell(Rc::new(RefCell::new(self.clone())), token).await;
let result = User::get(&mut user, id).await; let result = User::get(&mut user, id).await;
if self.limits_information.is_some() { if self.limits_information.is_some() {
self.limits_information.as_mut().unwrap().ratelimits = self.limits_information.as_mut().unwrap().ratelimits =

View File

@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize};
use crate::api::{Limit, LimitType}; use crate::api::{Limit, LimitType};
use crate::errors::ChorusResult; use crate::errors::ChorusResult;
use crate::gateway::{Gateway, GatewayHandle};
use crate::ratelimiter::ChorusRequest; use crate::ratelimiter::ChorusRequest;
use crate::types::types::subconfigs::limits::rates::RateLimits; use crate::types::types::subconfigs::limits::rates::RateLimits;
use crate::types::{GeneralConfiguration, User, UserSettings}; use crate::types::{GeneralConfiguration, User, UserSettings};
@ -88,13 +89,14 @@ impl fmt::Display for Token {
} }
} }
#[derive(Debug, Clone)] #[derive(Debug)]
pub struct UserMeta { pub struct UserMeta {
pub belongs_to: Rc<RefCell<Instance>>, pub belongs_to: Rc<RefCell<Instance>>,
pub token: String, pub token: String,
pub limits: Option<HashMap<LimitType, Limit>>, pub limits: Option<HashMap<LimitType, Limit>>,
pub settings: UserSettings, pub settings: UserSettings,
pub object: User, pub object: User,
pub gateway: GatewayHandle,
} }
impl UserMeta { impl UserMeta {
@ -112,6 +114,7 @@ impl UserMeta {
limits: Option<HashMap<LimitType, Limit>>, limits: Option<HashMap<LimitType, Limit>>,
settings: UserSettings, settings: UserSettings,
object: User, object: User,
gateway: GatewayHandle,
) -> UserMeta { ) -> UserMeta {
UserMeta { UserMeta {
belongs_to, belongs_to,
@ -119,19 +122,24 @@ impl UserMeta {
limits, limits,
settings, settings,
object, object,
gateway,
} }
} }
/// Creates a new 'shell' of a user. The user does not exist as an object, and exists so that you have /// Creates a new 'shell' of a user. The user does not exist as an object, and exists so that you have
/// a UserMeta object to make Rate Limited requests with. This is useful in scenarios like /// a UserMeta object to make Rate Limited requests with. This is useful in scenarios like
/// registering or logging in to the Instance, where you do not yet have a User object, but still /// registering or logging in to the Instance, where you do not yet have a User object, but still
/// need to make a RateLimited request. /// need to make a RateLimited request. To use the [`GatewayHandle`], you will have to identify
pub(crate) fn shell(instance: Rc<RefCell<Instance>>, token: String) -> UserMeta { /// first.
pub(crate) async fn shell(instance: Rc<RefCell<Instance>>, token: String) -> UserMeta {
let settings = UserSettings::default(); let settings = UserSettings::default();
let object = User::default(); let object = User::default();
let wss_url = instance.borrow().urls.wss.clone();
// Dummy gateway object
let gateway = Gateway::new(wss_url).await.unwrap();
UserMeta { UserMeta {
belongs_to: instance.clone(),
token, token,
belongs_to: instance.clone(),
limits: instance limits: instance
.borrow() .borrow()
.limits_information .limits_information
@ -139,6 +147,7 @@ impl UserMeta {
.map(|info| info.ratelimits.clone()), .map(|info| info.ratelimits.clone()),
settings, settings,
object, object,
gateway,
} }
} }
} }

View File

@ -1,3 +1,4 @@
use chorus::gateway::Gateway;
use chorus::{ use chorus::{
instance::{Instance, UserMeta}, instance::{Instance, UserMeta},
types::{ types::{
@ -18,8 +19,8 @@ pub(crate) struct TestBundle {
pub channel: Channel, pub channel: Channel,
} }
#[allow(unused)]
impl TestBundle { impl TestBundle {
#[allow(unused)]
pub(crate) async fn create_user(&mut self, username: &str) -> UserMeta { pub(crate) async fn create_user(&mut self, username: &str) -> UserMeta {
let register_schema = RegisterSchema { let register_schema = RegisterSchema {
username: username.to_string(), username: username.to_string(),
@ -32,6 +33,16 @@ impl TestBundle {
.await .await
.unwrap() .unwrap()
} }
pub(crate) async fn clone_user_without_gateway(&self) -> UserMeta {
UserMeta {
belongs_to: self.user.belongs_to.clone(),
token: self.user.token.clone(),
limits: self.user.limits.clone(),
settings: self.user.settings.clone(),
object: self.user.object.clone(),
gateway: Gateway::new(self.instance.urls.wss.clone()).await.unwrap(),
}
}
} }
// Set up a test by creating an Instance and a User. Reduces Test boilerplate. // Set up a test by creating an Instance and a User. Reduces Test boilerplate.

View File

@ -8,7 +8,8 @@ use chorus::types::{self, Channel};
async fn test_gateway_establish() { async fn test_gateway_establish() {
let bundle = common::setup().await; let bundle = common::setup().await;
Gateway::new(bundle.urls.wss).await.unwrap(); Gateway::new(bundle.urls.wss.clone()).await.unwrap();
common::teardown(bundle).await
} }
#[tokio::test] #[tokio::test]
@ -16,25 +17,21 @@ async fn test_gateway_establish() {
async fn test_gateway_authenticate() { async fn test_gateway_authenticate() {
let bundle = common::setup().await; let bundle = common::setup().await;
let gateway = Gateway::new(bundle.urls.wss).await.unwrap(); let gateway = Gateway::new(bundle.urls.wss.clone()).await.unwrap();
let mut identify = types::GatewayIdentifyPayload::common(); let mut identify = types::GatewayIdentifyPayload::common();
identify.token = bundle.user.token; identify.token = bundle.user.token.clone();
gateway.send_identify(identify).await; gateway.send_identify(identify).await;
common::teardown(bundle).await
} }
#[tokio::test] #[tokio::test]
async fn test_self_updating_structs() { async fn test_self_updating_structs() {
let mut bundle = common::setup().await; let mut bundle = common::setup().await;
let gateway = Gateway::new(bundle.urls.wss).await.unwrap(); let channel_updater = bundle.user.gateway.observe(bundle.channel.clone()).await;
let mut identify = types::GatewayIdentifyPayload::common(); let received_channel = channel_updater.borrow().clone();
identify.token = bundle.user.token.clone(); assert_eq!(received_channel, bundle.channel);
gateway.send_identify(identify).await;
let channel_receiver = gateway.observe(bundle.channel.clone()).await;
let received_channel = channel_receiver.borrow();
assert_eq!(*received_channel, bundle.channel);
drop(received_channel);
let channel = &mut bundle.channel; let channel = &mut bundle.channel;
let modify_data = types::ChannelModifySchema { let modify_data = types::ChannelModifySchema {
name: Some("beepboop".to_string()), name: Some("beepboop".to_string()),
@ -43,6 +40,7 @@ async fn test_self_updating_structs() {
Channel::modify(channel, modify_data, channel.id, &mut bundle.user) Channel::modify(channel, modify_data, channel.id, &mut bundle.user)
.await .await
.unwrap(); .unwrap();
let received_channel = channel_receiver.borrow(); let received_channel = channel_updater.borrow();
assert_eq!(received_channel.name.as_ref().unwrap(), "beepboop"); assert_eq!(received_channel.name.as_ref().unwrap(), "beepboop");
common::teardown(bundle).await
} }

View File

@ -1,14 +1,12 @@
use chorus::types::CreateChannelInviteSchema;
mod common; mod common;
use chorus::types::CreateChannelInviteSchema;
#[tokio::test] #[tokio::test]
async fn create_accept_invite() { async fn create_accept_invite() {
let mut bundle = common::setup().await; let mut bundle = common::setup().await;
let channel = bundle.channel.clone(); let channel = bundle.channel.clone();
let mut user = bundle.user.clone();
let create_channel_invite_schema = CreateChannelInviteSchema::default();
let mut other_user = bundle.create_user("testuser1312").await; let mut other_user = bundle.create_user("testuser1312").await;
let user = &mut bundle.user;
let create_channel_invite_schema = CreateChannelInviteSchema::default();
assert!(chorus::types::Guild::get(bundle.guild.id, &mut other_user) assert!(chorus::types::Guild::get(bundle.guild.id, &mut other_user)
.await .await
.is_err()); .is_err());