summaryrefslogtreecommitdiff
path: root/platform/javascript
diff options
context:
space:
mode:
authorFabio Alessandrelli <fabio.alessandrelli@gmail.com>2022-01-31 15:28:12 +0100
committerFabio Alessandrelli <fabio.alessandrelli@gmail.com>2022-02-06 18:53:50 +0100
commit948e66c3d6930924b54ec48a0dfc929040befb0a (patch)
treee188b040ed21bb5eb970a7d15e7cf3f18e037274 /platform/javascript
parent3cc72ac03f6d7254220b17e23384196112c60192 (diff)
[HTML5] Implement JavaScript PWA update callbacks.
Allows detecting when a new version of the progressive web app service worker is waiting (i.e. an update is pending), along a function to force the update and reload all clients.
Diffstat (limited to 'platform/javascript')
-rw-r--r--platform/javascript/api/api.cpp9
-rw-r--r--platform/javascript/api/javascript_singleton.h2
-rw-r--r--platform/javascript/godot_js.h2
-rw-r--r--platform/javascript/javascript_singleton.cpp8
-rw-r--r--platform/javascript/js/libs/library_godot_os.js55
-rw-r--r--platform/javascript/os_javascript.cpp16
-rw-r--r--platform/javascript/os_javascript.h5
7 files changed, 97 insertions, 0 deletions
diff --git a/platform/javascript/api/api.cpp b/platform/javascript/api/api.cpp
index 0c4accccc3..4190b24b8e 100644
--- a/platform/javascript/api/api.cpp
+++ b/platform/javascript/api/api.cpp
@@ -71,6 +71,9 @@ void JavaScript::_bind_methods() {
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "create_object", &JavaScript::_create_object_bind, mi);
}
ClassDB::bind_method(D_METHOD("download_buffer", "buffer", "name", "mime"), &JavaScript::download_buffer, DEFVAL("application/octet-stream"));
+ ClassDB::bind_method(D_METHOD("pwa_needs_update"), &JavaScript::pwa_needs_update);
+ ClassDB::bind_method(D_METHOD("pwa_update"), &JavaScript::pwa_update);
+ ADD_SIGNAL(MethodInfo("pwa_update_available"));
}
#if !defined(JAVASCRIPT_ENABLED) || !defined(JAVASCRIPT_EVAL_ENABLED)
@@ -102,6 +105,12 @@ Variant JavaScript::_create_object_bind(const Variant **p_args, int p_argcount,
}
#endif
#if !defined(JAVASCRIPT_ENABLED)
+bool JavaScript::pwa_needs_update() const {
+ return false;
+}
+Error JavaScript::pwa_update() {
+ return ERR_UNAVAILABLE;
+}
void JavaScript::download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime) {
}
#endif
diff --git a/platform/javascript/api/javascript_singleton.h b/platform/javascript/api/javascript_singleton.h
index 63f1aec624..e93b0a18a1 100644
--- a/platform/javascript/api/javascript_singleton.h
+++ b/platform/javascript/api/javascript_singleton.h
@@ -59,6 +59,8 @@ public:
Ref<JavaScriptObject> create_callback(const Callable &p_callable);
Variant _create_object_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
void download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime = "application/octet-stream");
+ bool pwa_needs_update() const;
+ Error pwa_update();
static JavaScript *get_singleton();
JavaScript();
diff --git a/platform/javascript/godot_js.h b/platform/javascript/godot_js.h
index 15de8b5dc7..2cb5c3025c 100644
--- a/platform/javascript/godot_js.h
+++ b/platform/javascript/godot_js.h
@@ -49,6 +49,8 @@ extern void godot_js_os_fs_sync(void (*p_callback)());
extern int godot_js_os_execute(const char *p_json);
extern void godot_js_os_shell_open(const char *p_uri);
extern int godot_js_os_hw_concurrency_get();
+extern int godot_js_pwa_cb(void (*p_callback)());
+extern int godot_js_pwa_update();
// Input
extern void godot_js_input_mouse_button_cb(int (*p_callback)(int p_pressed, int p_button, double p_x, double p_y, int p_modifiers));
diff --git a/platform/javascript/javascript_singleton.cpp b/platform/javascript/javascript_singleton.cpp
index b10e8007c0..77858bff01 100644
--- a/platform/javascript/javascript_singleton.cpp
+++ b/platform/javascript/javascript_singleton.cpp
@@ -30,6 +30,7 @@
#include "api/javascript_singleton.h"
#include "emscripten.h"
+#include "os_javascript.h"
extern "C" {
extern void godot_js_os_download_buffer(const uint8_t *p_buf, int p_buf_size, const char *p_name, const char *p_mime);
@@ -355,3 +356,10 @@ Variant JavaScript::eval(const String &p_code, bool p_use_global_exec_context) {
void JavaScript::download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime) {
godot_js_os_download_buffer(p_arr.ptr(), p_arr.size(), p_name.utf8().get_data(), p_mime.utf8().get_data());
}
+
+bool JavaScript::pwa_needs_update() const {
+ return OS_JavaScript::get_singleton()->pwa_needs_update();
+}
+Error JavaScript::pwa_update() {
+ return OS_JavaScript::get_singleton()->pwa_update();
+}
diff --git a/platform/javascript/js/libs/library_godot_os.js b/platform/javascript/js/libs/library_godot_os.js
index 662d215443..12d06a8d51 100644
--- a/platform/javascript/js/libs/library_godot_os.js
+++ b/platform/javascript/js/libs/library_godot_os.js
@@ -368,3 +368,58 @@ const GodotEventListeners = {
},
};
mergeInto(LibraryManager.library, GodotEventListeners);
+
+const GodotPWA = {
+
+ $GodotPWA__deps: ['$GodotRuntime', '$GodotEventListeners'],
+ $GodotPWA: {
+ hasUpdate: false,
+
+ updateState: function (cb, reg) {
+ if (!reg) {
+ return;
+ }
+ if (!reg.active) {
+ return;
+ }
+ if (reg.waiting) {
+ GodotPWA.hasUpdate = true;
+ cb();
+ }
+ GodotEventListeners.add(reg, 'updatefound', function () {
+ const installing = reg.installing;
+ GodotEventListeners.add(installing, 'statechange', function () {
+ if (installing.state === 'installed') {
+ GodotPWA.hasUpdate = true;
+ cb();
+ }
+ });
+ });
+ },
+ },
+
+ godot_js_pwa_cb__sig: 'vi',
+ godot_js_pwa_cb: function (p_update_cb) {
+ if ('serviceWorker' in navigator) {
+ const cb = GodotRuntime.get_func(p_update_cb);
+ navigator.serviceWorker.getRegistration().then(GodotPWA.updateState.bind(null, cb));
+ }
+ },
+
+ godot_js_pwa_update__sig: 'i',
+ godot_js_pwa_update: function () {
+ if ('serviceWorker' in navigator && GodotPWA.hasUpdate) {
+ navigator.serviceWorker.getRegistration().then(function (reg) {
+ if (!reg || !reg.waiting) {
+ return;
+ }
+ reg.waiting.postMessage('update');
+ });
+ return 0;
+ }
+ return 1;
+ },
+};
+
+autoAddDeps(GodotPWA, '$GodotPWA');
+mergeInto(LibraryManager.library, GodotPWA);
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 39eea13ca1..de5ca44f9d 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -45,6 +45,7 @@
#include <emscripten.h>
#include <stdlib.h>
+#include "api/javascript_singleton.h"
#include "godot_js.h"
void OS_JavaScript::alert(const String &p_alert, const String &p_title) {
@@ -203,6 +204,19 @@ void OS_JavaScript::file_access_close_callback(const String &p_file, int p_flags
}
}
+void OS_JavaScript::update_pwa_state_callback() {
+ if (OS_JavaScript::get_singleton()) {
+ OS_JavaScript::get_singleton()->pwa_is_waiting = true;
+ }
+ if (JavaScript::get_singleton()) {
+ JavaScript::get_singleton()->emit_signal("pwa_update_available");
+ }
+}
+
+Error OS_JavaScript::pwa_update() {
+ return godot_js_pwa_update() ? FAILED : OK;
+}
+
bool OS_JavaScript::is_userfs_persistent() const {
return idb_available;
}
@@ -226,6 +240,8 @@ OS_JavaScript::OS_JavaScript() {
godot_js_config_locale_get(locale_ptr, 16);
setenv("LANG", locale_ptr, true);
+ godot_js_pwa_cb(&OS_JavaScript::update_pwa_state_callback);
+
if (AudioDriverJavaScript::is_available()) {
#ifdef NO_THREADS
audio_drivers.push_back(memnew(AudioDriverScriptProcessor));
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index 3404fe9dcf..9e272f9aa1 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -45,11 +45,13 @@ class OS_JavaScript : public OS_Unix {
bool idb_is_syncing = false;
bool idb_available = false;
bool idb_needs_sync = false;
+ bool pwa_is_waiting = false;
static void main_loop_callback();
static void file_access_close_callback(const String &p_file, int p_flags);
static void fs_sync_callback();
+ static void update_pwa_state_callback();
protected:
void initialize() override;
@@ -65,6 +67,9 @@ public:
// Override return type to make writing static callbacks less tedious.
static OS_JavaScript *get_singleton();
+ bool pwa_needs_update() const { return pwa_is_waiting; }
+ Error pwa_update();
+
void initialize_joypads() override;
MainLoop *get_main_loop() const override;