Recommendations on App architecture
-
@SeRiusRod - Quasar’s boot files aren’t for server-side code or rather don’t run server-side. Boot files get ran at the boot up time of your app and are used to initialize/ setup things like i18n, API connectivity, etc. So, you need an API, either via REST, GraphQL or even Electron to be able to accomplish server-side tasks.
Scott
-
@SeRiusRod said in Recommendations on App architecture:
I have mqtt already running as a module.
Can you show how this code is running? I may have been mistaken and mqtt can run in the browser via websockets. However to accomplish your main goal that the scheduler always runs (and to make sure that two schedulers aren’t running at the same time), you really should architect this app as a node process running on the server and a thin quasar client to display / edit data.
-
@beets said in Recommendations on App architecture:
Can you show how this code is running?
Of course:
/* /src/boot/mqtt.js */ import Vue from 'vue' const bus = new Vue() const mqtt = require('mqtt') export default ({ app }) => { window.mqtt = mqtt const client = mqtt.connect('mqtt://<myserver>') window.mqtt.bus = bus window.mqttClient = client client.on('connect', () => { console.log('MQTT server connected successfully') // # means subscribe to all data client.subscribe('#', { qos: 0 }, (error) => { if (!error) { console.log('Subscription successful') } else { console.log('Subscription failed') } }) }) // Receive return data client.on('message', (topic, message) => { console.log(topic, ': \t\t\t\t', message.toString()) }) // Disconnect and reconnect client.on('reconnect', (error) => { console.log('Reconnecting...', error) }) // Link exception handling client.on('error', (error) => { console.log('Connection failed...', error) }) setInterval(function () { client.publish('tcc', 'Hello!') }, 5000) } export { mqtt }
This is a lightened sample. Not that I have much more. I was still struggling to create a project wide storage to dump the values received.
But you were completely right. There’s no code executed as long as there is no client connected.Now I’m building a nodejs service that receives mqtt info and stores in a json object that is committed to fs. Then it will schedule based on the events in that object, and also serve that json via sockets to the quasar frontend.
Any suggestions on how to make that global json storage object?
-
@SeRiusRod said in Recommendations on App architecture:
Any suggestions on how to make that global json storage object?
Vuex is the typical answer here. It would be a pretty simple store, with likely just one variable called
data
or whatever. First question is, have you set anything up with vuex (the src/store folder in quasar) ? -
@beets
That’s on the web side. But what about the server side? -
@SeRiusRod Sorry I thought you had that figured out from here:
stores in a json object that is committed to fs.
If you’re just looking to store an object, a global variable works fine, unless I’m still misunderstanding.
-
I’ve tried with global variables, but I could not make it work.
Now I’ve made a separate module for the storage management:// storage.js const fs = require('fs'); let settings = null; let devices = null; function getSettings() { try { settings = JSON.parse(fs.readFileSync('./settings.json', 'utf8')); } catch (error) { console.log('settings.json file not found.'); } if (!settings) settings = { A: true, B: false, }; console.log(settings); return settings; } function setSettings(newSettings) { fs.writeFileSync('./settings.json', JSON.stringify(newSettings)); } function getDevices() { try { devices = JSON.parse(fs.readFileSync('./devices.json', 'utf8')); } catch (error) { console.log('devices.json file not found.'); } if (!devices) devices = {}; console.log(devices); return devices; } function setDevices(newDevices) { fs.writeFileSync('./devices.json', JSON.stringify(newDevices)); } module.exports = { settings, devices, getSettings, setSettings, getDevices, setDevices, };
// server.js const config = require('./config'); var storage = require('./storage.js'); const mqtt = require('./mqtt.js') function main() { var settings = storage.getSettings(); console.log(`settings ${settings}`); //Works console.log(`storage.settings ${storage.settings}`); //Doesn't setInterval(function() { console.log('*Timer tick!*'); }, 5000); } main();
If you look on the two console outputs, the second one is null. And I don’t see why. So now I want to populate storage on mqtt.js, but isn’t available there.
-
@beets said in Recommendations on App architecture:
If you’re just looking to store an object, a global variable works fine, unless I’m still misunderstanding.
Yes, you’re right. I was having a background error that prevented my project to work as intended and that confused me.
-
I’ve made a bare NodeJs backend and setup a global variable for devices storage. That added a socket.io file that periodically sends a device.
On the Quasar frontend, I’ve added a boot file and setup one page for receiving the data. But I can’t find why it doesn’t receive anything, and the backend doesn’t inform about client’s connection. Perhaps you can give me a hand:Backend:
// socket.js const config = require('./config'); const app = require('express')(); const http = require('http').Server(app); const io = require('socket.io')(http); console.log('socket: module loaded'); //This is shown app.get('/', (req, res) => { res.status(200).send('This is the backend server.'); //This works }); function sendDevice(id) { const device = devices.find((i) => i.id === id); io.emit('device', device); } function updateDevice(id, data) { var device = devices.find((i) => i.id === id); if (!device) devices.push(data); else device = data; pendingCommit = true; } http.listen(config.socketPort, () => { console.log('socket: websocket listening on *:' + config.socketPort); //This works }); // All of this doesn't seem to work io.on('connection', (socket) => { console.log(`socket: client connected with id: ${socket.id}`); socket.on('updateDevice', function(data) { if (!data.id) { console.error('socket: [ERROR] Received a device update request without a correct id.'); return; } updateDevice(data.id, data); }); setInterval(function() { sendDevice('1'); }, 5000); io.on('disconnect', () => { console.log(`socket: client disconnected with id: ${socket.id}`); }); }); module.exports = { sendDevice };
Frontend:
// boot/socket.js import io from 'socket.io-client' const socket = io.connect('http://localhost:3002') export default ({ Vue }) => { Vue.prototype.$socket = socket } export { socket }
<!-- pages/info.vue --> <template> <q-page padding class="window-height window-width row justify-center"> Selected: {{selected}}<br/> <!-- Shows the correct Id --> Name: {{device.display_name}} <!-- Shows default --> <q-knob readonly v-model="device.battery_level" show-value size="150px" :thickness="0.22" color="green" track-color="green-2" class="q-ma-md" > {{ device.battery_level }}% </q-knob> </q-page> </template> <script> export default { name: 'Info', data () { return { selected: '', settings: [], device: { id: '', display_name: 'Empty', battery_level: '-1' } } }, mounted () { this.selected = this.$q.localStorage.getItem('selectedItem') this.$socket.on('device', (data) => { this.device = [...this.device, data] }) } } </script>
-
Okey. I was getting a silent Cors error.