polyphony-chat / chorus

A Rust library for interacting with multiple Polyphony- and Spacebar-Compatible instances at once.
https://crates.io/crates/chorus
Mozilla Public License 2.0
16 stars 7 forks source link

Weird Gateway behaviour #556

Closed bitfl0wer closed 2 weeks ago

bitfl0wer commented 2 weeks ago

CC: @kozabrada123

A little bit of storytime:

I am currently working on the symfonia gateway server.

use std::thread::sleep;
use std::time::{self, Duration};

use chorus::gateway::GatewayOptions;
use chorus::types::RegisterSchema;
use chorus::UrlBundle;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let urls = UrlBundle {
        root: "http://localhost".to_string(),
        api: "http://localhost:3001/api/v9/".to_string(),
        wss: "ws://localhost:3003".to_string(),
        cdn: "http://none".to_string(),
    };
    let mut instance = chorus::instance::Instance::from_url_bundle(
        urls,
        Some(GatewayOptions {
            encoding: chorus::gateway::GatewayEncoding::Json,
            transport_compression: chorus::gateway::GatewayTransportCompression::None,
        }),
    )
    .await?;

    let username = generate_random_ascii_string(10);
    let email_prefix = generate_random_ascii_string(10);

    let register_schema = RegisterSchema {
        username,
        password: Some("ineedapassword?DAmn!1".to_string()),
        consent: true,
        email: Some(format!("{}@idontknow.com", email_prefix)),
        fingerprint: None,
        invite: None,
        date_of_birth: None,
        gift_code_sku_id: None,
        captcha_key: None,
        promotional_email_opt_in: None,
    };
    let user = instance.register_account(register_schema).await?;
    dbg!(user);
    Ok(())
}

fn generate_random_ascii_string(length: usize) -> String {
    let mut rng = rand::thread_rng();
    let mut s = String::with_capacity(length);

    for _ in 0..length {
        // Generate a random ASCII character (32-126 are printable ASCII characters)
        let ascii_value: u8 = rand::Rng::gen_range(&mut rng, 32..=126);
        s.push(ascii_value as char);
    }

    s
}

This is how I am currently testing symfonia. This compiles to a binary, which I then run. it's really simple: create a random username, random email, create an instance and create a user, which, under the hood, connects to the gateway.

Creating the account works. Connecting to the gateway is weird, though.

At first, I used the main branch of chorus for this testing binary. This worked in a sense where I saw that the server sent the Hello and received the heartbeat event. With the dev branch, I only get:

2024-08-26 20:09:32 | TRACE  | symfonia::gateway                   | New connection received
2024-08-26 20:09:34 | TRACE  | symfonia::gateway::establish_connection | Received first message: Err(Protocol(ResetWithoutClosingHandshake))
2024-08-26 20:09:34 | DEBUG  | symfonia::gateway::establish_connection | User gateway connection could not be established: WebSocket protocol error: Connection reset without closing handshake

this makes me think that the error is in chorus, because with the main branch it works, but on dev, it does not. But: Chorus is being tested against the spacebar server, and all checks run green there, which makes me think that the issue must be somewhere on my side - the implementation of the websocket server.

let endpoint_url = self.urls.api.clone() + "/auth/register";
        let chorus_request = ChorusRequest {
            request: Client::new()
                .post(endpoint_url)
                .body(to_string(&register_schema).unwrap())
                .header("Content-Type", "application/json"),
            limit_type: LimitType::AuthRegister,
        };
        // 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
        // the instances' limits to pass them on as user_rate_limits later.
        let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None").await;

        let token = chorus_request
            .deserialize_response::<Token>(&mut user)
            .await?
            .token;
        user.set_token(&token);

        let object = User::get(&mut user, None).await?;
        let settings = User::get_settings(&mut user).await?;

        *user.object.write().unwrap() = object;
        *user.settings.write().unwrap() = settings;

        let mut identify = GatewayIdentifyPayload::common();
        identify.token = user.token();
        user.gateway.send_identify(identify).await;

This is an excerpt from chorus and the register_account function. ChorusUser::shell creates/establishes a gateway connection, where it will connect, wait for a hello, and then send a heartbeat and the identify.

now, funnily enough, if i change

let token = chorus_request
           .deserialize_response::<Token>(&mut user)
           .await?
           .token;
       user.set_token(&token);
       let object = User::get(&mut user, None).await?;
       let settings = User::get_settings(&mut user).await?;
       *user.object.write().unwrap() = object;
       *user.settings.write().unwrap() = settings;
       // Send identify
       let mut identify = GatewayIdentifyPayload::common();
       identify.token = user.token();
       user.gateway.send_identify(identify).await;

to

let token = chorus_request
           .deserialize_response::<Token>(&mut user)
           .await?
           .token;
       user.set_token(&token);
       // Send identify
       let mut identify = GatewayIdentifyPayload::common();
       identify.token = user.token();
       user.gateway.send_identify(identify).await;
       let object = User::get(&mut user, None).await?;
       let settings = User::get_settings(&mut user).await?;
       *user.object.write().unwrap() = object;
       *user.settings.write().unwrap() = settings;

I do not get this error. BUT: The first message received by the Server is the identify payload. Which is wrong. The first message should be the heartbeat!

But I don't understand why that happens - i only moved the last three lines a little up. the gateway connection should have been initialized before then, no? i mean, its not like i moved "send the identify payload" to before "create the shell user"

why is the order screwed up? and why does it not work at all, if i dont make this change?