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); };