Skip to content

Commit 874e046

Browse files
ItsLJcoolRaltyro
authored andcommitted
Implements hxWebSockets, and Implements Functionality to connect to a Server as a Client. (#803)
* peak incoming * FUCKING HELL I GIVE UP FUCK IT USE hxWebSocket BRUHH * it just works :trollface: * Implementing a way to addon to the Handshake Header * so guys, i am the smart, trust :trollface: * Properly converts the message from the server into either String, Bytes, FunkinPacket. * Documentation on `FunkinWebSocket` and added `Metrics` to it :) * whoop * Reformatted how `FunkinPacket` is managed, and fixed some issues in `FunkinWebSocket`, and update it to reflect new `FunkinPacket` * Small fixes and small features I forgor to implement * ocd bro I can't leave this chilling in changes bro im sorry * fix to ensure that `fromJson` and `appendJson` in `FunkinPacket` will never return null ig * Fixed an issue where the client would crash if the server sent a raw string. * QOL implementation to actually use `FunkinPacket.status` inside `FunkinWebSocket` * implement `send_bytes` in source with Threading, so you can send large binary files easier
1 parent c77d5de commit 874e046

7 files changed

Lines changed: 511 additions & 65 deletions

File tree

building/libs.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
<git name="hxdiscord_rpc" url="https://github.com/CodenameCrew/cne-hxdiscord_rpc" ref="old" skipDeps="true" />
1717
<lib name="funkin-modchart" skipDeps="true" />
1818
<lib name="hxvlc" version="1.9.3" skipDeps="true" />
19+
<lib name="hxWebSockets" />
1920

2021
<!-- Documentation and other features -->
2122
<git name="away3d" url="https://github.com/CodenameCrew/away3d" />

project.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@
130130
<haxelib name="flixel" />
131131
<haxelib name="flixel-addons" />
132132

133+
<haxelib name="hxWebSockets" />
134+
133135
<haxelib name="hxvlc" if="VIDEO_CUTSCENES" />
134136
<haxelib name="away3d" if="THREE_D_SUPPORT" />
135137
<haxelib name="format" />
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package funkin.backend.system.net;
2+
3+
import flixel.util.typeLimit.OneOfTwo;
4+
5+
import haxe.io.Bytes;
6+
import haxe.io.BytesOutput;
7+
8+
class FunkinPacket implements haxe.Constraints.IMap<String, Dynamic> {
9+
// Status of the packet. 200 is an OK response.
10+
public var status:Int = -1;
11+
12+
// The JSON fields of the packet, as a Map.
13+
private var fields:Map<String, Dynamic> = [];
14+
15+
// If the recieved data is binary or contains binary, this will contain the raw bytes.
16+
public var bytes:Bytes = null;
17+
18+
public function new() {}
19+
20+
public static function fromJson(json:OneOfTwo<String, haxe.DynamicAccess<Dynamic>>):FunkinPacket { return (new FunkinPacket().appendJson(json)); }
21+
22+
public function appendJson(json:OneOfTwo<String, haxe.DynamicAccess<Dynamic>>):FunkinPacket {
23+
var parsedJson:haxe.DynamicAccess<Dynamic>;
24+
if (json is String) {
25+
try {
26+
parsedJson = haxe.Json.parse(json);
27+
if (parsedJson == null) return this;
28+
29+
} catch(e) {
30+
this.set("message", json);
31+
return this;
32+
}
33+
} else parsedJson = json;
34+
for (key => value in parsedJson) this.set(key, value);
35+
return this;
36+
}
37+
38+
public function toJson():haxe.DynamicAccess<Dynamic> {
39+
var json:haxe.DynamicAccess<Dynamic> = {};
40+
for (key => value in fields) json[key] = value;
41+
return json;
42+
}
43+
44+
inline public function stringify():String { return haxe.Json.stringify(toJson()); }
45+
46+
public function toBytes():Bytes {
47+
var output = new BytesOutput();
48+
output.writeString(haxe.Json.stringify(toJson()));
49+
return output.getBytes();
50+
}
51+
52+
inline public function get(key:String):Null<Dynamic> { return fields.get(key); }
53+
inline public function set(key:String, value:Dynamic):Void { fields.set(key, value); }
54+
inline public function exists(key:String):Bool { return fields.exists(key); }
55+
inline public function remove(key:String):Bool { return fields.remove(key); }
56+
57+
inline public function keys():Iterator<String> { return fields.keys(); }
58+
inline public function iterator():Iterator<Dynamic> { return fields.iterator(); }
59+
inline public function keyValueIterator():KeyValueIterator<String, Dynamic> { return fields.keyValueIterator(); }
60+
61+
public function copy():FunkinPacket {
62+
var copy = new FunkinPacket();
63+
copy.fields = this.fields.copy();
64+
copy.status = this.status;
65+
return copy;
66+
}
67+
68+
inline public function clear():Void { fields.clear(); }
69+
inline public function toString():String { return 'FunkinPacket (Status: $status)'; }
70+
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package funkin.backend.system.net;
2+
3+
#if sys
4+
import sys.net.Host;
5+
import sys.net.Socket as SysSocket;
6+
import haxe.io.Bytes;
7+
8+
@:keep
9+
class FunkinSocket implements IFlxDestroyable {
10+
public var socket:SysSocket = new SysSocket();
11+
12+
public var metrics:Metrics = new Metrics();
13+
14+
public var FAST_SEND(default, set):Bool = true;
15+
private function set_FAST_SEND(value:Bool):Bool {
16+
FAST_SEND = value;
17+
socket.setFastSend(value);
18+
return value;
19+
}
20+
public var BLOCKING(default, set):Bool = false;
21+
private function set_BLOCKING(value:Bool):Bool {
22+
BLOCKING = value;
23+
socket.setBlocking(value);
24+
return value;
25+
}
26+
27+
public var host:Host;
28+
public var port:Int;
29+
30+
public function new(?_host:String = "127.0.0.1", ?_port:Int = 5000) {
31+
FAST_SEND = true;
32+
BLOCKING = false;
33+
this.host = new Host(_host);
34+
this.port = _port;
35+
}
36+
37+
// Reading Area
38+
public function readAll():Null<Bytes> {
39+
try {
40+
var bytes = this.socket.input.readAll();
41+
if (bytes == null) return null;
42+
metrics.updateBytesReceived(bytes.length);
43+
return bytes;
44+
} catch(e) { }
45+
return null;
46+
}
47+
public function readLine():Null<String> {
48+
try {
49+
var bytes = this.socket.input.readLine();
50+
if (bytes == null) return null;
51+
metrics.updateBytesReceived(bytes.length);
52+
return bytes;
53+
} catch(e) { }
54+
return null;
55+
}
56+
public function read(nBytes:Int):Null<Bytes> {
57+
try {
58+
var bytes = this.socket.input.read(nBytes);
59+
if (bytes == null) return null;
60+
metrics.updateBytesReceived(bytes.length);
61+
return bytes;
62+
} catch(e) { }
63+
return null;
64+
}
65+
public function readBytes(bytes:Bytes):Int {
66+
try {
67+
var length = this.socket.input.readBytes(bytes, 0, bytes.length);
68+
metrics.updateBytesReceived(length);
69+
return length;
70+
} catch(e) { }
71+
return 0;
72+
}
73+
74+
// Writing Area
75+
public function prepare(nbytes:Int):Void { socket.output.prepare(nbytes); }
76+
public function write(bytes:Bytes):Bool {
77+
try {
78+
this.socket.output.write(bytes);
79+
metrics.updateBytesSent(bytes.length);
80+
return true;
81+
} catch (e) { }
82+
return false;
83+
}
84+
public function writeString(str:String):Bool {
85+
try {
86+
this.socket.output.writeString(str);
87+
metrics.updateBytesSent(Bytes.ofString(str).length);
88+
return true;
89+
} catch(e) { }
90+
return false;
91+
}
92+
93+
public function bind(?expectingConnections:Int = 1):FunkinSocket {
94+
Logs.traceColored([
95+
Logs.logText('[FunkinSocket] ', BLUE),
96+
Logs.logText('Binding to ', NONE), Logs.logText(host.toString(), YELLOW), Logs.logText(':', NONE), Logs.logText(Std.string(port), CYAN),
97+
]);
98+
socket.bind(host, port);
99+
socket.listen(expectingConnections);
100+
return this;
101+
}
102+
103+
public function connect():FunkinSocket {
104+
Logs.traceColored([
105+
Logs.logText('[FunkinSocket] ', BLUE),
106+
Logs.logText('Connecting to ', NONE), Logs.logText(host.toString(), YELLOW), Logs.logText(':', NONE), Logs.logText(Std.string(port), CYAN),
107+
]);
108+
socket.connect(host, port);
109+
return this;
110+
}
111+
112+
public function close() {
113+
try {
114+
if (socket != null) socket.close();
115+
Logs.traceColored([
116+
Logs.logText('[FunkinSocket] ', BLUE),
117+
Logs.logText('Closing socket from ', NONE), Logs.logText(host.toString(), YELLOW), Logs.logText(':', NONE), Logs.logText(Std.string(port), CYAN),
118+
]);
119+
} catch(e) {
120+
Logs.traceColored([
121+
Logs.logText('[FunkinSocket] ', BLUE),
122+
Logs.logText('Failed to close socket: ${e}', NONE),
123+
]);
124+
}
125+
}
126+
127+
public function destroy() { close(); }
128+
}
129+
#end

0 commit comments

Comments
 (0)