Merge pull request #11 from amhsirak/develop

feat: record & workflow routes
This commit is contained in:
amhsirak
2024-06-09 00:47:28 +05:30
committed by GitHub
3 changed files with 245 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
import { router as record } from './record';
import { router as workflow } from './workflow';
import { router as storage } from './storage';
export {
record,
workflow,
storage,
};

113
server/src/routes/record.ts Normal file
View File

@@ -0,0 +1,113 @@
/**
* RESTful API endpoints handling remote browser recording sessions.
*/
import { Router } from 'express';
import {
initializeRemoteBrowserForRecording,
destroyRemoteBrowser,
getActiveBrowserId,
interpretWholeWorkflow,
stopRunningInterpretation,
getRemoteBrowserCurrentUrl, getRemoteBrowserCurrentTabs,
} from '../browser-management/controller'
import { chromium } from "playwright";
import logger from "../logger";
export const router = Router();
/**
* Logs information about remote browser recording session.
*/
router.all('/', (req, res, next) => {
logger.log('debug', `The record API was invoked: ${req.url}`)
next() // pass control to the next handler
})
/**
* GET endpoint for starting the remote browser recording session.
* returns session's id
*/
router.get('/start', (req, res) => {
const id = initializeRemoteBrowserForRecording({
browser: chromium,
launchOptions: {
headless: true,
}
});
return res.send(id);
});
/**
* POST endpoint for starting the remote browser recording session accepting browser launch options.
* returns session's id
*/
router.post('/start', (req, res) => {
const id = initializeRemoteBrowserForRecording({
browser: chromium,
launchOptions: req.body,
});
return res.send(id);
});
/**
* GET endpoint for terminating the remote browser recording session.
* returns whether the termination was successful
*/
router.get('/stop/:browserId', async (req, res) => {
const success = await destroyRemoteBrowser(req.params.browserId);
return res.send(success);
});
/**
* GET endpoint for getting the id of the active remote browser.
*/
router.get('/active', (req, res) => {
const id = getActiveBrowserId();
return res.send(id);
});
/**
* GET endpoint for getting the current url of the active remote browser.
*/
router.get('/active/url', (req, res) => {
const id = getActiveBrowserId();
if (id) {
const url = getRemoteBrowserCurrentUrl(id);
return res.send(url);
}
return res.send(null);
});
/**
* GET endpoint for getting the current tabs of the active remote browser.
*/
router.get('/active/tabs', (req, res) => {
const id = getActiveBrowserId();
if (id) {
const hosts = getRemoteBrowserCurrentTabs(id);
return res.send(hosts);
}
return res.send([]);
});
/**
* GET endpoint for starting an interpretation of the currently generated workflow.
*/
router.get('/interpret', async (req, res) => {
try {
await interpretWholeWorkflow();
return res.send('interpretation done');
} catch (e) {
return res.send('interpretation done');
return res.status(400);
}
});
/**
* GET endpoint for stopping an ongoing interpretation of the currently generated workflow.
*/
router.get('/interpret/stop', async (req, res) => {
await stopRunningInterpretation();
return res.send('interpretation stopped');
});

View File

@@ -0,0 +1,123 @@
/**
* RESTful API endpoints handling currently generated workflow management.
*/
import { Router } from 'express';
import logger from "../logger";
import { browserPool } from "../server";
import { readFile } from "../workflow-management/storage";
export const router = Router();
/**
* Logs information about workflow API.
*/
router.all('/', (req, res, next) => {
logger.log('debug', `The workflow API was invoked: ${req.url}`)
next() // pass control to the next handler
})
/**
* GET endpoint for a recording linked to a remote browser instance.
* returns session's id
*/
router.get('/:browserId', (req, res) => {
const activeBrowser = browserPool.getRemoteBrowser(req.params.browserId);
let workflowFile = null;
if (activeBrowser && activeBrowser.generator) {
workflowFile = activeBrowser.generator.getWorkflowFile();
}
return res.send(workflowFile);
});
/**
* Get endpoint returning the parameter array of the recording associated with the browserId browser instance.
*/
router.get('/params/:browserId', (req, res) => {
const activeBrowser = browserPool.getRemoteBrowser(req.params.browserId);
let params = null;
if (activeBrowser && activeBrowser.generator) {
params = activeBrowser.generator.getParams();
}
return res.send(params);
});
/**
* DELETE endpoint for deleting a pair from the generated workflow.
*/
router.delete('/pair/:index', (req, res) => {
const id = browserPool.getActiveBrowserId();
if (id) {
const browser = browserPool.getRemoteBrowser(id);
if (browser) {
browser.generator?.removePairFromWorkflow(parseInt(req.params.index));
const workflowFile = browser.generator?.getWorkflowFile();
return res.send(workflowFile);
}
}
return res.send(null);
});
/**
* POST endpoint for adding a pair to the generated workflow.
*/
router.post('/pair/:index', (req, res) => {
const id = browserPool.getActiveBrowserId();
if (id) {
const browser = browserPool.getRemoteBrowser(id);
logger.log('debug', `Adding pair to workflow`);
if (browser) {
logger.log('debug', `Adding pair to workflow: ${JSON.stringify(req.body)}`);
if (req.body.pair) {
browser.generator?.addPairToWorkflow(parseInt(req.params.index), req.body.pair);
const workflowFile = browser.generator?.getWorkflowFile();
return res.send(workflowFile);
}
}
}
return res.send(null);
});
/**
* PUT endpoint for updating a pair in the generated workflow.
*/
router.put('/pair/:index', (req, res) => {
const id = browserPool.getActiveBrowserId();
if (id) {
const browser = browserPool.getRemoteBrowser(id);
logger.log('debug', `Updating pair in workflow`);
if (browser) {
logger.log('debug', `New value: ${JSON.stringify(req.body)}`);
if (req.body.pair) {
browser.generator?.updatePairInWorkflow(parseInt(req.params.index), req.body.pair);
const workflowFile = browser.generator?.getWorkflowFile();
return res.send(workflowFile);
}
}
}
return res.send(null);
});
/**
* PUT endpoint for updating the currently generated workflow file from the one in the storage.
*/
router.put('/:browserId/:fileName', async (req, res) => {
try {
const browser = browserPool.getRemoteBrowser(req.params.browserId);
logger.log('debug', `Updating workflow file`);
if (browser && browser.generator) {
const recording = await readFile(`./../storage/recordings/${req.params.fileName}.waw.json`)
const parsedRecording = JSON.parse(recording);
if (parsedRecording.recording) {
browser.generator?.updateWorkflowFile(parsedRecording.recording, parsedRecording.recording_meta);
const workflowFile = browser.generator?.getWorkflowFile();
return res.send(workflowFile);
}
}
return res.send(null);
} catch (e) {
const { message } = e as Error;
logger.log('info', `Error while reading a recording with name: ${req.params.fileName}.waw.json`);
return res.send(null);
}
});