Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions building/libs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<git name="hxdiscord_rpc" url="https://github.com/CodenameCrew/cne-hxdiscord_rpc" ref="old" skipDeps="true" />
<lib name="funkin-modchart" skipDeps="true" />
<lib name="hxvlc" version="1.9.3" skipDeps="true" />
<lib name="hxWebSockets" />

<!-- Documentation and other features -->
<git name="away3d" url="https://github.com/CodenameCrew/away3d" />
Expand Down
2 changes: 2 additions & 0 deletions project.xml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@
<haxelib name="flixel" />
<haxelib name="flixel-addons" />

<haxelib name="hxWebSockets" />

<haxelib name="hxvlc" if="VIDEO_CUTSCENES" />
<haxelib name="away3d" if="THREE_D_SUPPORT" />
<haxelib name="format" />
Expand Down
65 changes: 65 additions & 0 deletions source/funkin/backend/system/net/FunkinPacket.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package funkin.backend.system.net;

import flixel.util.typeLimit.OneOfTwo;

import haxe.io.Bytes;
import haxe.io.BytesOutput;

class FunkinPacket implements haxe.Constraints.IMap<String, Dynamic> {
// Status of the packet. 200 is an OK response.
public var status:Int = -1;

// The JSON fields of the packet, as a Map.
private var fields:Map<String, Dynamic> = [];

// If the recieved data is binary or contains binary, this will contain the raw bytes.
public var bytes:Bytes = null;

public function new() { }

public static function fromJson(json:OneOfTwo<String, haxe.DynamicAccess<Dynamic>>):Null<FunkinPacket> {
var packet = new FunkinPacket();
packet.appendJson(json);
return packet;
}

public function appendJson(json:OneOfTwo<String, haxe.DynamicAccess<Dynamic>>):Void {
var parsedJson:haxe.DynamicAccess<Dynamic> = (json is String) ? haxe.Json.parse(json) : json;
if (parsedJson == null) return;

for (key => value in parsedJson) this.set(key, value);
}

public function toJson():haxe.DynamicAccess<Dynamic> {
var json:haxe.DynamicAccess<Dynamic> = {};
for (key => value in fields) json[key] = value;
return json;
}

inline public function stringify():String { return haxe.Json.stringify(toJson()); }

public function toBytes():Bytes {
var output = new BytesOutput();
output.writeString(haxe.Json.stringify(toJson()));
return output.getBytes();
}

inline public function get(key:String):Null<Dynamic> { return fields.get(key); }
inline public function set(key:String, value:Dynamic):Void { fields.set(key, value); }
inline public function exists(key:String):Bool { return fields.exists(key); }
inline public function remove(key:String):Bool { return fields.remove(key); }

inline public function keys():Iterator<String> { return fields.keys(); }
inline public function iterator():Iterator<Dynamic> { return fields.iterator(); }
inline public function keyValueIterator():KeyValueIterator<String, Dynamic> { return fields.keyValueIterator(); }

public function copy():FunkinPacket {
var copy = new FunkinPacket();
copy.fields = this.fields.copy();
copy.status = this.status;
return copy;
}

inline public function clear():Void { fields.clear(); }
inline public function toString():String { return 'FunkinPacket (Status: $status)'; }
}
129 changes: 129 additions & 0 deletions source/funkin/backend/system/net/FunkinSocket.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package funkin.backend.system.net;

#if sys
import sys.net.Host;
import sys.net.Socket as SysSocket;
import haxe.io.Bytes;

@:keep
class FunkinSocket implements IFlxDestroyable {
public var socket:SysSocket = new SysSocket();

public var metrics:Metrics = new Metrics();

public var FAST_SEND(default, set):Bool = true;
private function set_FAST_SEND(value:Bool):Bool {
FAST_SEND = value;
socket.setFastSend(value);
return value;
}
public var BLOCKING(default, set):Bool = false;
private function set_BLOCKING(value:Bool):Bool {
BLOCKING = value;
socket.setBlocking(value);
return value;
}

public var host:Host;
public var port:Int;

public function new(?_host:String = "127.0.0.1", ?_port:Int = 5000) {
FAST_SEND = true;
BLOCKING = false;
this.host = new Host(_host);
this.port = _port;
}

// Reading Area
public function readAll():Null<Bytes> {
try {
var bytes = this.socket.input.readAll();
if (bytes == null) return null;
metrics.updateBytesReceived(bytes.length);
return bytes;
} catch(e) { }
return null;
}
public function readLine():Null<String> {
try {
var bytes = this.socket.input.readLine();
if (bytes == null) return null;
metrics.updateBytesReceived(bytes.length);
return bytes;
} catch(e) { }
return null;
}
public function read(nBytes:Int):Null<Bytes> {
try {
var bytes = this.socket.input.read(nBytes);
if (bytes == null) return null;
metrics.updateBytesReceived(bytes.length);
return bytes;
} catch(e) { }
return null;
}
public function readBytes(bytes:Bytes):Int {
try {
var length = this.socket.input.readBytes(bytes, 0, bytes.length);
metrics.updateBytesReceived(length);
return length;
} catch(e) { }
return 0;
}

// Writing Area
public function prepare(nbytes:Int):Void { socket.output.prepare(nbytes); }
public function write(bytes:Bytes):Bool {
try {
this.socket.output.write(bytes);
metrics.updateBytesSent(bytes.length);
return true;
} catch (e) { }
return false;
}
public function writeString(str:String):Bool {
try {
this.socket.output.writeString(str);
metrics.updateBytesSent(Bytes.ofString(str).length);
return true;
} catch(e) { }
return false;
}

public function bind(?expectingConnections:Int = 1):FunkinSocket {
Logs.traceColored([
Logs.logText('[FunkinSocket] ', BLUE),
Logs.logText('Binding to ', NONE), Logs.logText(host.toString(), YELLOW), Logs.logText(':', NONE), Logs.logText(Std.string(port), CYAN),
]);
socket.bind(host, port);
socket.listen(expectingConnections);
return this;
}

public function connect():FunkinSocket {
Logs.traceColored([
Logs.logText('[FunkinSocket] ', BLUE),
Logs.logText('Connecting to ', NONE), Logs.logText(host.toString(), YELLOW), Logs.logText(':', NONE), Logs.logText(Std.string(port), CYAN),
]);
socket.connect(host, port);
return this;
}

public function close() {
try {
if (socket != null) socket.close();
Logs.traceColored([
Logs.logText('[FunkinSocket] ', BLUE),
Logs.logText('Closing socket from ', NONE), Logs.logText(host.toString(), YELLOW), Logs.logText(':', NONE), Logs.logText(Std.string(port), CYAN),
]);
} catch(e) {
Logs.traceColored([
Logs.logText('[FunkinSocket] ', BLUE),
Logs.logText('Failed to close socket: ${e}', NONE),
]);
}
}

public function destroy() { close(); }
}
#end
Loading