-use wasm_bindgen::JsValue;
+use js_sys::{Function, JsString, Promise};
+use std::collections::HashMap;
+use wasm_bindgen::{JsCast, JsValue};
+use wasm_bindgen_futures::JsFuture;
use web_sys::{window, Document, Request, RequestInit, Window};
+use crate::constants::BACKEND_URL;
+
pub fn get_window_document() -> Result<(Window, Document), String> {
let window = window().ok_or_else(|| String::from("Failed to get window"))?;
let document = window
Ok(request)
}
+
+pub async fn send_to_backend(entries: HashMap<String, String>) -> Result<String, String> {
+ let mut send_json_string = String::from("{");
+ for (key, value) in entries {
+ send_json_string.push('"');
+ send_json_string.push_str(&key);
+ send_json_string.push_str("\":\"");
+ send_json_string.push_str(&value);
+ send_json_string.push_str("\",");
+ }
+ send_json_string.truncate(send_json_string.len() - 1);
+ send_json_string.push('}');
+
+ // TODO check usage of "no-cors"
+ let function = Function::new_no_args(&format!(
+ "
+ let fetch_settings = {{}};
+ fetch_settings.method = 'POST';
+ fetch_settings.headers = {{}};
+ fetch_settings.headers['Content-Type'] = 'application/json';
+ fetch_settings.headers['Accept'] = 'text/html,application/json';
+ //fetch_settings.mode = 'no-cors';
+ fetch_settings.body = '{}';
+
+ return fetch('{}', fetch_settings)
+ .then((response) => {{
+ return response.text();
+ }});
+ ",
+ send_json_string, BACKEND_URL,
+ ));
+
+ let jsvalue: JsValue = function
+ .call0(&function)
+ .map_err(|e| format!("Failed to POST to backend: {:?}", e))?;
+ let promise: Promise = jsvalue.dyn_into().map_err(|e| {
+ format!(
+ "Failed to get Promise out of JsValue when POSTing to backend: {:?}",
+ e
+ )
+ })?;
+ let future_result: JsValue = JsFuture::from(promise)
+ .await
+ .map_err(|e| format!("Failed to await promise when POSTing to backend: {:?}", e))?;
+
+ let json_string = String::from(JsString::from(future_result));
+
+ Ok(json_string)
+}
use crate::game_logic::{check_win_draw, WinType};
use crate::html_helper::{
append_to_info_text, create_json_request, element_append_class, element_remove_class,
- get_window_document,
+ get_window_document, send_to_backend,
};
use crate::random_helper::get_seeded_random;
-use crate::state::{BoardState, GameState, MainMenuMessage, SharedState, Turn};
+use crate::state::{
+ BoardState, GameState, MainMenuMessage, PairingRequestResponse, SharedState, Turn,
+};
use std::cell::Cell;
+use std::collections::HashMap;
use std::rc::Rc;
use js_sys::{Function, Promise};
fn get_networked_player_id(&mut self, ctx: &Context<Self>) {
// make a request to get the player_id
ctx.link().send_future(async {
- // get window
- let window = web_sys::window().expect("Should be able to get Window");
- // get request
- let request = create_json_request(BACKEND_URL, "{\"type\": \"pairing_request\"}")
- .expect("Should be able to create the JSON request for player_id");
- // send request
- let promise = window.fetch_with_request(&request);
- // get request result
- let jsvalue_result = JsFuture::from(promise)
- .await
- .map_err(|e| format!("{:?}", e));
- if let Err(e) = jsvalue_result {
- return WrapperMsg::BackendResponse(BREnum::Error(format!(
- "ERROR jsvalue_result: {:?}",
- e
- )));
- }
- log::warn!("{:?}", jsvalue_result.as_ref().unwrap());
- // get response from request result
- let response_result: Result<Response, _> = jsvalue_result.unwrap().dyn_into();
- if let Err(e) = response_result {
- return WrapperMsg::BackendResponse(BREnum::Error(format!(
- "ERROR response_result: {:?}",
- e
- )));
- }
- let json_jsvalue_promise_result = response_result.unwrap().json();
- if let Err(e) = json_jsvalue_promise_result {
- return WrapperMsg::BackendResponse(BREnum::Error(format!(
- "ERROR json_jsvalue_promise_result: {:?}",
- e
- )));
- }
- let json_jsvalue_result = JsFuture::from(json_jsvalue_promise_result.unwrap()).await;
- if let Err(e) = json_jsvalue_result {
- return WrapperMsg::BackendResponse(BREnum::Error(format!(
- "ERROR json_jsvalue_result: {:?}",
- e
- )));
- }
- let json_result = json_jsvalue_result.unwrap().into_serde();
- if let Err(e) = json_result {
- return WrapperMsg::BackendResponse(BREnum::Error(format!(
- "ERROR json_result: {:?}",
- e
- )));
- }
- // get serde json Value from result
- let json_value: SerdeJSONValue = json_result.unwrap();
- log::warn!("{:?}", json_value);
+ let mut json_entries = HashMap::new();
+ json_entries.insert("type".into(), "pairing_request".into());
- // get and check "type" in JSON
- let type_opt = json_value.get("type");
- if type_opt.is_none() {
- return WrapperMsg::BackendResponse(BREnum::Error(
- "ERROR: No \"type\" entry in JSON".into(),
- ));
- }
- let json_type = type_opt.unwrap();
- if let Some(type_string) = json_type.as_str() {
- if type_string != "pairing_response" {
- return WrapperMsg::BackendResponse(BREnum::Error(
- "ERROR: Invalid \"type\" from response JSON".into(),
- ));
- }
- } else {
- return WrapperMsg::BackendResponse(BREnum::Error(
- "ERROR: Missing \"type\" from response JSON".into(),
- ));
+ let send_to_backend_result = send_to_backend(json_entries).await;
+ if let Err(e) = send_to_backend_result {
+ return WrapperMsg::BackendResponse(BREnum::Error(format!("{:?}", e)));
}
- // get and check "id" in JSON
- let player_id: u32;
- if let Some(wrapped_player_id) = json_value.get("id") {
- if let Some(player_id_u64) = wrapped_player_id.as_u64() {
- let player_id_conv_result: Result<u32, _> = player_id_u64.try_into();
- if player_id_conv_result.is_err() {
- return WrapperMsg::BackendResponse(BREnum::Error(
- "ERROR: \"id\" is too large".into(),
- ));
- }
- player_id = player_id_conv_result.unwrap();
- } else {
- return WrapperMsg::BackendResponse(BREnum::Error(
- "ERROR: \"id\" is not a u64".into(),
- ));
- }
- } else {
- return WrapperMsg::BackendResponse(BREnum::Error(
- "ERROR: Missing \"id\" from response JSON".into(),
- ));
+ let request_result: Result<PairingRequestResponse, _> =
+ serde_json::from_str(&send_to_backend_result.unwrap());
+ if let Err(e) = request_result {
+ return WrapperMsg::BackendResponse(BREnum::Error(format!("{:?}", e)));
}
+ let request = request_result.unwrap();
- // get and check status
- #[derive(Copy, Clone, Debug, PartialEq, Eq)]
- enum Status {
- Waiting,
- Paired,
- }
- let mut status: Status;
- if let Some(status_value) = json_value.get("status") {
- if let Some(status_str) = status_value.as_str() {
- if status_str == "waiting" {
- status = Status::Waiting;
- } else if status_str == "paired" {
- status = Status::Paired;
- } else {
- return WrapperMsg::BackendResponse(BREnum::Error(
- "ERROR: Got invalid \"status\" response in JSON".into(),
- ));
- }
- } else {
- return WrapperMsg::BackendResponse(BREnum::Error(
- "ERROR: \"status\" response in JSON is not a str".into(),
- ));
- }
- } else {
+ if request.r#type != "pairing_response" {
return WrapperMsg::BackendResponse(BREnum::Error(
- "ERROR: \"status\" response is missing in JSON".into(),
+ "Backend returned invalid type for pairing_request".into(),
));
}
- // set "disconnect" callback here so that the client sends
- // disconnect message when the page is closed
+ // set up onbeforeunload to disconnect with the received id
let function = Function::new_no_args(&format!(
"
- window.onunload = function(event) {{
- let request_conf = {{}};
- request_conf.method = 'POST';
- request_conf.headers = \"'Content-Type': 'application/json'\";
- request_conf.body = \"{{ \"type\": \"disconnect\", \"id\": {} }}\";
-
- const request = new Request('{}', request_conf);
-
- fetch(request);
- }};
+ window.addEventListener(\"beforeunload\", function(event) {{
+ let xhr = new XMLHttpRequest();
+ xhr.open('POST', '{}');
+ xhr.send('{{\"type\": \"disconnect\", \"id\": {}}}');
+ }});
",
- player_id, BACKEND_URL
+ BACKEND_URL, request.id
));
function.call0(&function).ok();
- if status == Status::Paired {
- // Get which side current player is on if paired
- // TODO
- return WrapperMsg::BackendResponse(BREnum::Error("ERROR: unimplemented".into()));
+ if let Some(color) = request.color {
+ WrapperMsg::BackendResponse(BREnum::GotID(
+ request.id,
+ if color == "cyan" {
+ Some(Turn::CyanPlayer)
+ } else {
+ Some(Turn::MagentaPlayer)
+ },
+ ))
} else {
- WrapperMsg::BackendResponse(BREnum::GotID(player_id, None))
+ WrapperMsg::BackendResponse(BREnum::GotID(request.id, None))
}
});
}
}
BREnum::GotID(id, turn_opt) => {
self.player_id = Some(id);
+ log::warn!("Got player id {}", id);
}
},
} // match (msg)