OpenDroneMap-WebODM/app/static/app/js/classes/plugins/ApiFactory.js

120 wiersze
3.7 KiB
JavaScript

import SystemJS from 'SystemJS';
export default class ApiFactory{
// @param events {EventEmitter}
constructor(events){
this.events = events;
}
// @param api {Object}
create(api){
// Adds two functions to obj
// - eventName
// - triggerEventName
// We could just use events, but methods
// are more robust as we can detect more easily if
// things break
const addEndpoint = (obj, eventName, preTrigger = () => {}) => {
const emitResponse = response => {
// Timeout needed for modules that have no dependencies
// and load synchronously. Gives time to setup the listeners.
setTimeout(() => {
this.events.emit(`${api.namespace}::${eventName}::Response`, response);
}, 0);
};
obj[eventName] = (callbackOrDeps, callbackOrUndef) => {
if (Array.isArray(callbackOrDeps)){
// Deps
// Load dependencies, then raise event as usual
// by appending the dependencies to the argument list
this.events.addListener(`${api.namespace}::${eventName}`, args => {
Promise.all(callbackOrDeps.map(dep => SystemJS.import(dep)))
.then((...deps) => {
// For each dependency, see if it exports a default module (ES6 style)
// if it does, export just the default module, otherwise export all modules
deps = deps.map(dep => {
return dep.map(exp => exp.default ? exp.default : exp);
});
const response = {
result: callbackOrUndef(...(Array.from([args]).concat(...deps))),
placeholder: args._placeholder
};
emitResponse(response);
});
});
}else{
// Callback
this.events.addListener(`${api.namespace}::${eventName}`, args => {
const response = {
result: callbackOrDeps(args),
placeholder: args._placeholder
};
emitResponse(response);
});
}
}
const triggerEventName = "trigger" + eventName[0].toUpperCase() + eventName.slice(1);
obj[triggerEventName] = (args, responseCb) => {
if (!args) args = {};
args._placeholder = {};
preTrigger(args, responseCb);
if (responseCb){
this.events.addListener(`${api.namespace}::${eventName}::Response`, response => {
// Give time to all listeners to receive the replies
// then remove the listener to avoid sending duplicate responses
const curSub = this.events._currentSubscription;
setTimeout(() => {
curSub.remove();
}, 0);
if (response.placeholder === args._placeholder) responseCb(response.result);
});
}
this.events.emit(`${api.namespace}::${eventName}`, args);
};
}
let obj = {};
api.endpoints.forEach(endpoint => {
if (!Array.isArray(endpoint)) endpoint = [endpoint];
addEndpoint(obj, ...endpoint);
});
if (api.helpers){
obj = Object.assign(obj, api.helpers);
}
// Handle syncronous function on/off/export
(api.functions || []).forEach(func => {
let callbacks = [];
obj[func] = (...args) => {
for (let i = 0; i < callbacks.length; i++){
if ((callbacks[i])(...args)) return true;
}
return false;
};
const onName = "on" + func[0].toUpperCase() + func.slice(1);
const offName = "off" + func[0].toUpperCase() + func.slice(1);
obj[onName] = f => {
callbacks.push(f);
};
obj[offName] = f => {
callbacks = callbacks.filter(cb => cb !== f);
};
});
return obj;
}
}