add an api command to gethonks
Ted Unangst tedu@tedunangst.com
Tue, 12 Nov 2019 01:09:08 -0500
6 files changed,
155 insertions(+),
1 deletions(-)
M
database.go
→
database.go
@@ -474,6 +474,7 @@ }
if err != nil { log.Printf("error saving honk: %s", err) } + honkhonkline() return err }
M
docs/honk.3
→
docs/honk.3
@@ -87,6 +87,25 @@ The ActivityPub ID that this honk is in reply to.
.El .Pp Upon success, the honk action will return the URL for the created honk. +.Ss gethonks +The +.Dq gethonks +.Fa action +can be used to query for honks. +The following parameters are used. +.Bl -tag -width placename +.It Fa page +Should be one of +.Dq home +or +.Dq atme . +.It Fa after +Only return honks after the specified ID. +.It Fa wait +If there are no results, wait this many seconds for something to appear. +.El +.Pp +The result will be returned as json. .Sh EXAMPLES Refer to the sample code in the .Pa toys
M
toys/Makefile
→
toys/Makefile
@@ -1,8 +1,11 @@
-all: gettoken saytheday +all: gettoken saytheday youvegothonks gettoken: gettoken.go go build gettoken.go saytheday: saytheday.go go build saytheday.go + +youvegothonks: youvegothonks.go + go build youvegothonks.go
M
toys/README
→
toys/README
@@ -1,3 +1,9 @@
These are all standalone programs, meant to be compiled individually. A little of this, a little of that. + +gettoken.go - obtains an authorization token + +saytheday.go - posts a new honk + +youvegothonks.go - polls for new mesages
A
toys/youvegothonks.go
@@ -0,0 +1,79 @@
+package main + +import ( + "flag" + "fmt" + "io/ioutil" + "log" + "encoding/json" + "net/http" + "net/url" + "os" + "time" +) + +type Honk struct { + ID int + Honker string + Noise string +} + +type HonkSet struct { + Honks []Honk +} + +func gethonks(server, token string, wanted int) HonkSet { + form := make(url.Values) + form.Add("action", "gethonks") + form.Add("page", "atme") + form.Add("after", fmt.Sprintf("%d", wanted)) + form.Add("wait", "30") + apiurl := fmt.Sprintf("https://%s/api?%s", server, form.Encode()) + req, err := http.NewRequest("GET", apiurl, nil) + if err != nil { + log.Fatal(err) + } + req.Header.Add("Authorization", token) + resp, err := http.DefaultClient.Do(req) + if err != nil { + log.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + answer, _ := ioutil.ReadAll(resp.Body) + log.Fatalf("status: %d: %s", resp.StatusCode, answer) + } + var honks HonkSet + d := json.NewDecoder(resp.Body) + err = d.Decode(&honks) + if err != nil { + log.Fatal(err) + } + return honks +} + +func main() { + server := "" + token := "" + flag.StringVar(&server, "server", server, "server to connnect") + flag.StringVar(&token, "token", token, "auth token to use") + flag.Parse() + + if server == "" || token == "" { + flag.Usage() + os.Exit(1) + } + + wanted := 0 + + for { + honks := gethonks(server, token, wanted) + for _, h := range honks.Honks { + fmt.Printf("you've got a honk from %s\n%s\n", h.Honker, h.Noise) + if wanted < h.ID { + wanted = h.ID + } + } + time.Sleep(1 * time.Second) + } +}
M
web.go
→
web.go
@@ -2038,15 +2038,61 @@ log.Printf("frag error: %s", err)
} } +var honkline = make(chan bool) + +func honkhonkline() { + for { + select { + case honkline <- true: + default: + return + } + } +} + func apihandler(w http.ResponseWriter, r *http.Request) { u := login.GetUserInfo(r) + userid := u.UserID action := r.FormValue("action") + wait, _ := strconv.ParseInt(r.FormValue("wait"), 10, 0) log.Printf("api request '%s' on behalf of %s", action, u.Username) switch action { case "honk": submithonk(w, r, true) + case "gethonks": + var honks []*Honk + wanted, _ := strconv.ParseInt(r.FormValue("after"), 10, 0) + page := r.FormValue("page") + var waitchan <-chan time.Time + requery: + switch page { + case "atme": + honks = gethonksforme(userid, wanted) + honks = osmosis(honks, userid, false) + case "home": + honks = gethonksforuser(userid, wanted) + honks = osmosis(honks, userid, true) + default: + http.Error(w, "unknown page", http.StatusNotFound) + return + } + if len(honks) == 0 && wait > 0 { + if waitchan == nil { + waitchan = time.After(time.Duration(wait) * time.Second) + } + select { + case <-honkline: + goto requery + case <-waitchan: + } + } + reverbolate(userid, honks) + j := junk.New() + j["honks"] = honks + j.Write(w) default: http.Error(w, "unknown action", http.StatusNotFound) + return } }