aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMinteck <nekostarfan@gmail.com>2021-04-30 14:40:11 +0200
committerMinteck <nekostarfan@gmail.com>2021-04-30 14:40:11 +0200
commit0ef318f533ef86f6033b758f1850d24a065a7cc0 (patch)
treec4bc8e8ea75464117fd37d44b74200ce72197684
downloadkartik-legacy-server-0ef318f533ef86f6033b758f1850d24a065a7cc0.tar.gz
kartik-legacy-server-0ef318f533ef86f6033b758f1850d24a065a7cc0.tar.bz2
kartik-legacy-server-0ef318f533ef86f6033b758f1850d24a065a7cc0.zip
Initial commit
-rw-r--r--.idea/.gitignore5
-rw-r--r--.idea/jsLibraryMappings.xml6
-rw-r--r--.idea/kartikserver.iml12
-rw-r--r--.idea/modules.xml8
-rw-r--r--demo/guest.js130
-rw-r--r--demo/host.js124
-rw-r--r--index.js353
-rw-r--r--package.json13
8 files changed, 651 insertions, 0 deletions
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..b58b603
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,5 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml
new file mode 100644
index 0000000..d23208f
--- /dev/null
+++ b/.idea/jsLibraryMappings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="JavaScriptLibraryMappings">
+ <includedPredefinedLibrary name="Node.js Core" />
+ </component>
+</project> \ No newline at end of file
diff --git a/.idea/kartikserver.iml b/.idea/kartikserver.iml
new file mode 100644
index 0000000..0c8867d
--- /dev/null
+++ b/.idea/kartikserver.iml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+ <component name="NewModuleRootManager">
+ <content url="file://$MODULE_DIR$">
+ <excludeFolder url="file://$MODULE_DIR$/temp" />
+ <excludeFolder url="file://$MODULE_DIR$/.tmp" />
+ <excludeFolder url="file://$MODULE_DIR$/tmp" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ </component>
+</module> \ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..573cee6
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ProjectModuleManager">
+ <modules>
+ <module fileurl="file://$PROJECT_DIR$/.idea/kartikserver.iml" filepath="$PROJECT_DIR$/.idea/kartikserver.iml" />
+ </modules>
+ </component>
+</project> \ No newline at end of file
diff --git a/demo/guest.js b/demo/guest.js
new file mode 100644
index 0000000..24177b8
--- /dev/null
+++ b/demo/guest.js
@@ -0,0 +1,130 @@
+global.pingStart = null;
+
+const sampleData = {
+ _type: "init",
+ name: "Kartik Core",
+ version: "21.04.5",
+ id: null,
+ moded: false
+}
+const linkTo = process.argv[2];
+console.log("Will link to client " + linkTo);
+
+function crash(e) {
+ console.log("Communication error");
+ console.error(e);
+ process.exit(2);
+}
+
+function exit() {
+ process.exit();
+}
+
+var net = require('net');
+
+var host = 'localhost';
+var port = 8888;
+
+var client = new net.Socket();
+client.initialized = false;
+
+client.connect(port, host, () => {
+ console.log("Connected to " + host + ":" + port);
+ client.write(JSON.stringify(sampleData));
+})
+
+client.on('data', (data) => {
+ try {
+ d = data.toString();
+ try {
+ info = JSON.parse(d);
+ } catch(e) {
+ if (e.message.startsWith("Unexpected token")) {
+ info = JSON.parse(d.substr(0, e.message.split(" ")[e.message.split(" ").length - 1]));
+ }
+ }
+ } catch (e) {
+ crash(e)
+ }
+ if (typeof info['_type'] != "string") {
+ crash(new Error("Invalid JSON data"));
+ }
+ if (!client.initialized) {
+ switch (info['_type']) {
+ case "init":
+ if (info['name'] !== "Kartik Server") {
+ crash(new Error("Invalid server"));
+ }
+ console.log("Connection initialized. Server running " + info.name + " version " + info.version + ", client ID " + info.id);
+ client.initialized = true;
+ console.log("Linking to client " + linkTo + "...")
+ client.write(JSON.stringify({
+ _type: "link",
+ client: linkTo
+ }));
+ break;
+ case "error":
+ console.log(info['type'] + ": " + info['message']);
+ break;
+ default:
+ crash(new Error("Trying to receive data but client not initialized"));
+ break;
+ }
+ } else {
+ switch (info['_type']) {
+ case "init":
+ crash(new Error("Trying to initialize client but client is already initialized"));
+ break;
+ case "error":
+ console.log(info['type'] + ": " + info['message']);
+ break;
+ case "linked":
+ console.log("Now hooked into link: (H) " + info['ids']['host'] + " <-> " + info['ids']['guest'] + " (G)");
+ setInterval(() => {
+ client.write(JSON.stringify({
+ _type: "ipc",
+ action: "Ping",
+ message: null
+ }))
+ global.pingStart = new Date();
+ }, 1000)
+ break;
+ default:
+ if (info['_type'] === "ipc" && info['action'] === "Ping") {
+ client.write(JSON.stringify({
+ _type: "ipc",
+ action: "Pong",
+ message: null
+ }))
+ return;
+ }
+ if (info['_type'] === "ipc" && info['action'] === "Pong") {
+ pingEnd = new Date();
+ ping = Math.round(pingEnd - pingStart);
+ global.pingStart = null;
+ console.log("Ping: " + ping + " ms");
+ return;
+ }
+ console.log("Data:");
+ console.dir(info);
+ break;
+ }
+ }
+})
+
+client.on('close', () => {
+ console.log("Kicked from server");
+ exit();
+})
+
+client.on('error', (e) => {
+ switch (e.code) {
+ case "ECONNREFUSED":
+ console.log("Unable to connect to server");
+ break;
+ default:
+ console.log("Internal error");
+ break;
+ }
+ crash(e);
+}) \ No newline at end of file
diff --git a/demo/host.js b/demo/host.js
new file mode 100644
index 0000000..e91f4c7
--- /dev/null
+++ b/demo/host.js
@@ -0,0 +1,124 @@
+global.pingStart = null;
+
+const sampleData = {
+ _type: "init",
+ name: "Kartik Core",
+ version: "21.04.5",
+ id: null,
+ modded: false
+}
+
+function crash(e) {
+ console.log("Communication error");
+ console.error(e);
+ process.exit(2);
+}
+
+function exit() {
+ process.exit();
+}
+
+var net = require('net');
+
+var host = 'localhost';
+var port = 8888;
+
+var client = new net.Socket();
+client.initialized = false;
+
+client.connect(port, host, () => {
+ console.log("Connected to " + host + ":" + port);
+ client.write(JSON.stringify(sampleData));
+})
+
+client.on('data', (data) => {
+ try {
+ d = data.toString();
+ try {
+ info = JSON.parse(d);
+ } catch(e) {
+ if (e.message.startsWith("Unexpected token")) {
+ info = JSON.parse(d.substr(0, e.message.split(" ")[e.message.split(" ").length - 1]));
+ }
+ }
+ } catch (e) {
+ crash(e)
+ }
+ if (typeof info['_type'] != "string") {
+ crash(new Error("Invalid JSON data"));
+ }
+ if (!client.initialized) {
+ switch (info['_type']) {
+ case "init":
+ if (info['name'] !== "Kartik Server") {
+ crash(new Error("Invalid server"));
+ }
+ console.log("Connection initialized. Server running " + info.name + " version " + info.version + ", client ID " + info.id);
+ client.initialized = true;
+ break;
+ case "error":
+ console.log(info['type'] + ": " + info['message']);
+ break;
+ default:
+ crash(new Error("Trying to receive data but client not initialized"));
+ break;
+ }
+ } else {
+ switch (info['_type']) {
+ case "init":
+ crash(new Error("Trying to initialize client but client is already initialized"));
+ break;
+ case "error":
+ console.log(info['type'] + ": " + info['message']);
+ break;
+ break;
+ case "linked":
+ console.log("Now hooked into link: (H) " + info['ids']['host'] + " <-> " + info['ids']['guest'] + " (G)");
+ setInterval(() => {
+ client.write(JSON.stringify({
+ _type: "ipc",
+ action: "Ping",
+ message: null
+ }))
+ global.pingStart = new Date();
+ }, 1000)
+ break;
+ default:
+ if (info['_type'] === "ipc" && info['action'] === "Ping") {
+ client.write(JSON.stringify({
+ _type: "ipc",
+ action: "Pong",
+ message: null
+ }))
+ return;
+ }
+ if (info['_type'] === "ipc" && info['action'] === "Pong") {
+ pingEnd = new Date();
+ ping = Math.round(pingEnd - pingStart);
+ global.pingStart = null;
+ console.log("Ping: " + ping + " ms");
+ return;
+ }
+ console.log("Data:");
+ console.dir(info);
+ break;
+ }
+ }
+})
+
+client.on('close', () => {
+ console.log("Kicked from server");
+ exit();
+})
+
+client.on('error', (e) => {
+ switch (e.code) {
+ case "ECONNREFUSED":
+ console.log("Unable to connect to server");
+ break;
+ default:
+ console.log("Internal error");
+ break;
+ }
+ crash(e);
+}) \ No newline at end of file
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..d4db372
--- /dev/null
+++ b/index.js
@@ -0,0 +1,353 @@
+const ServerPort = 8888;
+const AllowMods = false;
+
+const _version = "0.1";
+const Net = require('net');
+const clients = {};
+
+class MessageBuffer {
+ constructor(delimiter) {
+ this.delimiter = delimiter
+ this.buffer = ""
+ }
+
+ isFinished() {
+ if (
+ this.buffer.length === 0 ||
+ this.buffer.indexOf(this.delimiter) === -1
+ ) {
+ return true
+ }
+ return false
+ }
+
+ push(data) {
+ this.buffer += data
+ }
+
+ getMessage() {
+ const delimiterIndex = this.buffer.indexOf(this.delimiter)
+ if (delimiterIndex !== -1) {
+ const message = this.buffer.slice(0, delimiterIndex)
+ this.buffer = this.buffer.replace(message + this.delimiter, "")
+ return message
+ }
+ return null
+ }
+
+ handleData() {
+ /**
+ * Try to accumulate the buffer with messages
+ *
+ * If the server isnt sending delimiters for some reason
+ * then nothing will ever come back for these requests
+ */
+ const message = this.getMessage()
+ return message
+ }
+}
+
+class KartikError extends Error {
+ constructor(message, type) {
+ super(message);
+ this.name = "KartikError";
+ this.ktype = type;
+ }
+}
+
+const server = new Net.Server();
+
+server.on('connection', (socket) => {
+ socket.connectionId = (Math.random().toString(16).split(".")[1] + Math.random().toString(16).split(".")[1]).substr(0, 8);
+ socket.linkedTo = null;
+ clients[socket.connectionId] = socket;
+ console.log("New connection " + socket.connectionId)
+
+ socket.write(JSON.stringify(
+ {
+ _type: "init",
+ name: "Kartik Server",
+ version: _version,
+ id: socket.connectionId,
+ modded: null
+ }
+ ) + "\n")
+
+ setTimeout(() => {
+ try {
+ if (socket.linkedTo === null) {
+ throw new KartikError("Not linked within 3 minutes", "net.minteckprojects.kartik.KartikServer.ClientConnectTimeoutException");
+ }
+ } catch (e) {
+ console.error(e);
+ if (e.name !== "KartikError") {
+ e.ktype = "nodejs.lang." + e.name.replaceAll("Error", "Exception");
+ }
+ socket.write(JSON.stringify({
+ _type: "error",
+ message: e.message,
+ type: e.ktype
+ }) + "\n")
+ socket.end();
+ }
+ }, 180000)
+
+ /*let received = "";
+ socket.on("data", (data) => {
+ data = data.toString();
+
+ received = received + data.substr(1);
+ console.log("{{" + data + "}}");
+ if (data.startsWith(":")) {
+ return;
+ }
+ try {
+ raw = chunk.toString().replaceAll("}{", "}|{");
+
+ datas = raw.split("|").filter(i => i.trim() !== "");
+ datas.forEach((data) => {
+ try {
+ info = JSON.parse(data);
+ } catch(e) {
+ console.dir(data);
+ throw e;
+ }
+
+ if (data.length > 1200) {
+ console.dir(data);
+ throw new KartikError("Received data is too long", "net.minteckprojects.kartik.KartikServer.DataLengthException");
+ }
+
+ if (typeof info['_type'] != "string") {
+ throw new KartikError("Invalid JSON data", "net.minteckprojects.kartik.KartikServer.JsonDataException");
+ }
+ if (!socket.initialized) {
+ switch (info['_type']) {
+ case "init":
+ if (info['name'] !== "Kartik Core") {
+ throw new KartikError("Invalid client", "net.minteckprojects.kartik.KartikServer.AuthenticationException");
+ }
+ if (!info.modded) {
+ console.log("Connection initialized. Client running " + info.name + " version " + info.version + ", official client");
+ } else {
+ console.log("Connection initialized. Client running " + info.name + " version " + info.version + ", MODDED client");
+ if (!AllowMods) {
+ console.log("Modded clients are not accepted");
+ socket.end();
+ }
+ }
+ socket.initialized = true;
+ break;
+ default:
+ throw new KartikError("Trying to receive data but client not initialized", "net.minteckprojects.kartik.KartikServer.AuthenticationException");
+ }
+ } else {
+ switch (info['_type']) {
+ case "init":
+ throw new KartikError("Trying to initialize client but client is already initialized", "net.minteckprojects.kartik.KartikServer.AuthenticationException");
+ case "link":
+ if (typeof info['client'] !== "string" || isNaN(parseInt(info['client'], 16))) {
+ throw new KartikError("Invalid client link ID", "net.minteckprojects.kartik.KartikServer.GuestIdentifierException");
+ }
+ if (typeof clients[info['client']] === "undefined") {
+ throw new KartikError("Guest client not found", "net.minteckprojects.kartik.KartikServer.GuestConnectException");
+ }
+ if (clients[info['client']].linkedTo === null) {
+ socket.linkedTo = clients[info['client']];
+ clients[info['client']].linkedTo = socket;
+ socket.linkedTo.role = "host";
+ socket.linkedTo.write(JSON.stringify(
+ {
+ _type: "linked",
+ role: "host",
+ ids: {
+ host: socket.linkedTo.connectionId,
+ guest: socket.connectionId
+ }
+ }
+ ))
+ socket.role = "guest";
+ socket.write(JSON.stringify(
+ {
+ _type: "linked",
+ role: "guest",
+ ids: {
+ host: socket.linkedTo.connectionId,
+ guest: socket.connectionId
+ }
+ }
+ ))
+ console.log("Link created: (H) " + socket.connectionId + " <-> " + socket.linkedTo.connectionId + " (G)")
+ } else {
+ throw new KartikError("Client already linked to another client", "net.minteckprojects.kartik.KartikServer.GuestAllocationException")
+ }
+ break;
+ default:
+ if (socket.linkedTo === null) {
+ throw new KartikError("Client not linked to another client", "net.minteckprojects.kartik.KartikServer.DataRoutingException");
+ } else {
+ socket.linkedTo.write(JSON.stringify(info));
+ }
+ }
+ }
+ })
+ } catch (e) {
+ console.error(e);
+ if (e.name !== "KartikError") {
+ e.ktype = "nodejs.lang." + e.name.replaceAll("Error", "Exception");
+ }
+ socket.write(JSON.stringify({
+ _type: "error",
+ message: e.message,
+ type: e.ktype
+ }))
+ socket.end();
+ }
+ })*/
+
+ let received = new MessageBuffer("\n")
+ socket.on("data", data => {
+ received.push(data)
+ while (!received.isFinished()) {
+ const chunk = received.handleData()
+ try {
+ raw = chunk.toString().replaceAll("}{", "}|{");
+
+ datas = raw.split("|").filter(i => i.trim() !== "");
+ datas.forEach((data) => {
+ try {
+ info = JSON.parse(data);
+ } catch(e) {
+ console.dir(data);
+ throw e;
+ }
+
+ if (data.length > 1200) {
+ console.dir(data);
+ throw new KartikError("Received data is too long", "net.minteckprojects.kartik.KartikServer.DataLengthException");
+ }
+
+ if (typeof info['_type'] != "string") {
+ throw new KartikError("Invalid JSON data", "net.minteckprojects.kartik.KartikServer.JsonDataException");
+ }
+ if (!socket.initialized) {
+ switch (info['_type']) {
+ case "init":
+ if (info['name'] !== "Kartik Core") {
+ throw new KartikError("Invalid client", "net.minteckprojects.kartik.KartikServer.AuthenticationException");
+ }
+ if (!info.modded) {
+ console.log("Connection initialized. Client running " + info.name + " version " + info.version + ", official client");
+ } else {
+ console.log("Connection initialized. Client running " + info.name + " version " + info.version + ", MODDED client");
+ if (!AllowMods) {
+ console.log("Modded clients are not accepted");
+ socket.end();
+ }
+ }
+ socket.initialized = true;
+ break;
+ default:
+ throw new KartikError("Trying to receive data but client not initialized", "net.minteckprojects.kartik.KartikServer.AuthenticationException");
+ }
+ } else {
+ switch (info['_type']) {
+ case "init":
+ throw new KartikError("Trying to initialize client but client is already initialized", "net.minteckprojects.kartik.KartikServer.AuthenticationException");
+ case "link":
+ if (typeof info['client'] !== "string" || isNaN(parseInt(info['client'], 16))) {
+ throw new KartikError("Invalid client link ID", "net.minteckprojects.kartik.KartikServer.GuestIdentifierException");
+ }
+ if (typeof clients[info['client']] === "undefined") {
+ throw new KartikError("Guest client not found", "net.minteckprojects.kartik.KartikServer.GuestConnectException");
+ }
+ if (clients[info['client']].linkedTo === null) {
+ socket.linkedTo = clients[info['client']];
+ clients[info['client']].linkedTo = socket;
+ socket.linkedTo.role = "host";
+ socket.linkedTo.write(JSON.stringify(
+ {
+ _type: "linked",
+ role: "host",
+ ids: {
+ host: socket.linkedTo.connectionId,
+ guest: socket.connectionId
+ }
+ }
+ ) + "\n")
+ socket.role = "guest";
+ socket.write(JSON.stringify(
+ {
+ _type: "linked",
+ role: "guest",
+ ids: {
+ host: socket.linkedTo.connectionId,
+ guest: socket.connectionId
+ }
+ }
+ ) + "\n")
+ console.log("Link created: (H) " + socket.connectionId + " <-> " + socket.linkedTo.connectionId + " (G)")
+ } else {
+ throw new KartikError("Client already linked to another client", "net.minteckprojects.kartik.KartikServer.GuestAllocationException")
+ }
+ break;
+ default:
+ if (socket.linkedTo === null) {
+ throw new KartikError("Client not linked to another client", "net.minteckprojects.kartik.KartikServer.DataRoutingException");
+ } else {
+ socket.linkedTo.write(JSON.stringify(info) + "\n");
+ }
+ }
+ }
+ })
+ } catch (e) {
+ console.error(e);
+ if (e.name !== "KartikError") {
+ e.ktype = "nodejs.lang." + e.name.replaceAll("Error", "Exception");
+ }
+ socket.write(JSON.stringify({
+ _type: "error",
+ message: e.message,
+ type: e.ktype
+ }) + "\n")
+ socket.end();
+ }
+ }
+ })
+
+ socket.on('error', (err) => {
+ console.error(err);
+ try {
+ if (err.code === "ECONNRESET") {
+ try {
+ socket.linkedTo.end();
+ } catch (e) {
+ console.log("Cannot end other client's session");
+ }
+ }
+ } catch (e) {
+ console.log("Cannot check if connection reset")
+ }
+ })
+
+ socket.on('end', (chunk) => {
+ console.log("Connection from " + socket.connectionId + " closed");
+ if (socket.linkedTo !== null) {
+ if (socket.role === "guest") {
+ console.log("Link broken: (H) " + socket.linkedTo.connectionId + " <-> " + socket.connectionId + " (G)");
+ } else {
+ console.log("Link broken: (H) " + socket.connectionId + " <-> " + socket.linkedTo.connectionId + " (G)");
+ }
+ try {
+ socket.linkedTo.end();
+ } catch (e) {
+ console.log("Cannot end other client's session");
+ }
+ }
+ delete clients[socket.connectionId];
+ })
+})
+
+server.listen(ServerPort, () => {
+ console.log("Kartik Server " + _version + " listening for connections on 0.0.0.0:" + ServerPort)
+})
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..6013376
--- /dev/null
+++ b/package.json
@@ -0,0 +1,13 @@
+{
+ "name": "kartikserver",
+ "version": "1.0.0",
+ "description": "A server to play Kartik with online friends",
+ "main": "index.js",
+ "scripts": {
+ "test": "node index.js",
+ "run": "node index.js"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "GPL-3.0-or-later"
+}