fix: stabilize web registration and asset loading
This commit is contained in:
@@ -17,8 +17,8 @@ const CONFIG_PATHS: Array[String] = [
|
||||
]
|
||||
|
||||
const DEFAULT_PROFILE: String = "production"
|
||||
const DEFAULT_API_BASE_URL: String = "https://whaletownend.xinghangee.icu"
|
||||
const DEFAULT_WS_URL: String = "wss://whaletownend.xinghangee.icu/game"
|
||||
const DEFAULT_API_BASE_URL: String = "https://whaletown.novamailio.com/api"
|
||||
const DEFAULT_WS_URL: String = "wss://whaletown.novamailio.com/game"
|
||||
|
||||
const API_BASE_URL_ENV_KEY: String = "WHALETOWN_API_BASE_URL"
|
||||
const CHAT_WS_URL_ENV_KEY: String = "WHALETOWN_CHAT_WS_URL"
|
||||
@@ -35,6 +35,10 @@ static func get_api_base_url() -> String:
|
||||
if not env_url.is_empty():
|
||||
return _trim_trailing_slash(env_url)
|
||||
|
||||
var browser_url := _get_browser_same_origin_url("/api")
|
||||
if not browser_url.is_empty():
|
||||
return browser_url
|
||||
|
||||
var network_config := _get_active_network_config()
|
||||
var url: String = str(network_config.get("api_base_url", "")).strip_edges()
|
||||
if not url.is_empty():
|
||||
@@ -51,6 +55,10 @@ static func get_chat_ws_url() -> String:
|
||||
if not env_url.is_empty():
|
||||
return env_url
|
||||
|
||||
var browser_url := _get_browser_same_origin_websocket_url("/game")
|
||||
if not browser_url.is_empty():
|
||||
return browser_url
|
||||
|
||||
var network_config := _get_active_network_config()
|
||||
var url: String = str(network_config.get("chat_ws_url", network_config.get("game_ws_url", ""))).strip_edges()
|
||||
if not url.is_empty():
|
||||
@@ -75,6 +83,10 @@ static func get_location_ws_url() -> String:
|
||||
if not game_env_url.is_empty():
|
||||
return game_env_url
|
||||
|
||||
var browser_url := _get_browser_same_origin_websocket_url("/game")
|
||||
if not browser_url.is_empty():
|
||||
return browser_url
|
||||
|
||||
var network_config := _get_active_network_config()
|
||||
var url: String = str(network_config.get("location_ws_url", network_config.get("game_ws_url", ""))).strip_edges()
|
||||
if not url.is_empty():
|
||||
@@ -154,7 +166,7 @@ static func _load_config() -> Dictionary:
|
||||
return {}
|
||||
|
||||
static func _get_browser_query_value(key: String) -> String:
|
||||
if OS.get_name() != "Web" or not OS.is_debug_build():
|
||||
if OS.get_name() != "Web":
|
||||
return ""
|
||||
|
||||
if not Engine.has_singleton("JavaScriptBridge"):
|
||||
@@ -168,6 +180,25 @@ static func _get_browser_query_value(key: String) -> String:
|
||||
var value: Variant = js_bridge.eval(script, true)
|
||||
return str(value).strip_edges()
|
||||
|
||||
static func _get_browser_same_origin_url(path: String) -> String:
|
||||
if OS.get_name() != "Web" or not Engine.has_singleton("JavaScriptBridge"):
|
||||
return ""
|
||||
var js_bridge: Object = Engine.get_singleton("JavaScriptBridge")
|
||||
if js_bridge == null:
|
||||
return ""
|
||||
var origin: String = str(js_bridge.eval("window.location.origin || ''", true)).strip_edges()
|
||||
if not origin.begins_with("http://") and not origin.begins_with("https://"):
|
||||
return ""
|
||||
return _trim_trailing_slash(origin) + path
|
||||
|
||||
static func _get_browser_same_origin_websocket_url(path: String) -> String:
|
||||
var http_url := _get_browser_same_origin_url("")
|
||||
if http_url.begins_with("https://"):
|
||||
return "wss://" + http_url.substr(8) + path
|
||||
if http_url.begins_with("http://"):
|
||||
return "ws://" + http_url.substr(7) + path
|
||||
return ""
|
||||
|
||||
static func _get_browser_url_override(key: String, allowed_schemes: Array[String]) -> String:
|
||||
var value := _get_browser_query_value(key)
|
||||
if value.is_empty():
|
||||
|
||||
123
_Core/utils/WebFilePicker.gd
Normal file
123
_Core/utils/WebFilePicker.gd
Normal file
@@ -0,0 +1,123 @@
|
||||
extends RefCounted
|
||||
|
||||
var _javascript_callback: Variant
|
||||
var _result_callback: Callable
|
||||
var _callback_name: String = ""
|
||||
|
||||
func open(accept: String, max_bytes: int, result_callback: Callable) -> bool:
|
||||
if OS.get_name() != "Web" or not Engine.has_singleton("JavaScriptBridge"):
|
||||
return false
|
||||
if _result_callback.is_valid():
|
||||
return false
|
||||
|
||||
var javascript_bridge: Object = Engine.get_singleton("JavaScriptBridge")
|
||||
_callback_name = "__whaletownFilePicker%d" % get_instance_id()
|
||||
_result_callback = result_callback
|
||||
_javascript_callback = javascript_bridge.create_callback(_on_javascript_result)
|
||||
var window: Variant = javascript_bridge.get_interface("window")
|
||||
if window == null:
|
||||
_reset()
|
||||
return false
|
||||
window[_callback_name] = _javascript_callback
|
||||
|
||||
var script := """
|
||||
(() => {
|
||||
const callbackName = %s;
|
||||
const callback = window[callbackName];
|
||||
if (typeof callback !== "function") return false;
|
||||
|
||||
const previous = document.getElementById("whaletown-web-file-picker");
|
||||
if (previous) previous.remove();
|
||||
|
||||
const input = document.createElement("input");
|
||||
input.id = "whaletown-web-file-picker";
|
||||
input.type = "file";
|
||||
input.accept = %s;
|
||||
input.style.display = "none";
|
||||
let finished = false;
|
||||
|
||||
const finish = (status, name, mime, payload) => {
|
||||
if (finished) return;
|
||||
finished = true;
|
||||
callback(status, name || "", mime || "", payload || "");
|
||||
input.remove();
|
||||
delete window[callbackName];
|
||||
};
|
||||
|
||||
input.addEventListener("cancel", () => finish("cancel", "", "", ""));
|
||||
input.addEventListener("change", () => {
|
||||
const file = input.files && input.files[0];
|
||||
if (!file) {
|
||||
finish("cancel", "", "", "");
|
||||
return;
|
||||
}
|
||||
if (file.size > %d) {
|
||||
finish("too_large", file.name, file.type, "");
|
||||
return;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onerror = () => finish("read_error", file.name, file.type, "");
|
||||
reader.onload = () => {
|
||||
const bytes = new Uint8Array(reader.result);
|
||||
const chunks = [];
|
||||
const chunkSize = 0x8000;
|
||||
for (let offset = 0; offset < bytes.length; offset += chunkSize) {
|
||||
chunks.push(String.fromCharCode(...bytes.subarray(offset, offset + chunkSize)));
|
||||
}
|
||||
finish("ok", file.name, file.type, btoa(chunks.join("")));
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
});
|
||||
|
||||
document.body.appendChild(input);
|
||||
input.click();
|
||||
return true;
|
||||
})()
|
||||
""" % [JSON.stringify(_callback_name), JSON.stringify(accept), max_bytes]
|
||||
var opened: Variant = javascript_bridge.eval(script, true)
|
||||
if opened != true:
|
||||
_reset()
|
||||
return false
|
||||
return true
|
||||
|
||||
func _on_javascript_result(arguments: Array) -> void:
|
||||
var callback := _result_callback
|
||||
_reset()
|
||||
if not callback.is_valid():
|
||||
return
|
||||
var status := str(arguments[0]) if arguments.size() > 0 else "read_error"
|
||||
var file_name := str(arguments[1]) if arguments.size() > 1 else ""
|
||||
var mime_type := str(arguments[2]) if arguments.size() > 2 else ""
|
||||
var base64_data := str(arguments[3]) if arguments.size() > 3 else ""
|
||||
callback.call(status, file_name, mime_type, base64_data)
|
||||
|
||||
func _reset() -> void:
|
||||
_javascript_callback = null
|
||||
_result_callback = Callable()
|
||||
_callback_name = ""
|
||||
|
||||
static func save_base64_file(base64_data: String, file_name: String, prefix: String) -> String:
|
||||
if base64_data.is_empty():
|
||||
return ""
|
||||
var bytes := Marshalls.base64_to_raw(base64_data)
|
||||
if bytes.is_empty():
|
||||
return ""
|
||||
|
||||
var extension := file_name.get_extension().to_lower()
|
||||
if not ["png", "jpg", "jpeg", "webp"].has(extension):
|
||||
extension = "bin"
|
||||
var root := DirAccess.open("user://")
|
||||
if root == null:
|
||||
return ""
|
||||
if not root.dir_exists("web_uploads") and root.make_dir("web_uploads") != OK:
|
||||
return ""
|
||||
|
||||
var safe_prefix := prefix.to_lower().replace(" ", "_")
|
||||
var path := "user://web_uploads/%s_%d.%s" % [safe_prefix, Time.get_ticks_msec(), extension]
|
||||
var file := FileAccess.open(path, FileAccess.WRITE)
|
||||
if file == null:
|
||||
return ""
|
||||
file.store_buffer(bytes)
|
||||
file.close()
|
||||
return path
|
||||
1
_Core/utils/WebFilePicker.gd.uid
Normal file
1
_Core/utils/WebFilePicker.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dqvrn7yv0ap4y
|
||||
Reference in New Issue
Block a user