use std::error::Error;
use futures::stream::{SplitSink, SplitStream};
use futures::StreamExt;
use log::{debug, error, info, Level, trace};
use wasm_bindgen::prelude::*;
use ws_stream_wasm::{WsMessage, WsMeta, WsStream};
use protocol::State;
use protocol::PROTOCOL_VERSION;
use protocol::MessageS2C;
use protocol::MessageC2S;
use futures::SinkExt;
#[macro_use]
pub mod macros;
#[wasm_bindgen]
extern {
pub fn alert(s: &str);
}
#[wasm_bindgen]
pub fn send_chat(chat: &str) {
info!("sending chat: {}", chat);
}
#[wasm_bindgen]
pub async fn rust_init(gateway: &str, username: &str) -> Result<(), JsError> {
console_log::init_with_level(Level::Debug).unwrap();
info!("Logger setup successfully");
match main(gateway, username).await {
Ok(c) => c,
Err(e) => {
error!("Error initializing gateway client: {}", e);
return Err(JsError::new(&e.to_string()));
}
};
info!("Gateway client exited");
Ok(())
}
pub struct Client {
pub state: State,
pub tx: SplitSink<WsStream, WsMessage>,
pub rx: SplitStream<WsStream>
}
pub async fn main(gateway: &str, username: &str) -> Result<(), Box<dyn Error>> {
info!("FAST CONNECT: {}", gateway);
let gateway_url = url::Url::parse(gateway)?;
trace!("Gateway URL parsed");
let (_ws, ws_stream) = WsMeta::connect(gateway_url, None).await?;
trace!("Connected to gateway socket");
let (tx, rx) = ws_stream.split();
let mut client = Client {
state: State::Handshake,
tx,
rx
};
trace!("Split stream, handshaking with server");
send!(client.tx, &MessageC2S::Hello {
next_state: State::Play,
version: PROTOCOL_VERSION,
requested_username: username.to_string()
}).await?;
trace!("Sent handshake start packet");
if let Some(msg) = recv_now!(client.rx)? {
let typed_msg: MessageS2C = msg;
match typed_msg {
MessageS2C::Hello { version, given_username, next_state } => {
info!("FAST CONNECT - connected to server protocol {} given username {}, switching to state {:?}", version, given_username, next_state);
client.state = next_state;
},
MessageS2C::Goodbye { reason } => {
error!("server disconnected before finishing handshake: {:?}", reason);
return Err(format!("disconnected by server: {:?}", reason).into());
}
}
} else {
error!("Server closed the connection")
}
Ok(())
}