evmux-app-framework 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/package.json +21 -0
- package/src/AppsDataManager/AppsDataManager.js +52 -0
- package/src/AppsObserver/AppsObserver.js +131 -0
- package/src/EvmuxAppsApi/EvmuxAppsApi.js +75 -0
- package/src/EvmuxAppsApi/HelpersFromCore.js +85 -0
- package/src/PostMessageManager/PostMessageManager.js +80 -0
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# evmuxAppFramework
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "evmux-app-framework",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "webpack",
|
|
8
|
+
"build:prod": "webpack --mode production",
|
|
9
|
+
"dev": "webpack serve --mode development",
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [],
|
|
13
|
+
"author": "",
|
|
14
|
+
"license": "ISC",
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"html-webpack-plugin": "^5.5.0",
|
|
17
|
+
"webpack": "^5.75.0",
|
|
18
|
+
"webpack-cli": "^5.0.0",
|
|
19
|
+
"webpack-dev-server": "^4.11.1"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import { createPromise, generateGuid, pubSub } from '../EvmuxAppsApi/HelpersFromCore'
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export class AppsDataManager {
|
|
7
|
+
/*
|
|
8
|
+
_requests: {} */
|
|
9
|
+
|
|
10
|
+
constructor(){
|
|
11
|
+
this._userApps = {}
|
|
12
|
+
this._userAppInstances = {}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
updateUserAppData(appId, appData, merge = false) {
|
|
17
|
+
if (!merge || !this._userApps[appId]) {
|
|
18
|
+
this._userApps[appId] = appData;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
this._userApps[appId] = { ...this._userApps[appId], ...appData };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
updateUserAppInstance(instanceId, instanceData, merge = false) {
|
|
26
|
+
if (!merge || !this._userAppInstances[instanceId]) {
|
|
27
|
+
this._userAppInstances[instanceId] = instanceData;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
this._userAppInstances[instanceId] = { ...this._userAppInstances[instanceId], ...instanceData };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async getUserAppDataByAppId(userAppId) {
|
|
35
|
+
return this._userApps[userAppId];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async getUserAppInstanceById(userInstanceId, includeAppData = false) {
|
|
39
|
+
|
|
40
|
+
let appInstance = this._userAppInstances[userInstanceId];
|
|
41
|
+
|
|
42
|
+
if (appInstance && includeAppData)
|
|
43
|
+
{
|
|
44
|
+
appInstance.appData = await this.getUserAppDataByAppId(appInstance.userAppId)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return appInstance;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let appsDataManager = new AppsDataManager();
|
|
52
|
+
export default appsDataManager;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import { createPromise, generateGuid, pubSub } from '../EvmuxAppsApi/HelpersFromCore'
|
|
4
|
+
|
|
5
|
+
import PostMessageManager from '../PostMessageManager/PostMessageManager';
|
|
6
|
+
import appsDataManager from '../AppsDataManager/AppsDataManager';
|
|
7
|
+
|
|
8
|
+
let createEventResultObject = (eventName, result) => {
|
|
9
|
+
|
|
10
|
+
let eventObj = {
|
|
11
|
+
requestName: "EvEvent",
|
|
12
|
+
eventName,
|
|
13
|
+
data: {...result}
|
|
14
|
+
}
|
|
15
|
+
return eventObj;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AppsObserver {
|
|
20
|
+
/*
|
|
21
|
+
_requests: {} */
|
|
22
|
+
|
|
23
|
+
constructor(){
|
|
24
|
+
this._userAppInstances = {}
|
|
25
|
+
this._messagesEventHandlers = new pubSub()
|
|
26
|
+
this._eventHandler = new pubSub()
|
|
27
|
+
window.onmessage = this.onPostMessage.bind(this);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
raiseEvent(eventName, data) {
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
getAppSettingsForAppInstanceId(appInstanceId)
|
|
35
|
+
{
|
|
36
|
+
return {}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
_makeSureAppInstanceExist(userAppInstanceId)
|
|
40
|
+
{
|
|
41
|
+
this._userAppInstances[userAppInstanceId] = this._userAppInstances[userAppInstanceId] || { }
|
|
42
|
+
this._userAppInstances[userAppInstanceId].instances = this._userAppInstances[userAppInstanceId].instances || {};
|
|
43
|
+
this._userAppInstances[userAppInstanceId].events = this._userAppInstances[userAppInstanceId].events || {};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async onPostMessage(evt) {
|
|
47
|
+
|
|
48
|
+
let requestObj = {};
|
|
49
|
+
try {
|
|
50
|
+
requestObj = JSON.parse(evt.data);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.log("xxxx", error)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let result = null
|
|
56
|
+
|
|
57
|
+
if (requestObj.request == "updateSettings")
|
|
58
|
+
{
|
|
59
|
+
|
|
60
|
+
if (this._userAppInstances[requestObj.userAppInstanceId]) {
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
this._eventHandler.publish("updateSettings", requestObj)
|
|
64
|
+
|
|
65
|
+
if (this._userAppInstances[requestObj.userAppInstanceId].events['settingsUpdated'])
|
|
66
|
+
{
|
|
67
|
+
let eventObj = createEventResultObject("settingsUpdated", requestObj.data)
|
|
68
|
+
let stringObjToSend = JSON.stringify(eventObj)
|
|
69
|
+
for (const [key, instanceWindow] of Object.entries(this._userAppInstances[requestObj.userAppInstanceId].instances)) {
|
|
70
|
+
instanceWindow.window.postMessage(stringObjToSend, "*")
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else if (requestObj.request == "getSettings")
|
|
77
|
+
{
|
|
78
|
+
|
|
79
|
+
if (this._userAppInstances[requestObj.userAppInstanceId]) {
|
|
80
|
+
|
|
81
|
+
let eventObj = createEventResultObject("settings", requestObj.data)
|
|
82
|
+
let stringObjToSend = JSON.stringify(eventObj)
|
|
83
|
+
result = (await appsDataManager.getUserAppInstanceById(requestObj.userAppInstanceId, false)).settings
|
|
84
|
+
//this._userAppInstances[requestObj.userAppInstanceId].window.postMessage(stringObjToSend, "*")
|
|
85
|
+
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else if (requestObj.request == "startLoad")
|
|
89
|
+
{
|
|
90
|
+
this._makeSureAppInstanceExist(requestObj.userAppInstanceId);
|
|
91
|
+
this._userAppInstances[requestObj.userAppInstanceId].instances[requestObj.componentId] = { window: evt.source }
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
else if (requestObj.request == "loaded")
|
|
95
|
+
{
|
|
96
|
+
this._makeSureAppInstanceExist(requestObj.userAppInstanceId);
|
|
97
|
+
|
|
98
|
+
this._userAppInstances[requestObj.userAppInstanceId].instances[requestObj.componentId] = { window: evt.source }
|
|
99
|
+
|
|
100
|
+
result = this.getAppSettingsForAppInstanceId(requestObj.userAppInstanceId)
|
|
101
|
+
}
|
|
102
|
+
else if (requestObj.request == "registerEvent")
|
|
103
|
+
{
|
|
104
|
+
// verify that the app can register to this event
|
|
105
|
+
this._makeSureAppInstanceExist(requestObj.userAppInstanceId);
|
|
106
|
+
this._userAppInstances[requestObj.userAppInstanceId].events[requestObj.data.eventName] = true
|
|
107
|
+
}
|
|
108
|
+
else if (requestObj.request == "unregisterEvent")
|
|
109
|
+
{
|
|
110
|
+
this._makeSureAppInstanceExist(requestObj.userAppInstanceId);
|
|
111
|
+
delete this._userAppInstances[requestObj.userAppInstanceId].events[requestObj.data.eventName]
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
PostMessageManager.respondForPromiseBasedRequest(requestObj, evt.source, evt.origin, result);
|
|
115
|
+
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
onUserAppComponentUnload(userAppInstanceId, componentId)
|
|
119
|
+
{
|
|
120
|
+
if (this._userAppInstances[userAppInstanceId].instances[componentId]) {
|
|
121
|
+
delete this._userAppInstances[userAppInstanceId].instances[componentId]
|
|
122
|
+
if (Object.keys(this._userAppInstances[userAppInstanceId].instances).length == 0)
|
|
123
|
+
{
|
|
124
|
+
delete this._userAppInstances[userAppInstanceId]
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
export default new AppsObserver();
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import PostMessageManager from '../PostMessageManager/PostMessageManager.js'
|
|
2
|
+
|
|
3
|
+
const availableEvents = ["settingsUpdated", "viewerCountChanged", ""]
|
|
4
|
+
|
|
5
|
+
export default class EvmuxAppsApi {
|
|
6
|
+
|
|
7
|
+
constructor(userAppInstanceId, componentId) {
|
|
8
|
+
if (userAppInstanceId == null)
|
|
9
|
+
{
|
|
10
|
+
let appIdFromUrl = new URLSearchParams(window.location.search).get("appInstanceId");
|
|
11
|
+
|
|
12
|
+
if (appIdFromUrl !== null)
|
|
13
|
+
userAppInstanceId = appIdFromUrl;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (componentId == undefined)
|
|
17
|
+
{
|
|
18
|
+
let componentIdFromUrl = new URLSearchParams(window.location.search).get("compId");
|
|
19
|
+
|
|
20
|
+
if (componentIdFromUrl !== null)
|
|
21
|
+
componentId = componentIdFromUrl;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
this._postMessageManager = new PostMessageManager();
|
|
25
|
+
this._userAppInstanceId = userAppInstanceId;
|
|
26
|
+
this._componentId = componentId;
|
|
27
|
+
|
|
28
|
+
let reqObj = {request: "startLoad", userAppInstanceId: this._userAppInstanceId, componentId: this._componentId}
|
|
29
|
+
this._postMessageManager.sendRequest(reqObj);
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async registerEvent(eventName, callback)
|
|
34
|
+
{
|
|
35
|
+
this._postMessageManager._messagesEventHandlers.subscribe(eventName, callback)
|
|
36
|
+
|
|
37
|
+
let reqObj = { request: "registerEvent", userAppInstanceId: this._userAppInstanceId, componentId: this._componentId }
|
|
38
|
+
reqObj.data = {
|
|
39
|
+
eventName
|
|
40
|
+
}
|
|
41
|
+
return this._postMessageManager.sendRequestAsync(reqObj);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async unregisterEvent(eventName, callback)
|
|
45
|
+
{
|
|
46
|
+
this._postMessageManager._messagesEventHandlers.unsubscribe(eventName, callback)
|
|
47
|
+
let reqObj = { request: "unregisterEvent", userAppInstanceId: this._userAppInstanceId, componentId: this._componentId }
|
|
48
|
+
reqObj.data = {
|
|
49
|
+
eventName
|
|
50
|
+
}
|
|
51
|
+
return this._postMessageManager.sendRequestAsync(reqObj);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async reportLoaded() {
|
|
55
|
+
let reqObj = {request: "loaded", userAppInstanceId: this._userAppInstanceId, componentId: this._componentId}
|
|
56
|
+
return this._postMessageManager.sendRequestAsync(reqObj);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async getSettings() {
|
|
60
|
+
|
|
61
|
+
let reqObj = {request: "getSettings", userAppInstanceId: this._userAppInstanceId, componentId: this._componentId}
|
|
62
|
+
return this._postMessageManager.sendRequestAsync(reqObj);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async updateSettings(settingsObj) {
|
|
66
|
+
|
|
67
|
+
let requestObj = {
|
|
68
|
+
request: "updateSettings",
|
|
69
|
+
userAppInstanceId: this._userAppInstanceId,
|
|
70
|
+
componentId: this._componentId,
|
|
71
|
+
data: { ...settingsObj }
|
|
72
|
+
}
|
|
73
|
+
return this._postMessageManager.sendRequestAsync(requestObj);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export function createPromise(){
|
|
2
|
+
let resolve = null
|
|
3
|
+
let reject = null
|
|
4
|
+
|
|
5
|
+
let prom = new Promise((resolveF, rejectF) => {
|
|
6
|
+
resolve = resolveF
|
|
7
|
+
reject = rejectF
|
|
8
|
+
} )
|
|
9
|
+
|
|
10
|
+
return [prom, resolve, reject]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function generateGuid() {
|
|
14
|
+
var result, i, j;
|
|
15
|
+
result = '';
|
|
16
|
+
for(j=0; j<32; j++) {
|
|
17
|
+
if( j == 8 || j == 12 || j == 16 || j == 20)
|
|
18
|
+
result = result + '-';
|
|
19
|
+
i = Math.floor(Math.random()*16).toString(16).toUpperCase();
|
|
20
|
+
result = result + i;
|
|
21
|
+
}
|
|
22
|
+
return result.toLowerCase();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
export class pubSub
|
|
28
|
+
{
|
|
29
|
+
// this.subscribers = {};
|
|
30
|
+
|
|
31
|
+
constructor() {
|
|
32
|
+
this.subscribers = {};
|
|
33
|
+
}
|
|
34
|
+
init() {
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
publish(eventName, data /* EventArgs */) {
|
|
38
|
+
if (!Array.isArray(this.subscribers[eventName]))
|
|
39
|
+
return;
|
|
40
|
+
|
|
41
|
+
this.subscribers[eventName].forEach(
|
|
42
|
+
(subscriberCallback) => {
|
|
43
|
+
try{
|
|
44
|
+
subscriberCallback(eventName, data)
|
|
45
|
+
}catch (e) {
|
|
46
|
+
console.error(e)
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
subscribe(eventName, callback) {
|
|
53
|
+
if (!Array.isArray(this.subscribers[eventName])) {
|
|
54
|
+
this.subscribers[eventName] = [];
|
|
55
|
+
}
|
|
56
|
+
if (this.subscribers[eventName].indexOf(callback) >= 0)
|
|
57
|
+
return () => this.unsubscribe(eventName, callback);
|
|
58
|
+
this.subscribers[eventName].push(callback);
|
|
59
|
+
|
|
60
|
+
return () => this.unsubscribe(eventName, callback);
|
|
61
|
+
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
unsubscribe(eventName, callback) {
|
|
65
|
+
|
|
66
|
+
if (!Array.isArray(this.subscribers[eventName])) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (this.subscribers[eventName].indexOf(callback) < 0)
|
|
71
|
+
return false;
|
|
72
|
+
|
|
73
|
+
this.subscribers[eventName] = this.subscribers[eventName].filter((cb) => {
|
|
74
|
+
// Does not include the callback in the new array
|
|
75
|
+
if (cb === callback) {
|
|
76
|
+
return false
|
|
77
|
+
}
|
|
78
|
+
return true
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
}
|
|
85
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import {createPromise, generateGuid, pubSub} from '../EvmuxAppsApi/HelpersFromCore'
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export default class PostMessageManager {
|
|
7
|
+
/*
|
|
8
|
+
_requests: {} */
|
|
9
|
+
|
|
10
|
+
constructor(){
|
|
11
|
+
this._requests = {};
|
|
12
|
+
this._messagesEventHandlers = new pubSub()
|
|
13
|
+
window.onmessage = this.onPostMessage.bind(this);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static respondForPromiseBasedRequest(requestObj, targetWindow, targetAdress = '*', result)
|
|
17
|
+
{
|
|
18
|
+
if (targetAdress == 'null')
|
|
19
|
+
targetAdress = '*'
|
|
20
|
+
if (requestObj.promisedBased)
|
|
21
|
+
{
|
|
22
|
+
let objectToAttach = {requestGuid: requestObj.requestGuid, response: result}
|
|
23
|
+
targetWindow.postMessage(JSON.stringify(objectToAttach), '*');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async sendRequestAsync(requestObj, targetWindow = null) {
|
|
28
|
+
|
|
29
|
+
let reqId = generateGuid();
|
|
30
|
+
let [prom, resolve, reject] = createPromise();
|
|
31
|
+
|
|
32
|
+
this._requests[reqId] = {
|
|
33
|
+
prom,
|
|
34
|
+
resolve,
|
|
35
|
+
reject,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
requestObj.requestGuid = reqId;
|
|
39
|
+
requestObj.promisedBased = true;
|
|
40
|
+
|
|
41
|
+
targetWindow = targetWindow ? targetWindow : window.parent;
|
|
42
|
+
targetWindow.postMessage(JSON.stringify(requestObj), "*");
|
|
43
|
+
|
|
44
|
+
return prom;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
sendRequest(requestObj, targetWindow = null) {
|
|
48
|
+
|
|
49
|
+
let reqId = generateGuid();
|
|
50
|
+
|
|
51
|
+
requestObj.requestGuid = reqId;
|
|
52
|
+
|
|
53
|
+
targetWindow = targetWindow ? targetWindow : window.parent;
|
|
54
|
+
targetWindow.postMessage(JSON.stringify(requestObj), "*");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
onPostMessage(evt) {
|
|
59
|
+
try {
|
|
60
|
+
let reqObj = evt && JSON.parse(evt.data)
|
|
61
|
+
if (reqObj.requestGuid && this._requests[reqObj.requestGuid])
|
|
62
|
+
{
|
|
63
|
+
let res = this._requests[reqObj.requestGuid];
|
|
64
|
+
delete this._requests[reqObj.requestGuid]
|
|
65
|
+
return res.resolve(reqObj)
|
|
66
|
+
}
|
|
67
|
+
else if (reqObj.requestName == "EvEvent")
|
|
68
|
+
{
|
|
69
|
+
this._messagesEventHandlers.publish(reqObj.eventName, reqObj.data)
|
|
70
|
+
}
|
|
71
|
+
} catch (error) {
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
unregisterFromEvents(){
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
}
|