app.ts 2.3 KB

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