@xuda.io/runtime-bundle
Version:
The Xuda Runtime Bundle refers to a collection of scripts and libraries packaged together to provide the necessary runtime environment for executing plugins or components in the Xuda platform.
484 lines (422 loc) • 15.3 kB
JavaScript
const _this = {};
export const init_module = (e) => {
_this.func = e.func;
_this.glb = e.glb;
_this.SESSION_OBJ = e.SESSION_OBJ;
_this.APP_OBJ = e.APP_OBJ;
_this.IS_DOCKER = e.IS_DOCKER;
_this.IS_API_SERVER = e.IS_API_SERVER;
_this.IS_PROCESS_SERVER = e.IS_PROCESS_SERVER;
};
export const live_preview_loader = async function (SESSION_ID) {
_this.glb.DEBUG_MODE = true;
// $(_this.SESSION_OBJ[SESSION_ID].root_element).css(
// "background-color",
// "white"
// ); // removed Aug 15,25
const ret = await init_studio_websocket(SESSION_ID);
if (ret.error) {
$(_session.root_element).show();
_this.func.UI.utils.progressScreen.show(SESSION_ID, 'Connection closed :(', null, true);
throw 'Connection closed :(';
}
var data = ret.e;
if (data.service === 'init_runtime_websocket') {
await _this.func.UI.main.embed_loader(SESSION_ID);
} else {
var data = e;
const call_embed = function () {
_session.prog_id = data.data.id;
console.log('call_embed', data.data.id);
_this.func.UI.screen.call_embed(SESSION_ID, data.data.id);
};
if (data.service === 'run_program_command') {
if (_this.func.UI.utils.get_url_attribute(SESSION_ID, 'prog') || (typeof live_preview_getCookie !== 'undefined' && live_preview_getCookie('prog_id') && data.data.id !== live_preview_getCookie('prog_id') && live_preview_getCookie('gtp_prog_dynamic') === '0' && _this.func.utils.get_device()))
return; // in case live preview is a program specific mode
try {
throw 'run new program, terminate prev execution';
} catch (ex) {
call_embed();
}
}
if (data.service === 'debug_command') {
_this.func.utils.debug.read_command(data.data);
return;
}
}
};
const init_studio_websocket = async function (SESSION_ID) {
return new Promise(async function (resolve, reject) {
var _session = _this.SESSION_OBJ[SESSION_ID];
var app_id = _session.app_id;
const set_connected = async function (stat) {
var datasource_changes = {
[0]: {
['data_system']: { SYS_GLOBAL_BOL_CONNECTED: stat },
},
};
await func.datasource.update(SESSION_ID, datasource_changes);
};
const peer_actions_module = await func.common.get_module(SESSION_ID, 'xuda-peer-actions-module.esm.js');
var preview_name = _session.url_params.preview_name || _session.opt.preview_name;
// const peer = new Peer();
const connect_peer = function () {
const peer = new Peer(SESSION_ID, {
host: `${_session.domain}`,
path: '/peer',
secure: true,
config: {
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{ urls: 'stun:stun.l.google.com:5349' },
{ urls: 'stun:stun1.l.google.com:3478' },
{ urls: 'stun:stun1.l.google.com:5349' },
{ urls: 'stun:stun2.l.google.com:19302' },
{ urls: 'stun:stun2.l.google.com:5349' },
{ urls: 'stun:stun3.l.google.com:3478' },
{ urls: 'stun:stun3.l.google.com:5349' },
{ urls: 'stun:stun4.l.google.com:19302' },
{ urls: 'stun:stun4.l.google.com:5349' },
],
},
});
STUDIO_PEER = peer;
peer.on('open', function (peer_id) {
var peer_token = _session.gtp_token;
const connect_peer = function () {
if ($('.loader').length) {
$('.loader_msg').html('Awaiting connection to Xuda Studio');
}
const conn = peer.connect(peer_token, {
metadata: {
url_params: _session.url_params,
client_info: _session.SYS_GLOBAL_OBJ_CLIENT_INFO,
preview_name,
user_info: _session.login_info,
live_token_id: _session.opt.live_token_id,
live_token_stat: _session.opt.live_token_stat,
},
});
conn.on('open', (e) => {
STUDIO_PEER_CONN_SEND_METHOD = conn.send.bind(conn);
STUDIO_PEER_CONN_ID = conn.connectionId;
set_connected(1);
conn.on('data', (data) => {
// console.log(data);
if (data.service === 'auth' && data.data.live_token_stat === 2) {
if (SESSION_OBJ[SESSION_ID].system_ready) {
conn.send({
service: 'system_ready',
// id: peer_id,
});
if (STUDIO_PEER_CONN_MSG_QUEUE.length) {
for (let val of STUDIO_PEER_CONN_MSG_QUEUE) {
val.id = conn.connectionId;
conn.send(val);
}
STUDIO_PEER_CONN_MSG_QUEUE = [];
}
}
return connect_to_ws(peer_id);
}
peer_actions_module.peer_actions(SESSION_ID, STUDIO_PEER_CONN_SEND_METHOD, data);
});
conn.on('error', (e) => {
console.error('peer conn', e);
});
conn.on('close', function (conn) {
set_connected(0);
$('body').removeClass('live_preview_online');
if (_session.opt.live_token_stat === 2) {
func.UI.utils.progressScreen.show(SESSION_ID, 'Connection lost. Attempting to reconnect...', false, true);
console.log('Connection lost. Attempting to reconnect...');
setTimeout(function () {
// connect_peer();
location.reload();
}, 5000); // wait 5 seconds before trying to reconnect
}
});
});
conn.on('error', (e) => {
console.error('peer conn', e);
});
// TBD
peer.on('call', function (call) {
const displayMediaStreamConstraints = {
video: {
cursor: 'always',
},
audio: true,
preferCurrentTab: true,
};
const success = function (stream) {
call.answer(stream);
};
const error = function (error) {
call.answer(error);
};
if (navigator.mediaDevices.getDisplayMedia) {
navigator.mediaDevices.getDisplayMedia(displayMediaStreamConstraints).then(success).catch(error);
} else {
navigator.getDisplayMedia(displayMediaStreamConstraints).then(success).catch(error);
}
// try {
// navigator.mediaDevices
// .getDisplayMedia( displayMediaStreamConstraints)
// .then(function (stream) {
// call.answer(stream); // Answer the call with an A/V stream.
// });
// } catch (err) {
// call.answer();
// }
});
// connect_to_ws(peer_id); // temp to remove
};
connect_peer();
});
peer.on('error', function (e) {
if ($('.loader').length) {
$('.loader_msg').html('Session has expired. Please renew the token session in Studio and reload.');
}
});
// peer.on("call", function (call) {
// const displayMediaStreamConstraints = {
// video: {
// cursor: "always",
// },
// audio: true,
// preferCurrentTab: true,
// };
// const success = function (stream) {
// call.answer(stream);
// };
// const error = function (error) {
// call.answer(error);
// };
// if (navigator.mediaDevices.getDisplayMedia) {
// navigator.mediaDevices
// .getDisplayMedia(displayMediaStreamConstraints)
// .then(success)
// .catch(error);
// } else {
// navigator
// .getDisplayMedia(displayMediaStreamConstraints)
// .then(success)
// .catch(error);
// }
// // try {
// // navigator.mediaDevices
// // .getDisplayMedia( displayMediaStreamConstraints)
// // .then(function (stream) {
// // call.answer(stream); // Answer the call with an A/V stream.
// // });
// // } catch (err) {
// // call.answer();
// // }
// });
/////////////////////////////////
};
const broadcast_channel = function () {
const channel = new BroadcastChannel(_session.gtp_token);
STUDIO_PEER = channel;
channel.onmessage = (event) => {
if (event.data.session_id !== SESSION_ID) return;
// if (event.data.service === "ping") {
// return channel.postMessage({
// service: "pong",
// session_id: SESSION_ID,
// });
// }
peer_actions_module.peer_actions(SESSION_ID, STUDIO_PEER_CONN_SEND_METHOD, event.data);
};
channel.postMessage({
service: 'connection',
metadata: {
url_params: _session.url_params,
client_info: _session.SYS_GLOBAL_OBJ_CLIENT_INFO,
preview_name,
user_info: _session.login_info,
session_id: SESSION_ID,
},
});
STUDIO_PEER_CONN_SEND_METHOD = channel.postMessage.bind(channel);
set_connected(1);
window.addEventListener('onCloseWindow', (event) => {
console.log('onCloseWindow');
channel.postMessage({
service: 'disconnected',
session_id: SESSION_ID,
type: 'onCloseWindow',
});
});
window.addEventListener('beforeunload', (event) => {
console.log('beforeunload');
channel.postMessage({
service: 'disconnected',
session_id: SESSION_ID,
type: 'beforeunload',
});
});
window.addEventListener('unload', (event) => {
console.log('beforeunload');
channel.postMessage({
service: 'disconnected',
session_id: SESSION_ID,
type: 'unload',
});
});
// return connect_to_ws(SESSION_ID);
resolve({ e: { service: 'init_runtime_websocket' } });
};
const connect_to_ws = function (peer_id) {
try {
const url = 'https://' + _session.domain;
STUDIO_WEBSOCKET = io(url, {
secure: true,
reconnection: _this.glb.debug_js ? false : true,
// reconnectionDelay:10000,
// reconnectionDelayMax: 30000,
rejectUnauthorized: false,
path: '/ws/socket.io',
});
const ws_data = {
service: 'init',
id: peer_id,
uid: _session.USR_OBJ._id,
source: 'runtime',
app_id: app_id,
preview_name: preview_name,
client_info: _session.SYS_GLOBAL_OBJ_CLIENT_INFO,
session_id: SESSION_ID,
gtp_token: _session.gtp_token,
app_token: _session.app_token,
};
STUDIO_WEBSOCKET.on('connect', () => {
STUDIO_WEBSOCKET_CONNECTION_ID = STUDIO_WEBSOCKET.id;
STUDIO_WEBSOCKET.emit('join-room', ws_data);
resolve({ e: { service: 'init_runtime_websocket' } });
});
STUDIO_WEBSOCKET.on('studio-connected', (data) => {
if (!data.reconnected) {
STUDIO_WEBSOCKET.emit('init-studio', {
...ws_data,
reconnected: true,
});
}
$(_session.root_element).addClass('live_preview_connected');
// $("body").addClass("live_preview_connected");
});
STUDIO_WEBSOCKET.on('user-disconnected', (data) => {
$(_session.root_element).removeClass('live_preview_connected');
$(_session.root_element).removeClass('live_preview_online');
});
STUDIO_WEBSOCKET.on('disconnect', () => {
console.log('disconnect', STUDIO_WEBSOCKET.id); // undefined
});
STUDIO_WEBSOCKET.io.on('reconnect', (attempt) => {
console.log('reconnect', attempt);
});
} catch (e) {
// connection to ws broken
resolve(true);
}
};
if (_session.local_live_preview === 'true') {
return broadcast_channel();
}
connect_peer();
});
};
export const send_STUDIO_WEBSOCKET = function (SESSION_ID, service) {
var _session = _this.SESSION_OBJ[SESSION_ID];
const data = {
service: service,
data: _session.USR_OBJ,
id: STUDIO_PEER_CONN_ID,
uid: _session.USR_OBJ._id,
source: 'runtime',
app_id: _session.app_id,
gtp_token: _session.gtp_token,
app_token: _session.app_token,
};
if (!STUDIO_PEER_CONN_SEND_METHOD) {
STUDIO_PEER_CONN_MSG_QUEUE.push(data);
return;
}
STUDIO_PEER_CONN_SEND_METHOD(data);
};
func.UI.screen.live_preview_hot_module_reload = async function (SESSION_ID, doc) {
// const $elm = func.UI.utils.find_in_element_data(
// "xuData",
// $(SESSION_OBJ[SESSION_ID].root_element),
// "prog_id",
// doc._id
// );
// console.log($elm);
const $elm = func.UI.utils.find_in_element_data('xuPanelData', $(SESSION_OBJ[SESSION_ID].root_element), 'parent_element_ui_id');
var panels_obj = {};
if (!$elm.length) {
// refresh screens
for await (const [key, val] of Object.entries(SESSION_OBJ[SESSION_ID].DS_GLB)) {
if (val.prog_id === doc._id) {
await func.action.execute(SESSION_ID, 'act_reload', val);
break;
}
}
return;
}
// refresh panels
for await (const [elem_key, elem_val] of Object.entries($elm)) {
if (elem_key === 'length') break;
var $div = $(elem_val);
let xuData = $div.data().xuData;
if (!$div.data().xuPanelData) continue;
let dsSession = xuData.paramsP.dsSessionP;
var _session = SESSION_OBJ[SESSION_ID];
let _ds = _session?.DS_GLB[dsSession];
if (!_ds) continue;
if (_ds.prog_id !== doc._id) {
continue;
}
const parent_element_ui_id = $div.data().xuPanelData.parent_element_ui_id;
if (!panels_obj[parent_element_ui_id]) {
panels_obj[parent_element_ui_id] = {
_ds,
$div,
ids: [],
};
}
panels_obj[parent_element_ui_id].ids.push($div.attr('xu-ui-id'));
}
for await (const [parent_element_ui_id, panel_val] of Object.entries(panels_obj)) {
var $div_elm = panel_val.$div
.parent()
.parent()
.find("[xu-ui-id='" + parent_element_ui_id + "']");
// restore original panel
try {
const $org_panel = panel_val.$div.data().xuPanelData.$panel_div; //panel_val.$div.clone(true);
const new_$div = await func.UI.screen.render_ui_tree(
SESSION_ID,
$div_elm,
_.cloneDeep(panel_val.$div.data().xuPanelData.node),
{},
$org_panel.data().xuData.paramsP,
null,
null,
$org_panel.data().xuData.key,
null,
$org_panel.data().xuData.parent_node,
null,
$org_panel.data().xuData.$root_container,
);
// remove old panel content
$.each(panel_val.ids, async function (key, val) {
$("[xu-ui-id='" + val + "']").remove();
});
} catch (error) {
debugger;
}
}
return panels_obj;
};