Fix butlerd RPC -32700: normalize integral JSON floats to ints
Godot JSON.parse decodes every JSON number as a float, so integer ids (7670) round-trip through JSON.stringify as 7670.0, which Go's int64 fields reject with RPC error -32700. Normalize at the parse boundary so profile/game/upload ids serialize correctly. Also drop the nonexistent 'fresh' parameter from Fetch.ProfileOwnedKeys.
This commit is contained in:
parent
5d686a5b02
commit
408991a693
2 changed files with 33 additions and 7 deletions
|
|
@ -184,7 +184,7 @@ func _thread_process(_delta: float) -> void:
|
||||||
var line: String = lines[i].strip_edges()
|
var line: String = lines[i].strip_edges()
|
||||||
if line == "":
|
if line == "":
|
||||||
continue
|
continue
|
||||||
var parsed: Variant = JSON.parse_string(line)
|
var parsed: Variant = _normalize_json(JSON.parse_string(line))
|
||||||
if typeof(parsed) != TYPE_DICTIONARY:
|
if typeof(parsed) != TYPE_DICTIONARY:
|
||||||
continue
|
continue
|
||||||
var msg: Dictionary = parsed
|
var msg: Dictionary = parsed
|
||||||
|
|
@ -210,7 +210,7 @@ func _thread_process(_delta: float) -> void:
|
||||||
_recv_buffer = _recv_buffer.substr(idx + 1)
|
_recv_buffer = _recv_buffer.substr(idx + 1)
|
||||||
if line.strip_edges() == "":
|
if line.strip_edges() == "":
|
||||||
continue
|
continue
|
||||||
var parsed: Variant = JSON.parse_string(line)
|
var parsed: Variant = _normalize_json(JSON.parse_string(line))
|
||||||
if typeof(parsed) != TYPE_DICTIONARY:
|
if typeof(parsed) != TYPE_DICTIONARY:
|
||||||
continue
|
continue
|
||||||
var msg: Dictionary = parsed
|
var msg: Dictionary = parsed
|
||||||
|
|
@ -261,6 +261,33 @@ func _send_line(text: String) -> void:
|
||||||
socket.put_data((text + "\n").to_utf8_buffer())
|
socket.put_data((text + "\n").to_utf8_buffer())
|
||||||
|
|
||||||
|
|
||||||
|
## Godot's JSON.parse decodes every JSON number as a float (so 7670 becomes
|
||||||
|
## 7670.0), and JSON.stringify then re-serializes it as "7670.0". butlerd's Go
|
||||||
|
## structs use int64 for ids, and Go's encoding/json rejects "7670.0" for an
|
||||||
|
## int64 field (RPC error -32700). Normalizing integral floats back to ints at
|
||||||
|
## the parse boundary keeps every id (profileId, game.id, upload.id, ...)
|
||||||
|
## typed correctly so downstream RPC params serialize without the trailing
|
||||||
|
## ".0".
|
||||||
|
func _normalize_json(value: Variant) -> Variant:
|
||||||
|
match typeof(value):
|
||||||
|
TYPE_DICTIONARY:
|
||||||
|
var out := {}
|
||||||
|
for key in value:
|
||||||
|
out[key] = _normalize_json(value[key])
|
||||||
|
return out
|
||||||
|
TYPE_ARRAY:
|
||||||
|
var out := []
|
||||||
|
for item in value:
|
||||||
|
out.append(_normalize_json(item))
|
||||||
|
return out
|
||||||
|
TYPE_FLOAT:
|
||||||
|
if is_finite(value) and value == floor(value):
|
||||||
|
return int(value)
|
||||||
|
return value
|
||||||
|
_:
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
## Sends a JSON-RPC request and waits (via signal await, not a busy loop, so
|
## Sends a JSON-RPC request and waits (via signal await, not a busy loop, so
|
||||||
## [method _thread_process] keeps ticking and can deliver the response) for
|
## [method _thread_process] keeps ticking and can deliver the response) for
|
||||||
## the matching response. Mirrors the `_wait_for_command` pattern used by the
|
## the matching response. Mirrors the `_wait_for_command` pattern used by the
|
||||||
|
|
@ -306,16 +333,15 @@ func _login_with_api_key(api_key: String) -> void:
|
||||||
|
|
||||||
## Returns every game the logged-in profile owns a download key for.
|
## Returns every game the logged-in profile owns a download key for.
|
||||||
## Each item looks like: {"downloadKey": {...}, "game": {...}}
|
## Each item looks like: {"downloadKey": {...}, "game": {...}}
|
||||||
func get_owned_games(fresh: bool = false) -> Array:
|
func get_owned_games() -> Array:
|
||||||
return await thread_group.exec(_get_owned_games.bind(fresh))
|
return await thread_group.exec(_get_owned_games)
|
||||||
|
|
||||||
|
|
||||||
func _get_owned_games(fresh: bool) -> Array:
|
func _get_owned_games() -> Array:
|
||||||
if not is_logged_in:
|
if not is_logged_in:
|
||||||
return []
|
return []
|
||||||
var res := await _rpc_call("Fetch.ProfileOwnedKeys", {
|
var res := await _rpc_call("Fetch.ProfileOwnedKeys", {
|
||||||
"profileId": profile.get("user", {}).get("id", profile.get("id", 0)),
|
"profileId": profile.get("user", {}).get("id", profile.get("id", 0)),
|
||||||
"fresh": fresh,
|
|
||||||
})
|
})
|
||||||
if "error" in res:
|
if "error" in res:
|
||||||
logger.warn("Fetch.ProfileOwnedKeys failed: " + str(res["error"]))
|
logger.warn("Fetch.ProfileOwnedKeys failed: " + str(res["error"]))
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ func _load_library(caching_flags: int = Cache.FLAGS.LOAD | Cache.FLAGS.SAVE) ->
|
||||||
return []
|
return []
|
||||||
|
|
||||||
logger.info("Fetching itch.io library...")
|
logger.info("Fetching itch.io library...")
|
||||||
var owned: Array = await itch.get_owned_games(false)
|
var owned: Array = await itch.get_owned_games()
|
||||||
var caves: Array = await itch.get_caves()
|
var caves: Array = await itch.get_caves()
|
||||||
|
|
||||||
var caves_by_game_id := {}
|
var caves_by_game_id := {}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue