Skip to content

Commit 8fab9a4

Browse files
committed
feat: extension interface for inter extension communication
1 parent 1326f80 commit 8fab9a4

File tree

3 files changed

+144
-0
lines changed

3 files changed

+144
-0
lines changed

src/utils/ExtensionInterface.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* GNU AGPL-3.0 License
3+
*
4+
* Modified Work Copyright (c) 2021 - present core.ai . All rights reserved.
5+
* Original work Copyright (c) 2012 - 2021 Adobe Systems Incorporated. All rights reserved.
6+
*
7+
* This program is free software: you can redistribute it and/or modify it
8+
* under the terms of the GNU Affero General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful, but WITHOUT
13+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
15+
* for more details.
16+
*
17+
* You should have received a copy of the GNU Affero General Public License
18+
* along with this program. If not, see https://opensource.org/licenses/AGPL-3.0.
19+
*
20+
*/
21+
22+
/*global less */
23+
// jshint ignore: start
24+
25+
/**
26+
* ExtensionInterface defines utility methods for communicating between extensions safely.
27+
*/
28+
define(function (require, exports, module) {
29+
const EVENT_EXTENSION_INTERFACE_REGISTERED = "extensionInterfaceRegistered";
30+
31+
let EventDispatcher = require("utils/EventDispatcher");
32+
33+
let _extensionInterfaceMap = {};
34+
35+
/**
36+
* Registers a named extension interface. Will overwrite if an interface of the same name is already present.
37+
* @param {string} extensionInterfaceName
38+
* @param {Object} interfaceObject
39+
*/
40+
function registerExtensionInterface(extensionInterfaceName, interfaceObject) {
41+
_extensionInterfaceMap[extensionInterfaceName] = interfaceObject;
42+
exports.trigger(EVENT_EXTENSION_INTERFACE_REGISTERED, extensionInterfaceName, interfaceObject);
43+
}
44+
45+
/**
46+
* Returns true is an interface of the given name exists.
47+
* @param {string} extensionInterfaceName
48+
* @return {boolean}
49+
*/
50+
function isExistsExtensionInterface(extensionInterfaceName) {
51+
return _extensionInterfaceMap[extensionInterfaceName] !== undefined;
52+
}
53+
54+
/**
55+
* Returns a promise that gets resolved only when an ExtensionInterface of the given name is registered. Use this
56+
* getter to get hold of extensions interface predictably.
57+
* @param extensionInterfaceName
58+
* @return {Promise}
59+
*/
60+
function awaitGetExtensionInterface(extensionInterfaceName) {
61+
return new Promise((resolve, reject)=>{
62+
let registrationEventHandler = function (event, registeredInterfaceName, interfaceObj) {
63+
if(registeredInterfaceName === extensionInterfaceName){
64+
exports.off(EVENT_EXTENSION_INTERFACE_REGISTERED, registrationEventHandler);
65+
resolve(interfaceObj);
66+
}
67+
};
68+
exports.on(EVENT_EXTENSION_INTERFACE_REGISTERED, registrationEventHandler);
69+
});
70+
}
71+
72+
EventDispatcher.makeEventDispatcher(exports);
73+
// Public API
74+
exports.registerExtensionInterface = registerExtensionInterface;
75+
exports.awaitGetExtensionInterface = awaitGetExtensionInterface;
76+
exports.isExistsExtensionInterface = isExistsExtensionInterface;
77+
// Events
78+
exports.EVENT_EXTENSION_INTERFACE_REGISTERED = EVENT_EXTENSION_INTERFACE_REGISTERED;
79+
});

test/UnitTestSuite.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ define(function (require, exports, module) {
4141
require("spec/EditorManager-test");
4242
require("spec/EventDispatcher-test");
4343
require("spec/ExtensionInstallation-test");
44+
require("spec/ExtensionInterface-test");
4445
require("spec/ExtensionLoader-test");
4546
require("spec/ExtensionManager-test");
4647
require("spec/ExtensionUtils-test");
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* GNU AGPL-3.0 License
3+
*
4+
* Modified Work Copyright (c) 2021 - present core.ai . All rights reserved.
5+
* Original work Copyright (c) 2013 - 2021 Adobe Systems Incorporated. All rights reserved.
6+
*
7+
* This program is free software: you can redistribute it and/or modify it
8+
* under the terms of the GNU Affero General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful, but WITHOUT
13+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
15+
* for more details.
16+
*
17+
* You should have received a copy of the GNU Affero General Public License
18+
* along with this program. If not, see https://opensource.org/licenses/AGPL-3.0.
19+
*
20+
*/
21+
22+
/*global describe, it, expect, beforeFirst, afterLast, beforeEach, afterEach, waitsFor, runs, waitsForDone */
23+
24+
define(function (require, exports, module) {
25+
const ExtensionInterface = require("utils/ExtensionInterface"),
26+
INTERFACE_OBJ = {
27+
"hello": "world"
28+
};
29+
30+
describe("Extension Interface tests", function () {
31+
it("should return a registered interface", function () {
32+
const INTERFACE_1 = "int1";
33+
ExtensionInterface.registerExtensionInterface(INTERFACE_1, INTERFACE_OBJ);
34+
expect(ExtensionInterface.isExistsExtensionInterface(INTERFACE_1)).toEqual(true);
35+
});
36+
37+
it("should raise event on extension registration", function () {
38+
const INTERFACE_1 = "int1";
39+
let notified = false, interfaceObjNotified = null;
40+
ExtensionInterface.on(ExtensionInterface.EVENT_EXTENSION_INTERFACE_REGISTERED, (event, name, intrfaceObj)=>{
41+
notified = name;
42+
interfaceObjNotified = intrfaceObj;
43+
});
44+
ExtensionInterface.registerExtensionInterface(INTERFACE_1, INTERFACE_OBJ);
45+
expect(ExtensionInterface.isExistsExtensionInterface(INTERFACE_1)).toEqual(true);
46+
waitsFor(function () {
47+
return notified === INTERFACE_1 && interfaceObjNotified === INTERFACE_OBJ;
48+
}, 100, "extension interface registration notification");
49+
});
50+
51+
it("should await and get the extension interface", function () {
52+
const INTERFACE_2 = "int2";
53+
let extensionInterface = null;
54+
ExtensionInterface.awaitGetExtensionInterface(INTERFACE_2).then((interfaceObj)=>{
55+
extensionInterface = interfaceObj;
56+
});
57+
58+
ExtensionInterface.registerExtensionInterface(INTERFACE_2, INTERFACE_OBJ);
59+
waitsFor(function () {
60+
return extensionInterface === INTERFACE_OBJ;
61+
}, 100, "awaiting extension interface");
62+
});
63+
});
64+
});

0 commit comments

Comments
 (0)