aboutsummaryrefslogtreecommitdiffstats
path: root/src/server
diff options
context:
space:
mode:
authorRblSb <msrblsb@gmail.com>2020-02-24 07:58:56 +0300
committerRblSb <msrblsb@gmail.com>2020-02-24 07:58:56 +0300
commit9c6cd2c2310d2e3ce3d1a6e3350a97e7ba0ca657 (patch)
tree3eb12f0eee7ba05b7e70c740561eff31e06b608a /src/server
parentc561fb9e2e42e4968f2b48cd535f208e90f8c12c (diff)
Start working on user folder
Diffstat (limited to 'src/server')
-rw-r--r--src/server/HttpServer.hx79
-rw-r--r--src/server/Main.hx66
-rw-r--r--src/server/Utils.hx11
3 files changed, 109 insertions, 47 deletions
diff --git a/src/server/HttpServer.hx b/src/server/HttpServer.hx
index b49301b..a5b752b 100644
--- a/src/server/HttpServer.hx
+++ b/src/server/HttpServer.hx
@@ -1,12 +1,11 @@
package server;
+import sys.FileSystem;
import js.node.Buffer;
import haxe.io.Path;
import js.node.Fs;
-import sys.io.File;
import js.node.http.IncomingMessage;
import js.node.http.ServerResponse;
-import js.Node.__dirname;
import js.node.Path as JsPath;
using StringTools;
@@ -33,18 +32,31 @@ class HttpServer {
];
static var dir:String;
+ static var customDir:String;
+ static var hasCustomRes = false;
+ static var allowedLocalFiles:Map<String, Bool> = [];
- public static function init(directory:String):Void {
- dir = directory;
+ public static function init(dir:String, ?customDir:String):Void {
+ HttpServer.dir = dir;
+ if (customDir == null) return;
+ HttpServer.customDir = customDir;
+ hasCustomRes = FileSystem.exists(customDir);
}
public static function serveFiles(req:IncomingMessage, res:ServerResponse):Void {
- var filePath = dir + req.url;
- if (req.url == "/") filePath = '$dir/index.html';
+ var url = req.url;
+ if (url == "/") url = "/index.html";
+ var filePath = dir + url;
final extension = Path.extension(filePath).toLowerCase();
final contentType = getMimeType(extension);
+ if (req.connection.remoteAddress == req.connection.localAddress
+ || allowedLocalFiles[url]) {
+ final isExists = serveLocalFile(res, url, extension, contentType);
+ if (isExists) return;
+ }
+
if (!isChildOf(dir, filePath)) {
res.statusCode = 500;
var rel = JsPath.relative(dir, filePath);
@@ -52,21 +64,14 @@ class HttpServer {
return;
}
- // load client code from build folder
- if (filePath == '$dir/client.js') {
- filePath = '$__dirname/client.js';
+ if (hasCustomRes) {
+ final path = customDir + url;
+ if (Fs.existsSync(path)) filePath = path;
}
- Fs.readFile(filePath, function(err:Dynamic, data:Buffer) {
+ Fs.readFile(filePath, (err:Dynamic, data:Buffer) -> {
if (err != null) {
- if (err.code == "ENOENT") {
- res.statusCode = 404;
- var rel = JsPath.relative(dir, filePath);
- res.end('File $rel not found.');
- } else {
- res.statusCode = 500;
- res.end('Error getting the file: $err.');
- }
+ readFileError(err, res, filePath);
return;
}
res.setHeader("Content-Type", contentType);
@@ -78,13 +83,40 @@ class HttpServer {
});
}
+ static function readFileError(err:Dynamic, res:ServerResponse, filePath:String):Void {
+ if (err.code == "ENOENT") {
+ res.statusCode = 404;
+ var rel = JsPath.relative(dir, filePath);
+ res.end('File $rel not found.');
+ } else {
+ res.statusCode = 500;
+ res.end('Error getting the file: $err.');
+ }
+ }
+
+ static function serveLocalFile(res:ServerResponse, filePath:String, ext:String, contentType:String):Bool {
+ if (ext != "mp4" && ext != "mp3" && ext != "wav") return false;
+ if (!Fs.existsSync(filePath)) return false;
+ allowedLocalFiles[filePath] = true;
+ Fs.readFile(filePath, (err:Dynamic, data:Buffer) -> {
+ if (err != null) {
+ readFileError(err, res, filePath);
+ return;
+ }
+ res.setHeader("Content-Type", contentType);
+ res.end(data);
+ });
+ return true;
+ }
+
static final matchLang = ~/^[A-z]+/;
+ static final matchVarString = ~/\${([A-z_]+)}/g;
static function localizeHtml(data:String, lang:String):String {
if (lang != null && matchLang.match(lang)) {
lang = matchLang.matched(0);
} else lang = "en";
- data = ~/\${([A-z_]+)}/g.map(data, (regExp) -> {
+ data = matchVarString.map(data, (regExp) -> {
final key = regExp.matched(1);
return Lang.get(lang, key);
});
@@ -92,14 +124,13 @@ class HttpServer {
}
static function isChildOf(parent:String, child:String):Bool {
- final path = JsPath;
- final relative = path.relative(parent, child);
- return relative.length > 0 && !relative.startsWith('..') && !path.isAbsolute(relative);
+ final rel = JsPath.relative(parent, child);
+ return rel.length > 0 && !rel.startsWith('..') && !JsPath.isAbsolute(rel);
}
static function getMimeType(ext:String):String {
- var contentType = mimeTypes[ext];
- if (contentType == null) contentType = "application/octet-stream";
+ final contentType = mimeTypes[ext];
+ if (contentType == null) return "application/octet-stream";
return contentType;
}
diff --git a/src/server/Main.hx b/src/server/Main.hx
index e2b9b18..442abc8 100644
--- a/src/server/Main.hx
+++ b/src/server/Main.hx
@@ -10,8 +10,10 @@ import js.Node.process;
import js.Node.__dirname;
import js.npm.ws.Server as WSServer;
import js.npm.ws.WebSocket;
+import js.node.http.IncomingMessage;
import js.node.Http;
import Types;
+using StringTools;
using ClientTools;
using Lambda;
@@ -19,6 +21,9 @@ class Main {
final rootDir = '$__dirname/..';
final wss:WSServer;
+ final localIp:String;
+ var globalIp:String;
+ final port:Int;
final config:Config;
final clients:Array<Client> = [];
final freeIds:Array<Int> = [];
@@ -33,25 +38,31 @@ class Main {
wss = new WSServer({port: wsPort});
wss.on("connection", onConnect);
function exit() {
+ // TODO save state
process.exit();
}
process.on("exit", exit);
process.on("SIGINT", exit); // ctrl+c
+ process.on("SIGUSR1", exit); // kill pid
+ process.on("SIGUSR2", exit);
process.on("uncaughtException", (log) -> {
trace(log);
});
process.on("unhandledRejection", (reason, promise) -> {
trace("Unhandled Rejection at:", reason);
});
+ localIp = Utils.getLocalIp();
+ globalIp = localIp;
+ this.port = port;
Utils.getGlobalIp(ip -> {
- final local = Utils.getLocalIp();
- trace('Local: http://$local:$port');
- trace('Global: http://$ip:$port');
+ globalIp = ip;
+ trace('Local: http://$localIp:$port');
+ trace('Global: http://$globalIp:$port');
});
final dir = '$rootDir/res';
- HttpServer.init(dir);
+ HttpServer.init(dir, '$rootDir/user/res');
Lang.init('$dir/langs');
Http.createServer((req, res) -> {
@@ -61,7 +72,7 @@ class Main {
function getUserConfig():Config {
final config:Config = Json.parse(File.getContent('$rootDir/default-config.json'));
- final customPath = '$rootDir/config.json';
+ final customPath = '$rootDir/user/config.json';
if (!FileSystem.exists(customPath)) return config;
final customConfig:Config = Json.parse(File.getContent(customPath));
for (field in Reflect.fields(customConfig)) {
@@ -71,13 +82,13 @@ class Main {
return config;
}
- function onConnect(ws:WebSocket, req):Void {
+ function onConnect(ws:WebSocket, req:IncomingMessage):Void {
final ip = req.connection.remoteAddress;
final id = freeIds.length > 0 ? freeIds.shift() : clients.length;
final name = 'Guest ${id + 1}';
trace('$name connected ($ip)');
final isAdmin = req.connection.localAddress == ip;
- final client = new Client(ws, id, name, 0);
+ final client = new Client(ws, req, id, name, 0);
if (isAdmin) client.group.set(Admin);
clients.push(client);
if (clients.length == 1 && videoList.length > 0)
@@ -93,7 +104,8 @@ class Main {
clients: [
for (client in clients) client.getData()
],
- videoList: videoList
+ videoList: videoList,
+ globalIp: globalIp
}
});
sendClientList();
@@ -103,7 +115,7 @@ class Main {
});
ws.on("close", err -> {
trace('Client ${client.name} disconnected');
- sortedPush(freeIds, client.id);
+ Utils.sortedPush(freeIds, client.id);
clients.remove(client);
sendClientList();
if (client.isLeader) {
@@ -116,17 +128,6 @@ class Main {
});
}
- function sortedPush(ids:Array<Int>, id:Int):Void {
- for (i in 0...ids.length) {
- final n = ids[i];
- if (id < n) {
- ids.insert(i, id);
- return;
- }
- }
- ids.push(id);
- }
-
function onMessage(client:Client, data:WsEvent):Void {
switch (data.type) {
case Connected:
@@ -149,6 +150,7 @@ class Main {
}
});
sendClientList();
+
case LoginError:
case Logout:
final oldName = client.name;
@@ -163,6 +165,7 @@ class Main {
}
});
sendClientList();
+
case Message:
var text = data.message.text;
if (text.length == 0) return;
@@ -175,15 +178,23 @@ class Main {
messages.push({text: text, name: client.name, time: time});
if (messages.length > config.serverChatHistory) messages.shift();
broadcast(data);
+
case AddVideo:
- if (data.addVideo.atEnd) videoList.push(data.addVideo.item);
- else videoList.insert(1, data.addVideo.item);
+ final item = data.addVideo.item;
+ final localOrigin = '$localIp:$port';
+ if (item.url.indexOf(localOrigin) != -1) {
+ item.url = item.url.replace(localOrigin, '$globalIp:$port');
+ }
+ if (data.addVideo.atEnd) videoList.push(item);
+ else videoList.insert(1, item);
broadcast(data);
// Initial timer start if VideoLoaded is not happen
if (videoList.length == 1) restartWaitTimer();
+
case VideoLoaded:
// Called if client loads next video and can play it
prepareVideoPlayback();
+
case RemoveVideo:
if (videoList.length == 0) return;
final url = data.removeVideo.url;
@@ -193,16 +204,19 @@ class Main {
);
broadcast(data);
if (videoList.length > 0) restartWaitTimer();
+
case Pause:
if (videoList.length == 0) return;
if (!client.isLeader) return;
videoTimer.pause();
broadcast(data);
+
case Play:
if (videoList.length == 0) return;
if (!client.isLeader) return;
videoTimer.play();
broadcast(data);
+
case GetTime:
if (videoList.length == 0) return;
if (videoTimer.getTime() > videoList[0].duration) {
@@ -220,11 +234,13 @@ class Main {
time: videoTimer.getTime(),
paused: videoTimer.isPaused()
}});
+
case SetTime:
if (videoList.length == 0) return;
if (!client.isLeader) return;
videoTimer.setTime(data.setTime.time);
broadcastExcept(client, data);
+
case Rewind:
if (videoList.length == 0) return;
// TODO permission
@@ -232,6 +248,7 @@ class Main {
if (data.rewind.time < 0) data.rewind.time = 0;
videoTimer.setTime(data.rewind.time);
broadcast(data);
+
case SetLeader:
clients.setLeader(data.setLeader.clientName);
broadcast({
@@ -248,12 +265,15 @@ class Main {
}
});
}
+
case ClearChat:
if (client.isAdmin) broadcast(data);
+
case ClearPlaylist:
videoTimer.stop();
videoList.resize(0);
broadcast(data);
+
case ShufflePlaylist:
if (videoList.length == 0) return;
final first = videoList.shift();
@@ -262,7 +282,7 @@ class Main {
broadcast({type: UpdatePlaylist, updatePlaylist: {
videoList: videoList
}});
- case UpdatePlaylist:
+ case UpdatePlaylist: // client-only
}
}
diff --git a/src/server/Utils.hx b/src/server/Utils.hx
index 2ecbd42..22ddc77 100644
--- a/src/server/Utils.hx
+++ b/src/server/Utils.hx
@@ -28,6 +28,17 @@ class Utils {
return "127.0.0.1";
}
+ public static function sortedPush(ids:Array<Int>, id:Int):Void {
+ for (i in 0...ids.length) {
+ final n = ids[i];
+ if (id < n) {
+ ids.insert(i, id);
+ return;
+ }
+ }
+ ids.push(id);
+ }
+
public static function shuffle<T>(arr:Array<T>):Void {
for (i in 0...arr.length) {
final n = Std.random(arr.length);
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage