You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
322 lines
12 KiB
322 lines
12 KiB
import type { IAppAccessors } from '@rocket.chat/apps-engine/definition/accessors/IAppAccessors.ts';
|
|
import type { IApiEndpointMetadata } from '@rocket.chat/apps-engine/definition/api/IApiEndpointMetadata.ts';
|
|
import type { IEnvironmentWrite } from '@rocket.chat/apps-engine/definition/accessors/IEnvironmentWrite.ts';
|
|
import type { IEnvironmentRead } from '@rocket.chat/apps-engine/definition/accessors/IEnvironmentRead.ts';
|
|
import type { IConfigurationModify } from '@rocket.chat/apps-engine/definition/accessors/IConfigurationModify.ts';
|
|
import type { IRead } from '@rocket.chat/apps-engine/definition/accessors/IRead.ts';
|
|
import type { IModify } from '@rocket.chat/apps-engine/definition/accessors/IModify.ts';
|
|
import type { INotifier } from '@rocket.chat/apps-engine/definition/accessors/INotifier.ts';
|
|
import type { IPersistence } from '@rocket.chat/apps-engine/definition/accessors/IPersistence.ts';
|
|
import type { IHttp, IHttpExtend } from '@rocket.chat/apps-engine/definition/accessors/IHttp.ts';
|
|
import type { IConfigurationExtend } from '@rocket.chat/apps-engine/definition/accessors/IConfigurationExtend.ts';
|
|
import type { ISlashCommand } from '@rocket.chat/apps-engine/definition/slashcommands/ISlashCommand.ts';
|
|
import type { IProcessor } from '@rocket.chat/apps-engine/definition/scheduler/IProcessor.ts';
|
|
import type { IApi } from '@rocket.chat/apps-engine/definition/api/IApi.ts';
|
|
import type { IVideoConfProvider } from '@rocket.chat/apps-engine/definition/videoConfProviders/IVideoConfProvider.ts';
|
|
import type {
|
|
IOutboundPhoneMessageProvider,
|
|
IOutboundEmailMessageProvider,
|
|
} from '@rocket.chat/apps-engine/definition/outboundCommunication/IOutboundCommsProvider.ts';
|
|
|
|
import { Http } from './http.ts';
|
|
import { HttpExtend } from './extenders/HttpExtender.ts';
|
|
import * as Messenger from '../messenger.ts';
|
|
import { AppObjectRegistry } from '../../AppObjectRegistry.ts';
|
|
import { ModifyCreator } from './modify/ModifyCreator.ts';
|
|
import { ModifyUpdater } from './modify/ModifyUpdater.ts';
|
|
import { ModifyExtender } from './modify/ModifyExtender.ts';
|
|
import { Notifier } from './notifier.ts';
|
|
import { formatErrorResponse } from './formatResponseErrorHandler.ts';
|
|
|
|
const httpMethods = ['get', 'post', 'put', 'delete', 'head', 'options', 'patch'] as const;
|
|
|
|
// We need to create this object first thing, as we'll handle references to it later on
|
|
if (!AppObjectRegistry.has('apiEndpoints')) {
|
|
AppObjectRegistry.set('apiEndpoints', []);
|
|
}
|
|
|
|
export class AppAccessors {
|
|
private defaultAppAccessors?: IAppAccessors;
|
|
private environmentRead?: IEnvironmentRead;
|
|
private environmentWriter?: IEnvironmentWrite;
|
|
private configModifier?: IConfigurationModify;
|
|
private configExtender?: IConfigurationExtend;
|
|
private reader?: IRead;
|
|
private modifier?: IModify;
|
|
private persistence?: IPersistence;
|
|
private creator?: ModifyCreator;
|
|
private updater?: ModifyUpdater;
|
|
private extender?: ModifyExtender;
|
|
private httpExtend: IHttpExtend = new HttpExtend();
|
|
private http?: IHttp;
|
|
private notifier?: INotifier;
|
|
|
|
private proxify: <T>(namespace: string, overrides?: Record<string, (...args: unknown[]) => unknown>) => T;
|
|
|
|
constructor(private readonly senderFn: typeof Messenger.sendRequest) {
|
|
this.proxify = <T>(namespace: string, overrides: Record<string, (...args: unknown[]) => unknown> = {}): T =>
|
|
new Proxy(
|
|
{ __kind: `accessor:${namespace}` },
|
|
{
|
|
get:
|
|
(_target: unknown, prop: string) =>
|
|
(...params: unknown[]) => {
|
|
// We don't want to send a request for this prop
|
|
if (prop === 'toJSON') {
|
|
return {};
|
|
}
|
|
|
|
// If the prop is inteded to be overriden by the caller
|
|
if (prop in overrides) {
|
|
return overrides[prop].apply(undefined, params);
|
|
}
|
|
|
|
return senderFn({
|
|
method: `accessor:${namespace}:${prop}`,
|
|
params,
|
|
})
|
|
.then((response) => response.result)
|
|
.catch((err) => {
|
|
throw formatErrorResponse(err);
|
|
});
|
|
},
|
|
},
|
|
) as T;
|
|
|
|
this.http = new Http(this.getReader(), this.getPersistence(), this.httpExtend, this.getSenderFn());
|
|
this.notifier = new Notifier(this.getSenderFn());
|
|
}
|
|
|
|
public getSenderFn() {
|
|
return this.senderFn;
|
|
}
|
|
|
|
public getEnvironmentRead(): IEnvironmentRead {
|
|
if (!this.environmentRead) {
|
|
this.environmentRead = {
|
|
getSettings: () => this.proxify('getEnvironmentRead:getSettings'),
|
|
getServerSettings: () => this.proxify('getEnvironmentRead:getServerSettings'),
|
|
getEnvironmentVariables: () => this.proxify('getEnvironmentRead:getEnvironmentVariables'),
|
|
};
|
|
}
|
|
|
|
return this.environmentRead;
|
|
}
|
|
|
|
public getEnvironmentWrite() {
|
|
if (!this.environmentWriter) {
|
|
this.environmentWriter = {
|
|
getSettings: () => this.proxify('getEnvironmentWrite:getSettings'),
|
|
getServerSettings: () => this.proxify('getEnvironmentWrite:getServerSettings'),
|
|
};
|
|
}
|
|
|
|
return this.environmentWriter;
|
|
}
|
|
|
|
public getConfigurationModify() {
|
|
if (!this.configModifier) {
|
|
this.configModifier = {
|
|
scheduler: this.proxify('getConfigurationModify:scheduler'),
|
|
slashCommands: {
|
|
_proxy: this.proxify('getConfigurationModify:slashCommands'),
|
|
modifySlashCommand(slashcommand: ISlashCommand) {
|
|
// Store the slashcommand instance to use when the Apps-Engine calls the slashcommand
|
|
AppObjectRegistry.set(`slashcommand:${slashcommand.command}`, slashcommand);
|
|
|
|
return this._proxy.modifySlashCommand(slashcommand);
|
|
},
|
|
disableSlashCommand(command: string) {
|
|
return this._proxy.disableSlashCommand(command);
|
|
},
|
|
enableSlashCommand(command: string) {
|
|
return this._proxy.enableSlashCommand(command);
|
|
},
|
|
},
|
|
serverSettings: this.proxify('getConfigurationModify:serverSettings'),
|
|
};
|
|
}
|
|
|
|
return this.configModifier;
|
|
}
|
|
|
|
public getConfigurationExtend() {
|
|
if (!this.configExtender) {
|
|
const senderFn = this.senderFn;
|
|
|
|
this.configExtender = {
|
|
ui: this.proxify('getConfigurationExtend:ui'),
|
|
http: this.httpExtend,
|
|
settings: this.proxify('getConfigurationExtend:settings'),
|
|
externalComponents: this.proxify('getConfigurationExtend:externalComponents'),
|
|
api: {
|
|
_proxy: this.proxify('getConfigurationExtend:api'),
|
|
async provideApi(api: IApi) {
|
|
const apiEndpoints = AppObjectRegistry.get<IApiEndpointMetadata[]>('apiEndpoints')!;
|
|
|
|
api.endpoints.forEach((endpoint) => {
|
|
endpoint._availableMethods = httpMethods.filter((method) => typeof endpoint[method] === 'function');
|
|
|
|
// We need to keep a reference to the endpoint around for us to call the executor later
|
|
AppObjectRegistry.set(`api:${endpoint.path}`, endpoint);
|
|
});
|
|
|
|
const result = await this._proxy.provideApi(api);
|
|
|
|
// Let's call the listApis method to cache the info from the endpoints
|
|
// Also, since this is a side-effect, we do it async so we can return to the caller
|
|
senderFn({ method: 'accessor:api:listApis' })
|
|
.then((response) => apiEndpoints.push(...(response.result as IApiEndpointMetadata[])))
|
|
.catch((err) => err.error);
|
|
|
|
return result;
|
|
},
|
|
},
|
|
scheduler: {
|
|
_proxy: this.proxify('getConfigurationExtend:scheduler'),
|
|
registerProcessors(processors: IProcessor[]) {
|
|
// Store the processor instance to use when the Apps-Engine calls the processor
|
|
processors.forEach((processor) => {
|
|
AppObjectRegistry.set(`scheduler:${processor.id}`, processor);
|
|
});
|
|
|
|
return this._proxy.registerProcessors(processors);
|
|
},
|
|
},
|
|
videoConfProviders: {
|
|
_proxy: this.proxify('getConfigurationExtend:videoConfProviders'),
|
|
provideVideoConfProvider(provider: IVideoConfProvider) {
|
|
// Store the videoConfProvider instance to use when the Apps-Engine calls the videoConfProvider
|
|
AppObjectRegistry.set(`videoConfProvider:${provider.name}`, provider);
|
|
|
|
return this._proxy.provideVideoConfProvider(provider);
|
|
},
|
|
},
|
|
outboundCommunication: {
|
|
_proxy: this.proxify('getConfigurationExtend:outboundCommunication'),
|
|
registerEmailProvider(provider: IOutboundEmailMessageProvider) {
|
|
AppObjectRegistry.set(`outboundCommunication:${provider.name}-${provider.type}`, provider);
|
|
return this._proxy.registerEmailProvider(provider);
|
|
},
|
|
registerPhoneProvider(provider: IOutboundPhoneMessageProvider) {
|
|
AppObjectRegistry.set(`outboundCommunication:${provider.name}-${provider.type}`, provider);
|
|
return this._proxy.registerPhoneProvider(provider);
|
|
},
|
|
},
|
|
slashCommands: {
|
|
_proxy: this.proxify('getConfigurationExtend:slashCommands'),
|
|
provideSlashCommand(slashcommand: ISlashCommand) {
|
|
// Store the slashcommand instance to use when the Apps-Engine calls the slashcommand
|
|
AppObjectRegistry.set(`slashcommand:${slashcommand.command}`, slashcommand);
|
|
|
|
return this._proxy.provideSlashCommand(slashcommand);
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
return this.configExtender;
|
|
}
|
|
|
|
public getDefaultAppAccessors() {
|
|
if (!this.defaultAppAccessors) {
|
|
this.defaultAppAccessors = {
|
|
environmentReader: this.getEnvironmentRead(),
|
|
environmentWriter: this.getEnvironmentWrite(),
|
|
reader: this.getReader(),
|
|
http: this.getHttp(),
|
|
providedApiEndpoints: AppObjectRegistry.get<IApiEndpointMetadata[]>('apiEndpoints') as IApiEndpointMetadata[],
|
|
};
|
|
}
|
|
|
|
return this.defaultAppAccessors;
|
|
}
|
|
|
|
public getReader() {
|
|
if (!this.reader) {
|
|
this.reader = {
|
|
getEnvironmentReader: () => ({
|
|
getSettings: () => this.proxify('getReader:getEnvironmentReader:getSettings'),
|
|
getServerSettings: () => this.proxify('getReader:getEnvironmentReader:getServerSettings'),
|
|
getEnvironmentVariables: () => this.proxify('getReader:getEnvironmentReader:getEnvironmentVariables'),
|
|
}),
|
|
getMessageReader: () => this.proxify('getReader:getMessageReader'),
|
|
getPersistenceReader: () => this.proxify('getReader:getPersistenceReader'),
|
|
getRoomReader: () => this.proxify('getReader:getRoomReader'),
|
|
getUserReader: () => this.proxify('getReader:getUserReader'),
|
|
getNotifier: () => this.getNotifier(),
|
|
getLivechatReader: () => this.proxify('getReader:getLivechatReader'),
|
|
getUploadReader: () => this.proxify('getReader:getUploadReader'),
|
|
getCloudWorkspaceReader: () => this.proxify('getReader:getCloudWorkspaceReader'),
|
|
getVideoConferenceReader: () => this.proxify('getReader:getVideoConferenceReader'),
|
|
getOAuthAppsReader: () => this.proxify('getReader:getOAuthAppsReader'),
|
|
getThreadReader: () => this.proxify('getReader:getThreadReader'),
|
|
getRoleReader: () => this.proxify('getReader:getRoleReader'),
|
|
getContactReader: () => this.proxify('getReader:getContactReader'),
|
|
getExperimentalReader: () => this.proxify('getReader:getExperimentalReader'),
|
|
};
|
|
}
|
|
|
|
return this.reader;
|
|
}
|
|
|
|
public getModifier() {
|
|
if (!this.modifier) {
|
|
this.modifier = {
|
|
getCreator: this.getCreator.bind(this),
|
|
getUpdater: this.getUpdater.bind(this),
|
|
getExtender: this.getExtender.bind(this),
|
|
getDeleter: () => this.proxify('getModifier:getDeleter'),
|
|
getNotifier: () => this.getNotifier(),
|
|
getUiController: () => this.proxify('getModifier:getUiController'),
|
|
getScheduler: () => this.proxify('getModifier:getScheduler'),
|
|
getOAuthAppsModifier: () => this.proxify('getModifier:getOAuthAppsModifier'),
|
|
getModerationModifier: () => this.proxify('getModifier:getModerationModifier'),
|
|
};
|
|
}
|
|
|
|
return this.modifier;
|
|
}
|
|
|
|
public getPersistence() {
|
|
if (!this.persistence) {
|
|
this.persistence = this.proxify('getPersistence');
|
|
}
|
|
|
|
return this.persistence;
|
|
}
|
|
|
|
public getHttp() {
|
|
return this.http;
|
|
}
|
|
|
|
private getCreator() {
|
|
if (!this.creator) {
|
|
this.creator = new ModifyCreator(this.senderFn);
|
|
}
|
|
|
|
return this.creator;
|
|
}
|
|
|
|
private getUpdater() {
|
|
if (!this.updater) {
|
|
this.updater = new ModifyUpdater(this.senderFn);
|
|
}
|
|
|
|
return this.updater;
|
|
}
|
|
|
|
private getExtender() {
|
|
if (!this.extender) {
|
|
this.extender = new ModifyExtender(this.senderFn);
|
|
}
|
|
|
|
return this.extender;
|
|
}
|
|
|
|
private getNotifier() {
|
|
return this.notifier;
|
|
}
|
|
}
|
|
|
|
export const AppAccessorsInstance = new AppAccessors(Messenger.sendRequest);
|
|
|