mirror of
https://github.com/Koenkk/zigbee2mqtt.git
synced 2026-08-26 20:50:07 +00:00
Simplify user extensions api (#6420)
* Simplify user extensions api * Change structure
This commit is contained in:
@@ -15,9 +15,9 @@ class ExternalExtension extends Extension {
|
||||
this.addExtension = addExtension;
|
||||
this.enableDisableExtension = enableDisableExtension;
|
||||
this.extensionsBaseDir = 'extension';
|
||||
this.loadExtension = this.loadExtension.bind(this);
|
||||
this.requestLookup = {
|
||||
'save': this.saveExtension.bind(this),
|
||||
'read': this.readExtensionCode.bind(this),
|
||||
};
|
||||
this.loadUserDefinedExtensions();
|
||||
}
|
||||
@@ -28,13 +28,16 @@ class ExternalExtension extends Extension {
|
||||
getListOfUserDefinedExtensions() {
|
||||
const basePath = this.getExtensionsBasePath();
|
||||
if (fs.existsSync(basePath)) {
|
||||
return fs.readdirSync(basePath).filter((f) => f.endsWith('.js'));
|
||||
return fs.readdirSync(basePath).filter((f) => f.endsWith('.js')).map((fileName) => {
|
||||
const extensonFilePath = path.join(basePath, fileName);
|
||||
return {'name': fileName, 'code': fs.readFileSync(extensonFilePath, 'utf-8')};
|
||||
});
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
saveExtension({name, content}) {
|
||||
const ModuleConstructor = utils.loadModuleFromText(content);
|
||||
saveExtension({name, code}) {
|
||||
const ModuleConstructor = utils.loadModuleFromText(code);
|
||||
this.loadExtension(ModuleConstructor);
|
||||
const basePath = this.getExtensionsBasePath();
|
||||
/* istanbul ignore else */
|
||||
@@ -42,15 +45,11 @@ class ExternalExtension extends Extension {
|
||||
fs.mkdirSync(basePath);
|
||||
}
|
||||
const extensonFilePath = path.join(basePath, name);
|
||||
fs.writeFileSync(extensonFilePath, content);
|
||||
fs.writeFileSync(extensonFilePath, code);
|
||||
this.publishExtensions();
|
||||
return utils.getResponse(`Extension ${name} loaded`, {}, null);
|
||||
}
|
||||
readExtensionCode({name}) {
|
||||
const extensonFilePath = path.join(this.getExtensionsBasePath(), name);
|
||||
const response = {name, content: fs.readFileSync(extensonFilePath, 'utf-8')};
|
||||
return utils.getResponse(`Extension ${name} code read`, response, null);
|
||||
}
|
||||
|
||||
|
||||
async onMQTTMessage(topic, message) {
|
||||
const match = topic.match(requestRegex);
|
||||
@@ -74,11 +73,9 @@ class ExternalExtension extends Extension {
|
||||
|
||||
loadUserDefinedExtensions() {
|
||||
const extensions = this.getListOfUserDefinedExtensions();
|
||||
const extensionPath = this.getExtensionsBasePath();
|
||||
for (const extension of extensions) {
|
||||
const Extension = utils.loadModuleFromFile(path.join(extensionPath, extension));
|
||||
this.loadExtension(Extension);
|
||||
}
|
||||
extensions
|
||||
.map(({code}) => utils.loadModuleFromText(code))
|
||||
.map(this.loadExtension);
|
||||
}
|
||||
async onMQTTConnected() {
|
||||
this.publishExtensions();
|
||||
|
||||
@@ -44,12 +44,7 @@ describe('User extensions', () => {
|
||||
await controller.start();
|
||||
await flushPromises();
|
||||
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/example/extension', 'test', { retain: false, qos: 0 }, expect.any(Function));
|
||||
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bridge/extensions', stringify(['exampleExtension.js']), { retain: true, qos: 0 }, expect.any(Function));
|
||||
MQTT.publish.mockClear();
|
||||
MQTT.events.message('zigbee2mqtt/bridge/extension/request/read', stringify({"name": "exampleExtension.js"}));
|
||||
await flushPromises();
|
||||
const expectedResponse = {"data": {"name": "exampleExtension.js", "content": extensionCode}, "status":"ok"};
|
||||
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bridge/extension/response/read', stringify(expectedResponse), { retain: false, qos: 0 }, expect.any(Function));
|
||||
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bridge/extensions', stringify([{"name": "exampleExtension.js", "code": extensionCode}]), { retain: true, qos: 0 }, expect.any(Function));
|
||||
});
|
||||
|
||||
it('Load user extension from api call', async () => {
|
||||
@@ -59,9 +54,9 @@ describe('User extensions', () => {
|
||||
await controller.start();
|
||||
await flushPromises();
|
||||
MQTT.publish.mockClear();
|
||||
MQTT.events.message('zigbee2mqtt/bridge/extension/request/save', stringify({"name": "foo.js", "content": extensionCode}));
|
||||
MQTT.events.message('zigbee2mqtt/bridge/extension/request/save', stringify({"name": "foo.js", "code": extensionCode}));
|
||||
await flushPromises();
|
||||
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bridge/extensions', stringify(['foo.js']), { retain: true, qos: 0 }, expect.any(Function));
|
||||
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bridge/extensions', stringify([{"name": "foo.js", "code": extensionCode}]), { retain: true, qos: 0 }, expect.any(Function));
|
||||
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/example/extension', 'call from constructor', { retain: false, qos: 0 }, expect.any(Function));
|
||||
expect(mkdirSyncSpy).toHaveBeenCalledWith(extensionPath);
|
||||
});
|
||||
@@ -73,7 +68,7 @@ describe('User extensions', () => {
|
||||
await controller.start();
|
||||
await flushPromises();
|
||||
MQTT.publish.mockClear();
|
||||
MQTT.events.message('zigbee2mqtt/bridge/extension/request/save', stringify({"name": "foo.js", "content": extensionCode}));
|
||||
MQTT.events.message('zigbee2mqtt/bridge/extension/request/save', stringify({"name": "foo.js", "code": extensionCode}));
|
||||
await flushPromises();
|
||||
|
||||
expect(MQTT.publish).toHaveBeenCalledWith('zigbee2mqtt/bridge/extension/response/save', stringify({"data":{},"error":"Unexpected identifier","status":"error"}), { retain: false, qos: 0 }, expect.any(Function));
|
||||
|
||||
Reference in New Issue
Block a user