Skip to content
71 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

The runner base keeps its old comment, so the pushed base image still matches its folder1//! Calling outside systems. Every answer comes back as a status and a body,
2//! so each provider decides what a refusal means.
3
4use serde_json::Value;
5use worker::{Fetch, Headers, Method, Request, RequestInit, Result};
6
7pub struct Answer {
8 pub status: u16,
9 pub body: String,
10}
11
12impl Answer {
13 pub fn ok(&self) -> bool {
14 (200..300).contains(&self.status)
15 }
16
17 pub fn json(&self) -> Value {
18 serde_json::from_str(&self.body).unwrap_or(Value::Null)
19 }
20
21 /// What went wrong, briefly, for a person to read.
22 pub fn problem(&self, system: &str) -> String {
23 let said = self.json();
24 let message = said["message"]
25 .as_str()
26 .or_else(|| said["detail"].as_str())
27 .or_else(|| said["error"]["message"].as_str())
28 .or_else(|| said["errorMessages"][0].as_str())
29 .or_else(|| said["errors"][0]["message"].as_str())
30 .map(str::to_owned)
31 .unwrap_or_else(|| self.body.chars().take(200).collect());
32 match self.status {
33 401 => format!("{system} did not accept the credentials ({message})."),
34 403 => format!("{system} refused: the credentials cannot do this ({message})."),
35 404 => format!("{system} has nothing there ({message})."),
36 status => format!("{system} answered {status}: {message}"),
37 }
38 }
39}
40
41pub async fn send(method: Method, url: &str, headers: &[(&str, &str)], body: Option<String>) -> Result<Answer> {
42 let sent = Headers::new();
43 sent.set("user-agent", "g1t (+https://g1t.sh)")?;
44 sent.set("accept", "application/json")?;
45 for (name, value) in headers {
46 sent.set(name, value)?;
47 }
48 if body.is_some() && !headers.iter().any(|(name, _)| name.eq_ignore_ascii_case("content-type")) {
49 sent.set("content-type", "application/json")?;
50 }
51 let mut init = RequestInit::new();
52 init.with_method(method).with_headers(sent);
53 if let Some(body) = body {
54 init.with_body(Some(body.into()));
55 }
56 let mut response = Fetch::Request(Request::new_with_init(url, &init)?).send().await?;
57 Ok(Answer {
58 status: response.status_code(),
59 body: response.text().await.unwrap_or_default(),
60 })
61}
62
63/// `text`, cut to `max` characters at a line break where one is near.
64pub fn shorten(text: &str, max: usize) -> String {
65 if text.chars().count() <= max {
66 return text.to_owned();
67 }
68 let cut: String = text.chars().take(max).collect();
69 let at = cut.rfind('\n').filter(|at| *at > max / 2).unwrap_or(cut.len());
70 format!("{}\n\n…", cut[..at].trim_end())
71}

This file's history is long; its oldest lines are credited to the oldest commit read.