app.ts 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import { createError, opine, ErrorRequestHandler, Router, server } from "./deps.ts";
  2. import { BBB } from './bbb.ts';
  3. // give your tinyscale server a secret so it looks like a BBB server
  4. const secret = Deno.env.get("TINYSCALE_SECRET") || ""
  5. if (!secret) throw "No secret set for tinyscale"
  6. // store your BBB servers in servers.json
  7. const file: string = await Deno.readTextFile('servers.json')
  8. const servers: server[] = JSON.parse(file)
  9. // create an iterator so that we can treat all servers equally
  10. let iterator = servers[Symbol.iterator]();
  11. console.log(servers)
  12. // pick the next server, using an iterator to cycle through all servers available
  13. function get_available_server(): server {
  14. let candidate = iterator.next()
  15. if (candidate.done) {
  16. iterator = servers[Symbol.iterator]()
  17. candidate = iterator.next()
  18. }
  19. console.log(`Using next server ${candidate.value.host}`)
  20. return candidate.value;
  21. }
  22. const router = Router()
  23. // the api itself answering to every call
  24. router.all("/bigbluebutton/api/:call", async (req, res, next) => {
  25. const handler = new BBB(req)
  26. if (!handler.authenticated(secret)) {
  27. res.setStatus(401).end()
  28. return
  29. }
  30. let server: server
  31. try {
  32. server = await handler.find_meeting_id(servers)
  33. } catch (e) {
  34. console.log(`Found no server with Meeting ID ${handler.meeting_id}`)
  35. server = get_available_server()
  36. }
  37. console.log(`Redirecting to ${server.host}`)
  38. res.redirect(handler.rewritten_query(server))
  39. });
  40. // the fake answering machine to make sure we are recognized as a proper api
  41. router.get("/bigbluebutton/api", (req, res, next) => {
  42. console.log('sending fake xml response')
  43. res.set('Content-Type', 'text/xml');
  44. res.send(`<response>
  45. <returncode>SUCCESS</returncode>
  46. <version>2.0</version>
  47. </response>`);
  48. })
  49. const errorHandler: ErrorRequestHandler = (err, req, res, next) => {
  50. res.setStatus(err.status ?? 500);
  51. console.log(res.status, req.originalUrl)
  52. res.end();
  53. };
  54. const app = opine()
  55. .use("/", router)
  56. .use((req, res, next) => { next(createError(404)); })
  57. .use(errorHandler);
  58. export default app;