123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- var fs = require("fs");
- var http = require("http");
- var crypto = require("crypto");
- var pathlib = require("path");
- var urllib = require("url");
-
- var conf = JSON.parse(fs.readFileSync("conf.json"));
- var index = fs.readFileSync("index.html", "utf-8")
- .replace(/<<transition_time>>/g, conf.transition_time);
-
- function error(res, err) {
- console.trace(err);
- res.end(err.toString());
- }
-
- function mimetype(path) {
- var ext = pathlib.extname(path)
- .substring(1)
- .toLowerCase();
-
- switch (ext) {
-
- case "html":
- case "xml":
- return "text/"+ext;
-
- case "png":
- case "jpg":
- case "jpeg":
- case "gif":
- return "image/"+ext;
-
- case "svg":
- return "image/svg+xml";
-
- case "mov":
- case "mp4":
- case "ogv":
- case "webm":
- return "video/"+ext;
-
- case "mp3":
- case "ogg":
- case "flac":
- case "m4a":
- return "audio/"+ext;
-
- default:
- return "application/octet-stream";
- }
- }
-
- function sendfile(res, path) {
- res.writeHead(200, {
- "content-type": mimetype(path)
- });
-
- fs.createReadStream(path)
- .on("error", err => error(res, err))
- .pipe(res);
- }
-
- // The individual slide
- function Slide(dir) {
- var self = {};
-
- self.dir = dir;
- self.name = pathlib.parse(dir).name;
-
- self.serveSlide = function(parts, res) {
- sendfile(res, pathlib.join(dir, "index.html"));
- }
-
- self.serveFiles = function(parts, res) {
-
- // Redirect to / if /{name} is requested
- if (parts.pathname.replace(/\//g, "") === self.name) {
- res.writeHead(302, { location: "/" });
- return res.end();
- }
-
- var name = parts.pathname.substring(1).replace(self.name, "");
- sendfile(res, pathlib.join(dir, name));
- }
-
- self.dirExists = function() {
- try {
- fs.accessSync(dir, fs.F_OK);
- return true;
- } catch (err) {
- return false;
- }
- }
-
- return self;
- }
-
- // The slideshow, whose job it is to manage all slides
- // and tell the client whether it has to update or not
- function Slideshow(dir, changeInterval) {
- var self = {};
-
- var currentSlide = null;
- var awaiters = [];
- var slides = [];
-
- self.sendEvent = function(evt, args) {
- var str = JSON.stringify({ evt: evt, args: args });
- awaiters.forEach(res => res.end(str));
- awaiters = [];
- }
-
- self.serve = function(req, res) {
- var parts = urllib.parse(req.url);
-
- // /: Send the base site to the client
- if (parts.pathname === "/") {
- res.end(index);
-
- // /init: send initial information about current slide
- } else if (parts.pathname === "/init") {
- res.end(currentSlide ? currentSlide.name : "");
-
- // /await: long polling, request won't end before a new slide comes
- } else if (parts.pathname === "/await") {
- awaiters.push(res);
-
- // /slide: serve the current slide's html
- } else if (parts.pathname === "/slide" && currentSlide) {
- currentSlide.serveSlide(parts, res);
-
- // Serve other files
- } else {
- var served = false;
-
- for (var slide of slides) {
-
- // If client requests /{slide-name}/*
- if (slide.name === parts.pathname.substr(1, slide.name.length)) {
- slide.serveFiles(parts, res);
- served = true;
- break;
- }
- }
-
- if (!served) {
- res.writeHead(404);
- res.end("404");
- }
- }
- }
-
- // This function starts the slideshow and goes through the slides
- // one by one. When done, it starts again by calling this function again.
- function init() {
- slides = fs.readdirSync(dir)
- .sort()
- .map(file => Slide(pathlib.join(dir, file)));
-
- var slideIndex = 0;
- currentSlide = slides[slideIndex];
-
- var interval = setInterval(() => {
- slideIndex += 1;
-
- // Go to the next slide, or restart
- if ((slideIndex >= slides.length)
- || (!slides[slideIndex].dirExists())) {
- clearInterval(interval);
- init();
- } else {
- currentSlide = slides[slideIndex];
- }
-
- // End all awaiting connections to notify slide change
- self.sendEvent("next", { name: currentSlide.name });
- }, changeInterval);
- }
- init();
-
- return self;
- }
-
- var slideshow = Slideshow(conf.slides, conf.interval);
-
- function onexit() {
- slideshow.sendEvent("reload");
- process.exit();
- }
- process.on("exit", onexit);
- process.on("SIGINT", onexit);
- process.on("SIGTERM", onexit);
-
- var server = http.createServer((req, res) => {
- slideshow.serve(req, res);
- });
- server.on("error", err => {
- console.error(err.toString());
- system.exit(1);
- });
- server.listen(conf.port);
- console.log("Server running on port "+conf.port+".");
|