diff options
| -rw-r--r-- | main.c3 | 28 | ||||
| -rw-r--r-- | radapi.c3 | 821 |
2 files changed, 795 insertions, 54 deletions
@@ -21,6 +21,8 @@ module radgen; import std::io; import std::encoding::json; import std::collections::object; +import std::collections::pair; +import std::math::random; import curl; import radapi; @@ -30,22 +32,18 @@ fn int main(String[] args) { Client* c = radapi::new_client(url); - c.request(Request.REPO_ROOT, "?show=all&perPage=16384&page=0"); - - Object* j = json::tparse(c.response())!!; - - int i = 0; - while (i < j.array.len()) + Node n = c.request(Request.NODE, "", {}).node; + io::printn(n.id); + Rid[] rds = c.request(Request.NODES_INVENTORY, "?perPage=100000000&show=all", {.nid = n.id}).nodes_inventory; + while (true) { - io::print(j.get_at(i).get_string("rid"))!!; - io::print(" "); - io::printn(j.get_at(i).get("payloads").get("xyz.radicle.project").get("data").get_string("name"))!!; - i++; + int j = rand(rds.len); + io::printn(rds[j]); + Commit[] cs = c.request(Request.HISTORY, "", {.rid = rds[j]}).history; + int i = rand(cs.len); + io::printn(cs[i].id); + CommitFull cf = c.request(Request.COMMIT, "", {.rid = rds[j], .sha = cs[i].id}).commit; + io::printn(cf); } - - c.request(Request.REPO, "", j.get_at(0).get_string("rid"))!!; - - io::printn((String)c.buffer.[..c.buffer_index]); - return 0; } @@ -20,36 +20,326 @@ module radapi; import std::io; import std::core::string; +import std::collections::pair; +import std::collections::object; +import std::collections::maybe; +import std::encoding::json; import curl; -enum Request : int (String path, int args) +enum Request : int (String path) { - DELEGATES_REPOS { "/delegates/$1/repos", 1 }, - NODE { "/node", 0 }, - NODE_POLICIES_REPOS { "/node/policies/repos", 0 }, - NODE_POLICIES_REPO { "/node/policies/repos/$1", 1 }, - NODES { "/nodes/$1", 1 }, - NODES_INVENTORY { "/nodes/$1/inventory", 1 }, - REPO_ROOT { "/repos", 0 }, - REPO_SEARCH { "/repos/search", 0 }, - REPO { "/repos/$1", 1 }, - HISTORY { "/repos/$1/commits", 1 }, - COMMIT { "/repos/$1/commits/$2", 2 }, - DIFF { "/repos/$1/diff/$2/$3", 3 }, - ACTIVITY { "/repos/$1/activity", 1 }, - TREE_ROOT { "/repos/$1/tree/$2/", 2 }, - TREE { "/repos/$1/tree/$2/$3", 3 }, - STATS_TREE { "/repos/$1/stats/tree/$2", 2 }, - REMOTES { "/repos/$1/remotes", 1 }, - REMOTE { "/repos/$1/remotes/$2", 2 }, - BLOB { "/repos/$1/blob/$2/$3", 3 }, - README { "/repos/$1/readme/$2", 2 }, - JOB { "/repos/$1/jobs/$2", 2 }, - ISSUES { "/repos/$1/issues", 1 }, - ISSUE { "/repos/$1/issues/$2", 2 }, - PATCHES { "/repos/$1/patches", 1 }, - PATCH { "/repos/$1/patches/$2", 2 }, - STATS { "/stats", 0 }, + DELEGATES_REPOS { "/delegates/{did}/repos" }, + NODE { "/node" }, + NODE_POLICIES_REPOS { "/node/policies/repos" }, + NODE_POLICIES_REPO { "/node/policies/repos/{rid}" }, + NODES { "/nodes/{nid}" }, + NODES_INVENTORY { "/nodes/{nid}/inventory" }, + REPO_ROOT { "/repos" }, + REPO_SEARCH { "/repos/search" }, + REPO { "/repos/{rid}" }, + HISTORY { "/repos/{rid}/commits" }, + COMMIT { "/repos/{rid}/commits/{sha}" }, + DIFF { "/repos/{rid}/diff/{base}/{oid}" }, + ACTIVITY { "/repos/{rid}/activity" }, + TREE_ROOT { "/repos/{rid}/tree/{sha}/" }, + TREE { "/repos/{rid}/tree/{sha}/{path}" }, + STATS_TREE { "/repos/{rid}/stats/tree/{sha}" }, + REMOTES { "/repos/{rid}/remotes" }, + REMOTE { "/repos/{rid}/remotes/{peer}" }, + BLOB { "/repos/{rid}/blob/{sha}/{path}" }, + README { "/repos/{rid}/readme/{sha}" }, + JOB { "/repos/{rid}/jobs/{sha}" }, + ISSUES { "/repos/{rid}/issues" }, + ISSUE { "/repos/{rid}/issues/{id}" }, + PATCHES { "/repos/{rid}/patches" }, + PATCH { "/repos/{rid}/patches/{id}" }, + STATS { "/stats" }, +} + +alias ResponseRaw = String; + +struct SearchRepo +{ + Rid rid; + struct payloads + { + struct xyz { struct radicle { struct project + { + String defaultBranch; + String description; + String name; + }}} + } + Delegate[] delegates; + int seeds; +} + +struct Repo +{ + struct payloads + { + struct xyz { struct radicle { struct project + { + struct data + { + String defaultBranch; + String description; + String name; + } + struct meta + { + Sha head; + struct issues + { + int open; + int closed; + } + struct patches + { + int open; + int draft; + int archived; + int merged; + } + } + }}} + } + Delegate[] delegates; + int threshold; + struct visibility + { + String type; + } + Rid rid; + int seeding; + struct refs + { + Pair{String,Tag}[] tags; + Pair{String,Sha}[] refs; + } +} + +struct Delegate +{ + Did id; + Maybe{String} delegate_alias; +} + +struct Tag +{ + Sha commit; + Maybe{Tagger} tagger; + Maybe{String} message; +} + +struct Tagger +{ + String name; + String email; + int timestamp; +} + +struct Node +{ + Nid id; + String agent; + struct config + { + String node_alias; + struct peers + { + String type; + } + String[] connect; + String[] externalAddresses; + String network; + String log; + String relay; + struct limits + { + int routingMaxSize; + int routingMaxAge; + int gossipMaxAge; + int fetchConcurrency; + int maxOpenFiles; + struct rate + { + struct inbound + { + double fillRate; + int capacity; + } + struct outbound + { + double fillRate; + int capacity; + } + } + struct connection + { + int inbound; + int outbound; + } + String fetchPackReceive; + } + int workers; + struct seedingPolicy + { + String default_policy; + } + } + String state; + Maybe{String} description; +} + +struct RepoPolicy { + String policy; + String scope; +} + +struct NodeMeta +{ + String node_alias; + Did did; + struct ssh + { + String full; + String hash; + } +} + +struct Commit +{ + Sha id; + struct author + { + String name; + String email; + } + String summary; + String description; + Sha[] parents; + struct committer + { + String name; + String email; + int time; + } +} + +struct CommitFull +{ + Commit commit; + Diff diff; + Pair{String,File}[] files; + String[] branches; +} + +struct File +{ + Oid id; + bool binary; + String content; +} + +struct Diff +{ + FileDiff[] files; + struct stats + { + int filesChanged; + int insertions; + int deletions; + } +} + +struct FileDiff +{ + String status; + Maybe{Path} path; + Maybe{Path} oldPath; + Maybe{Path} newPath; + struct diff + { + String type; + Hunk[] hunks; + struct stats + { + int additions; + int deletions; + } + String eof; + } + Maybe{FileDesc} old; + Maybe{FileDesc} new; +} + +struct FileDesc +{ + Oid oid; + String mode; +} + +struct Hunk +{ + String header; + Line[] lines; + struct old + { + int start; + int end; + } + struct new + { + int start; + int end; + } +} + +struct Line +{ + String type; + String line; + Maybe{int} lineNo; + Maybe{int} lineNoOld; + Maybe{int} lineNoNew; +} + +struct DiffFull +{ + Diff diff; + Pair{Oid,File}[] files; + Commit[] commits; +} + +union Response +{ + Repo[] delegates_repos; + Node node; + Pair{Rid,RepoPolicy}[] node_policies_repos; + RepoPolicy node_policies_repo; + NodeMeta nodes; + Rid[] nodes_inventory; + Repo[] repo_root; + SearchRepo[] repo_search; + Repo repo; + Commit[] history; + CommitFull commit; + DiffFull diff; + ResponseRaw activity; + ResponseRaw tree_root; + ResponseRaw tree; + ResponseRaw stats_tree; + ResponseRaw remotes; + ResponseRaw remote; + ResponseRaw blob; + ResponseRaw readme; + ResponseRaw job; + ResponseRaw issues; + ResponseRaw issue; + ResponseRaw patches; + ResponseRaw patch; + ResponseRaw stats; } struct Client @@ -60,6 +350,27 @@ struct Client usz buffer_index; } +alias Did = String; +alias Nid = String; +alias Rid = String; +alias Sha = String; +alias Base = Sha; +alias Oid = Sha; +alias Path = String; +alias Peer = String; + +struct Args +{ + Did did; + Nid nid; + Rid rid; + Sha sha; + Base base; + Oid oid; + Path path; + Peer peer; +} + fn Client* new_client(String endpoint) { Client* self = mem::alloc(Client); @@ -71,30 +382,462 @@ fn Client* new_client(String endpoint) return self; } -fn CurlResult Client.request(Client* self, Request r, String params, String... args) +fn Response Client.request(Client* self, Request r, String params, Args args) { self.buffer_index = 0; CurlResult cr; String s; @pool() { - s = self.endpoint.tconcat(r.path); - int i; - while (i < r.args) - { - s = s.treplace(string::tformat("$%d", i+1), args[i]); - i++; - } - s = s.tconcat(params); + s = self.endpoint + .tconcat(r.path) + .treplace("{did}", args.did) + .treplace("{nid}", args.nid) + .treplace("{rid}", args.rid) + .treplace("{sha}", args.sha) + .treplace("{base}", args.base) + .treplace("{oid}", args.oid) + .treplace("{path}", args.path) + .treplace("{peer}", args.peer) + .tconcat(params); curl::easy_setopt(self.c, CurlOption.URL, s); cr = curl::easy_perform(self.c); + }; + Object* j = json::tparse(self.raw_response())!!; + switch (r) + { + case Request.DELEGATES_REPOS: return (Response){.delegates_repos = parse_repos(j) }; + case Request.NODE: return (Response){.node = parse_node(j) }; + case Request.NODE_POLICIES_REPOS: return (Response){.node_policies_repos = parse_repo_policies(j)}; + case Request.NODE_POLICIES_REPO: return (Response){.node_policies_repo = parse_repo_policy(j) }; + case Request.NODES: return (Response){.nodes = parse_node_meta(j) }; + case Request.NODES_INVENTORY: return (Response){.nodes_inventory = parse_rids(j) }; + case Request.REPO_ROOT: return (Response){.repo_root = parse_repos(j) }; + case Request.REPO_SEARCH: return (Response){.repo_search = parse_search_repos(j) }; + case Request.REPO: return (Response){.repo = parse_repo(j) }; + case Request.HISTORY: return (Response){.history = parse_commits(j) }; + case Request.COMMIT: return (Response){.commit = parse_commit_full(j) }; + case Request.DIFF: return (Response){.diff = parse_diff_full(j) }; + case Request.ACTIVITY: return (Response){.activity = self.raw_response() }; + case Request.TREE_ROOT: return (Response){.tree_root = self.raw_response() }; + case Request.TREE: return (Response){.tree = self.raw_response() }; + case Request.STATS_TREE: return (Response){.stats_tree = self.raw_response() }; + case Request.REMOTES: return (Response){.remotes = self.raw_response() }; + case Request.REMOTE: return (Response){.remote = self.raw_response() }; + case Request.BLOB: return (Response){.blob = self.raw_response() }; + case Request.README: return (Response){.readme = self.raw_response() }; + case Request.JOB: return (Response){.job = self.raw_response() }; + case Request.ISSUES: return (Response){.issues = self.raw_response() }; + case Request.ISSUE: return (Response){.issue = self.raw_response() }; + case Request.PATCHES: return (Response){.patches = self.raw_response() }; + case Request.PATCH: return (Response){.patch = self.raw_response() }; + case Request.STATS: return (Response){.stats = self.raw_response() }; + } +} + +fn Line parse_line(Object* j) +{ + Line l; + l.type = j.get_string("type")!!; + l.line = j.get_string("line")!!; + if (j.has_key("lineNo")) + { + l.lineNo.has_value = true; + l.lineNo.value = j.get_int("lineNo")!!; + } else { + l.lineNo.has_value = false; + } + if (j.has_key("lineNoOld")) + { + l.lineNoOld.has_value = true; + l.lineNoOld.value = j.get_int("lineNoOld")!!; + } else { + l.lineNoOld.has_value = false; + } + if (j.has_key("lineNoNew")) + { + l.lineNoNew.has_value = true; + l.lineNoNew.value = j.get_int("lineNoNew")!!; + } else { + l.lineNoNew.has_value = false; + } + return l; +} + +fn Hunk parse_hunk(Object* j) +{ + Hunk h; + int i; + h.header = j.get_string("header")!!; + i = 0; + while (i < j.get("lines").array.len()!!) + { + h.lines = array::tconcat(h.lines, (Line[1]){parse_line(j.get("lines").get_at(i)!!)}); + i++; + } + h.old.start = j.get("old").get_int("start")!!; + h.old.end = j.get("old").get_int("end")!!; + h.new.start = j.get("new").get_int("start")!!; + h.new.end = j.get("new").get_int("end")!!; + return h; +} + +fn FileDiff parse_file_diff(Object* j) +{ + FileDiff fd; + int i; + fd.status = j.get_string("status")!!; + if (j.has_key("path")) + { + fd.path.has_value = true; + fd.path.value = j.get_string("path")!!; + } else { + fd.path.has_value = false; + } + if (j.has_key("oldPath")) + { + fd.oldPath.has_value = true; + fd.oldPath.value = j.get_string("oldPath")!!; + } else { + fd.oldPath.has_value = false; + } + if (j.has_key("newPath")) + { + fd.newPath.has_value = true; + fd.newPath.value = j.get_string("newPath")!!; + } else { + fd.newPath.has_value = false; + } + if (j.has_key("diff")) + { + fd.diff.type = j.get("diff").get_string("type")!!; + if (fd.diff.type != "binary") + { + i = 0; + while (i < j.get("diff").get("hunks").array.len()!!) + { + fd.diff.hunks = array::tconcat(fd.diff.hunks, (Hunk[1]){parse_hunk(j.get("diff").get("hunks").get_at(i)!!)}); + i++; + } + fd.diff.stats.additions = j.get("diff").get("stats").get_int("additions")!!; + fd.diff.stats.deletions = j.get("diff").get("stats").get_int("deletions")!!; + fd.diff.eof = j.get("diff").get_string("eof")!!; + } + } + if (j.has_key("old")) + { + fd.old.has_value = true; + fd.old.value.oid = j.get("old").get_string("oid")!!; + fd.old.value.mode = j.get("old").get_string("mode")!!; + } else { + fd.old.has_value = false; + } + if (j.has_key("new")) + { + fd.new.has_value = true; + fd.new.value.oid = j.get("new").get_string("oid")!!; + fd.new.value.mode = j.get("new").get_string("mode")!!; + } else { + fd.new.has_value = false; + } + return fd; +} + +fn Diff parse_diff(Object* j) +{ + Diff d; + int i = 0; + while (i < j.get("files").array.len()!!) + { + d.files = array::tconcat(d.files, (FileDiff[1]){parse_file_diff(j.get("files").get_at(i)!!)}); + i++; + } + d.stats.filesChanged = j.get("stats").get_int("filesChanged")!!; + d.stats.insertions = j.get("stats").get_int("insertions")!!; + d.stats.deletions = j.get("stats").get_int("deletions")!!; + return d; +} + +fn File parse_file(Object* j) +{ + File f; + f.id = j.get_string("id")!!; + f.binary = j.get_bool("binary")!!; + f.content = j.get_string("content")!!; + return f; +} + +fn CommitFull parse_commit_full(Object* j) +{ + CommitFull cf; + int i; + cf.commit = parse_commit(j.get("commit")!!); + cf.diff = parse_diff(j.get("diff")!!); + Object.@each_entry(j.get("files")!!; String key, Object* value) + { + cf.files = array::tconcat(cf.files, (Pair{String,File}[1]){{key, parse_file(value)}}); }; - return cr; + i = 0; + while (i < j.get("branches").array.len()!!) + { + cf.branches = array::tconcat(cf.branches, (String[1]){j.get("branches").get_string_at(i)!!}); + i++; + } + return cf; +} + +fn DiffFull parse_diff_full(Object* j) +{ + DiffFull df; + int i; + df.diff = parse_diff(j.get("diff")!!); + Object.@each_entry(j.get("files")!!; String key, Object* value) + { + df.files = array::tconcat(df.files, (Pair{Oid,File}[1]){{key, parse_file(value)}}); + }; + i = 0; + while (i < j.get("commits").array.len()!!) + { + df.commits = array::tconcat(df.commits, (Commit[1]){parse_commit(j.get("commits").get_at(i)!!)}); + i++; + } + return df; +} + +fn Commit[] parse_commits(Object* j) +{ + Commit[] cs; + int i = 0; + while (i < j.array.len()) + { + cs = array::tconcat(cs, (Commit[1]){parse_commit(j.get_at(i))}); + i++; + } + return cs; +} + +fn Commit parse_commit(Object* j) +{ + Commit c; + int i; + c.id = j.get_string("id")!!; + c.author.name = j.get("author").get_string("name")!!; + c.author.email = j.get("author").get_string("email")!!; + c.summary = j.get_string("summary")!!; + c.description = j.get_string("description")!!; + i = 0; + while (i < j.get("parents").array.len()!!) + { + c.parents = array::tconcat(c.parents, (Sha[1]){j.get("parents").get_string_at(i)!!}); + i++; + } + c.committer.name = j.get("committer").get_string("name")!!; + c.committer.email = j.get("committer").get_string("email")!!; + c.committer.time = j.get("committer").get_int("time")!!; + return c; +} + +fn Rid[] parse_rids(Object* j) +{ + Rid[] rs; + int i = 0; + while (i < j.array.len()) + { + rs = array::tconcat(rs, (Rid[1]){j.get_string_at(i)!!}); + i++; + } + return rs; +} + +fn NodeMeta parse_node_meta(Object* j) +{ + NodeMeta nm; + nm.node_alias = j.get_string("alias")!!; + nm.did = j.get_string("did")!!; + nm.ssh.full = j.get("ssh").get_string("full")!!; + nm.ssh.hash = j.get("ssh").get_string("hash")!!; + return nm; +} + +fn Pair{Rid,RepoPolicy}[] parse_repo_policies(Object* j) +{ + Pair{Rid,RepoPolicy}[] rps; + int i = 0; + while (i < j.array.len()) + { + rps = array::tconcat(rps, (Pair{Rid,RepoPolicy}[1]){{j.get_at(i).get_string("rid")!!, parse_repo_policy(j.get_at(i).get("policy")!!)}}); + i++; + } + return rps; +} + +fn RepoPolicy parse_repo_policy(Object* j) +{ + RepoPolicy rp; + rp.policy = j.get_string("policy")!!; + rp.scope = j.get_string("scope")!!; + return rp; +} + +fn Node parse_node(Object* j) +{ + Node n; + int i; + n.id = j.get_string("id")!!; + n.agent = j.get_string("agent")!!; + n.config.node_alias = j.get("config").get_string("alias")!!; + n.config.peers.type = j.get("config").get("peers").get_string("type")!!; + i = 0; + while (i < j.get("config").get("connect").array.len()!!) + { + n.config.connect = array::tconcat(n.config.connect, (String[1]){j.get("config").get("connect").get_string_at(i)!!}); + i++; + } + i = 0; + while (i < j.get("config").get("externalAddresses").array.len()!!) + { + n.config.externalAddresses = array::tconcat(n.config.externalAddresses, (String[1]){j.get("config").get("externalAddresses").get_string_at(i)!!}); + i++; + } + n.config.network = j.get("config").get_string("network")!!; + n.config.log = j.get("config").get_string("log")!!; + n.config.relay = j.get("config").get_string("relay")!!; + n.config.limits.routingMaxSize = j.get("config").get("limits").get_int("routingMaxSize")!!; + n.config.limits.routingMaxAge = j.get("config").get("limits").get_int("routingMaxAge")!!; + n.config.limits.gossipMaxAge = j.get("config").get("limits").get_int("gossipMaxAge")!!; + n.config.limits.fetchConcurrency = j.get("config").get("limits").get_int("fetchConcurrency")!!; + n.config.limits.maxOpenFiles = j.get("config").get("limits").get_int("maxOpenFiles")!!; + n.config.limits.rate.inbound.fillRate = j.get("config").get("limits").get("rate").get("inbound").get_float("fillRate")!!; + n.config.limits.rate.inbound.capacity = j.get("config").get("limits").get("rate").get("inbound").get_int("capacity")!!; + n.config.limits.rate.outbound.fillRate = j.get("config").get("limits").get("rate").get("outbound").get_float("fillRate")!!; + n.config.limits.rate.outbound.capacity = j.get("config").get("limits").get("rate").get("outbound").get_int("capacity")!!; + n.config.limits.connection.inbound = j.get("config").get("limits").get("connection").get_int("inbound")!!; + n.config.limits.connection.outbound = j.get("config").get("limits").get("connection").get_int("outbound")!!; + n.config.workers = j.get("config").get_int("workers")!!; + n.config.seedingPolicy.default_policy = j.get("config").get("seedingPolicy").get_string("default")!!; + n.state = j.get_string("state")!!; + if (j.has_key("description")) + { + n.description = {j.get_string("description")!!, true}; + } else { + n.description.has_value = false; + } + return n; +} + +fn Repo[] parse_repos(Object* j) +{ + Repo[] rs; + int i = 0; + while (i < j.array.len()) + { + rs = array::tconcat(rs, (Repo[1]){parse_repo(j.get_at(i))}); + i++; + } + return rs; +} + +fn Repo parse_repo(Object* j) +{ + Repo r; + int i; + r.payloads.xyz.radicle.project.data.defaultBranch = j.get("payloads").get("xyz.radicle.project").get("data").get_string("defaultBranch")!!; + r.payloads.xyz.radicle.project.data.description = j.get("payloads").get("xyz.radicle.project").get("data").get_string("description")!!; + r.payloads.xyz.radicle.project.data.name = j.get("payloads").get("xyz.radicle.project").get("data").get_string("name")!!; + r.payloads.xyz.radicle.project.meta.head = j.get("payloads").get("xyz.radicle.project").get("meta").get_string("head")!!; + r.payloads.xyz.radicle.project.meta.issues.open = j.get("payloads").get("xyz.radicle.project").get("meta").get("issues").get_int("open")!!; + r.payloads.xyz.radicle.project.meta.issues.closed = j.get("payloads").get("xyz.radicle.project").get("meta").get("issues").get_int("closed")!!; + r.payloads.xyz.radicle.project.meta.patches.open = j.get("payloads").get("xyz.radicle.project").get("meta").get("patches").get_int("open")!!; + r.payloads.xyz.radicle.project.meta.patches.draft = j.get("payloads").get("xyz.radicle.project").get("meta").get("patches").get_int("draft")!!; + r.payloads.xyz.radicle.project.meta.patches.archived = j.get("payloads").get("xyz.radicle.project").get("meta").get("patches").get_int("archived")!!; + r.payloads.xyz.radicle.project.meta.patches.merged = j.get("payloads").get("xyz.radicle.project").get("meta").get("patches").get_int("merged")!!; + i = 0; + while (i < j.get("delegates").array.len()!!) + { + r.delegates = array::tconcat(r.delegates, (Delegate[1]){parse_delegate(j.get("delegates").get_at(i)!!)}); + i++; + } + r.threshold = j.get_int("threshold")!!; + r.visibility.type = j.get("visibility").get_string("type")!!; + r.rid = j.get_string("rid")!!; + r.seeding = j.get_int("seeding")!!; + i = 0; + Object.@each_entry(j.get("refs").get("tags")!!; String key, Object* value) + { + r.refs.tags = array::tconcat(r.refs.tags, (Pair{String,Tag}[1]){{key, parse_tag(value)}}); + }; + Object.@each_entry(j.get("refs").get("refs")!!; String key, Object* value) + { + r.refs.refs = array::tconcat(r.refs.refs, (Pair{String,Sha}[1]){{key, value.s}}); + }; + return r; +} + +fn SearchRepo[] parse_search_repos(Object* j) +{ + SearchRepo[] srs; + int i = 0; + while (i < j.array.len()) + { + srs = array::tconcat(srs, (SearchRepo[1]){parse_search_repo(j.get_at(i))}); + i++; + } + return srs; +} + +fn SearchRepo parse_search_repo(Object* j) +{ + SearchRepo sr; + int i; + sr.payloads.xyz.radicle.project.defaultBranch = j.get("payloads").get("xyz.radicle.project").get_string("defaultBranch")!!; + sr.payloads.xyz.radicle.project.description = j.get("payloads").get("xyz.radicle.project").get_string("description")!!; + sr.payloads.xyz.radicle.project.name = j.get("payloads").get("xyz.radicle.project").get_string("name")!!; + i = 0; + while (i < j.get("delegates").array.len()!!) + { + sr.delegates = array::tconcat(sr.delegates, (Delegate[1]){parse_delegate(j.get("delegates").get_at(i)!!)}); + i++; + } + sr.rid = j.get_string("rid")!!; + sr.seeds = j.get_int("seeds")!!; + return sr; +} + +fn Delegate parse_delegate(Object* j) +{ + Delegate d; + d.id = j.get_string("id")!!; + if (j.has_key("alias")) + { + d.delegate_alias.has_value = true; + d.delegate_alias.value = j.get_string("alias")!!; + } else { + d.delegate_alias.has_value = false; + } + return d; +} + +fn Tag parse_tag(Object* j) +{ + io::printn(j); + Tag t; + t.commit = j.get_string("commit")!!; + if (j.has_key("tagger")) + { + t.tagger.has_value = true; + t.tagger.value.name = j.get("tagger").get_string("name") ?? ""; + t.tagger.value.email = j.get("tagger").get_string("email") ?? ""; + t.tagger.value.timestamp = j.get("tagger").get_int("timestamp") ?? 0; + } else { + t.tagger.has_value = false; + } + t.message = {j.get_string("message"), true} ?? {"", false}; + return t; } -fn String Client.response(Client* self) +fn ResponseRaw Client.raw_response(Client* self) { - return (String)self.buffer.[..self.buffer_index]; + return (ResponseRaw)self.buffer.[..self.buffer_index]; } fn usz cb(char* buffer, usz size, usz nitems, Client* client) |
