Skip to content

Commit

Permalink
fix(add_sqlite3_for_persistent_storage): decoupled frontend and backe…
Browse files Browse the repository at this point in the history
…nd with regards to the playlist, so playlist runs in the node-server and emits messages to the frontend when the playlist changes
  • Loading branch information
caleyg committed Apr 22, 2023
1 parent 43ef131 commit c1c49db
Show file tree
Hide file tree
Showing 9 changed files with 381 additions and 155 deletions.
145 changes: 145 additions & 0 deletions app/playlist.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
const _ = require("lodash");
const {discoveries} = require("./discovery");
const {getPlaylistFromDB} = require("../db/controllers/playlist");

const WebSocket = require('ws');
const http = require('http');
const {
v4: uuidv4,
} = require('uuid');

const playlist = {};
exports.playlist = playlist;

let currentPlaylist = []
let currentPlaylistData = []
let pixelBlazeData = []
let pixelBlazeIds = []
let playlistTimeout = null
let playlistLoopTimeout = null
let initInterval = null
init = () => {
getPlaylistFromDB()
.then((data) => {
currentPlaylist = [] // resetting current play so it doesn't grow to infinity
currentPlaylist.push(...data) // adding new playlist items to list
if (JSON.stringify(currentPlaylist) !== JSON.stringify(currentPlaylistData)) {
currentPlaylistData = []
currentPlaylistData.push(...data)
}
})
.catch('there was an error gathering playlist details')

// gather pixelblaze data
pixelBlazeData = _.map(discoveries, function (v, k) {
let res = _.pick(v, ['lastSeen', 'address']);
_.assign(res, v.controller.props);
return res;
})
pixelBlazeIds = _.map(pixelBlazeData, 'id')
}

initInterval = setInterval(init ,100)

const server = http.createServer();
const port = 1890;
const playlistServer = new WebSocket.Server({server});
server.listen(port, () => {
console.log(`Playlist server is running on port ${port}`);
});

const playlistClients = {};

playlistServer.on('connection', (connection) => {
// Generate a unique code for every user
const clientId = uuidv4()
console.log(`Recieved a new connection.`);

// Store the new connection and handle messages
playlistClients[clientId] = connection;
console.log(`${clientId} connected.`);
connection.on('message', async (data) => {
let message
try {
message = JSON.parse(data);
} catch (err) {
sendError(playlistServer, `Wrong format ${err}`)
return
}
if (message.type === 'LAUNCH_PLAYLIST_NOW') {
console.log('received launch playlist now message!')
await runPlaylistLoopNow()
}
})
});

const sendError = (ws, message) => {
const messageObject = {
type: 'ERROR',
payload: message,
};
ws.send(JSON.stringify(messageObject));
};
const broadcastMessage = (json) => {
const data = JSON.stringify(json);
for(let userId in playlistClients) {
let playlistClient = playlistClients[userId];
if(playlistClient.readyState === WebSocket.OPEN) {
playlistClient.send(data);
}
};
};
const sendPattern = (pattern) => {
const name = pattern.name
_.each(pixelBlazeIds, async id => {
id = String(id);
let controller = discoveries[id] && discoveries[id].controller;
if (controller) {
const command = {
programName: pattern.name
}
await controller.setCommand(command);
}
})
let message = {
currentRunningPattern: name,
currentPlaylist: currentPlaylist
}
broadcastMessage(message)
}

const delaySendPattern = (pattern) => {
return new Promise((resolve) => {
resolve(sendPattern(pattern))
})
}
const iterateOnPlaylist = async () => {
for (let index = 0; index < currentPlaylist.length; index++) {
const pattern = currentPlaylist[index]
await delaySendPattern(pattern)
await new Promise(resolve => {
playlistTimeout = setTimeout(resolve, pattern.duration * 1000)
});
}
}
module.exports.playlistLoop = async () => {
while (true) {
await new Promise(resolve => {
playlistLoopTimeout = setTimeout(resolve, 100)
});
if(pixelBlazeIds.length) {
await iterateOnPlaylist()
}
initInterval = null
playlistTimeout = null
playlistLoopTimeout = null
}
}
const runPlaylistLoopNow = async () => {
clearInterval(initInterval)
clearInterval(playlistTimeout)
clearInterval(playlistLoopTimeout)

await this.playlistLoop()
}
this.playlistLoop()
4 changes: 2 additions & 2 deletions db/api/router.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@

