1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
use dejson;
use encoding::json;
use mcproto;
use strings;
use trace;
use uuid;
export type Response = struct {
description: str,
version_name: str,
version_protocol: i32,
players_online: u32,
players_max: u32,
players_sample: [](str, uuid::uuid),
previews_chat: bool,
forces_reportable_chat: bool,
};
export fn decode_response(ctx: *mcproto::Context) (Response | trace::failed) = {
const ctx_ = mcproto::context(ctx, "json");
const json = mcproto::decode_string(&ctx_, 32767)?;
mcproto::expect_end(ctx)?;
const json = match (json::loadstr(json)) {
case let json: json::value =>
yield json;
case let err: json::error =>
return mcproto::error(&ctx_, "Invalid JSON: {}", json::strerror(err));
};
defer json::finish(json);
const deser = dejson::newdeser(&json);
match (deser_response(&deser)) {
case let res: Response =>
return res;
case let err: dejson::error =>
defer free(err);
return mcproto::error(&ctx_, "Invalid response contents: {}", err);
};
};
export fn deser_response(de: *dejson::deser) (Response | dejson::error) = {
let success = false;
let res = Response { ... };
defer if (!success) response_finish(res);
res.description = match (dejson::optfield(de, "description")?) {
case let de_description: dejson::deser =>
yield json::dumpstr(*de_description.val);
case void =>
yield "";
};
const de_version = dejson::field(de, "version")?;
res.version_name = strings::dup(dejson::string(
&dejson::field(&de_version, "name")?)?);
res.version_protocol = dejson::number_i32(
&dejson::field(&de_version, "protocol")?)?;
const de_players = dejson::field(de, "players")?;
res.players_online = dejson::number_u32(
&dejson::field(&de_players, "online")?)?;
res.players_max = dejson::number_u32(
&dejson::field(&de_players, "max")?)?;
match (dejson::optfield(&de_players, "sample")?) {
case let de_sample: dejson::deser =>
const nsample = dejson::length(&de_sample)?;
for (let i = 0z; i < nsample; i += 1) {
const de_player = dejson::index(&de_sample, i)?;
const name = dejson::string(
&dejson::field(&de_player, "name")?)?;
const de_id = dejson::field(&de_player, "id")?;
const id = dejson::string(&de_id)?;
const id = match (uuid::decodestr(id)) {
case let id: uuid::uuid =>
yield id;
case uuid::invalid =>
return dejson::fail(&de_id, "Invalid UUID");
};
append(res.players_sample, (strings::dup(name), id));
};
case void => void;
};
res.previews_chat = match (dejson::optfield(de, "previewsChat")) {
case let de_previews_chat: dejson::deser =>
yield dejson::boolean(&de_previews_chat)?;
case void =>
yield false;
};
res.forces_reportable_chat = match (
dejson::optfield(de, "enforcesSecureChat")) {
case let de_forces_reportable_chat: dejson::deser =>
yield dejson::boolean(&de_forces_reportable_chat)?;
case void =>
yield false;
};
success = true;
return res;
};
export fn response_finish(res: Response) void = {
free(res.description);
free(res.version_name);
for (let i = 0z; i < len(res.players_sample); i += 1) {
free(res.players_sample[i].0);
};
free(res.players_sample);
};
|