web/src/modules/sub-web.js

630 lines
18 KiB
JavaScript

const { __glob, __web } = require("./global-variables");
const { LogType } = require("loguix");
const log = require("loguix");
const auth = require("./sub-auth");
const cook = require("cookie")
const wlog = new LogType("Web")
const subplayer = require('./sub-player');
const { List } = require("./sub-list")
const subplaylist = require("./sub-playlist")
const nodesfinder = require("./nodes-finder")
const { Server } = require("socket.io")
var fs = require("fs")
var path = require("path")
const { Metric } = require("webmetrik");
const markdownit = require("markdown-it")({
html: true,
linkify: true,
typographer: true
})
const Lyrics = require('song-lyrics-api');
const lyrics = new Lyrics();
module.exports.WebServer = class {
constructor() {
wlog.step.init("start_server", "Démarrage du serveur Express (Web)")
init()
}
}
function init() {
const createError = require('http-errors');
const express = require('express');
const cookieParser = require('cookie-parser');
const favicon = require('express-favicon');
const app = express();
const port = normalizePort(process.env.PORT || '4000');
const server = require('http').createServer(app);
const io = require('socket.io')(server)
const indexRouter = require(__web.ROUTER + "index.js");
const loginRouter = require(__web.ROUTER + "login.js");
const internalRouter = require(__web.ROUTER + "internal.js")
IOConnection(io)
app.set('views', __web.TEMPLATES); // general config
app.set('view engine', 'ejs');
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(__web.PUBLIC));
app.set('port', port);
app.use('/', indexRouter);
app.use('/login', loginRouter);
app.use("/internal", internalRouter)
app.use("/userspictures", express.static(__glob.PICTURE_DIR))
app.use(favicon(__web.ICON));
app.use(function (req, res, next) {
next(createError(404));
});
app.use(function (err, req, res, next) {
// Set locals, only providing error
// in development
res.locals.message = err.message;
res.locals.error = req.app.get('env')
=== 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
server.listen(port);
server.on('error', (error) => {
if (error.syscall !== 'listen') {
throw error;
}
let bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// Handle specific listen errors with
// friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind
+ ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
});
server.on('listening', () => {
let addr = server.address();
let bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
wlog.log("Serveur démarré sur le port : " + bind )
});
wlog.step.end("start_server")
}
// EXPRESS FUNCTIONS
function normalizePort(val) {
let port = parseInt(val, 10);
if (isNaN(port)) {
// Named pipe
return val;
}
if (port >= 0) {
// Port number
return port;
}
return false;
}
/**
*
* @param {Server} io
*/
function IOConnection(io) {
/**
* @type {LogType}
*/
const alog = log.getInstance("Authentification")
const usersOnline = new Array()
process.on("UPDATE_SELF", () => {
if(io) {
AlwaysRequest("UPDATE_SELF")
AlwaysRequest("ALL_CONNECTED_USER", usersOnline)
}
})
process.on("UPDATE_NODES", () => {
if(io) {
const data = nodesfinder.getNodesData()
AdminRequest("NODES", data)
}
})
process.on("PLAYLIST_REFRESH", () => {
if(io) {
AlwaysRequest("PLAYLIST_REFRESH", "OK")
}
})
process.on("MUSIC_UPDATE_STATE", () => {
if(io) {
const data = subplayer.updateMusicState()
AlwaysRequest("MUSIC_STATE", data)
}
})
io.on("connection", (socket) => {
var token = cook.parse(socket.handshake.headers.cookie).token
var user = auth.getUser(token)
if(user) {
if(user.admin == true) {
socket.join("admin")
}
const online_users_data = auth.getSimpleUser(token)
if(online_users_data) {
// Check if user is already connected and if not push it
if(!usersOnline.find(item => item.username == online_users_data.username)) {
usersOnline.push(online_users_data)
}
alog.log(online_users_data.username + " - Connexion du serveur avec le socket : " + socket.id + " - " + socket.handshake.address + " - " + socket.handshake.headers["user-agent"])
}
AlwaysRequest("ALL_CONNECTED_USER", usersOnline)
socket.on("disconnect", () => {
alog.log(user.user.username + " - Déconnexion du serveur - Socket : " + socket.id)
socket.leave("admin")
var index = usersOnline.indexOf(online_users_data)
if(index > -1) {
usersOnline.splice(index, 1)
}
AlwaysRequest("ALL_CONNECTED_USER", usersOnline)
})
GetRequest("USER_INFO", () => {
GetAnswer("USER_INFO", user)
alog.log("Envoi des informations Discord de '" + user.user.username + "' à '" + socket.id + "'" )
})
GetRequest("USER_LIST", () => {
GetAnswer("USER_LIST", auth.getSimpleUsers())
})
GetRequest('MUSIC_STATE', () => {
const data = subplayer.updateMusicState()
GetAnswer("MUSIC_STATE", "Bienvenue " + user.user.username + " ! " )
AlwaysRequest("MUSIC_STATE", data)
})
GetRequest("PLAYLIST", () => {
const playlistResult = subplaylist.getUser(user.user.id)
GetAnswer("PLAYLIST", playlistResult)
})
GetRequest("PAUSE", () => {
subplayer.pause()
GetAnswer("PAUSE", "OK")
})
GetRequest("BACKWARD", () => {
subplayer.previous()
GetAnswer("BACKWARD", "OK")
})
GetRequest("FORWARD", () => {
subplayer.skip()
GetAnswer("FORWARD", "OK")
})
GetRequest("LOOP", () => {
subplayer.loop()
GetAnswer("LOOP", "OK")
})
GetRequest("SHUFFLE", () => {
subplayer.changeShuffle()
GetAnswer("SHUFFLE", "OK")
})
GetRequest("DISCONNECT", () => {
subplayer.leave()
GetAnswer("DISCONNECT", "OK")
})
GetRequest("NODES", () => {
process.emit("UPDATE_NODES")
GetAnswer("NODES", "OK")
})
GetRequest("ALL_CONNECTED_USER", () => {
GetAnswer("ALL_CONNECTED_USER", "OK")
AlwaysRequest("ALL_CONNECTED_USER", usersOnline)
})
GetRequest("README", () => {
var content = markdownit.render(fs.readFileSync(__glob.README).toString())
GetAnswer("README", content)
})
GetRequest("OOBE_CHECK", () => {
GetAnswer("OOBE_CHECK", auth.getOOBE(user.user.id))
})
GetRequest("OOBE_VALID", () => {
auth.setOOBE(user.user.id)
GetAnswer("OOBE_VALID", "OK")
})
GetRequest("MOVEOUT", () => {
subplayer.moveOut(user.user.id)
GetAnswer("MOVEOUT", "OK")
})
PostRequest("SEEK", (data) => {
subplayer.seek(data)
PostAnswer("SEEK", "OK")
})
PostRequest("VOLUME", (data) => {
subplayer.setVol(data)
PostAnswer("VOLUME", "OK")
})
PostRequest("PLAY_QUEUE", (data) => {
var sublist = new List()
subplayer.addSong(sublist.playQueue(data), user.user.id, true)
PostAnswer("PLAY_QUEUE", "OK")
})
PostRequest("CHANGE_QUEUE", (data) => {
var sublist = new List()
sublist.changeQueue(data)
PostAnswer("CHANGE_QUEUE", "OK")
})
PostRequest("DELETE_QUEUE", (data) => {
var sublist = new List()
sublist.removeByIndex(data)
PostAnswer("DELETE_QUEUE", "OK")
})
PostRequest("DELETE_ALL_QUEUE", () => {
var sublist = new List()
sublist.removeAll()
PostAnswer("DELETE_QUEUE", "OK")
})
PostRequest("MOVE_QUEUE", (data) => {
var sublist = new List()
sublist.moveUp(data)
PostAnswer("MOVE_QUEUE", "OK")
})
PostRequest("MOVE_QUEUE_BY_ENTIRE", (data) => {
var sublist = new List()
sublist.replaceList(data)
PostAnswer("MOVE_QUEUE_BY_ENTIRE", "OK")
})
PostRequest("REPORT", (data) => {
data.username = user
subplayer.report(null, null, data)
PostAnswer("REPORT", "OK")
})
PostRequest("SEARCH", async (data) => {
const results = await subplayer.search(data)
PostAnswer("SEARCH", results)
})
PostRequest("ADD_SONG", async (data) => {
subplayer.addSong(data, user.user.id)
PostAnswer("ADD_SONG", "OK")
playStats(user.user.username)
})
PostRequest("ADD_SONG_NOW", async (data) => {
subplayer.addSong(data, user.user.id, true)
PostAnswer("ADD_SONG_NOW", "OK")
playStats(user.user.username)
})
PostRequest("FP_ADD_SONG", async (data) => {
subplayer.addSong(data, user.user.id, false, true)
PostAnswer("FP_ADD_SONG", "OK")
playStats(user.user.username)
})
PostRequest("FP_ADD_SONG_NOW", async (data) => {
subplayer.addSong(data, user.user.id, true, true)
PostAnswer("FP_ADD_SONG_NOW", "OK")
playStats(user.user.username)
})
PostRequest("PLAY_PLAYLIST", async (data) => {
subplaylist.playPlaylist(user.user.id, data)
PostAnswer("PLAY_PLAYLIST", "OK")
playStats(user.user.username)
})
PostRequest("PLAY_PLAYLIST_NOW", async (data) => {
subplaylist.playPlaylist(user.user.id, data, true)
PostAnswer("PLAY_PLAYLIST_NOW", "OK")
playStats(user.user.username)
})
PostRequest("CREATE_PLAYLIST", async (data) => {
subplaylist.addPlaylist(user.user.id, data)
socket.emit("DO_UPDATE_PLAYLIST")
PostAnswer("CREATE_PLAYLIST", "OK")
})
PostRequest("DELETE_PLAYLIST", async (data) => {
subplaylist.removePlaylist(user.user.id, data)
socket.emit("DO_UPDATE_PLAYLIST")
PostAnswer("DELETE_PLAYLIST", "OK")
})
PostRequest("SEND_PLAYLIST", async (data) => {
subplaylist.copyPlaylist(user.user.id, data.key, data.dest)
socket.emit("DO_UPDATE_PLAYLIST")
PostAnswer("SEND_PLAYLIST", "OK")
})
PostRequest("RENAME_PLAYLIST", async (data) => {
subplaylist.renamePlaylist(user.user.id, data.id, data.name)
socket.emit("DO_UPDATE_PLAYLIST")
PostAnswer("RENAME_PLAYLIST", "OK")
})
PostRequest("ADD_SONG_TO_PLAYLIST", async (data) => {
subplaylist.addSong(user.user.id, data.id, data.url)
socket.emit("DO_UPDATE_PLAYLIST")
PostAnswer("ADD_SONG_TO_PLAYLIST", "OK")
})
PostRequest("DELETE_SONG_TO_PLAYLIST", async (data) => {
subplaylist.removeSong(user.user.id, data.id, data.identifier)
socket.emit("DO_UPDATE_PLAYLIST")
PostAnswer("DELETE_SONG_TO_PLAYLIST", "OK")
})
PostRequest("FP_PLAY_PLAYLIST", async (data) => {
subplayer.addSongsFromPlaylist(data, user.user.id)
PostAnswer("FP_PLAY_PLAYLIST", "OK")
})
PostRequest("FP_PLAY_PLAYLIST_NOW", async (data) => {
subplayer.addSongsFromPlaylist(data, user.user.id, true)
PostAnswer("FP_PLAY_PLAYLIST", "OK")
})
PostRequest("LYRICS", async (data) => {
lyrics.getLyrics(data)
.then((response) => {
PostAnswer("LYRICS", response[0].lyrics)
})
.catch((error) => {
PostAnswer("LYRICS", null)
})
})
if(user.admin == true) {
GetRequest("LOGS", () => {
const logs_data = new Array()
const logs_folder = fs.readdirSync(__glob.LOGS)
for(var log of logs_folder) {
logs_data.push({"name":log, "value": fs.readFileSync(__glob.LOGS + path.sep + log).toString()})
}
GetAnswer("LOGS", logs_data)
})
GetRequest("USERS", () => {
const users_data = auth.getUsers()
AdminRequest("USERS", users_data)
})
PostRequest("NODES/ADD", (data) => {
nodesfinder.addNodes(data)
PostAnswer("NODES/ADD", "OK")
process.emit("UPDATE_NODES")
})
PostRequest("NODES/DELETE", (data) => {
nodesfinder.deleteNode(data)
PostAnswer("NODES/DELETE", "OK")
process.emit("UPDATE_NODES")
})
PostRequest("NODES/RELOAD", (data) => {
nodesfinder.reloadNode(data)
PostAnswer("NODES/RELOAD", "OK")
process.emit("UPDATE_NODES")
})
PostRequest("USERS/ADMIN", (data) => {
auth.setAdmin(data)
PostAnswer("USERS/ADMIN", "OK")
const users_data = auth.getUsers()
AdminRequest("USERS", users_data)
})
PostRequest("USERS/BAN", (data) => {
auth.setBan(data)
PostAnswer("USERS/BAN", "OK")
const users_data = auth.getUsers()
AdminRequest("USERS", users_data)
})
PostRequest("USERS/DELETE", (data) => {
auth.removeUser(data)
PostAnswer("USERS/DELETE", "OK")
const users_data = auth.getUsers()
AdminRequest("USERS", users_data)
})
GetRequest("RESTART", () => {
const pm2 = require('pm2');
pm2.restart('Subsonics')
GetAnswer("RESTART", "OK")
})
}
}
function GetRequest(GQname, GQcallback) {
socket.on("GET/" + GQname, () => {
wlog.log(user.user.username + " - Socket : " + socket.id + " - GET/" + GQname + " - [RECIEVED]")
GQcallback()
})
}
function GetAnswer(GRname, GRvalue) {
wlog.log(user.user.username + " - Socket : " + socket.id + " - GET/" + GRname + " - [ANSWERED]")
socket.emit("ANSWER/GET/" + GRname, GRvalue)
}
function PostRequest(GQname, GQcallback) {
socket.on("POST/" + GQname, (value) => {
wlog.log(user.user.username + " - Socket : " + socket.id + " - POST/" + GQname + " - [RECIEVED]")
GQcallback(value)
})
}
function PostAnswer(GRname, GRvalue) {
wlog.log(user.user.username + " - Socket : " + socket.id + " - POST/" + GRname + " - [ANSWERED]")
socket.emit("ANSWER/POST/" + GRname, GRvalue)
}
})
function AlwaysRequest(GRname, GRvalue) {
io.sockets.emit("ALWAYS/" + GRname, GRvalue)
}
function AdminRequest(GRname, GRvalue) {
io.to("admin").emit("ALWAYS/" + GRname, GRvalue)
}
function playStats(username) {
var userMusicPlayed = new Metric("userMusicPlayed_" + username, "Nombre de musiques jouées par l'utilisateur : " + username)
userMusicPlayed.setValue(userMusicPlayed.getValue() + 1)
}
}