const playlistDbRoutes = require('../controllers/playlist-controllers')
const playlistDbRoutes = require('../controllers/playlist')

// Create router
module.exports = function (app) {
app.get('/playlist/getPatterns', playlistDbRoutes.getAllPlaylistPatterns)
app.post('/playlist/addPattern', playlistDbRoutes.addPatternToPlaylist)
app.put('/playlist/removePattern', playlistDbRoutes.removePatternToPlaylist)
app.put('/playlist/removePattern', playlistDbRoutes.removePatternFromPlaylist)
app.put('/playlist/newPlaylist', playlistDbRoutes.newPlaylist)
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
const knex = require('../db')
const _ = require("lodash");
const playlist_table = 'playlist'

exports.getAllPlaylistPatterns = async (req, res) => {
knex
exports.doesPatternExistInPlaylist = async (req) => {
return await knex
.select('*')
.from(playlist_table)
.where('name', "=", req.body.name)
.then((res) => {
if (res.length === 0) return false
if (res.length !== 0) return true
})
}
exports.getPlaylistFromDB = async () => {
return await knex
.select('*')
.from('playlist')
.then(playlistData => {
.from(playlist_table)
.then((data) => {
return data
})
}
exports.getAllPlaylistPatterns = async (req, res) => {
this.getPlaylistFromDB().then(playlistData => {
res.status(200)
.json(playlistData);
})
Expand All @@ -15,21 +32,17 @@ exports.getAllPlaylistPatterns = async (req, res) => {
}

exports.addPatternToPlaylist = async (req, res) => {
const doesPatternExistInPlaylist = await knex
.select('*')
.from('playlist')
.where('name', "=", req.body.name)
.then((res) => {
if(res.length === 0) return false
if(res.length !== 0) return true
const doesPatternExistInPlaylist = await this.doesPatternExistInPlaylist(req)
.then((condition) => {
return condition
})
// update existing pattern in playlist
if(doesPatternExistInPlaylist) {
knex
await knex
.update({
duration: req.body.duration,
})
.into('playlist')
.into(playlist_table)
.where(
'name', '=', req.body.name
)
Expand All @@ -42,12 +55,12 @@ exports.addPatternToPlaylist = async (req, res) => {
}
// insert new pattern into playlist
if(!doesPatternExistInPlaylist) {
knex
await knex
.insert({
name: req.body.name,
duration: req.body.duration,
})
.into('playlist')
.into(playlist_table)
.then(() => {
res.status(200)
.json({message: `Pattern \'${req.body.name}\' with a duration of ${req.body.duration} created.`})
Expand All @@ -59,9 +72,9 @@ exports.addPatternToPlaylist = async (req, res) => {
}
}

exports.removePatternToPlaylist = async (req, res) => {
knex
.into('playlist')
exports.removePatternFromPlaylist = async (req, res) => {
await knex
.into(playlist_table)
.where('name', req.body.name)
.del()
.then( () => {
Expand All @@ -78,15 +91,27 @@ exports.removePatternToPlaylist = async (req, res) => {
}

exports.newPlaylist = async (req, res) => {
await knex
.into('playlist')
.where('id','!=', 'null')
.del()
await knex.transaction(async trx => {
//clear table first
await knex
.into(playlist_table)
.where('id','!=', 'null')
.del()
.transacting(trx);
// insert new pattern
await knex
.insert({
name: req.body.name,
duration: req.body.duration,
})
.into(playlist_table)
.transacting(trx);
})
.then( () => {
res.status(200)
.json({ message: `Creating a new playlist with pattern '${req.body.name}' from playlist.`});
}
)
res.status(200)
.json({ message: `Creating a new playlist with pattern '${req.body.name}' from playlist.`});
}
)
.catch(err => {
res.status(500)
.json({
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"react-dom": "^16.13.1",
"react-scripts": "^3.4.1",
"sqlite3": "^5.1.6",
"uuid": "^9.0.0",
"ws": "^7.4.6"
},
"scripts": {
Expand Down
3 changes: 2 additions & 1 deletion server.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const app = express()
const bodyParser = require('body-parser');
const compression = require('compression');
const repl = require('repl');

require("./app/playlist");
discovery.start({
host: '0.0.0.0',
port: 1889
Expand All @@ -26,6 +26,7 @@ app.listen(PORT)


const r = repl.start('> ');

r.on('exit', () => {
console.log('Received "exit" event from repl!');
process.exit();
Expand Down
Loading

0 comments on commit c1c49db

Please sign in to comment.