Attempt to using Nakama as replacement of Low-Level ENet

This commit is contained in:
2025-12-02 00:58:44 +08:00
parent b27b612989
commit ead155afed
74 changed files with 14205 additions and 23315 deletions
@@ -0,0 +1,34 @@
extends RefCounted
class_name SatoriAsyncResult
var exception : SatoriException:
set(v):
pass
get:
return get_exception()
var _ex = null
func _init(p_ex = null):
_ex = p_ex
func is_exception():
return get_exception() != null
func was_cancelled():
return is_exception() and get_exception().cancelled
func get_exception() -> SatoriException:
return _ex as SatoriException
func _to_string():
if is_exception():
return get_exception()._to_string()
return "SatoriAsyncResult<>"
static func _safe_ret(p_obj, p_type : GDScript):
if is_instance_of(p_obj, p_type):
return p_obj
elif p_obj is SatoriException:
return p_type.new(p_obj)
return p_type.new(SatoriException.new())
@@ -0,0 +1 @@
uid://dhrty7nqady0k
@@ -0,0 +1,42 @@
extends RefCounted
# An exception generated during a request.
# Usually contains at least an error message.
class_name SatoriException
var _status_code : int = -1
var status_code : int:
set(v):
pass
get:
return _status_code
var _grpc_status_code : int = -1
var grpc_status_code : int:
set(v):
pass
get:
return _grpc_status_code
var _message : String = ""
var message : String:
set(v):
pass
get:
return _message
var _cancelled : bool = false
var cancelled : bool:
set(v):
pass
get:
return _cancelled
func _init(p_message : String = "", p_status_code : int = -1, p_grpc_status_code : int = -1, p_cancelled : bool = false):
_status_code = p_status_code
_grpc_status_code = p_grpc_status_code
_message = p_message
_cancelled = p_cancelled
func _to_string() -> String:
return "SatoriException(StatusCode={%s}, Message='{%s}', GrpcStatusCode={%s})" % [_status_code, _message, _grpc_status_code]
@@ -0,0 +1 @@
uid://ds56ldehv1e2i
@@ -0,0 +1,38 @@
extends RefCounted
class_name SatoriLogger
enum LOG_LEVEL {NONE, ERROR, WARNING, INFO, VERBOSE, DEBUG}
var _level = LOG_LEVEL.ERROR
var _module = "Satori"
func _init(p_module : String = "Satori", p_level : int = LOG_LEVEL.ERROR):
_level = p_level
_module = p_module
func _log(level : int, msg):
if level <= _level:
if level == LOG_LEVEL.ERROR:
printerr("=== %s : ERROR === %s" % [_module, str(msg)])
else:
var what = "=== UNKNOWN === "
for k in LOG_LEVEL:
if level == LOG_LEVEL[k]:
what = "=== %s : %s === " % [_module, k]
break
print(what + str(msg))
func error(msg):
_log(LOG_LEVEL.ERROR, msg)
func warning(msg):
_log(LOG_LEVEL.WARNING, msg)
func info(msg):
_log(LOG_LEVEL.INFO, msg)
func verbose(msg):
_log(LOG_LEVEL.VERBOSE, msg)
func debug(msg):
_log(LOG_LEVEL.DEBUG, msg)
@@ -0,0 +1 @@
uid://dk3qpgkfd74x0
@@ -0,0 +1,163 @@
extends RefCounted
class_name SatoriSerializer
static func serialize(p_obj : Object) -> Dictionary:
var out = {}
var schema = p_obj.get("_SCHEMA")
if schema == null:
return {} # No schema defined
for k in schema:
var prop = schema[k]
var val = p_obj.get(prop["name"])
if val == null:
continue
var type = prop["type"]
var content = prop.get("content", TYPE_NIL)
if typeof(content) == TYPE_STRING:
content = TYPE_OBJECT
var val_type = typeof(val)
match val_type:
TYPE_OBJECT: # Simple objects
out[k] = serialize(val)
TYPE_ARRAY: # Array of objects
var arr = []
if val.size() > 0 and typeof(val[0]) == TYPE_OBJECT: # Array of objects
for e in val:
arr.append(serialize(e))
else:
arr = val
out[k] = arr
TYPE_PACKED_INT32_ARRAY, TYPE_PACKED_STRING_ARRAY: # Array of ints, bools, or strings
var arr = []
for e in val:
if content == TYPE_BOOL:
e = bool(e)
if typeof(e) != content:
continue
arr.append(e)
out[k] = arr
TYPE_DICTIONARY: # Maps
var dict = {}
if content == TYPE_OBJECT: # Map of objects
for l in val:
if typeof(val[l]) != TYPE_OBJECT:
continue
dict[l] = serialize(val[l])
else: # Map of simple types
for l in val:
var e = val[l]
if content == TYPE_FLOAT:
e = float(e)
elif content == TYPE_INT:
e = int(e)
elif content == TYPE_BOOL:
e = bool(e)
if typeof(e) != content:
continue
dict[l] = e
out[k] = dict
_:
out[k] = val
return out
static func deserialize(p_ns : GDScript, p_cls_name : String, p_dict : Dictionary) -> Object:
var cls : GDScript = p_ns.get(p_cls_name)
var schema = cls.get("_SCHEMA")
if schema == null:
return SatoriException.new() # No schema defined
var obj = cls.new()
for k in schema:
var prop = schema[k]
var pname = prop["name"]
var type = prop["type"]
var required = prop["required"]
var content = prop.get("content", TYPE_NIL)
var type_cmp = type
if typeof(type) == TYPE_STRING: # A class
type_cmp = TYPE_DICTIONARY
if type_cmp == TYPE_PACKED_STRING_ARRAY or type_cmp == TYPE_PACKED_INT32_ARRAY: # A specialized array
type_cmp = TYPE_ARRAY
var content_cmp = content
if typeof(content) == TYPE_STRING: # A dictionary or array of classes
content_cmp = TYPE_DICTIONARY
var val = p_dict.get(k, null)
# Ints might and up being recognized as floats. Change that if needed
if type_cmp == TYPE_INT:
if typeof(val) == TYPE_FLOAT:
val = int(val)
elif typeof(val) == TYPE_STRING and val.is_valid_int():
val = val.to_int()
if typeof(val) == type_cmp:
if typeof(type) == TYPE_STRING:
obj.set(pname, deserialize(p_ns, type, val))
elif type_cmp == TYPE_DICTIONARY:
var v = {}
for l in val:
if typeof(content) == TYPE_STRING:
v[l] = deserialize(p_ns, content, val[l])
elif content == TYPE_FLOAT:
v[l] = float(val[l])
elif content == TYPE_INT:
v[l] = int(val[l])
elif content == TYPE_BOOL:
v[l] = bool(val[l])
else:
v[l] = str(val[l])
obj.set(pname, v)
elif type_cmp == TYPE_ARRAY:
var v
match content:
TYPE_INT, TYPE_BOOL: v = PackedInt32Array()
TYPE_STRING: v = PackedStringArray()
_: v = Array()
for e in val:
if typeof(e) == TYPE_DICTIONARY:
v.append(e) # Avoid deserialization if e is already a dictionary
elif typeof(content) == TYPE_STRING:
v.append(deserialize(p_ns, content, e))
elif content == TYPE_FLOAT:
v.append(float(e))
elif content == TYPE_INT:
v.append(int(e))
elif content == TYPE_BOOL:
v.append(bool(e))
else:
v.append(str(e))
obj.set(pname, v)
else:
obj.set(pname, val)
elif required:
obj._ex = SatoriException.new("ERROR [%s]: Missing or invalid required prop %s = %s:\n\t%s" % [p_cls_name, prop, p_dict.get(k), p_dict])
return obj
return obj
###
# Compatibility with Godot 3.1 which does not expose String.http_escape
###
const HEX = ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"]
static func escape_http(p_str : String) -> String:
var out : String = ""
for o in p_str:
if (o == '.' or o == '-' or o == '_' or o == '~' or
(o >= 'a' and o <= 'z') or
(o >= 'A' and o <= 'Z') or
(o >= '0' and o <= '9')):
out += o
else:
for b in o.to_utf8_buffer():
out += "%%%s" % to_hex(b)
return out
static func to_hex(p_val : int) -> String:
var v := p_val
var o := ""
while v != 0:
o = HEX[v % 16] + o
v /= 16
return o
@@ -0,0 +1 @@
uid://dcgodt1wuq4ei