Commit bd6c0519 authored by Jan Grewe's avatar Jan Grewe
Browse files

use WebSockets to tell frontend about new photos

parent 5be8e0de
Pipeline #4 passed with stage
...@@ -21,22 +21,21 @@ var net = require('net'); ...@@ -21,22 +21,21 @@ var net = require('net');
var dgram = require('dgram'); var dgram = require('dgram');
var fs = require('fs'); var fs = require('fs');
var gm = require('gm'); var gm = require('gm');
/* Express */
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon'); var favicon = require('serve-favicon');
var logger = require('morgan'); var logger = require('morgan');
var cookieParser = require('cookie-parser'); var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser'); var bodyParser = require('body-parser');
var express = require('express');
var app = express();
var server = http.createServer(app);
var io = require('socket.io')(server);
var routes = require('./routes/index'); var routes = require('./routes/index');
var latestPhoto = require('./routes/latest'); var latestPhoto = require('./routes/latest');
var allPhotos = require('./routes/all'); var allPhotos = require('./routes/all');
var app = express();
process.title = 'WiPho'; process.title = 'WiPho';
var gracefulShutdown = function() { var gracefulShutdown = function() {
console.log("Shutting down..."); console.log("Shutting down...");
...@@ -44,7 +43,9 @@ var gracefulShutdown = function() { ...@@ -44,7 +43,9 @@ var gracefulShutdown = function() {
} }
process.on ('SIGTERM', gracefulShutdown); process.on ('SIGTERM', gracefulShutdown);
process.on ('SIGINT', gracefulShutdown); process.on ('SIGINT', gracefulShutdown);
app.set('port', config.httpPort || 3000);
// view engine setup // view engine setup
app.set('views', path.join(__dirname, 'views')); app.set('views', path.join(__dirname, 'views'));
...@@ -95,6 +96,25 @@ app.use(function(err, req, res, next) { ...@@ -95,6 +96,25 @@ app.use(function(err, req, res, next) {
module.exports = app; module.exports = app;
io.on('connection', function (socket) {
//console.log('Display connected!');
socket.on('disconnect', function(){
//console.log('Display disconnected');
});
socket.on('display', function(data) {
if(data.status == 'success') {
console.log('Photo displayed!');
} else {
console.log('Photo not displayed!');
}
});
});
server.listen(app.get('port'), function() {
console.log("WiPho is listening on port " + app.get('port'));
});
/* WiPho */ /* WiPho */
photos = new Array(); photos = new Array();
...@@ -108,227 +128,228 @@ findCard(); ...@@ -108,227 +128,228 @@ findCard();
function downloadPhotos() { function downloadPhotos() {
if(alreadyDownloading == true || downloadList.length < 1) if(alreadyDownloading == true || downloadList.length < 1)
return true; return true;
alreadyDownloading = true; alreadyDownloading = true;
var photo = downloadList.pop(); var photo = downloadList.pop();
var localFile = pathPhotos+'/'+photo; var localFile = pathPhotos+'/'+photo;
var localPreview = pathPreviews+'/'+photo; var localPreview = pathPreviews+'/'+photo;
console.log('['+photo+'] Downloading from http://'+cardAddr+cardPath+'/'+photo); console.log('['+photo+'] Downloading from http://'+cardAddr+cardPath+'/'+photo);
var file = fs.createWriteStream(localFile); var file = fs.createWriteStream(localFile);
file.on('error', function(err) { file.on('error', function(err) {
console.log("FS: "+err); console.log("FS: "+err);
}); });
file.on('finish', function() { file.on('finish', function() {
file.close(); file.close();
alreadyDownloading = false; alreadyDownloading = false;
console.log('['+photo+'] Saved as '+localFile); console.log('['+photo+'] Saved as '+localFile);
gm(localFile).autoOrient().resize(previewWidth, previewHeight).write(localPreview, function (err) { gm(localFile).autoOrient().resize(previewWidth, previewHeight).write(localPreview, function (err) {
if (!err) { if (!err) {
console.log('['+photo+'] Resized to '+previewWidth+'x'+previewHeight); console.log('['+photo+'] Resized to '+previewWidth+'x'+previewHeight);
if(photos.length == 0 || photo != photos[photos.length-1].name) { if(photos.length == 0 || photo != photos[photos.length-1].name) {
photos.push({id: photoIndex, name: photo}); photos.push({id: photoIndex, name: photo});
photoIndex++; photoIndex++;
} io.emit('photo', { path: photo });
}
}else{
console.log('Photo resize error: '+err); }else{
} console.log('Photo resize error: '+err);
}
});
});
if(downloadPrevious == true) {
getPhotoList(); if(downloadPrevious == true) {
} getPhotoList();
}
if(downloadList.length > 0) {
downloadPhotos(); if(downloadList.length > 0) {
}else{ downloadPhotos();
console.log("All photos downloaded, waiting for new ones..."); }else{
} console.log("All photos downloaded, waiting for new ones...");
}
});
});
var options = {
hostname: cardAddr, var options = {
port: 80, hostname: cardAddr,
path: cardPath+'/'+photo, port: 80,
method: 'GET' path: cardPath+'/'+photo,
}; method: 'GET'
};
var request = http.get(options, function(response) {
response.pipe(file); var request = http.get(options, function(response) {
}); response.pipe(file);
});
request.on('error', function(e) {
console.log("HTTP Error: " + e.message); request.on('error', function(e) {
}); console.log("HTTP Error: " + e.message);
});
} }
function getPhotoList() { function getPhotoList() {
downloadPrevious = false; downloadPrevious = false;
var options = { var options = {
host: cardAddr, host: cardAddr,
port: 80, port: 80,
path: '/cgi-bin/tslist?PATH=/www'+cardPath+'&keepfresh='+Date.now().toString() path: '/cgi-bin/tslist?PATH=/www'+cardPath+'&keepfresh='+Date.now().toString()
}; };
http.get(options, function(resp){ http.get(options, function(resp){
console.log("Getting list of photos on card..."); console.log("Getting list of photos on card...");
resp.on('data', function(data){ resp.on('data', function(data){
var strFiles = data.toString().split(os.EOL)[2]; var strFiles = data.toString().split(os.EOL)[2];
var regex = /FileName\d+=([a-zA-Z0-9_\.]+)&FileType\d+=File&/g; var regex = /FileName\d+=([a-zA-Z0-9_\.]+)&FileType\d+=File&/g;
var arrPhotos = new Array(); var arrPhotos = new Array();
while (match = regex.exec(strFiles)) { while (match = regex.exec(strFiles)) {
arrPhotos.push(match[1]); arrPhotos.push(match[1]);
} }
var i = 0; var i = 0;
arrPhotos.forEach(function(photo) { arrPhotos.forEach(function(photo) {
fs.exists(pathPhotos+'/'+photo, function(exists) { fs.exists(pathPhotos+'/'+photo, function(exists) {
if (exists) { if (exists) {
//console.log('['+photo+'] Photo '+photo+' already downloaded!'); //console.log('['+photo+'] Photo '+photo+' already downloaded!');
}else{ }else{
console.log('['+photo+'] Photo '+photo+' not downloaded yet, adding to download list!'); console.log('['+photo+'] Photo '+photo+' not downloaded yet, adding to download list!');
downloadList.push(photo); downloadList.push(photo);
} }
i++; i++;
if(i == arrPhotos.length-1) { if(i == arrPhotos.length-1) {
if(downloadList.length > 0) { if(downloadList.length > 0) {
downloadPhotos(); downloadPhotos();
}else{ }else{
console.log("All photos already downloaded!"); console.log("All photos already downloaded!");
} }
} }
}); });
}); });
}); });
}).on("error", function(e){ }).on("error", function(e){
console.log("Error getting photo list: " + e.message); console.log("Error getting photo list: " + e.message);
getPhotoList(); getPhotoList();
}); });
} }
function enableShootAndView(ip) { function enableShootAndView(ip) {
var client = net.connect({port: 5566, host: ip}, function() { var client = net.connect({port: 5566, host: ip}, function() {
console.log('Enabling Shoot & View...'); console.log('Enabling Shoot & View...');
}); });
client.on('connect', function() { client.on('connect', function() {
console.log('Shoot & View enabled, waiting for photos...'); console.log('Shoot & View enabled, waiting for photos...');
if(cardPath != null) { if(cardPath != null) {
getPhotoList(); getPhotoList();
} }
}); });
client.on('error', function(err) { client.on('error', function(err) {
console.log('Shoot & View error: '+err); console.log('Shoot & View error: '+err);
findCard(); findCard();
}); });
client.on('data', function(data) { client.on('data', function(data) {
var path = data.toString().substr(5).replace(/\0/g, ''); var path = data.toString().substr(5).replace(/\0/g, '');
var photo = path.split('/').pop(); var photo = path.split('/').pop();
cardPath = path.substring(0, path.lastIndexOf('/')); cardPath = path.substring(0, path.lastIndexOf('/'));
downloadList.push(photo); downloadList.push(photo);
downloadPhotos(); downloadPhotos();
}); });
client.on('end', function() { client.on('end', function() {
console.log('Shoot & View stopped!'); console.log('Shoot & View stopped!');
}); });
} }
function pingCard(ip) { function pingCard(ip) {
req = http.get('http://'+ip+'/', function(res) { req = http.get('http://'+ip+'/', function(res) {
//console.log('Card is alive!'); //console.log('Card is alive!');
req.destroy(); req.destroy();
}); });
req.on('error', function(err) { req.on('error', function(err) {
cardFound = false; cardFound = false;
console.log('ERROR: ' + err); console.log('ERROR: ' + err);
req.destroy(); req.destroy();
clearInterval(itvPing); clearInterval(itvPing);
findCard(); findCard();
}); });
req.setTimeout(5000, function() { req.setTimeout(5000, function() {
cardFound = false; cardFound = false;
downloadPrevious = true; downloadPrevious = true;
console.log('Card has disappeared!'); console.log('Card has disappeared!');
req.destroy(); req.destroy();
clearInterval(itvPing); clearInterval(itvPing);
findCard(); findCard();
}); });
} }
function findCard() { function findCard() {
if(alreadySearching == true) if(alreadySearching == true)
return; return;
else else
alreadySearching = true; alreadySearching = true;
console.log("Searching for card..."); console.log("Searching for card...");
var socket = dgram.createSocket('udp4'); var socket = dgram.createSocket('udp4');
var message = new Buffer('dummy'); var message = new Buffer('dummy');
var itvSearch; var itvSearch;
socket.bind(58255, function() { socket.bind(58255, function() {
socket.setBroadcast(true); socket.setBroadcast(true);
}); });
socket.on('error', function (err) { socket.on('error', function (err) {
console.log("socket error:\n" + err.stack); console.log("socket error:\n" + err.stack);
socket.close(); socket.close();
findCard(); findCard();
}); });
socket.on('message', function (msg, rinfo) { socket.on('message', function (msg, rinfo) {
clearInterval(itvSearch); clearInterval(itvSearch);
socket.close(); socket.close();
msg = msg.toString(); msg = msg.toString();
cardAddr = msg.match(/ip=(.*)/)[1]; cardAddr = msg.match(/ip=(.*)/)[1];
cardFound = true; cardFound = true;
console.log("Found card on "+cardAddr); console.log("Found card on "+cardAddr);
enableShootAndView(cardAddr); enableShootAndView(cardAddr);
itvPing = setInterval(function() { itvPing = setInterval(function() {
pingCard(cardAddr); pingCard(cardAddr);
}, 5000); }, 5000);
alreadySearching = false; alreadySearching = false;
}); });
socket.on('listening', function () { socket.on('listening', function () {
var address = socket.address(); var address = socket.address();
sendSearch(); sendSearch();
itvSearch = setInterval(function() { itvSearch = setInterval(function() {
sendSearch(); sendSearch();
}, 2000); }, 2000);
function sendSearch() { function sendSearch() {
socket.send(message, 0, message.length, 55777, cardAddr, function(err, bytes) { socket.send(message, 0, message.length, 55777, cardAddr, function(err, bytes) {
if(err != null) if(err != null)
console.log("socket error:\n" + err.stack); console.log("socket error:\n" + err.stack);
}); });
} }
}); });
} }
\ No newline at end of file
#!/usr/bin/env node
var config = require('../config.json');
var debug = require('debug')('foo');
var app = require('../app');
app.set('port', config.httpPort || 3000);
var server = app.listen(app.get('port'), function() {
console.log("Express server listening on port " + app.get('port'));
});
...@@ -3,17 +3,18 @@ ...@@ -3,17 +3,18 @@
"version": "0.0.1", "version": "0.0.1",
"private": true, "private": true,
"scripts": { "scripts": {
"start": "node ./bin/www", "start": "node app.js",
"stop": "pkill --signal SIGINT WiPho" "stop": "pkill --signal SIGINT WiPho"
}, },
"dependencies": { "dependencies": {
"express": "~4.9.0", "body-parser": "^1.12.0",
"body-parser": "~1.8.1",
"cookie-parser": "~1.3.3", "cookie-parser": "~1.3.3",
"morgan": "~1.3.0", "debug": "^0.7.0",
"serve-favicon": "~2.1.3", "express": "~4.12.2",
"debug": "~2.0.0", "gm": "^1.17.0",
"jade": "~1.6.0", "jade": "^1.9.2",
"gm": "~1.16.0" "morgan": "^1.5.1",
"serve-favicon": "^2.2.0",
"socket.io": "^1.3.5"
} }
} }
var socket = io.connect();
$(document).ready(function() { $(document).ready(function() {
$('body').height($(window).height()); $('body').height($(window).height());
centerImage(); centerImage();
getLatest();
setInterval(function() {
getLatest();
}, 1000);
$(window).resize(function () { $(window).resize(function () {
centerImage(); centerImage();
}); });
...@@ -22,18 +20,15 @@ $(document).ready(function() { ...@@ -22,18 +20,15 @@ $(document).ready(function() {
centerImage(); centerImage();
$(this).animate({opacity: 1}, 400); $(this).animate({opacity: 1}, 400);
}); });
});
function getLatest() { socket.on('photo', function (data) {
$.getJSON('/latest', function(data) { $('#latest').animate({opacity: 0}, 400, function() {
if('/previews/'+data.name != $('#latest').attr('src')) { $(this).attr('src', '/previews/'+data.path);
$('#latest').animate({opacity: 0}, 400, function() { socket.emit('display', {status: 'success'});
$(this).attr('src', '/previews/'+data.name); });
});
}
}); });
}
});
function centerImage() { function centerImage() {
$('#latest').css({ $('#latest').css({
...@@ -41,4 +36,4 @@ function centerImage() { ...@@ -41,4 +36,4 @@ function centerImage() {
left: ($(window).width() - $('#latest').outerWidth()) / 2, left: ($(window).width() - $('#latest').outerWidth()) / 2,
top: ($(window).height() - $('#latest').outerHeight()) / 2, top: ($(window).height() - $('#latest').outerHeight()) / 2,
}); });
} }
\ No newline at end of file
var config = require('../config.json');