Skip to content

Commit 476ee48

Browse files
committed
fix(add_sqlite3_for_persistent_storage): decoupled frontend and backend with regards to the playlist, so playlist runs in the node-server and emits messages to the frontend when the playlist changes
1 parent 43ef131 commit 476ee48

File tree

10 files changed

+386
-156
lines changed

10 files changed

+386
-156
lines changed

app/discovery.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ module.exports.start = function (options) {
3636

3737
server.on('listening', function () {
3838
var address = server.address();
39-
console.log('Pixelblaze Discovery Server listening on ' + address.address + ": " + address.port);
39+
console.log('Pixelblaze Discovery Server listening on ' + address.address + ":" + address.port);
4040
});
4141

4242
server.on('message', function (message, remote) {

app/playlist.js

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
const _ = require("lodash");
2+
const {discoveries} = require("./discovery");
3+
const {getPlaylistFromDB} = require("../db/controllers/playlist");
4+
5+
const WebSocket = require('ws');
6+
const http = require('http');
7+
const {
8+
v4: uuidv4,
9+
} = require('uuid');
10+
11+
const playlist = {};
12+
exports.playlist = playlist;
13+
14+
let currentPlaylist = []
15+
let currentPlaylistData = []
16+
let pixelBlazeData = []
17+
let pixelBlazeIds = []
18+
let playlistTimeout = null
19+
let playlistLoopTimeout = null
20+
let initInterval = null
21+
init = () => {
22+
getPlaylistFromDB()
23+
.then((data) => {
24+
try {
25+
currentPlaylist = [] // resetting current play so it doesn't grow to infinity
26+
currentPlaylist.push(...data) // adding new playlist items to list
27+
if (JSON.stringify(currentPlaylist) !== JSON.stringify(currentPlaylistData)) {
28+
currentPlaylistData = []
29+
currentPlaylistData.push(...data)
30+
}
31+
} catch (err) {
32+
console.warn(`Error: ${err}`)
33+
}
34+
})
35+
.catch('there was an error gathering playlist details')
36+
37+
// gather pixelblaze data
38+
pixelBlazeData = _.map(discoveries, function (v, k) {
39+
let res = _.pick(v, ['lastSeen', 'address']);
40+
_.assign(res, v.controller.props);
41+
return res;
42+
})
43+
pixelBlazeIds = _.map(pixelBlazeData, 'id')
44+
}
45+
46+
initInterval = setInterval(init ,100)
47+
48+
const server = http.createServer();
49+
const address = '0.0.0.0'
50+
const port = 1890;
51+
const playlistServer = new WebSocket.Server({host: address , port: port});
52+
console.log(`Playlist server is running on ${address}:${port}`)
53+
54+
const playlistClients = {};
55+
56+
playlistServer.on('connection', (connection) => {
57+
// Generate a unique code for every user
58+
const clientId = uuidv4()
59+
console.log(`Recieved a new connection.`);
60+
61+
// Store the new connection and handle messages
62+
playlistClients[clientId] = connection;
63+
console.log(`${clientId} connected.`);
64+
connection.on('message', async (data) => {
65+
let message
66+
try {
67+
message = JSON.parse(data);
68+
} catch (err) {
69+
sendError(playlistServer, `Wrong format ${err}`)
70+
return
71+
}
72+
if (message.type === 'LAUNCH_PLAYLIST_NOW') {
73+
console.log('received launch playlist now message!')
74+
await runPlaylistLoopNow()
75+
}
76+
})
77+
});
78+
79+
const sendError = (ws, message) => {
80+
const messageObject = {
81+
type: 'ERROR',
82+
payload: message,
83+
};
84+
ws.send(JSON.stringify(messageObject));
85+
};
86+
const broadcastMessage = (json) => {
87+
const data = JSON.stringify(json);
88+
for(let userId in playlistClients) {
89+
let playlistClient = playlistClients[userId];
90+
if(playlistClient.readyState === WebSocket.OPEN) {
91+
playlistClient.send(data);
92+
}
93+
};
94+
};
95+
const sendPattern = (pattern) => {
96+
const name = pattern.name
97+
_.each(pixelBlazeIds, async id => {
98+
id = String(id);
99+
let controller = discoveries[id] && discoveries[id].controller;
100+
if (controller) {
101+
const command = {
102+
programName: pattern.name
103+
}
104+
await controller.setCommand(command);
105+
}
106+
})
107+
let message = {
108+
currentRunningPattern: name,
109+
currentPlaylist: currentPlaylist
110+
}
111+
broadcastMessage(message)
112+
}
113+
114+
const delaySendPattern = (pattern) => {
115+
return new Promise((resolve) => {
116+
resolve(sendPattern(pattern))
117+
})
118+
}
119+
const iterateOnPlaylist = async () => {
120+
for (let index = 0; index < currentPlaylist.length; index++) {
121+
const pattern = currentPlaylist[index]
122+
await delaySendPattern(pattern)
123+
await new Promise(resolve => {
124+
playlistTimeout = setTimeout(resolve, pattern.duration * 1000)
125+
});
126+
}
127+
}
128+
module.exports.playlistLoop = async () => {
129+
while (true) {
130+
await new Promise(resolve => {
131+
playlistLoopTimeout = setTimeout(resolve, 100)
132+
});
133+
if(pixelBlazeIds.length) {
134+
await iterateOnPlaylist()
135+
}
136+
initInterval = null
137+
playlistTimeout = null
138+
playlistLoopTimeout = null
139+
}
140+
}
141+
const runPlaylistLoopNow = async () => {
142+
clearInterval(initInterval)
143+
clearInterval(playlistTimeout)
144+
clearInterval(playlistLoopTimeout)
145+
146+
await this.playlistLoop()
147+
}
148+
this.playlistLoop()

db/api/router.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11

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

44
// Create router
55
module.exports = function (app) {
66
app.get('/playlist/getPatterns', playlistDbRoutes.getAllPlaylistPatterns)
77
app.post('/playlist/addPattern', playlistDbRoutes.addPatternToPlaylist)
8-
app.put('/playlist/removePattern', playlistDbRoutes.removePatternToPlaylist)
8+
app.put('/playlist/removePattern', playlistDbRoutes.removePatternFromPlaylist)
99
app.put('/playlist/newPlaylist', playlistDbRoutes.newPlaylist)
1010
}

db/controllers/playlist-controllers.js renamed to db/controllers/playlist.js

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,30 @@
11
const knex = require('../db')
2+
const _ = require("lodash");
3+
const playlist_table = 'playlist'
24

3-
exports.getAllPlaylistPatterns = async (req, res) => {
4-
knex
5+
exports.doesPatternExistInPlaylist = async (req) => {
6+
return await knex
57
.select('*')
6-
.from('playlist')
7-
.then(playlistData => {
8+
.from(playlist_table)
9+
.where('name', "=", req.body.name)
10+
.then((res) => {
11+
if (res.length === 0) return false
12+
if (res.length !== 0) return true
13+
})
14+
}
15+
exports.getPlaylistFromDB = async () => {
16+
return await knex
17+
.select('*')
18+
.from(playlist_table)
19+
.then((data) => {
20+
return data
21+
})
22+
.catch(err => {
23+
console.log(`There was an error retrieving playlist items: ${err}`)
24+
})
25+
}
26+
exports.getAllPlaylistPatterns = async (req, res) => {
27+
this.getPlaylistFromDB().then(playlistData => {
828
res.status(200)
929
.json(playlistData);
1030
})
@@ -15,21 +35,17 @@ exports.getAllPlaylistPatterns = async (req, res) => {
1535
}
1636

1737
exports.addPatternToPlaylist = async (req, res) => {
18-
const doesPatternExistInPlaylist = await knex
19-
.select('*')
20-
.from('playlist')
21-
.where('name', "=", req.body.name)
22-
.then((res) => {
23-
if(res.length === 0) return false
24-
if(res.length !== 0) return true
38+
const doesPatternExistInPlaylist = await this.doesPatternExistInPlaylist(req)
39+
.then((condition) => {
40+
return condition
2541
})
2642
// update existing pattern in playlist
2743
if(doesPatternExistInPlaylist) {
28-
knex
44+
await knex
2945
.update({
3046
duration: req.body.duration,
3147
})
32-
.into('playlist')
48+
.into(playlist_table)
3349
.where(
3450
'name', '=', req.body.name
3551
)
@@ -42,12 +58,12 @@ exports.addPatternToPlaylist = async (req, res) => {
4258
}
4359
// insert new pattern into playlist
4460
if(!doesPatternExistInPlaylist) {
45-
knex
61+
await knex
4662
.insert({
4763
name: req.body.name,
4864
duration: req.body.duration,
4965
})
50-
.into('playlist')
66+
.into(playlist_table)
5167
.then(() => {
5268
res.status(200)
5369
.json({message: `Pattern \'${req.body.name}\' with a duration of ${req.body.duration} created.`})
@@ -59,9 +75,9 @@ exports.addPatternToPlaylist = async (req, res) => {
5975
}
6076
}
6177

62-
exports.removePatternToPlaylist = async (req, res) => {
63-
knex
64-
.into('playlist')
78+
exports.removePatternFromPlaylist = async (req, res) => {
79+
await knex
80+
.into(playlist_table)
6581
.where('name', req.body.name)
6682
.del()
6783
.then( () => {
@@ -78,15 +94,27 @@ exports.removePatternToPlaylist = async (req, res) => {
7894
}
7995

8096
exports.newPlaylist = async (req, res) => {
81-
await knex
82-
.into('playlist')
83-
.where('id','!=', 'null')
84-
.del()
97+
await knex.transaction(async trx => {
98+
//clear table first
99+
await knex
100+
.into(playlist_table)
101+
.where('id','!=', 'null')
102+
.del()
103+
.transacting(trx);
104+
// insert new pattern
105+
await knex
106+
.insert({
107+
name: req.body.name,
108+
duration: req.body.duration,
109+
})
110+
.into(playlist_table)
111+
.transacting(trx);
112+
})
85113
.then( () => {
86-
res.status(200)
87-
.json({ message: `Creating a new playlist with pattern '${req.body.name}' from playlist.`});
88-
}
89-
)
114+
res.status(200)
115+
.json({ message: `Creating a new playlist with pattern '${req.body.name}' from playlist.`});
116+
}
117+
)
90118
.catch(err => {
91119
res.status(500)
92120
.json({

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"react-dom": "^16.13.1",
1717
"react-scripts": "^3.4.1",
1818
"sqlite3": "^5.1.6",
19+
"uuid": "^9.0.0",
1920
"ws": "^7.4.6"
2021
},
2122
"scripts": {

server.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const app = express()
44
const bodyParser = require('body-parser');
55
const compression = require('compression');
66
const repl = require('repl');
7-
7+
require("./app/playlist");
88
discovery.start({
99
host: '0.0.0.0',
1010
port: 1889
@@ -26,6 +26,7 @@ app.listen(PORT)
2626

2727

2828
const r = repl.start('> ');
29+
2930
r.on('exit', () => {
3031
console.log('Received "exit" event from repl!');
3132
process.exit();

0 commit comments

Comments
 (0)