diff --git a/app/src/App.vue b/app/src/App.vue index 4dbccf1..13ccf6d 100644 --- a/app/src/App.vue +++ b/app/src/App.vue @@ -49,8 +49,8 @@ export default { }, methods: { handleMessage(message) { + console.log(message); if (!(this.lyrics === message)) { - console.log(message); this.lyrics = message; } }, @@ -67,7 +67,8 @@ export default { diff --git a/app/src/main.js b/app/src/main.js index f173087..52192e8 100644 --- a/app/src/main.js +++ b/app/src/main.js @@ -5,7 +5,8 @@ import App from './App.vue' Vue.config.productionTip = false Vue.use(VueSSE, { - url: '/lowerthirdsserver', + url: '/stream', + format: 'json' }); new Vue({ diff --git a/server/package.json b/server/package.json index 574b239..9b88873 100644 --- a/server/package.json +++ b/server/package.json @@ -12,7 +12,9 @@ "dependencies": { "axios": "^0.21.1", "body-parser": "^1.19.0", + "compression": "^1.7.4", "express": "^4.17.1", + "express-sse": "^0.5.3", "http-proxy": "^1.18.1", "method-override": "^3.0.0" } diff --git a/server/server.js b/server/server.js index cb350b6..d4e6b51 100644 --- a/server/server.js +++ b/server/server.js @@ -1,14 +1,16 @@ const express = require("express"); +const compression = require('compression'); +const expressSSE = require("express-sse"); const httpProxy = require("http-proxy"); -const apiProxy = httpProxy.createProxyServer(); -const bodyParser = require("body-parser"); const axios = require("axios"); const path = require("path"); const methodOverride = require("method-override"); -const config = require("config.js"); +const config = require("./config.js"); const rcUrl = config.rcApi + "/lyrics"; const lyricUrl = config.lyricsApi + "/lyrics"; +const apiProxy = httpProxy.createProxyServer(); +const sse = new expressSSE(""); let lowerLyrics = ""; let newLyrics = ""; @@ -18,124 +20,100 @@ let stageLyrics = ""; const app = express(); const PORT = process.env.PORT || 3000; -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({extended: true})); -app.use(bodyParser.text()); -app.use(bodyParser.json({type:"application/vnd.api+json"})); +app.use(compression()); +app.use(express.json()); +app.use(express.urlencoded({extended: true})); +app.use(express.text()); +app.use(express.json({type:"application/vnd.api+json"})); app.use(methodOverride("_method")); -app.use(express.static("./app/public")); +// Proxy all non-api requests to the built app +app.use(express.static(path.join(__dirname, '../app/dist'))); +app.get('/', (req, res) => { + res.sendFile(path.join(__dirname, '../app/dist/index.html')); +}); // Reverse Proxy redirect to Remote Control API app.all("/rcApi/*", (req, res) => { - console.log("redirecting to Remote Control API"); - apiProxy.web(req, res, {target: config.rcApi}); + console.log("redirecting to Remote Control API"); + apiProxy.web(req, res, {target: config.rcApi}); }); // Reverse Proxy redirect to Lyrics API app.all("/lyricsApi/*", (req, res) => { - console.log("redirecting to Lyrics API"); - apiProxy.web(req, res, {target: config.lyricsApi}); + console.log("redirecting to Lyrics API"); + apiProxy.web(req, res, {target: config.lyricsApi}); }); -// Quelea RC API GET using Axios -axios.get(rcUrl).then(response => { - console.log("Here be the RC Lyrics " + response.data); -}) -.catch(error => { - console.log(error); -}); - - -// Quelea Lyrics API GET using Axios -// axios.get(lyricUrl).then(res => { -// console.log("Here be the Lyrics " + res.data); -// console.log(lowerLyrics); -// }) -// .catch(error => { -// console.log(error); -// }); - +// Update lyrics by polling every 250ms setInterval( async() => { + // Quelea Lyrics API GET using Axios + await axios.get(lyricUrl).then(res => { + newLyrics = res.data; + if (!(newLyrics === lowerLyrics)) { + lowerLyrics = newLyrics; + sse.updateInit(newLyrics); + sse.send(newLyrics); + } + }) + .catch(error => { + console.log(error); + }); - // Quelea Lyrics API GET using Axios - await axios.get(lyricUrl).then(res => { - // console.log("Here be the Lyrics " + res.data); - newLyrics = res.data; - // console.log(newLyrics); - if (newLyrics === lowerLyrics) { - // console.log("No change is good change"); - } - else { - lowerLyrics = newLyrics; - console.log("Here it is"); - // sendIt(); - // response.write('data:' + lowerLyrics + '\n\n') - } - }) - .catch(error => { - console.log(error); - }); - - // Quelea Lyrics API GET using Axios - await axios.get(rcUrl).then(res => { - // console.log("Here be the Lyrics " + res.data); - rcLyrics = res.data; - rcLyrics = rcLyrics.replace(/(\r\n|\n|\r)/gm," "); - // console.log(newLyrics); - if (rcLyrics === stageLyrics) { - console.log("No change is good change for the stage"); - } - else { - stageLyrics = rcLyrics; - console.log("Here are the stage lyrics"); - console.log(rcLyrics); - } - }) - .catch(error => { - console.log(error); - }); + // Quelea Lyrics API GET using Axios + await axios.get(rcUrl).then(res => { + // console.log("Here be the Lyrics " + res.data); + rcLyrics = res.data; + rcLyrics = rcLyrics.replace(/(\r\n|\n|\r)/gm," "); + // console.log(newLyrics); + if (!(rcLyrics === stageLyrics)) { + stageLyrics = rcLyrics; + } + }) + .catch(error => { + console.log(error); + }); }, 250); -// SSE Connection to the Lower Thirds Lyric Front End -app.get('/lowerthirdsserver', function (request, response) { - response.status(200).set({ - "connection": "keep-alive", - "cache-control": "no-cache", - "content-type": "text/event-stream", - }); - // const data = "Hello Earl!"; +// SSE Connection to Frontend +app.get('/stream', sse.init); - setInterval(() => { - response.write('data:' + lowerLyrics + '\n\n'); - }, 250); +// SSE Connection to the Frontend +app.get('/lowerthirdsserver', function (request, response) { + response.status(200).set({ + "connection": "keep-alive", + "cache-control": "no-cache", + "content-type": "text/event-stream", + }); + // const data = "Hello Earl!"; + + setInterval(() => { + response.write('data:' + lowerLyrics + '\n\n'); + }, 250); }); app.get('/stagesserver', function (request, response) { - response.status(200).set({ - "connection": "keep-alive", - "cache-control": "no-cache", - "content-type": "text/event-stream", - }); - // const data = "Hello Earl!"; + response.status(200).set({ + "connection": "keep-alive", + "cache-control": "no-cache", + "content-type": "text/event-stream", + }); + // const data = "Hello Earl!"; - setInterval(() => { - response.write('data:' + stageLyrics + '\n\n'); - }, 250); + setInterval(() => { + response.write('data:' + stageLyrics + '\n\n'); + }, 250); }); // Keep server running if connection to an API fails process.on('uncaughtException', (err) => { - console.log(err); + console.log(err); }); -// Routing for HTML files -require("../Quelea-On-The-Web/app/routing/htmlRoutes.js")(app); - // Run the server app.listen(PORT, () => { - console.log("Server listening on: http://localhost:" + PORT); + console.log("Server listening on: http://localhost:" + PORT); }); \ No newline at end of file diff --git a/server/yarn.lock b/server/yarn.lock index d7770b5..a4dcd80 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -accepts@~1.3.7: +accepts@~1.3.5, accepts@~1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== @@ -38,11 +38,36 @@ body-parser@1.19.0, body-parser@^1.19.0: raw-body "2.4.0" type-is "~1.6.17" +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + bytes@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + content-disposition@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" @@ -114,6 +139,11 @@ eventemitter3@^4.0.0: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== +express-sse@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/express-sse/-/express-sse-0.5.3.tgz#6e6cb1a85ef7b6ec1eb658e37e923907c482bd31" + integrity sha512-DJF0nofFGq0IXJLGq95hfrryP3ZprVAVpyZUnmAk6QhHnm7zCzsHBNFP0i4FKFo2XjOf+JiYUKjT7jQhIeljpg== + express@^4.17.1: version "4.17.1" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" @@ -261,6 +291,11 @@ mime-db@1.49.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed" integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA== +"mime-db@>= 1.43.0 < 2": + version "1.50.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.50.0.tgz#abd4ac94e98d3c0e185016c67ab45d5fde40c11f" + integrity sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A== + mime-types@~2.1.24: version "2.1.32" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.32.tgz#1d00e89e7de7fe02008db61001d9e02852670fd5" @@ -295,6 +330,11 @@ on-finished@~2.3.0: dependencies: ee-first "1.1.1" +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + parseurl@~1.3.2, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"