Skip to content

Commit

Permalink
feat: service mods, launching modules externally
Browse files Browse the repository at this point in the history
This commit includes:
- Services for mods
- Launching modules externally from an another application
-  Bug fixes for TizenBrew and Updater
  • Loading branch information
reisxd committed Jul 9, 2024
1 parent f625438 commit 5643fd8
Show file tree
Hide file tree
Showing 12 changed files with 89 additions and 34 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-new-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ jobs:
- name: Package Updater for Desktop
working-directory: tizenbrew-updater/TizenBrewUpdater
run: |
pkg -C GZip .
pkg -C GZip . --no-bytecode --public
- name: Upload TizenBrew package artifact for Old Tizen
uses: actions/upload-artifact@v2
Expand Down
1 change: 1 addition & 0 deletions docs/MODULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Site modification modules are basically the same as application modules, but the
- `packageType`: The type of the module. Should be `mods`
- `appName`: The name of the module (user friendly, like "TizenTube").
- `websiteURL`: The URL of the website.
- `serviceFile`: The main JavaScript file of the service. Used if exists.
- `main`: The JavaScript file to be injected to the website.
- `keys`: The keys that should be registered using the [TVInputDevice](https://developer.samsung.com/smarttv/develop/api-references/tizen-web-device-api-references/tvinputdevice-api.html) API.
- `tizenAppId`: The Tizen application ID of the application that should be modified. Will be used if it exists.
Expand Down
2 changes: 1 addition & 1 deletion tizenbrew-app/TizenBrew/config.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<widget xmlns:tizen="http://tizen.org/ns/widgets" xmlns="http://www.w3.org/ns/widgets" id="https://tizentube.live" version="1.3.0" viewmodes="maximized">
<widget xmlns:tizen="http://tizen.org/ns/widgets" xmlns="http://www.w3.org/ns/widgets" id="https://tizentube.live" version="1.3.1" viewmodes="maximized">
<access origin="*" subdomains="true"></access>
<tizen:app-control>
<tizen:src name="index.html" reload="disable"/>
Expand Down
2 changes: 1 addition & 1 deletion tizenbrew-app/TizenBrew/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@
break;
}

