|
|
@@ -13,33 +13,74 @@ function error(res, 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; |
|
|
|
|
|
|
|
function serve(parts, res) { |
|
|
|
if (parts.pathname === "/slide") { |
|
|
|
fs.createReadStream(pathlib.join(dir, "index.html")) |
|
|
|
.on("error", err => error(res, err)) |
|
|
|
.pipe(res); |
|
|
|
} else { |
|
|
|
fs.createReadStream(pathlib.join(dir, parts.pathname)) |
|
|
|
.on("error", err => error(res, err)) |
|
|
|
.pipe(res); |
|
|
|
} |
|
|
|
self.serveSlide = function(parts, res) { |
|
|
|
sendfile(res, pathlib.join(dir, "index.html")); |
|
|
|
} |
|
|
|
|
|
|
|
self.serve = function(parts, res) { |
|
|
|
try { |
|
|
|
serve(parts, res); |
|
|
|
} catch (err) { |
|
|
|
if (err.code && err.code === "ENOENT") |
|
|
|
res.writeHead(404); |
|
|
|
self.serveFiles = function(parts, res) { |
|
|
|
|
|
|
|
error(res, err); |
|
|
|
// 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)); |
|
|
|
} |
|
|
|
|
|
|
|
return self; |
|
|
@@ -52,6 +93,14 @@ function Slideshow(dir, changeInterval) { |
|
|
|
|
|
|
|
var currentSlide = null; |
|
|
|
var awaiters = []; |
|
|
|
var slides = []; |
|
|
|
|
|
|
|
self.sendEvent = function(evt, args) { |
|
|
|
awaiters.forEach(res => res.end(JSON.stringify({ |
|
|
|
evt: evt, |
|
|
|
args: args |
|
|
|
}))); |
|
|
|
} |
|
|
|
|
|
|
|
self.serve = function(req, res) { |
|
|
|
var parts = urllib.parse(req.url); |
|
|
@@ -60,24 +109,43 @@ function Slideshow(dir, changeInterval) { |
|
|
|
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); |
|
|
|
|
|
|
|
// There's a current slide: leave serving files up to the slide |
|
|
|
} else if (currentSlide) { |
|
|
|
currentSlide.serve(parts, res); |
|
|
|
// /slide: serve the current slide's html |
|
|
|
} else if (parts.pathname === "/slide" && currentSlide) { |
|
|
|
currentSlide.serveSlide(parts, res); |
|
|
|
|
|
|
|
// There's no current slide show |
|
|
|
// Serve other files |
|
|
|
} else { |
|
|
|
res.end("No current slideshow."); |
|
|
|
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() { |
|
|
|
var slides = fs.readdirSync(dir) |
|
|
|
slides = fs.readdirSync(dir) |
|
|
|
.sort() |
|
|
|
.map(file => Slide(pathlib.join(dir, file))); |
|
|
|
|
|
|
@@ -96,7 +164,7 @@ function Slideshow(dir, changeInterval) { |
|
|
|
} |
|
|
|
|
|
|
|
// End all awaiting connections to notify slide change |
|
|
|
awaiters.forEach(res => res.end()); |
|
|
|
self.sendEvent("next", { name: currentSlide.name }); |
|
|
|
}, changeInterval); |
|
|
|
} |
|
|
|
init(); |
|
|
@@ -106,6 +174,20 @@ function Slideshow(dir, changeInterval) { |
|
|
|
|
|
|
|
var slideshow = Slideshow(conf.slides, conf.interval); |
|
|
|
|
|
|
|
http.createServer((req, res) => { |
|
|
|
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); |
|
|
|
}).listen(conf.port); |
|
|
|
}); |
|
|
|
server.on("error", err => { |
|
|
|
console.error(err.toString()); |
|
|
|
system.exit(1); |
|
|
|
}); |
|
|
|
server.listen(conf.port); |
|
|
|
console.log("Server running on port "+conf.port+"."); |