-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.ts
87 lines (81 loc) · 2.89 KB
/
app.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import { opine, ErrorRequestHandler, Router, secret, HttpError, Color, deferred, Deferred } from "./deps.ts";
import { BBB } from './bbb.ts';
import { Servers } from './servers.ts'
import type { server } from './deps.ts'
const date = () => new Date().toLocaleTimeString('de')
const S = new Servers()
await S.init()
let queue: Record<string, Deferred<string>> = {}
const router = Router()
router.use((req, res, next)=> {
res.set('Content-Type', 'text/xml')
next()
});
// check authentication via checksum
router.use("/:call", (req, res, next) => {
const handler = new BBB(req)
const authenticated = handler.authenticated(secret)
res.locals.log = [`${date()} ${Color.green(handler.call)}${authenticated ? '':Color.red(' Rejected')}`]
if (authenticated) {
res.locals.handler = handler
next()
} else {
next(new HttpError(401));
}
})
// if the param is call, check for races
router.all('/create', async (req, res, next) => {
const meeting_id = req.query.meetingID
const existing_id = queue[meeting_id]
if (existing_id) {
console.log(`Race pending for meeting-ID: ${Color.red(meeting_id)}`)
await existing_id
}
queue[meeting_id] = deferred<string>();
next()
})
// the api itself answering to every call
router.all("/:call", async (req, res, next) => {
const handler = res.locals.handler
let server: server
try {
server = await handler.find_meeting_id(S.servers)
res.locals.log.push(`found, ${handler.call==='join'?'redirect to':'reply with'} ${server.host}`)
} catch (e) {
res.locals.log.push(`${Color.yellow("not found")},`)
if (handler.call === 'create') {
S.get_available_server()
res.locals.log.push(`open new room on ${Color.green(S.current_server.host)}`);
} else res.locals.log.push(`reply with ${S.current_server.host}`)
server = S.current_server
}
const redirect = handler.rewritten_query(server)
if (handler.call === 'join') {
res.redirect(redirect)
} else {
try {
const data = await fetch(redirect)
const body = await data.text()
if (handler.call === 'create') { queue[handler.meeting_id]?.resolve(body); delete queue[handler.meeting_id] }
res.send(body)
} catch (e) {
if (handler.call === 'create') { queue[handler.meeting_id]?.resolve(e); delete queue[handler.meeting_id] }
next(new HttpError(500));
}
}
console.log(res.locals.log.join(' '));
});
// the fake answering machine to make sure we are recognized as a proper api
router.get("/", (req, res, next) => {
res.send(`<response><returncode>SUCCESS</returncode><version>2.0</version></response>`);
})
const errorHandler: ErrorRequestHandler = (err, req, res, next) => {
res.setStatus(err.status ?? 500);
res.end();
console.log(`${Color.red(`${res.status}`)} ${req.originalUrl}`)
};
const app = opine()
.use("/bigbluebutton/api", router)
.use((req, res, next) => next(new HttpError(404)))
.use(errorHandler);
export default app;