if (packageType === 'service') {
if (packageType === 'service' || packageType === 'service-mods') {
window.send({ type: "startService", package: { name: packageName, type: moduleType } });
}
window.send({ type: "launch", package: { name: packageName, type: moduleType }, isTizen3, tvIp: webapis.network.getIp() });
Expand Down
67 changes: 47 additions & 20 deletions tizenbrew-app/TizenBrew/js/wsClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,6 @@ function onMessage(msg) {
send({ type: 'getServiceStatuses' });
} else {
send({ type: 'canLaunchInDebug' });
/*
const failedStartupAttempts = parseInt(localStorage.getItem('failedStartupAttempts'));
if (failedStartupAttempts < 2) {
localStorage.setItem('failedStartupAttempts', failedStartupAttempts + 1);
send({ type: 'relaunchInDebug', isTizen3, tvIp: webapis.network.getIp() });
tizen.application.getCurrentApplication().exit();
} else {
showError(`Error: Could not connect to the server after 3 attempts. Are you sure you changed the Host PC IP to 127.0.0.1?`);
localStorage.setItem('failedStartupAttempts', '0');
}*/
}
break;
}
Expand All @@ -64,7 +54,7 @@ function onMessage(msg) {
document.getElementById('appList').innerHTML = '';
for (const module of message.modules) {
document.getElementById('appList').innerHTML += `
<div data-packagename="${module.name}" data-appPath="${module.appPath}" class="card ${firstOne ? 'selected' : ''}" tabindex="0" data-keys="${module.keys.join(',')}" data-moddedTizenApp="${module.tizenAppId ? true : false}" data-packageType="${module.packageType}" data-moduleType="${module.moduleType}">
<div data-packagename="${module.name}" data-appPath="${module.appPath}" class="card ${firstOne ? 'selected' : ''}" tabindex="0" data-keys="${module.keys.join(',')}" data-moddedTizenApp="${module.tizenAppId ? true : false}" data-packageType="${module.serviceFile && module.packageType === 'mods' ? 'service-mods' : module.packageType}" data-moduleType="${module.moduleType}">
<div>
<h1>${module.appName}</h1>
<h3>
Expand Down Expand Up @@ -95,6 +85,39 @@ function onMessage(msg) {
canLaunchModules = true;
document.getElementById('wsText').innerText = 'Connected to server.';

const autoLaunchService = JSON.parse(localStorage.getItem('autoLaunchService'));

if (autoLaunchService) {
send({ type: 'startService', package: autoLaunchService });
}

if (message.appControlData) {
const moduleName = message.appControlData.module.name;
const moduleType = message.appControlData.module.type;
const keys = message.appControlData.module.keys;
const appPath = message.appControlData.module.appPath;
const tizenAppId = message.appControlData.module.tizenAppId;
const args = message.appControlData.args;

if (keys.length > 0) {
keys.forEach(key => {
tizen.tvinputdevice.registerKey(key);
});
}

if (message.appControlData.module.serviceFile) {
send({ type: 'startService', package: { name: moduleName, type: moduleType } });
}

setTimeout(() => {
send({ type: 'launch', package: { name: moduleName, type: moduleType } });
if (!tizenAppId) {
location.href = `${appPath}${args ? `?${args}` : ''}`;
}
}, 250);
return;
}

if (canAutoLaunch && localStorage.getItem('autoLaunch')) {
const autoLaunch = JSON.parse(localStorage.getItem('autoLaunch'));
const app = document.querySelector(`[data-packagename="${autoLaunch.name}"]`);
Expand All @@ -110,19 +133,13 @@ function onMessage(msg) {
tizen.tvinputdevice.registerKey(keys[i]);
}
}
var packageType = selectedItem.getAttribute("data-packageType");

var moduleType = selectedItem.getAttribute("data-moduleType");

if (!canLaunchModules) {
alert("You can't launch modules while the service hasn't connected yet.");

break;
}
var packageType = selectedItem.getAttribute("data-packageType");

if (packageType === 'service') {
if (packageType === 'service' || packageType === 'service-mods') {
send({ type: "startService", package: autoLaunch });
}

setTimeout(() => {
send({ type: 'launch', package: autoLaunch, isTizen3, tvIp: webapis.network.getIp() });
if (app.getAttribute('data-moddedTizenApp') === 'false') {
Expand Down Expand Up @@ -163,4 +180,14 @@ function onMessage(msg) {
function onOpen() {
// We have to get the debug status to know if we need to relaunch in debug mode.
send({ type: 'getDebugStatus' });
const data = tizen.application.getCurrentApplication().getRequestedAppControl().appControl.data;
if (data.length > 0) {
// TizenBrew allows other apps to launch a specific module outside of the TizenBrew app.
const moduleName = data[0].value.moduleName;
const moduleType = data[0].value.moduleType;
const args = data[0].value.args;

// Send the data to the server and launch it after TizenBrew relaunches.
send({ type: 'launchAppControl', package: { name: moduleName, type: moduleType }, args });
}
}
7 changes: 4 additions & 3 deletions tizenbrew-app/TizenBrew/moduleManager.html
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@
var hasConfirmined = confirm(`Do you want to remove ${packageName}?`);
if (hasConfirmined) {
var modules = JSON.parse(localStorage.getItem("modules"));
var newModules = modules.filter((module) => module.name != packageName && module.type != packageType);

var newModules = modules.filter((module) => module.name != packageName);
localStorage.setItem("modules", JSON.stringify(newModules));
location.reload();
}
Expand Down Expand Up @@ -116,7 +117,7 @@
document.getElementById("appList").innerHTML = "";
for (const module of modules) {
document.getElementById("appList").innerHTML += `
<div data-packagename="${module}" class="card ${firstOne ? "selected" : ""}" tabindex="0" data-packagetype="${module.type}">
<div data-packagename="${module.name}" class="card ${firstOne ? "selected" : ""}" tabindex="0" data-packagetype="${module.type}">
<h1>${module.name}</h1>
</div>
`;
Expand Down Expand Up @@ -156,7 +157,7 @@ <h3>This is primarily for development and for developers.</h3>
document.getElementById("appList").innerHTML += `
<div class="card" id="add" data-packagetype="${type}">
<h1>Add Module</h1>
<label class="label">Module Name (For ${type.toUpperCase}):</label>
<label class="label">Module Name (For ${type.toUpperCase()}):</label>
<input type="text" class="form-input" placeholder="@foxreis/tizentube" id="appName" tabindex="0">
</div>
`;
Expand Down
3 changes: 2 additions & 1 deletion tizenbrew-app/TizenBrew/service/debugger.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ function startDebugging(port, adb_conn, ip) {
).then(
debuggerJson => {
global.inDebug.webDebug = true;
global.currentClient.send(JSON.stringify({ type: 'canLaunchModules' }));
global.currentClient.send(JSON.stringify({ type: 'canLaunchModules', appControlData: global.appControlData }));
clearInterval(connectionInterval);
global.appControlData = null;
return attachDebugger(debuggerJson[0].webSocketDebuggerUrl, adb_conn);
}).catch(
e => {
Expand Down
6 changes: 6 additions & 0 deletions tizenbrew-app/TizenBrew/service/moduleLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ function loadModules(moduleList) {
appName: moduleJson.appName,
description: moduleJson.description,
appPath: moduleJson.websiteURL,
serviceFile: moduleJson.serviceFile,
packageType: moduleJson.packageType,
mainFile: moduleJson.main,
keys: moduleJson.keys || [],
Expand All @@ -47,6 +48,11 @@ function loadModules(moduleList) {
.catch(e => {
return {
appName: module.name,
name: module.name,
appPath: 'file://index.html',
keys: [],
moduleType: module.type,
packageType: 'app',
description: `Unknown module ${module.name}. Please check the module name and try again.`
}
});
Expand Down
18 changes: 18 additions & 0 deletions tizenbrew-app/TizenBrew/service/service.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ module.exports.onStart = function () {
};
global.currentClient = null;
global.services = new Map();
global.appControlData = null;

function createAdbConnection(isTizen3, ip, appId) {
if (adb) {
Expand Down Expand Up @@ -94,6 +95,20 @@ module.exports.onStart = function () {
}

switch (message.type) {
case 'launchAppControl': {
loadModules([message.package]).then(modules => {
const module = modules.find(m => m.name === message.package.name);
if (!module) {
ws.send(JSON.stringify({ type: 'error', message: 'Module not found.' }));
return;
}
global.appControlData = {
module,
args: message.args
};
});
break;
}
case 'getDebugStatus': {
ws.send(JSON.stringify({ type: 'debugStatus', inDebug: global.inDebug }));
break;
Expand Down Expand Up @@ -139,6 +154,9 @@ module.exports.onStart = function () {
type: 'app',
path: `http://127.0.0.1:8081/module/${message.package.type}/${encodeURIComponent(message.package.name)}/${module.appPath}`
}

global.inDebug.tizenDebug = false;
global.inDebug.webDebug = false;
}
});
break;
Expand Down
10 changes: 6 additions & 4 deletions tizenbrew-app/TizenBrew/service/serviceLauncher.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ function startService(module, pkg) {
let sandbox = {};

Object.getOwnPropertyNames(global).forEach(prop => {
const disAllowed = ['services', 'module', 'global', 'inDebug', 'currentClient', 'currentModule', 'process'];
const disAllowed = ['services', 'module', 'global', 'inDebug', 'currentClient', 'currentModule'];
if (disAllowed.includes(prop)) return;
sandbox[prop] = global[prop];
});



sandbox['require'] = require;
sandbox['module'] = { exports: {} };

fetch(`https://cdn.jsdelivr.net/${pkg.type}/${pkg.name}/${module.serviceFile}`)
.then(res => res.text())
.then(script => {
Expand All @@ -22,7 +24,7 @@ function startService(module, pkg) {
});

try {
vm.runInContext(script, global.services.get(pkg.name).context).catch(e => console.error(e));
vm.runInContext(script, global.services.get(pkg.name).context);
} catch (e) {
console.error(e);
global.services.get(pkg.name).hasCrashed = true;
Expand Down
2 changes: 1 addition & 1 deletion tizenbrew-updater/TizenBrewUpdater/config.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<widget xmlns:tizen="http://tizen.org/ns/widgets" xmlns="http://www.w3.org/ns/widgets" id="https://tizentube.live"
version="1.0.0" viewmodes="maximized">
version="1.0.1" viewmodes="maximized">
<access origin="*" subdomains="true" />
<tizen:app-control>
<tizen:src name='index.html' reload='disable'></tizen:src>
Expand Down
3 changes: 1 addition & 2 deletions tizenbrew-updater/TizenBrewUpdater/service/service.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ module.exports.onStart = function () {
const fetch = require('node-fetch');
const express = require('express');
const app = express();
app.use(express.static('/snapshot/TizenBrewUpdater'));
const fs = require('fs');
app.use(express.static(`${process.platform === 'win32' ? 'C:' : '' }/snapshot/TizenBrewUpdater`));
const server = new WebSocket.Server({ server: app.listen(8083) });

global.currentClient = null;
Expand Down

0 comments on commit 5643fd8

Please sign in to comment.