mirror of
https://github.com/lasthead0/yandex2mqtt.git
synced 2025-08-06 16:27:18 +03:00
188 lines
5.7 KiB
JavaScript
188 lines
5.7 KiB
JavaScript
'use strict';
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
/* */
|
|
const {createLogger, format, transports} = require('winston');
|
|
/* express and https */
|
|
const ejs = require('ejs');
|
|
const express = require('express');
|
|
const app = express();
|
|
const https = require('https');
|
|
/* parsers */
|
|
const cookieParser = require('cookie-parser');
|
|
/* error handler */
|
|
const errorHandler = require('errorhandler');
|
|
/* seesion and passport */
|
|
const session = require('express-session');
|
|
const passport = require('passport');
|
|
/* mqtt client for devices */
|
|
const mqtt = require('mqtt');
|
|
/* */
|
|
const config = require('./config');
|
|
config.notification = config.notification || [];
|
|
|
|
const Device = require('./device');
|
|
|
|
/* */
|
|
const clArgv = process.argv.slice(2);
|
|
|
|
/* Logging */
|
|
global.logger = createLogger({
|
|
level: 'info',
|
|
format: format.combine(
|
|
format.errors({stack: true}),
|
|
format.timestamp(),
|
|
format.printf(({level, message, timestamp, stack}) => {
|
|
return `${timestamp} ${level}: ${stack != undefined ? stack : message}`;
|
|
}),
|
|
),
|
|
transports: [
|
|
new transports.Console({
|
|
silent: clArgv.indexOf('--log-info') == -1
|
|
})
|
|
],
|
|
});
|
|
|
|
if (clArgv.indexOf('--log-error') > -1) global.logger.add(new transports.File({filename: 'log/error.log', level: 'error'}));
|
|
|
|
/* */
|
|
app.engine('ejs', ejs.__express);
|
|
app.set('view engine', 'ejs');
|
|
app.set('views', path.join(__dirname, './views'));
|
|
app.use(express.static('views'));
|
|
app.use(cookieParser());
|
|
app.use(express.json({
|
|
extended: false,
|
|
}));
|
|
app.use(express.urlencoded({
|
|
extended: true,
|
|
}));
|
|
app.use(errorHandler());
|
|
app.use(session({
|
|
secret: 'keyboard cat',
|
|
resave: false,
|
|
saveUninitialized: false,
|
|
}));
|
|
|
|
/* passport */
|
|
app.use(passport.initialize());
|
|
app.use(passport.session());
|
|
|
|
/* passport auth */
|
|
require('./auth');
|
|
|
|
/* routers */
|
|
const {site: r_site, oauth2: r_oauth2, user: r_user, client: r_client} = require('./routes');
|
|
|
|
app.get('/', r_site.index);
|
|
app.get('/login', r_site.loginForm);
|
|
app.post('/login', r_site.login);
|
|
app.get('/logout', r_site.logout);
|
|
app.get('/account', r_site.account);
|
|
app.get('/dialog/authorize', r_oauth2.authorization);
|
|
app.post('/dialog/authorize/decision', r_oauth2.decision);
|
|
app.post('/oauth/token', r_oauth2.token);
|
|
app.get('/api/userinfo', r_user.info);
|
|
app.get('/api/clientinfo', r_client.info);
|
|
app.get('/provider/v1.0', r_user.ping);
|
|
app.get('/provider', r_user.ping);
|
|
app.get('/provider/v1.0/user/devices', r_user.devices);
|
|
app.post('/provider/v1.0/user/devices/query', r_user.query);
|
|
app.post('/provider/v1.0/user/devices/action', r_user.action);
|
|
app.post('/provider/v1.0/user/unlink', r_user.unlink);
|
|
|
|
/* create https server */
|
|
const privateKey = fs.readFileSync(config.https.privateKey, 'utf8');
|
|
const certificate = fs.readFileSync(config.https.certificate, 'utf8');
|
|
const credentials = {
|
|
key: privateKey,
|
|
cert: certificate,
|
|
};
|
|
const httpsServer = https.createServer(credentials, app);
|
|
httpsServer.listen(config.https.port);
|
|
|
|
/* cache devices from config to global */
|
|
global.devices = [];
|
|
if (config.devices) {
|
|
config.devices.forEach(opts => {
|
|
global.devices.push(new Device(opts));
|
|
});
|
|
}
|
|
|
|
/* create subscriptions array */
|
|
const subscriptions = [];
|
|
global.devices.forEach(device => {
|
|
device.data.custom_data.mqtt.forEach(mqtt => {
|
|
const {instance, state: topic} = mqtt;
|
|
if (instance != undefined && topic != undefined) {
|
|
subscriptions.push({deviceId: device.data.id, instance, topic});
|
|
}
|
|
});
|
|
});
|
|
|
|
/* Create MQTT client (variable) in global */
|
|
global.mqttClient = mqtt.connect(`mqtt://${config.mqtt.host}`, {
|
|
port: config.mqtt.port,
|
|
username: config.mqtt.user,
|
|
password: config.mqtt.password
|
|
}).on('connect', () => { /* on connect event handler */
|
|
mqttClient.subscribe(subscriptions.map(pair => pair.topic));
|
|
}).on('offline', () => { /* on offline event handler */
|
|
/* */
|
|
}).on('message', (topic, message) => { /* on get message event handler */
|
|
const subscription = subscriptions.find(sub => topic.toLowerCase() === sub.topic.toLowerCase());
|
|
if (subscription == undefined) return;
|
|
|
|
const {deviceId, instance} = subscription;
|
|
const ldevice = global.devices.find(d => d.data.id == deviceId);
|
|
ldevice.updateState(`${message}`, instance);
|
|
|
|
/* Make Request to Yandex Dialog notification API */
|
|
Promise.all(config.notification.map(el => {
|
|
let {skill_id, oauth_token, user_id} = el;
|
|
|
|
return new Promise((resolve, reject) => {
|
|
let req = https.request({
|
|
hostname: 'dialogs.yandex.net',
|
|
port: 443,
|
|
path: `/api/v1/skills/${skill_id}/callback/state`,
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': `application/json`,
|
|
'Authorization': `OAuth ${oauth_token}`
|
|
}
|
|
}, res => {
|
|
res.on('data', d => {
|
|
global.logger.log('info', {message: `${d}`});
|
|
});
|
|
});
|
|
|
|
req.on('error', error => {
|
|
global.logger.log('error', {message: `${error}`});
|
|
});
|
|
|
|
let {id, capabilities, properties} = ldevice.getState();
|
|
req.write(JSON.stringify({
|
|
"ts": Math.floor(Date.now() / 1000),
|
|
"payload": {
|
|
"user_id": `${user_id}`,
|
|
"devices": [{
|
|
id,
|
|
capabilities: capabilities.filter(c => c.state.instance == instance),
|
|
properties: properties.filter(p => p.state.instance == instance)
|
|
}],
|
|
}
|
|
}));
|
|
|
|
req.end();
|
|
|
|
resolve(true);
|
|
});
|
|
}));
|
|
|
|
/* */
|
|
});
|
|
|
|
module.exports = app;
|