Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.js 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. "use strict";
  2. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  3. if (k2 === undefined) k2 = k;
  4. Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
  5. }) : (function(o, m, k, k2) {
  6. if (k2 === undefined) k2 = k;
  7. o[k2] = m[k];
  8. }));
  9. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  10. Object.defineProperty(o, "default", { enumerable: true, value: v });
  11. }) : function(o, v) {
  12. o["default"] = v;
  13. });
  14. var __importStar = (this && this.__importStar) || function (mod) {
  15. if (mod && mod.__esModule) return mod;
  16. var result = {};
  17. if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
  18. __setModuleDefault(result, mod);
  19. return result;
  20. };
  21. var __importDefault = (this && this.__importDefault) || function (mod) {
  22. return (mod && mod.__esModule) ? mod : { "default": mod };
  23. };
  24. Object.defineProperty(exports, "__esModule", { value: true });
  25. exports.Namespace = exports.Socket = exports.Server = void 0;
  26. const http = require("http");
  27. const fs_1 = require("fs");
  28. const zlib_1 = require("zlib");
  29. const accepts = require("accepts");
  30. const stream_1 = require("stream");
  31. const path = require("path");
  32. const engine = require("engine.io");
  33. const client_1 = require("./client");
  34. const events_1 = require("events");
  35. const namespace_1 = require("./namespace");
  36. Object.defineProperty(exports, "Namespace", { enumerable: true, get: function () { return namespace_1.Namespace; } });
  37. const parent_namespace_1 = require("./parent-namespace");
  38. const socket_io_adapter_1 = require("socket.io-adapter");
  39. const parser = __importStar(require("socket.io-parser"));
  40. const debug_1 = __importDefault(require("debug"));
  41. const socket_1 = require("./socket");
  42. Object.defineProperty(exports, "Socket", { enumerable: true, get: function () { return socket_1.Socket; } });
  43. const typed_events_1 = require("./typed-events");
  44. const debug = (0, debug_1.default)("socket.io:server");
  45. const clientVersion = require("../package.json").version;
  46. const dotMapRegex = /\.map/;
  47. class Server extends typed_events_1.StrictEventEmitter {
  48. constructor(srv, opts = {}) {
  49. super();
  50. /**
  51. * @private
  52. */
  53. this._nsps = new Map();
  54. this.parentNsps = new Map();
  55. if ("object" === typeof srv &&
  56. srv instanceof Object &&
  57. !srv.listen) {
  58. opts = srv;
  59. srv = undefined;
  60. }
  61. this.path(opts.path || "/socket.io");
  62. this.connectTimeout(opts.connectTimeout || 45000);
  63. this.serveClient(false !== opts.serveClient);
  64. this._parser = opts.parser || parser;
  65. this.encoder = new this._parser.Encoder();
  66. this.adapter(opts.adapter || socket_io_adapter_1.Adapter);
  67. this.sockets = this.of("/");
  68. this.opts = opts;
  69. if (srv)
  70. this.attach(srv);
  71. }
  72. serveClient(v) {
  73. if (!arguments.length)
  74. return this._serveClient;
  75. this._serveClient = v;
  76. return this;
  77. }
  78. /**
  79. * Executes the middleware for an incoming namespace not already created on the server.
  80. *
  81. * @param name - name of incoming namespace
  82. * @param auth - the auth parameters
  83. * @param fn - callback
  84. *
  85. * @private
  86. */
  87. _checkNamespace(name, auth, fn) {
  88. if (this.parentNsps.size === 0)
  89. return fn(false);
  90. const keysIterator = this.parentNsps.keys();
  91. const run = () => {
  92. const nextFn = keysIterator.next();
  93. if (nextFn.done) {
  94. return fn(false);
  95. }
  96. nextFn.value(name, auth, (err, allow) => {
  97. if (err || !allow) {
  98. run();
  99. }
  100. else {
  101. const namespace = this.parentNsps
  102. .get(nextFn.value)
  103. .createChild(name);
  104. // @ts-ignore
  105. this.sockets.emitReserved("new_namespace", namespace);
  106. fn(namespace);
  107. }
  108. });
  109. };
  110. run();
  111. }
  112. path(v) {
  113. if (!arguments.length)
  114. return this._path;
  115. this._path = v.replace(/\/$/, "");
  116. const escapedPath = this._path.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
  117. this.clientPathRegex = new RegExp("^" +
  118. escapedPath +
  119. "/socket\\.io(\\.min|\\.msgpack\\.min)?\\.js(\\.map)?(?:\\?|$)");
  120. return this;
  121. }
  122. connectTimeout(v) {
  123. if (v === undefined)
  124. return this._connectTimeout;
  125. this._connectTimeout = v;
  126. return this;
  127. }
  128. adapter(v) {
  129. if (!arguments.length)
  130. return this._adapter;
  131. this._adapter = v;
  132. for (const nsp of this._nsps.values()) {
  133. nsp._initAdapter();
  134. }
  135. return this;
  136. }
  137. /**
  138. * Attaches socket.io to a server or port.
  139. *
  140. * @param srv - server or port
  141. * @param opts - options passed to engine.io
  142. * @return self
  143. * @public
  144. */
  145. listen(srv, opts = {}) {
  146. return this.attach(srv, opts);
  147. }
  148. /**
  149. * Attaches socket.io to a server or port.
  150. *
  151. * @param srv - server or port
  152. * @param opts - options passed to engine.io
  153. * @return self
  154. * @public
  155. */
  156. attach(srv, opts = {}) {
  157. if ("function" == typeof srv) {
  158. const msg = "You are trying to attach socket.io to an express " +
  159. "request handler function. Please pass a http.Server instance.";
  160. throw new Error(msg);
  161. }
  162. // handle a port as a string
  163. if (Number(srv) == srv) {
  164. srv = Number(srv);
  165. }
  166. if ("number" == typeof srv) {
  167. debug("creating http server and binding to %d", srv);
  168. const port = srv;
  169. srv = http.createServer((req, res) => {
  170. res.writeHead(404);
  171. res.end();
  172. });
  173. srv.listen(port);
  174. }
  175. // merge the options passed to the Socket.IO server
  176. Object.assign(opts, this.opts);
  177. // set engine.io path to `/socket.io`
  178. opts.path = opts.path || this._path;
  179. this.initEngine(srv, opts);
  180. return this;
  181. }
  182. /**
  183. * Initialize engine
  184. *
  185. * @param srv - the server to attach to
  186. * @param opts - options passed to engine.io
  187. * @private
  188. */
  189. initEngine(srv, opts) {
  190. // initialize engine
  191. debug("creating engine.io instance with opts %j", opts);
  192. this.eio = engine.attach(srv, opts);
  193. // attach static file serving
  194. if (this._serveClient)
  195. this.attachServe(srv);
  196. // Export http server
  197. this.httpServer = srv;
  198. // bind to engine events
  199. this.bind(this.eio);
  200. }
  201. /**
  202. * Attaches the static file serving.
  203. *
  204. * @param srv http server
  205. * @private
  206. */
  207. attachServe(srv) {
  208. debug("attaching client serving req handler");
  209. const evs = srv.listeners("request").slice(0);
  210. srv.removeAllListeners("request");
  211. srv.on("request", (req, res) => {
  212. if (this.clientPathRegex.test(req.url)) {
  213. this.serve(req, res);
  214. }
  215. else {
  216. for (let i = 0; i < evs.length; i++) {
  217. evs[i].call(srv, req, res);
  218. }
  219. }
  220. });
  221. }
  222. /**
  223. * Handles a request serving of client source and map
  224. *
  225. * @param req
  226. * @param res
  227. * @private
  228. */
  229. serve(req, res) {
  230. const filename = req.url.replace(this._path, "").replace(/\?.*$/, "");
  231. const isMap = dotMapRegex.test(filename);
  232. const type = isMap ? "map" : "source";
  233. // Per the standard, ETags must be quoted:
  234. // https://tools.ietf.org/html/rfc7232#section-2.3
  235. const expectedEtag = '"' + clientVersion + '"';
  236. const weakEtag = "W/" + expectedEtag;
  237. const etag = req.headers["if-none-match"];
  238. if (etag) {
  239. if (expectedEtag === etag || weakEtag === etag) {
  240. debug("serve client %s 304", type);
  241. res.writeHead(304);
  242. res.end();
  243. return;
  244. }
  245. }
  246. debug("serve client %s", type);
  247. res.setHeader("Cache-Control", "public, max-age=0");
  248. res.setHeader("Content-Type", "application/" + (isMap ? "json" : "javascript"));
  249. res.setHeader("ETag", expectedEtag);
  250. Server.sendFile(filename, req, res);
  251. }
  252. /**
  253. * @param filename
  254. * @param req
  255. * @param res
  256. * @private
  257. */
  258. static sendFile(filename, req, res) {
  259. const readStream = (0, fs_1.createReadStream)(path.join(__dirname, "../client-dist/", filename));
  260. const encoding = accepts(req).encodings(["br", "gzip", "deflate"]);
  261. const onError = (err) => {
  262. if (err) {
  263. res.end();
  264. }
  265. };
  266. switch (encoding) {
  267. case "br":
  268. res.writeHead(200, { "content-encoding": "br" });
  269. readStream.pipe((0, zlib_1.createBrotliCompress)()).pipe(res);
  270. (0, stream_1.pipeline)(readStream, (0, zlib_1.createBrotliCompress)(), res, onError);
  271. break;
  272. case "gzip":
  273. res.writeHead(200, { "content-encoding": "gzip" });
  274. (0, stream_1.pipeline)(readStream, (0, zlib_1.createGzip)(), res, onError);
  275. break;
  276. case "deflate":
  277. res.writeHead(200, { "content-encoding": "deflate" });
  278. (0, stream_1.pipeline)(readStream, (0, zlib_1.createDeflate)(), res, onError);
  279. break;
  280. default:
  281. res.writeHead(200);
  282. (0, stream_1.pipeline)(readStream, res, onError);
  283. }
  284. }
  285. /**
  286. * Binds socket.io to an engine.io instance.
  287. *
  288. * @param {engine.Server} engine engine.io (or compatible) server
  289. * @return self
  290. * @public
  291. */
  292. bind(engine) {
  293. this.engine = engine;
  294. this.engine.on("connection", this.onconnection.bind(this));
  295. return this;
  296. }
  297. /**
  298. * Called with each incoming transport connection.
  299. *
  300. * @param {engine.Socket} conn
  301. * @return self
  302. * @private
  303. */
  304. onconnection(conn) {
  305. debug("incoming connection with id %s", conn.id);
  306. const client = new client_1.Client(this, conn);
  307. if (conn.protocol === 3) {
  308. // @ts-ignore
  309. client.connect("/");
  310. }
  311. return this;
  312. }
  313. /**
  314. * Looks up a namespace.
  315. *
  316. * @param {String|RegExp|Function} name nsp name
  317. * @param fn optional, nsp `connection` ev handler
  318. * @public
  319. */
  320. of(name, fn) {
  321. if (typeof name === "function" || name instanceof RegExp) {
  322. const parentNsp = new parent_namespace_1.ParentNamespace(this);
  323. debug("initializing parent namespace %s", parentNsp.name);
  324. if (typeof name === "function") {
  325. this.parentNsps.set(name, parentNsp);
  326. }
  327. else {
  328. this.parentNsps.set((nsp, conn, next) => next(null, name.test(nsp)), parentNsp);
  329. }
  330. if (fn) {
  331. // @ts-ignore
  332. parentNsp.on("connect", fn);
  333. }
  334. return parentNsp;
  335. }
  336. if (String(name)[0] !== "/")
  337. name = "/" + name;
  338. let nsp = this._nsps.get(name);
  339. if (!nsp) {
  340. debug("initializing namespace %s", name);
  341. nsp = new namespace_1.Namespace(this, name);
  342. this._nsps.set(name, nsp);
  343. if (name !== "/") {
  344. // @ts-ignore
  345. this.sockets.emitReserved("new_namespace", nsp);
  346. }
  347. }
  348. if (fn)
  349. nsp.on("connect", fn);
  350. return nsp;
  351. }
  352. /**
  353. * Closes server connection
  354. *
  355. * @param [fn] optional, called as `fn([err])` on error OR all conns closed
  356. * @public
  357. */
  358. close(fn) {
  359. for (const socket of this.sockets.sockets.values()) {
  360. socket._onclose("server shutting down");
  361. }
  362. this.engine.close();
  363. if (this.httpServer) {
  364. this.httpServer.close(fn);
  365. }
  366. else {
  367. fn && fn();
  368. }
  369. }
  370. /**
  371. * Sets up namespace middleware.
  372. *
  373. * @return self
  374. * @public
  375. */
  376. use(fn) {
  377. this.sockets.use(fn);
  378. return this;
  379. }
  380. /**
  381. * Targets a room when emitting.
  382. *
  383. * @param room
  384. * @return self
  385. * @public
  386. */
  387. to(room) {
  388. return this.sockets.to(room);
  389. }
  390. /**
  391. * Targets a room when emitting.
  392. *
  393. * @param room
  394. * @return self
  395. * @public
  396. */
  397. in(room) {
  398. return this.sockets.in(room);
  399. }
  400. /**
  401. * Excludes a room when emitting.
  402. *
  403. * @param name
  404. * @return self
  405. * @public
  406. */
  407. except(name) {
  408. return this.sockets.except(name);
  409. }
  410. /**
  411. * Sends a `message` event to all clients.
  412. *
  413. * @return self
  414. * @public
  415. */
  416. send(...args) {
  417. this.sockets.emit("message", ...args);
  418. return this;
  419. }
  420. /**
  421. * Sends a `message` event to all clients.
  422. *
  423. * @return self
  424. * @public
  425. */
  426. write(...args) {
  427. this.sockets.emit("message", ...args);
  428. return this;
  429. }
  430. /**
  431. * Emit a packet to other Socket.IO servers
  432. *
  433. * @param ev - the event name
  434. * @param args - an array of arguments, which may include an acknowledgement callback at the end
  435. * @public
  436. */
  437. serverSideEmit(ev, ...args) {
  438. return this.sockets.serverSideEmit(ev, ...args);
  439. }
  440. /**
  441. * Gets a list of socket ids.
  442. *
  443. * @public
  444. */
  445. allSockets() {
  446. return this.sockets.allSockets();
  447. }
  448. /**
  449. * Sets the compress flag.
  450. *
  451. * @param compress - if `true`, compresses the sending data
  452. * @return self
  453. * @public
  454. */
  455. compress(compress) {
  456. return this.sockets.compress(compress);
  457. }
  458. /**
  459. * Sets a modifier for a subsequent event emission that the event data may be lost if the client is not ready to
  460. * receive messages (because of network slowness or other issues, or because they’re connected through long polling
  461. * and is in the middle of a request-response cycle).
  462. *
  463. * @return self
  464. * @public
  465. */
  466. get volatile() {
  467. return this.sockets.volatile;
  468. }
  469. /**
  470. * Sets a modifier for a subsequent event emission that the event data will only be broadcast to the current node.
  471. *
  472. * @return self
  473. * @public
  474. */
  475. get local() {
  476. return this.sockets.local;
  477. }
  478. /**
  479. * Returns the matching socket instances
  480. *
  481. * @public
  482. */
  483. fetchSockets() {
  484. return this.sockets.fetchSockets();
  485. }
  486. /**
  487. * Makes the matching socket instances join the specified rooms
  488. *
  489. * @param room
  490. * @public
  491. */
  492. socketsJoin(room) {
  493. return this.sockets.socketsJoin(room);
  494. }
  495. /**
  496. * Makes the matching socket instances leave the specified rooms
  497. *
  498. * @param room
  499. * @public
  500. */
  501. socketsLeave(room) {
  502. return this.sockets.socketsLeave(room);
  503. }
  504. /**
  505. * Makes the matching socket instances disconnect
  506. *
  507. * @param close - whether to close the underlying connection
  508. * @public
  509. */
  510. disconnectSockets(close = false) {
  511. return this.sockets.disconnectSockets(close);
  512. }
  513. }
  514. exports.Server = Server;
  515. /**
  516. * Expose main namespace (/).
  517. */
  518. const emitterMethods = Object.keys(events_1.EventEmitter.prototype).filter(function (key) {
  519. return typeof events_1.EventEmitter.prototype[key] === "function";
  520. });
  521. emitterMethods.forEach(function (fn) {
  522. Server.prototype[fn] = function () {
  523. return this.sockets[fn].apply(this.sockets, arguments);
  524. };
  525. });
  526. module.exports = (srv, opts) => new Server(srv, opts);
  527. module.exports.Server = Server;
  528. module.exports.Namespace = namespace_1.Namespace;
  529. module.exports.Socket = socket_1.Socket;