@makeflow/gateway-server
Advanced tools
Comparing version 0.1.0-alpha.4 to 0.1.0-alpha.5
@@ -46,3 +46,3 @@ "use strict"; | ||
router.post('/commands/get-all-not-executed-commands-history', rpcService.processor(async () => { | ||
return commandService.getAllNotExecutedCommandHistoryItems(); | ||
return commandService.getAllNotExecutedCommands(); | ||
}, { | ||
@@ -59,3 +59,3 @@ authorization: true, | ||
router.post('/command/:name/execute', rpcService.processor(async ({ name, parameters }) => { | ||
await commandService.enqueueCommand(name, parameters); | ||
await commandService.enqueueCommandAndTryToExecute(name, parameters); | ||
}, { | ||
@@ -62,0 +62,0 @@ authorization: false, |
@@ -37,12 +37,12 @@ "use strict"; | ||
})); | ||
router.post('/makeflow/power-item/action/:action', rpcService.processor(async ({ action, configs, inputs }) => { | ||
let { token } = configs; | ||
router.post('/makeflow/power-item/action/:action', rpcService.processor(async ({ action, token, configs, inputs }) => { | ||
let { token: configToken } = configs; | ||
if (typeof token !== 'string') { | ||
throw new gateway_shared_1.ExpectedError('PARAMETERS_MISMATCH'); | ||
} | ||
await makeflowService.processAction(action, token, inputs); | ||
await makeflowService.processAction(action, configToken, token, inputs); | ||
}, { | ||
authorization: false, | ||
token: false, | ||
requiredParams: ['configs'], | ||
requiredParams: ['token', 'configs'], | ||
})); | ||
@@ -49,0 +49,0 @@ } |
@@ -1,8 +0,10 @@ | ||
import { CommandExecuteResult, ICommandWithOptions } from '@makeflow/gateway-shared'; | ||
declare abstract class CommandAdapter<TCommand extends ICommandWithOptions> { | ||
abstract executeCommand(command: TCommand): Promise<CommandExecuteResult | undefined>; | ||
import { Command, CommandExecuteResult } from '@makeflow/gateway-shared'; | ||
import { Dict } from 'tslang'; | ||
declare abstract class CommandAdapter { | ||
abstract executeCommand(command: Command, options?: Dict<unknown>): Promise<CommandExecuteResult>; | ||
checkOptions(_options: Dict<unknown> | undefined): void; | ||
} | ||
export interface ICommandAdapter extends CommandAdapter<ICommandWithOptions> { | ||
export interface ICommandAdapter extends CommandAdapter { | ||
} | ||
export declare const AbstractCommandAdapter: typeof CommandAdapter; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
class CommandAdapter { | ||
checkOptions(_options) { } | ||
} | ||
exports.AbstractCommandAdapter = CommandAdapter; | ||
//# sourceMappingURL=command-adapter.js.map |
@@ -1,8 +0,5 @@ | ||
import { CommandExecuteResult, ICommandWithOptions } from '@makeflow/gateway-shared'; | ||
import { Command, CommandExecuteResult } from '@makeflow/gateway-shared'; | ||
import { AbstractCommandAdapter } from './command-adapter'; | ||
export interface ExecutableCommand extends ICommandWithOptions { | ||
type: 'executable'; | ||
export declare class ExecutableCommandAdapter extends AbstractCommandAdapter { | ||
executeCommand({ source, parameters, }: Command): Promise<CommandExecuteResult>; | ||
} | ||
export declare class ExecutableCommandAdapter extends AbstractCommandAdapter<ExecutableCommand> { | ||
executeCommand({ source, parameters, }: ExecutableCommand): Promise<CommandExecuteResult>; | ||
} |
@@ -1,8 +0,5 @@ | ||
import { CommandExecuteResult, ICommandWithOptions } from '@makeflow/gateway-shared'; | ||
import { Command, CommandExecuteResult } from '@makeflow/gateway-shared'; | ||
import { AbstractCommandAdapter } from './command-adapter'; | ||
export interface NodeCommand extends ICommandWithOptions { | ||
type: 'node'; | ||
export declare class NodeCommandAdapter extends AbstractCommandAdapter { | ||
executeCommand({ source, parameters, }: Command): Promise<CommandExecuteResult>; | ||
} | ||
export declare class NodeCommandAdapter extends AbstractCommandAdapter<NodeCommand> { | ||
executeCommand({ source, parameters, }: NodeCommand): Promise<CommandExecuteResult>; | ||
} |
@@ -1,8 +0,5 @@ | ||
import { CommandExecuteResult, ICommandWithOptions } from '@makeflow/gateway-shared'; | ||
import { Command, CommandExecuteResult } from '@makeflow/gateway-shared'; | ||
import { AbstractCommandAdapter } from './command-adapter'; | ||
export interface ShellCommand extends ICommandWithOptions { | ||
type: 'shell'; | ||
export declare class ShellCommandAdapter extends AbstractCommandAdapter { | ||
executeCommand({ source, parameters, }: Command): Promise<CommandExecuteResult>; | ||
} | ||
export declare class ShellCommandAdapter extends AbstractCommandAdapter<ShellCommand> { | ||
executeCommand({ source, parameters, }: ShellCommand): Promise<CommandExecuteResult>; | ||
} |
@@ -1,2 +0,2 @@ | ||
import { CommandExecuteResult, CommandOptions, ICommandWithOptions } from '@makeflow/gateway-shared'; | ||
import { Command, CommandExecuteResult, CommandOptions } from '@makeflow/gateway-shared'; | ||
import { AbstractCommandAdapter } from './command-adapter'; | ||
@@ -6,8 +6,5 @@ export interface SqliteCommandOptions extends CommandOptions { | ||
} | ||
export interface SqliteCommand extends ICommandWithOptions { | ||
type: 'sqlite'; | ||
options: SqliteCommandOptions; | ||
export declare class SqliteCommandAdapter extends AbstractCommandAdapter { | ||
executeCommand({ source, parameters }: Command, { path }: SqliteCommandOptions): Promise<CommandExecuteResult>; | ||
checkOptions(options: SqliteCommandOptions): void; | ||
} | ||
export declare class SqliteCommandAdapter extends AbstractCommandAdapter<SqliteCommand> { | ||
executeCommand({ source, parameters, options: { path }, }: SqliteCommand): Promise<CommandExecuteResult>; | ||
} |
@@ -8,3 +8,3 @@ "use strict"; | ||
class SqliteCommandAdapter extends command_adapter_1.AbstractCommandAdapter { | ||
async executeCommand({ source, parameters = {}, options: { path }, }) { | ||
async executeCommand({ source, parameters = {} }, { path }) { | ||
try { | ||
@@ -22,4 +22,9 @@ let db = await sqlite_1.default.open(path); | ||
} | ||
checkOptions(options) { | ||
if (typeof options !== 'object' || typeof options.path !== 'string') { | ||
throw new Error('A path in options is required in sqlite scripts'); | ||
} | ||
} | ||
} | ||
exports.SqliteCommandAdapter = SqliteCommandAdapter; | ||
//# sourceMappingURL=sqlite-adapter.js.map |
@@ -35,11 +35,6 @@ "use strict"; | ||
const commandService = new services_1.CommandService(configService, fileService, dbService, commandAdapterMap, commandsPath); | ||
const makeflowService = new services_1.MakeflowService(commandService, tokenService, apiService, configService); | ||
const makeflowService = new services_1.MakeflowService(commandService, tokenService, apiService, dbService, configService); | ||
const rpcService = new services_1.RPCService(configService, tokenService); | ||
const httpService = new services_1.HTTPService(commandService, tokenService, makeflowService, rpcService, configService, httpServer, staticPath); | ||
const servicesReady = Promise.all([ | ||
dbService.ready, | ||
httpService.ready, | ||
commandService.ready, | ||
tokenService.ready, | ||
]); | ||
const servicesReady = Promise.all([dbService.ready, httpService.ready]); | ||
await servicesReady; | ||
@@ -46,0 +41,0 @@ httpServer.listen(port, () => console.info(`Listening on port ${port}...`)); |
@@ -1,2 +0,4 @@ | ||
import { CommandHistoryItem, CommandParameters } from '@makeflow/gateway-shared'; | ||
/// <reference types="node" /> | ||
import { EventEmitter } from 'events'; | ||
import { Command, CommandExecuteResult, CommandParameters } from '@makeflow/gateway-shared'; | ||
import { ICommandAdapter } from '../core'; | ||
@@ -12,3 +14,7 @@ import { CommandsConfig } from '../types'; | ||
} | ||
export declare class CommandService { | ||
export interface CommandService { | ||
on(event: 'command-executed', handler: (command: Command) => void): this; | ||
emit(event: 'command-executed', command: Command): boolean; | ||
} | ||
export declare class CommandService extends EventEmitter { | ||
private configService; | ||
@@ -19,3 +25,2 @@ private fileService; | ||
private commandsPath; | ||
readonly ready: Promise<void>; | ||
private readonly commandsConfigPath; | ||
@@ -26,13 +31,12 @@ constructor(configService: ConfigService, fileService: FileService, dbService: DBService, adapterMap: Map<string, ICommandAdapter>, commandsPath: string); | ||
getCommandsConfig(): Promise<CommandsConfig | undefined>; | ||
enqueueCommand(name: string, parameters?: CommandParameters, wait?: boolean): Promise<void>; | ||
enqueueCommand(name: string, parameters?: CommandParameters): Promise<Command>; | ||
enqueueCommandAndTryToExecute(name: string, parameters?: CommandParameters, waiting?: boolean): Promise<Command>; | ||
executeCommandFromQueue(id: number): Promise<void>; | ||
getCommandHistoryItems({ before: beforeId, after: afterId, limit, }: GetCommandHistoryItemsOptions): Promise<CommandHistoryItem[]>; | ||
getAllNotExecutedCommandHistoryItems(): Promise<CommandHistoryItem[]>; | ||
private executeCommand; | ||
private getCommandConfig; | ||
private initialize; | ||
private initializeDatabase; | ||
getCommandHistoryItems({ before: beforeId, after: afterId, limit, }: GetCommandHistoryItemsOptions): Promise<Command[]>; | ||
getAllNotExecutedCommands(): Promise<Command[]>; | ||
executeCommand(command: Command): Promise<CommandExecuteResult>; | ||
private requireCommandConfig; | ||
private insertCommandHistoryItem; | ||
private getCommandHistoryItemById; | ||
private markCommandHistoryExecuted; | ||
private getCommandById; | ||
private markCommandExecuted; | ||
} |
@@ -5,2 +5,3 @@ "use strict"; | ||
const child_process_1 = require("child_process"); | ||
const events_1 = require("events"); | ||
const Path = tslib_1.__importStar(require("path")); | ||
@@ -13,4 +14,5 @@ const Util = tslib_1.__importStar(require("util")); | ||
const rimraf = Util.promisify(rimraf_1.default); | ||
class CommandService { | ||
class CommandService extends events_1.EventEmitter { | ||
constructor(configService, fileService, dbService, adapterMap, commandsPath) { | ||
super(); | ||
this.configService = configService; | ||
@@ -21,3 +23,2 @@ this.fileService = fileService; | ||
this.commandsPath = commandsPath; | ||
this.ready = this.initialize(); | ||
} | ||
@@ -46,4 +47,4 @@ get commandsConfigPath() { | ||
} | ||
async enqueueCommand(name, parameters = {}, wait = false) { | ||
let { type, source, parameters: parametersConfig = [], manual = true, options = {}, } = await this.getCommandConfig(name); | ||
async enqueueCommand(name, parameters = {}) { | ||
let { type, source, parameters: parametersConfig = [], manual = true, } = await this.requireCommandConfig(name); | ||
let { filteredParameters, deniedParameters } = filterParameters(parameters, parametersConfig); | ||
@@ -55,31 +56,30 @@ let command = { | ||
parameters: filteredParameters, | ||
deniedParameters, | ||
manual, | ||
createdAt: Date.now(), | ||
}; | ||
let id = await this.insertCommandHistoryItem({ | ||
let id = await this.insertCommandHistoryItem(command); | ||
return { | ||
id, | ||
...command, | ||
deniedParameters, | ||
}); | ||
if (!manual) { | ||
if (wait) { | ||
await this.executeCommand({ id, ...command }, options); | ||
}; | ||
} | ||
async enqueueCommandAndTryToExecute(name, parameters = {}, waiting = false) { | ||
let command = await this.enqueueCommand(name, parameters); | ||
if (!command.manual) { | ||
if (waiting) { | ||
await this.executeCommand(command); | ||
} | ||
else { | ||
this.executeCommand({ id, ...command }, options).catch(console.error); | ||
this.executeCommand(command).catch(console.error); | ||
} | ||
} | ||
return command; | ||
} | ||
async executeCommandFromQueue(id) { | ||
let historyItem = await this.getCommandHistoryItemById(id); | ||
if (!historyItem) { | ||
let command = await this.getCommandById(id); | ||
if (!command) { | ||
return; | ||
} | ||
let { name, type, source, parameters } = historyItem; | ||
let { options = {} } = await this.getCommandConfig(name); | ||
let result = await this.executeCommand({ | ||
id, | ||
name, | ||
type, | ||
source, | ||
parameters, | ||
}, options); | ||
await this.markCommandHistoryExecuted(id, result); | ||
await this.executeCommand(command); | ||
} | ||
@@ -90,3 +90,3 @@ async getCommandHistoryItems({ before: beforeId, after: afterId, limit, }) { | ||
} | ||
let query = sql_template_strings_1.default `SELECT * FROM commands_history`; | ||
let query = sql_template_strings_1.default `SELECT * FROM commands`; | ||
if (beforeId || afterId) { | ||
@@ -108,7 +108,7 @@ query.append(sql_template_strings_1.default ` WHERE`); | ||
} | ||
async getAllNotExecutedCommandHistoryItems() { | ||
let doc = await this.dbService.db.all(sql_template_strings_1.default `SELECT * FROM commands_history WHERE executed_at is NULL ORDER BY created_at DESC`); | ||
async getAllNotExecutedCommands() { | ||
let doc = await this.dbService.db.all(sql_template_strings_1.default `SELECT * FROM commands WHERE executed_at is NULL ORDER BY created_at DESC`); | ||
return doc.map(convertCommandHistoryItemDocToCommandHistoryItem); | ||
} | ||
async executeCommand(command, options) { | ||
async executeCommand(command) { | ||
let adapter = this.adapterMap.get(command.type); | ||
@@ -118,12 +118,23 @@ if (!adapter) { | ||
} | ||
let resolvedSource = Path.resolve(this.commandsPath, command.source); | ||
command.source = resolvedSource; | ||
let result = await adapter.executeCommand({ | ||
let { options } = await this.requireCommandConfig(command.name); | ||
let result; | ||
try { | ||
adapter.checkOptions(options); | ||
let resolvedSource = Path.resolve(this.commandsPath, command.source); | ||
command.source = resolvedSource; | ||
result = await adapter.executeCommand(command, options && resolveCommandOptions(options)); | ||
} | ||
catch (error) { | ||
result = { | ||
error: error.message, | ||
}; | ||
} | ||
await this.markCommandExecuted(command.id, result); | ||
this.emit('command-executed', { | ||
...command, | ||
options: resolveCommandOptions(options), | ||
result, | ||
}); | ||
await this.markCommandHistoryExecuted(command.id, result); | ||
return result; | ||
} | ||
async getCommandConfig(name) { | ||
async requireCommandConfig(name) { | ||
let config = await this.getCommandsConfig(); | ||
@@ -139,33 +150,17 @@ if (!config) { | ||
} | ||
async initialize() { | ||
await this.initializeDatabase(); | ||
} | ||
async initializeDatabase() { | ||
await this.dbService.ready; | ||
await this.dbService.db.run(sql_template_strings_1.default ` | ||
CREATE TABLE IF NOT EXISTS commands_history ( | ||
id INTEGER PRIMARY KEY AUTOINCREMENT, | ||
name TEXT NOT NULL, | ||
type TEXT NOT NULL, | ||
source TEXT NOT NULL, | ||
parameters TEXT, | ||
denied_parameters TEXT, | ||
created_at INTEGER, | ||
executed_at INTEGER, | ||
output TEXT, | ||
error TEXT | ||
)`); | ||
} | ||
async insertCommandHistoryItem({ name, type, source, parameters, deniedParameters, }) { | ||
let statement = await this.dbService.db.run(sql_template_strings_1.default `INSERT INTO commands_history | ||
(name, type, source, parameters, denied_parameters, created_at) | ||
VALUES (${name}, ${type}, ${source}, ${JSON.stringify(parameters)}, ${JSON.stringify(deniedParameters)}, ${Date.now()})`); | ||
async insertCommandHistoryItem({ name, type, source, manual, parameters, deniedParameters, createdAt, }) { | ||
let statement = await this.dbService.db.run(sql_template_strings_1.default `INSERT INTO commands | ||
(name, type, source, manual, parameters, denied_parameters, created_at) | ||
VALUES (${name}, ${type}, ${source}, ${manual}, ${JSON.stringify(parameters)}, ${JSON.stringify(deniedParameters)}, ${createdAt})`); | ||
return statement.lastID; | ||
} | ||
async getCommandHistoryItemById(id) { | ||
let doc = await this.dbService.db.get(sql_template_strings_1.default `SELECT * FROM commands_history WHERE id=${id}`); | ||
async getCommandById(id) { | ||
let doc = await this.dbService.db.get(sql_template_strings_1.default `SELECT * FROM commands WHERE id=${id}`); | ||
if (!doc) { | ||
return undefined; | ||
} | ||
return convertCommandHistoryItemDocToCommandHistoryItem(doc); | ||
} | ||
async markCommandHistoryExecuted(id, { output, error } = {}) { | ||
await this.dbService.db.run(sql_template_strings_1.default `UPDATE commands_history SET output=${output}, error=${error}, executed_at=${Date.now()} WHERE id=${id}`); | ||
async markCommandExecuted(id, { output, error } = {}) { | ||
await this.dbService.db.run(sql_template_strings_1.default `UPDATE commands SET output=${output}, error=${error}, executed_at=${Date.now()} WHERE id=${id}`); | ||
} | ||
@@ -175,3 +170,3 @@ } | ||
function convertCommandHistoryItemDocToCommandHistoryItem(doc) { | ||
let { id, name, type, source, parameters, denied_parameters, output, error, created_at, executed_at, } = doc; | ||
let { id, name, type, source, manual, parameters, denied_parameters, output, error, created_at, executed_at, } = doc; | ||
return { | ||
@@ -182,2 +177,3 @@ id, | ||
source, | ||
manual, | ||
parameters: parameters && JSON.parse(parameters), | ||
@@ -184,0 +180,0 @@ deniedParameters: denied_parameters && JSON.parse(denied_parameters), |
@@ -20,3 +20,8 @@ "use strict"; | ||
} | ||
this._db = await sqlite_1.default.open(path); | ||
let db = await sqlite_1.default.open(path); | ||
// TODO: Improve | ||
await db.migrate({ | ||
migrationsPath: Path.join(__dirname, '../../migrations'), | ||
}); | ||
this._db = db; | ||
} | ||
@@ -23,0 +28,0 @@ } |
@@ -7,2 +7,3 @@ import { MFUserCandidate } from '@makeflow/gateway-shared'; | ||
import { ConfigService } from './config-service'; | ||
import { DBService } from './db-service'; | ||
import { TokenService } from './token-service'; | ||
@@ -13,4 +14,5 @@ export declare class MakeflowService { | ||
private apiService; | ||
private dbService; | ||
private configService; | ||
constructor(commandService: CommandService, tokenService: TokenService, apiService: APIService, configService: ConfigService); | ||
constructor(commandService: CommandService, tokenService: TokenService, apiService: APIService, dbService: DBService, configService: ConfigService); | ||
listUserCandidates(username: string, password: string): Promise<MFUserCandidate[]>; | ||
@@ -20,3 +22,3 @@ publishApp(): Promise<void>; | ||
authenticate(username: string, password: string, userId: string): Promise<void>; | ||
processAction(action: string, token: string, inputs: Dict<unknown>): Promise<void>; | ||
processAction(action: string, token: string, powerItemToken: string, inputs: Dict<unknown>): Promise<void>; | ||
checkAuthentication(): Promise<void>; | ||
@@ -27,3 +29,9 @@ private createAccessToken; | ||
private increasePowerAppVersion; | ||
private requestAPI; | ||
private requestMakeflowAPI; | ||
private insertPowerItem; | ||
private findPowerItem; | ||
private updatePowerItemResponse; | ||
private initialize; | ||
private onCommandExecuted; | ||
private updateMakeflowPowerItem; | ||
} |
@@ -7,12 +7,15 @@ "use strict"; | ||
const semver_1 = tslib_1.__importDefault(require("semver")); | ||
const sql_template_strings_1 = tslib_1.__importDefault(require("sql-template-strings")); | ||
const DEFAULT_POWER_APP_VERSION = '0.1.0'; | ||
class MakeflowService { | ||
constructor(commandService, tokenService, apiService, configService) { | ||
constructor(commandService, tokenService, apiService, dbService, configService) { | ||
this.commandService = commandService; | ||
this.tokenService = tokenService; | ||
this.apiService = apiService; | ||
this.dbService = dbService; | ||
this.configService = configService; | ||
this.initialize(); | ||
} | ||
async listUserCandidates(username, password) { | ||
return this.requestAPI('/account/list-users', { | ||
return this.requestMakeflowAPI('/account/list-users', { | ||
mobile: username, | ||
@@ -25,3 +28,3 @@ password, | ||
let definition = await this.generateAppDefinition(); | ||
await this.requestAPI('/power-app/publish', { | ||
await this.requestMakeflowAPI('/power-app/publish', { | ||
definition, | ||
@@ -70,5 +73,9 @@ }, { | ||
} | ||
async processAction(action, token, inputs) { | ||
async processAction(action, token, powerItemToken, inputs) { | ||
await this.tokenService.validateToken(token); | ||
await this.commandService.enqueueCommand(action, inputs); | ||
let command = await this.commandService.enqueueCommand(action, inputs); | ||
await this.insertPowerItem(command.id, powerItemToken); | ||
if (!command.manual) { | ||
this.commandService.executeCommand(command).catch(console.error); | ||
} | ||
} | ||
@@ -80,3 +87,3 @@ // TODO: check authentication from makeflow server. | ||
async createAccessToken(username, password, userId) { | ||
return this.requestAPI('/access-token/create', { | ||
return this.requestMakeflowAPI('/access-token/create', { | ||
mobile: username, | ||
@@ -115,3 +122,3 @@ password, | ||
} | ||
async requestAPI(path, body, options) { | ||
async requestMakeflowAPI(path, body, options) { | ||
let { makeflowAddress } = await this.configService.getConfig(); | ||
@@ -134,2 +141,49 @@ let makeflowAddressURL = new url_1.URL(makeflowAddress); | ||
} | ||
async insertPowerItem(commandId, token) { | ||
let statement = await this.dbService.db.run(sql_template_strings_1.default `INSERT INTO makeflow_power_items | ||
(command_id, token, response) | ||
VALUES (${commandId}, ${token}, "no-response")`); | ||
return statement.lastID; | ||
} | ||
async findPowerItem(commandId) { | ||
let doc = await this.dbService.db.get(sql_template_strings_1.default `SELECT * FROM makeflow_power_items WHERE command_id=${commandId}`); | ||
if (!doc) { | ||
return undefined; | ||
} | ||
let { id, command_id, token, response } = doc; | ||
return { | ||
id, | ||
commandId: command_id, | ||
token, | ||
response, | ||
}; | ||
} | ||
async updatePowerItemResponse(id, response) { | ||
await this.dbService.db.run(sql_template_strings_1.default `UPDATE makeflow_power_item_tokens SET response=${response} WHERE id=${id}`); | ||
} | ||
initialize() { | ||
this.commandService.on('command-executed', command => { | ||
this.onCommandExecuted(command).catch(console.error); | ||
}); | ||
} | ||
async onCommandExecuted({ id, result }) { | ||
let powerItem = await this.findPowerItem(id); | ||
if (!powerItem) { | ||
return; | ||
} | ||
let error = result && result.error; | ||
await this.updateMakeflowPowerItem(powerItem.token, { | ||
description: result && (result.output || result.error), | ||
stage: !error ? 'done' : undefined, | ||
}); | ||
await this.updatePowerItemResponse(powerItem.id, error ? 'error' : 'completed'); | ||
} | ||
async updateMakeflowPowerItem(token, { description, outputs, stage, }) { | ||
await this.requestMakeflowAPI('/power-item/update', { | ||
token, | ||
description, | ||
outputs, | ||
stage, | ||
}); | ||
} | ||
} | ||
@@ -136,0 +190,0 @@ exports.MakeflowService = MakeflowService; |
@@ -23,3 +23,3 @@ "use strict"; | ||
throw new gateway_shared_1.ExpectedError('MISSING_REQUIRED_FIELD', `Missing required field ${missingFields | ||
.map(fieldName => `${fieldName}`) | ||
.map(fieldName => `"${fieldName}"`) | ||
.join(', ')}`); | ||
@@ -26,0 +26,0 @@ } |
@@ -5,3 +5,2 @@ import { Token } from '@makeflow/gateway-shared'; | ||
private dbService; | ||
ready: Promise<void>; | ||
constructor(dbService: DBService); | ||
@@ -12,5 +11,4 @@ generateToken(label: string): Promise<string>; | ||
getActiveTokens(): Promise<Token[]>; | ||
private initializeDatabase; | ||
private findActiveTokenByHash; | ||
private insertToken; | ||
} |
@@ -11,3 +11,2 @@ "use strict"; | ||
this.dbService = dbService; | ||
this.ready = this.initializeDatabase(); | ||
} | ||
@@ -36,14 +35,2 @@ async generateToken(label) { | ||
} | ||
async initializeDatabase() { | ||
await this.dbService.ready; | ||
await this.dbService.db.run(sql_template_strings_1.default ` | ||
CREATE TABLE IF NOT EXISTS tokens ( | ||
id INTEGER PRIMARY KEY AUTOINCREMENT, | ||
label TEXT NOT NULL, | ||
hash TEXT NOT NULL, | ||
created_at NUMBER NOT NULL, | ||
deactivated_at NUMBER | ||
); | ||
`); | ||
} | ||
async findActiveTokenByHash(hash) { | ||
@@ -50,0 +37,0 @@ let doc = await this.dbService.db.get(sql_template_strings_1.default ` |
import { CommandConfig } from '@makeflow/gateway-shared'; | ||
export interface CommandHistoryDocument { | ||
export interface CommandDocument { | ||
id: number; | ||
@@ -7,2 +7,3 @@ name: string; | ||
source: string; | ||
manual: boolean; | ||
parameters?: string; | ||
@@ -9,0 +10,0 @@ denied_parameters?: string; |
@@ -6,1 +6,2 @@ export * from './command'; | ||
export * from './power-app'; | ||
export * from './makeflow'; |
{ | ||
"name": "@makeflow/gateway-server", | ||
"description": "Makeflow gateway server package", | ||
"version": "0.1.0-alpha.4", | ||
"version": "0.1.0-alpha.5", | ||
"author": "Chengdu Mufan Technology Co., Ltd.", | ||
@@ -11,3 +11,4 @@ "license": "MIT", | ||
"src/**/*.ts", | ||
"bld" | ||
"bld", | ||
"migrations" | ||
], | ||
@@ -18,3 +19,3 @@ "scripts": { | ||
"dependencies": { | ||
"@makeflow/gateway-shared": "^0.1.0-alpha.2", | ||
"@makeflow/gateway-shared": "^0.1.0-alpha.5", | ||
"koa": "^2.7.0", | ||
@@ -58,3 +59,3 @@ "koa-bodyparser": "^4.2.1", | ||
}, | ||
"gitHead": "982f58e3f16cacdd59d1621ee3ffb25fd7071bdb" | ||
"gitHead": "37a71aa5805981827a548c423a1eef8908380759" | ||
} |
@@ -98,3 +98,3 @@ import Router from 'koa-router'; | ||
async () => { | ||
return commandService.getAllNotExecutedCommandHistoryItems(); | ||
return commandService.getAllNotExecutedCommands(); | ||
}, | ||
@@ -125,3 +125,3 @@ { | ||
async ({name, parameters}) => { | ||
await commandService.enqueueCommand(name, parameters); | ||
await commandService.enqueueCommandAndTryToExecute(name, parameters); | ||
}, | ||
@@ -128,0 +128,0 @@ { |
@@ -82,4 +82,4 @@ import {ExpectedError} from '@makeflow/gateway-shared'; | ||
rpcService.processor( | ||
async ({action, configs, inputs}) => { | ||
let {token} = configs; | ||
async ({action, token, configs, inputs}) => { | ||
let {token: configToken} = configs; | ||
@@ -90,3 +90,3 @@ if (typeof token !== 'string') { | ||
await makeflowService.processAction(action, token, inputs); | ||
await makeflowService.processAction(action, configToken, token, inputs); | ||
}, | ||
@@ -96,3 +96,3 @@ { | ||
token: false, | ||
requiredParams: ['configs'], | ||
requiredParams: ['token', 'configs'], | ||
}, | ||
@@ -99,0 +99,0 @@ ), |
@@ -1,14 +0,15 @@ | ||
import { | ||
CommandExecuteResult, | ||
ICommandWithOptions, | ||
} from '@makeflow/gateway-shared'; | ||
import {Command, CommandExecuteResult} from '@makeflow/gateway-shared'; | ||
import {Dict} from 'tslang'; | ||
abstract class CommandAdapter<TCommand extends ICommandWithOptions> { | ||
abstract class CommandAdapter { | ||
abstract executeCommand( | ||
command: TCommand, | ||
): Promise<CommandExecuteResult | undefined>; | ||
command: Command, | ||
options?: Dict<unknown>, | ||
): Promise<CommandExecuteResult>; | ||
checkOptions(_options: Dict<unknown> | undefined): void {} | ||
} | ||
export interface ICommandAdapter extends CommandAdapter<ICommandWithOptions> {} | ||
export interface ICommandAdapter extends CommandAdapter {} | ||
export const AbstractCommandAdapter = CommandAdapter; |
import {exec as _exec} from 'child_process'; | ||
import * as Util from 'util'; | ||
import { | ||
CommandExecuteResult, | ||
ICommandWithOptions, | ||
} from '@makeflow/gateway-shared'; | ||
import {Command, CommandExecuteResult} from '@makeflow/gateway-shared'; | ||
@@ -13,13 +10,7 @@ import {AbstractCommandAdapter} from './command-adapter'; | ||
export interface ExecutableCommand extends ICommandWithOptions { | ||
type: 'executable'; | ||
} | ||
export class ExecutableCommandAdapter extends AbstractCommandAdapter< | ||
ExecutableCommand | ||
> { | ||
export class ExecutableCommandAdapter extends AbstractCommandAdapter { | ||
async executeCommand({ | ||
source, | ||
parameters, | ||
}: ExecutableCommand): Promise<CommandExecuteResult> { | ||
}: Command): Promise<CommandExecuteResult> { | ||
try { | ||
@@ -26,0 +17,0 @@ let {stdout, stderr} = await exec(source, { |
import * as ChildProcess from 'child_process'; | ||
import * as Util from 'util'; | ||
import { | ||
CommandExecuteResult, | ||
ICommandWithOptions, | ||
} from '@makeflow/gateway-shared'; | ||
import {Command, CommandExecuteResult} from '@makeflow/gateway-shared'; | ||
import {AbstractCommandAdapter} from './command-adapter'; | ||
export interface NodeCommand extends ICommandWithOptions { | ||
type: 'node'; | ||
} | ||
export class NodeCommandAdapter extends AbstractCommandAdapter<NodeCommand> { | ||
export class NodeCommandAdapter extends AbstractCommandAdapter { | ||
async executeCommand({ | ||
source, | ||
parameters, | ||
}: NodeCommand): Promise<CommandExecuteResult> { | ||
}: Command): Promise<CommandExecuteResult> { | ||
try { | ||
@@ -21,0 +14,0 @@ let {stdout, stderr} = await Util.promisify(ChildProcess.exec)( |
import * as ChildProcess from 'child_process'; | ||
import * as Util from 'util'; | ||
import { | ||
CommandExecuteResult, | ||
ICommandWithOptions, | ||
} from '@makeflow/gateway-shared'; | ||
import {Command, CommandExecuteResult} from '@makeflow/gateway-shared'; | ||
import {AbstractCommandAdapter} from './command-adapter'; | ||
export interface ShellCommand extends ICommandWithOptions { | ||
type: 'shell'; | ||
} | ||
export class ShellCommandAdapter extends AbstractCommandAdapter<ShellCommand> { | ||
export class ShellCommandAdapter extends AbstractCommandAdapter { | ||
async executeCommand({ | ||
source, | ||
parameters, | ||
}: ShellCommand): Promise<CommandExecuteResult> { | ||
}: Command): Promise<CommandExecuteResult> { | ||
try { | ||
@@ -21,0 +14,0 @@ let {stdout, stderr} = await Util.promisify(ChildProcess.exec)( |
import * as FS from 'fs'; | ||
import { | ||
Command, | ||
CommandExecuteResult, | ||
CommandOptions, | ||
ICommandWithOptions, | ||
} from '@makeflow/gateway-shared'; | ||
@@ -16,15 +16,7 @@ import sqlite from 'sqlite'; | ||
export interface SqliteCommand extends ICommandWithOptions { | ||
type: 'sqlite'; | ||
options: SqliteCommandOptions; | ||
} | ||
export class SqliteCommandAdapter extends AbstractCommandAdapter< | ||
SqliteCommand | ||
> { | ||
async executeCommand({ | ||
source, | ||
parameters = {}, | ||
options: {path}, | ||
}: SqliteCommand): Promise<CommandExecuteResult> { | ||
export class SqliteCommandAdapter extends AbstractCommandAdapter { | ||
async executeCommand( | ||
{source, parameters = {}}: Command, | ||
{path}: SqliteCommandOptions, | ||
): Promise<CommandExecuteResult> { | ||
try { | ||
@@ -51,2 +43,8 @@ let db = await sqlite.open(path); | ||
} | ||
checkOptions(options: SqliteCommandOptions): void { | ||
if (typeof options !== 'object' || typeof options.path !== 'string') { | ||
throw new Error('A path in options is required in sqlite scripts'); | ||
} | ||
} | ||
} |
@@ -93,2 +93,3 @@ import {createServer} from 'http'; | ||
apiService, | ||
dbService, | ||
configService, | ||
@@ -109,8 +110,3 @@ ); | ||
const servicesReady = Promise.all([ | ||
dbService.ready, | ||
httpService.ready, | ||
commandService.ready, | ||
tokenService.ready, | ||
]); | ||
const servicesReady = Promise.all([dbService.ready, httpService.ready]); | ||
@@ -117,0 +113,0 @@ await servicesReady; |
import {exec as _exec, execFile as _execFile} from 'child_process'; | ||
import {EventEmitter} from 'events'; | ||
import * as Path from 'path'; | ||
@@ -6,2 +7,3 @@ import * as Util from 'util'; | ||
import { | ||
Command, | ||
CommandConfig, | ||
@@ -12,7 +14,5 @@ CommandConfigOptions, | ||
CommandExecuteResult, | ||
CommandHistoryItem, | ||
CommandOptions, | ||
CommandParameters, | ||
ExpectedError, | ||
ICommand, | ||
} from '@makeflow/gateway-shared'; | ||
@@ -23,3 +23,3 @@ import _rimraf from 'rimraf'; | ||
import {ICommandAdapter} from '../core'; | ||
import {CommandHistoryDocument, CommandsConfig} from '../types'; | ||
import {CommandDocument, CommandsConfig} from '../types'; | ||
@@ -40,5 +40,9 @@ import {ConfigService} from './config-service'; | ||
export class CommandService { | ||
readonly ready: Promise<void>; | ||
export interface CommandService { | ||
on(event: 'command-executed', handler: (command: Command) => void): this; | ||
emit(event: 'command-executed', command: Command): boolean; | ||
} | ||
export class CommandService extends EventEmitter { | ||
private get commandsConfigPath(): string { | ||
@@ -55,3 +59,3 @@ return Path.resolve(this.commandsPath, 'config.json'); | ||
) { | ||
this.ready = this.initialize(); | ||
super(); | ||
} | ||
@@ -89,4 +93,3 @@ | ||
parameters: CommandParameters = {}, | ||
wait = false, | ||
): Promise<void> { | ||
): Promise<Command> { | ||
let { | ||
@@ -97,4 +100,3 @@ type, | ||
manual = true, | ||
options = {}, | ||
} = await this.getCommandConfig(name); | ||
} = await this.requireCommandConfig(name); | ||
@@ -106,3 +108,3 @@ let {filteredParameters, deniedParameters} = filterParameters( | ||
let command = { | ||
let command: Omit<Command, 'id'> = { | ||
name, | ||
@@ -112,41 +114,41 @@ type, | ||
parameters: filteredParameters, | ||
deniedParameters, | ||
manual, | ||
createdAt: Date.now(), | ||
}; | ||
let id = await this.insertCommandHistoryItem({ | ||
let id = await this.insertCommandHistoryItem(command); | ||
return { | ||
id, | ||
...command, | ||
deniedParameters, | ||
}); | ||
}; | ||
} | ||
if (!manual) { | ||
if (wait) { | ||
await this.executeCommand({id, ...command}, options); | ||
async enqueueCommandAndTryToExecute( | ||
name: string, | ||
parameters: CommandParameters = {}, | ||
waiting = false, | ||
): Promise<Command> { | ||
let command = await this.enqueueCommand(name, parameters); | ||
if (!command.manual) { | ||
if (waiting) { | ||
await this.executeCommand(command); | ||
} else { | ||
this.executeCommand({id, ...command}, options).catch(console.error); | ||
this.executeCommand(command).catch(console.error); | ||
} | ||
} | ||
return command; | ||
} | ||
async executeCommandFromQueue(id: number): Promise<void> { | ||
let historyItem = await this.getCommandHistoryItemById(id); | ||
let command = await this.getCommandById(id); | ||
if (!historyItem) { | ||
if (!command) { | ||
return; | ||
} | ||
let {name, type, source, parameters} = historyItem; | ||
let {options = {}} = await this.getCommandConfig(name); | ||
let result = await this.executeCommand( | ||
{ | ||
id, | ||
name, | ||
type, | ||
source, | ||
parameters, | ||
}, | ||
options, | ||
); | ||
await this.markCommandHistoryExecuted(id, result); | ||
await this.executeCommand(command); | ||
} | ||
@@ -158,3 +160,3 @@ | ||
limit, | ||
}: GetCommandHistoryItemsOptions): Promise<CommandHistoryItem[]> { | ||
}: GetCommandHistoryItemsOptions): Promise<Command[]> { | ||
if (beforeId && afterId) { | ||
@@ -166,3 +168,3 @@ throw new ExpectedError( | ||
let query = SQL`SELECT * FROM commands_history`; | ||
let query = SQL`SELECT * FROM commands`; | ||
@@ -192,5 +194,5 @@ if (beforeId || afterId) { | ||
async getAllNotExecutedCommandHistoryItems(): Promise<CommandHistoryItem[]> { | ||
async getAllNotExecutedCommands(): Promise<Command[]> { | ||
let doc = await this.dbService.db.all( | ||
SQL`SELECT * FROM commands_history WHERE executed_at is NULL ORDER BY created_at DESC`, | ||
SQL`SELECT * FROM commands WHERE executed_at is NULL ORDER BY created_at DESC`, | ||
); | ||
@@ -201,6 +203,3 @@ | ||
private async executeCommand( | ||
command: ICommand, | ||
options: CommandConfigOptions, | ||
): Promise<CommandExecuteResult | undefined> { | ||
async executeCommand(command: Command): Promise<CommandExecuteResult> { | ||
let adapter = this.adapterMap.get(command.type); | ||
@@ -212,17 +211,34 @@ | ||
let resolvedSource = Path.resolve(this.commandsPath, command.source); | ||
let {options} = await this.requireCommandConfig(command.name); | ||
command.source = resolvedSource; | ||
let result: CommandExecuteResult; | ||
let result = await adapter.executeCommand({ | ||
try { | ||
adapter.checkOptions(options); | ||
let resolvedSource = Path.resolve(this.commandsPath, command.source); | ||
command.source = resolvedSource; | ||
result = await adapter.executeCommand( | ||
command, | ||
options && resolveCommandOptions(options), | ||
); | ||
} catch (error) { | ||
result = { | ||
error: error.message, | ||
}; | ||
} | ||
await this.markCommandExecuted(command.id, result); | ||
this.emit('command-executed', { | ||
...command, | ||
options: resolveCommandOptions(options), | ||
result, | ||
}); | ||
await this.markCommandHistoryExecuted(command.id, result); | ||
return result; | ||
} | ||
private async getCommandConfig(name: string): Promise<CommandConfig> { | ||
private async requireCommandConfig(name: string): Promise<CommandConfig> { | ||
let config = await this.getCommandsConfig(); | ||
@@ -243,24 +259,2 @@ | ||
private async initialize(): Promise<void> { | ||
await this.initializeDatabase(); | ||
} | ||
private async initializeDatabase(): Promise<void> { | ||
await this.dbService.ready; | ||
await this.dbService.db.run(SQL` | ||
CREATE TABLE IF NOT EXISTS commands_history ( | ||
id INTEGER PRIMARY KEY AUTOINCREMENT, | ||
name TEXT NOT NULL, | ||
type TEXT NOT NULL, | ||
source TEXT NOT NULL, | ||
parameters TEXT, | ||
denied_parameters TEXT, | ||
created_at INTEGER, | ||
executed_at INTEGER, | ||
output TEXT, | ||
error TEXT | ||
)`); | ||
} | ||
private async insertCommandHistoryItem({ | ||
@@ -270,11 +264,13 @@ name, | ||
source, | ||
manual, | ||
parameters, | ||
deniedParameters, | ||
}: Omit<CommandHistoryItem, 'id' | 'createdAt'>): Promise<number> { | ||
createdAt, | ||
}: Omit<Command, 'id'>): Promise<number> { | ||
let statement = await this.dbService.db.run( | ||
SQL`INSERT INTO commands_history | ||
(name, type, source, parameters, denied_parameters, created_at) | ||
VALUES (${name}, ${type}, ${source}, ${JSON.stringify( | ||
SQL`INSERT INTO commands | ||
(name, type, source, manual, parameters, denied_parameters, created_at) | ||
VALUES (${name}, ${type}, ${source}, ${manual}, ${JSON.stringify( | ||
parameters, | ||
)}, ${JSON.stringify(deniedParameters)}, ${Date.now()})`, | ||
)}, ${JSON.stringify(deniedParameters)}, ${createdAt})`, | ||
); | ||
@@ -285,13 +281,15 @@ | ||
private async getCommandHistoryItemById( | ||
id: number, | ||
): Promise<CommandHistoryItem | undefined> { | ||
private async getCommandById(id: number): Promise<Command | undefined> { | ||
let doc = await this.dbService.db.get( | ||
SQL`SELECT * FROM commands_history WHERE id=${id}`, | ||
SQL`SELECT * FROM commands WHERE id=${id}`, | ||
); | ||
if (!doc) { | ||
return undefined; | ||
} | ||
return convertCommandHistoryItemDocToCommandHistoryItem(doc); | ||
} | ||
private async markCommandHistoryExecuted( | ||
private async markCommandExecuted( | ||
id: number, | ||
@@ -301,3 +299,3 @@ {output, error}: CommandExecuteResult = {}, | ||
await this.dbService.db.run( | ||
SQL`UPDATE commands_history SET output=${output}, error=${error}, executed_at=${Date.now()} WHERE id=${id}`, | ||
SQL`UPDATE commands SET output=${output}, error=${error}, executed_at=${Date.now()} WHERE id=${id}`, | ||
); | ||
@@ -308,4 +306,4 @@ } | ||
function convertCommandHistoryItemDocToCommandHistoryItem( | ||
doc: CommandHistoryDocument, | ||
): CommandHistoryItem { | ||
doc: CommandDocument, | ||
): Command { | ||
let { | ||
@@ -316,2 +314,3 @@ id, | ||
source, | ||
manual, | ||
parameters, | ||
@@ -330,2 +329,3 @@ denied_parameters, | ||
source, | ||
manual, | ||
parameters: parameters && JSON.parse(parameters), | ||
@@ -332,0 +332,0 @@ deniedParameters: denied_parameters && JSON.parse(denied_parameters), |
@@ -28,4 +28,11 @@ import * as FS from 'fs'; | ||
this._db = await sqlite.open(path); | ||
let db = await sqlite.open(path); | ||
// TODO: Improve | ||
await db.migrate({ | ||
migrationsPath: Path.join(__dirname, '../../migrations'), | ||
}); | ||
this._db = db; | ||
} | ||
} |
import {URL} from 'url'; | ||
import { | ||
Command, | ||
CommandConfig, | ||
@@ -10,2 +11,3 @@ CommandConfigParameter, | ||
import semver from 'semver'; | ||
import SQL from 'sql-template-strings'; | ||
import {Dict} from 'tslang'; | ||
@@ -16,4 +18,6 @@ | ||
PowerAppInputOptions, | ||
PowerItem, | ||
PowerItemDefinition, | ||
PowerItemFieldDefinition, | ||
PowerItemResponse, | ||
} from '../types'; | ||
@@ -24,2 +28,3 @@ | ||
import {ConfigService} from './config-service'; | ||
import {DBService} from './db-service'; | ||
import {TokenService} from './token-service'; | ||
@@ -47,4 +52,7 @@ | ||
private apiService: APIService, | ||
private dbService: DBService, | ||
private configService: ConfigService, | ||
) {} | ||
) { | ||
this.initialize(); | ||
} | ||
@@ -55,3 +63,3 @@ async listUserCandidates( | ||
): Promise<MFUserCandidate[]> { | ||
return this.requestAPI('/account/list-users', { | ||
return this.requestMakeflowAPI('/account/list-users', { | ||
mobile: username, | ||
@@ -66,3 +74,3 @@ password, | ||
await this.requestAPI( | ||
await this.requestMakeflowAPI( | ||
'/power-app/publish', | ||
@@ -143,2 +151,3 @@ { | ||
token: string, | ||
powerItemToken: string, | ||
inputs: Dict<unknown>, | ||
@@ -148,3 +157,9 @@ ): Promise<void> { | ||
await this.commandService.enqueueCommand(action, inputs); | ||
let command = await this.commandService.enqueueCommand(action, inputs); | ||
await this.insertPowerItem(command.id, powerItemToken); | ||
if (!command.manual) { | ||
this.commandService.executeCommand(command).catch(console.error); | ||
} | ||
} | ||
@@ -162,3 +177,3 @@ | ||
): Promise<string> { | ||
return this.requestAPI('/access-token/create', { | ||
return this.requestMakeflowAPI('/access-token/create', { | ||
mobile: username, | ||
@@ -212,3 +227,3 @@ password, | ||
private async requestAPI<TData>( | ||
private async requestMakeflowAPI<TData>( | ||
path: string, | ||
@@ -244,2 +259,87 @@ body?: Dict<unknown>, | ||
} | ||
private async insertPowerItem( | ||
commandId: number, | ||
token: string, | ||
): Promise<number> { | ||
let statement = await this.dbService.db.run( | ||
SQL`INSERT INTO makeflow_power_items | ||
(command_id, token, response) | ||
VALUES (${commandId}, ${token}, "no-response")`, | ||
); | ||
return statement.lastID; | ||
} | ||
private async findPowerItem( | ||
commandId: number, | ||
): Promise<PowerItem | undefined> { | ||
let doc = await this.dbService.db.get( | ||
SQL`SELECT * FROM makeflow_power_items WHERE command_id=${commandId}`, | ||
); | ||
if (!doc) { | ||
return undefined; | ||
} | ||
let {id, command_id, token, response} = doc; | ||
return { | ||
id, | ||
commandId: command_id, | ||
token, | ||
response, | ||
}; | ||
} | ||
private async updatePowerItemResponse( | ||
id: number, | ||
response: PowerItemResponse, | ||
): Promise<void> { | ||
await this.dbService.db.run( | ||
SQL`UPDATE makeflow_power_item_tokens SET response=${response} WHERE id=${id}`, | ||
); | ||
} | ||
private initialize(): void { | ||
this.commandService.on('command-executed', command => { | ||
this.onCommandExecuted(command).catch(console.error); | ||
}); | ||
} | ||
private async onCommandExecuted({id, result}: Command): Promise<void> { | ||
let powerItem = await this.findPowerItem(id); | ||
if (!powerItem) { | ||
return; | ||
} | ||
let error = result && result.error; | ||
await this.updateMakeflowPowerItem(powerItem.token, { | ||
description: result && (result.output || result.error), | ||
stage: !error ? 'done' : undefined, | ||
}); | ||
await this.updatePowerItemResponse( | ||
powerItem.id, | ||
error ? 'error' : 'completed', | ||
); | ||
} | ||
private async updateMakeflowPowerItem( | ||
token: string, | ||
{ | ||
description, | ||
outputs, | ||
stage, | ||
}: {description?: string; outputs?: Dict<unknown>; stage?: 'done' | 'none'}, | ||
): Promise<void> { | ||
await this.requestMakeflowAPI('/power-item/update', { | ||
token, | ||
description, | ||
outputs, | ||
stage, | ||
}); | ||
} | ||
} | ||
@@ -246,0 +346,0 @@ |
@@ -69,3 +69,3 @@ import {ExpectedError} from '@makeflow/gateway-shared'; | ||
`Missing required field ${missingFields | ||
.map(fieldName => `${fieldName}`) | ||
.map(fieldName => `"${fieldName}"`) | ||
.join(', ')}`, | ||
@@ -72,0 +72,0 @@ ); |
@@ -12,8 +12,4 @@ import crypto from 'crypto'; | ||
export class TokenService { | ||
ready: Promise<void>; | ||
constructor(private dbService: DBService) {} | ||
constructor(private dbService: DBService) { | ||
this.ready = this.initializeDatabase(); | ||
} | ||
async generateToken(label: string): Promise<string> { | ||
@@ -53,16 +49,2 @@ let token = uuid(); | ||
private async initializeDatabase(): Promise<void> { | ||
await this.dbService.ready; | ||
await this.dbService.db.run(SQL` | ||
CREATE TABLE IF NOT EXISTS tokens ( | ||
id INTEGER PRIMARY KEY AUTOINCREMENT, | ||
label TEXT NOT NULL, | ||
hash TEXT NOT NULL, | ||
created_at NUMBER NOT NULL, | ||
deactivated_at NUMBER | ||
); | ||
`); | ||
} | ||
private async findActiveTokenByHash( | ||
@@ -69,0 +51,0 @@ hash: string, |
import {CommandConfig} from '@makeflow/gateway-shared'; | ||
export interface CommandHistoryDocument { | ||
export interface CommandDocument { | ||
id: number; | ||
@@ -8,2 +8,3 @@ name: string; | ||
source: string; | ||
manual: boolean; | ||
parameters?: string; | ||
@@ -10,0 +11,0 @@ denied_parameters?: string; |
@@ -6,1 +6,2 @@ export * from './command'; | ||
export * from './power-app'; | ||
export * from './makeflow'; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
163541
132
3533