Discord
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
import { createRouter } from '@@/create-router';
|
||||
import * as errors from '@@/custom-errors';
|
||||
import { registerUserToken } from './relay-auth';
|
||||
import { getRelayPort, getUserRelayStatus, getUserTargets } from './relay';
|
||||
import { captureScreenshot, evaluateJS, navigateTo } from './cdp';
|
||||
|
||||
export const browserRouter = createRouter();
|
||||
|
||||
function getOpts(userId: number) {
|
||||
const port = getRelayPort();
|
||||
const token = registerUserToken(userId, port);
|
||||
return { relayPort: port, userToken: token };
|
||||
}
|
||||
|
||||
browserRouter.get('/status', async (ctx) => {
|
||||
const user = ctx.get('user');
|
||||
const status = getUserRelayStatus(user.id);
|
||||
return ctx.json(status);
|
||||
});
|
||||
|
||||
browserRouter.get('/relay-token', async (ctx) => {
|
||||
const user = ctx.get('user');
|
||||
const port = getRelayPort();
|
||||
const token = registerUserToken(user.id, port);
|
||||
return ctx.json({ token, port });
|
||||
});
|
||||
|
||||
browserRouter.get('/targets', async (ctx) => {
|
||||
const user = ctx.get('user');
|
||||
const targets = getUserTargets(user.id);
|
||||
return ctx.json(
|
||||
targets.map((t) => ({
|
||||
id: t.targetId,
|
||||
sessionId: t.sessionId,
|
||||
type: t.targetInfo.type ?? 'page',
|
||||
title: t.targetInfo.title ?? '',
|
||||
url: t.targetInfo.url ?? '',
|
||||
})),
|
||||
);
|
||||
});
|
||||
|
||||
browserRouter.get('/targets/:id/screenshot', async (ctx) => {
|
||||
const user = ctx.get('user');
|
||||
const targetId = ctx.req.param('id');
|
||||
const format = (ctx.req.query('format') as 'png' | 'jpeg') || 'png';
|
||||
|
||||
const opts = getOpts(user.id);
|
||||
// Find session ID for the target
|
||||
const targets = getUserTargets(user.id);
|
||||
const target = targets.find((t) => t.targetId === targetId);
|
||||
if (!target) throw errors.NOT_FOUND('Target not found');
|
||||
|
||||
try {
|
||||
const data = await captureScreenshot({ ...opts, targetId: target.sessionId }, format);
|
||||
return ctx.json({ data, format });
|
||||
} catch (err) {
|
||||
throw errors.INTERNAL_SERVER_ERROR(err instanceof Error ? err.message : 'Screenshot failed');
|
||||
}
|
||||
});
|
||||
|
||||
browserRouter.post('/targets/:id/evaluate', async (ctx) => {
|
||||
const user = ctx.get('user');
|
||||
const targetId = ctx.req.param('id');
|
||||
const body = ctx.get('body') as { expression?: string };
|
||||
|
||||
if (!body.expression) throw errors.BAD_REQUEST('expression is required');
|
||||
|
||||
const opts = getOpts(user.id);
|
||||
const targets = getUserTargets(user.id);
|
||||
const target = targets.find((t) => t.targetId === targetId);
|
||||
if (!target) throw errors.NOT_FOUND('Target not found');
|
||||
|
||||
try {
|
||||
const result = await evaluateJS({ ...opts, targetId: target.sessionId }, body.expression);
|
||||
return ctx.json({ result });
|
||||
} catch (err) {
|
||||
throw errors.INTERNAL_SERVER_ERROR(err instanceof Error ? err.message : 'Evaluation failed');
|
||||
}
|
||||
});
|
||||
|
||||
browserRouter.post('/targets/:id/navigate', async (ctx) => {
|
||||
const user = ctx.get('user');
|
||||
const targetId = ctx.req.param('id');
|
||||
const body = ctx.get('body') as { url?: string };
|
||||
|
||||
if (!body.url) throw errors.BAD_REQUEST('url is required');
|
||||
|
||||
const opts = getOpts(user.id);
|
||||
const targets = getUserTargets(user.id);
|
||||
const target = targets.find((t) => t.targetId === targetId);
|
||||
if (!target) throw errors.NOT_FOUND('Target not found');
|
||||
|
||||
try {
|
||||
await navigateTo({ ...opts, targetId: target.sessionId }, body.url);
|
||||
return ctx.json({ ok: true });
|
||||
} catch (err) {
|
||||
throw errors.INTERNAL_SERVER_ERROR(err instanceof Error ? err.message : 'Navigation failed');
|
||||
}
|
||||
});
|
||||
|
||||
browserRouter.post('/targets/:id/activate', async (ctx) => {
|
||||
const user = ctx.get('user');
|
||||
const targetId = ctx.req.param('id');
|
||||
|
||||
const port = getRelayPort();
|
||||
const token = registerUserToken(user.id, port);
|
||||
|
||||
try {
|
||||
const res = await fetch(`http://127.0.0.1:${port}/json/activate/${encodeURIComponent(targetId)}`, {
|
||||
headers: { 'x-officer-relay-token': token },
|
||||
});
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
return ctx.json({ ok: true });
|
||||
} catch (err) {
|
||||
throw errors.INTERNAL_SERVER_ERROR(err instanceof Error ? err.message : 'Activate failed');
|
||||
}
|
||||
});
|
||||
|
||||
browserRouter.post('/targets/:id/close', async (ctx) => {
|
||||
const user = ctx.get('user');
|
||||
const targetId = ctx.req.param('id');
|
||||
|
||||
const port = getRelayPort();
|
||||
const token = registerUserToken(user.id, port);
|
||||
|
||||
try {
|
||||
const res = await fetch(`http://127.0.0.1:${port}/json/close/${encodeURIComponent(targetId)}`, {
|
||||
headers: { 'x-officer-relay-token': token },
|
||||
});
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
return ctx.json({ ok: true });
|
||||
} catch (err) {
|
||||
throw errors.INTERNAL_SERVER_ERROR(err instanceof Error ? err.message : 'Close failed');
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user