fix bonks on timeline, flesh out HonkAdapter.Do and add an API wrapper
This commit is contained in:
parent
ab8249e0bf
commit
264be94427
4 changed files with 128 additions and 19 deletions
|
@ -1,10 +1,13 @@
|
|||
package adapter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
. "forge.lightcrystal.systems/nilix/underbbs/models"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
@ -111,7 +114,9 @@ func (self *HonkAdapter) Stop() {
|
|||
}
|
||||
|
||||
func (self *HonkAdapter) Subscribe(filter string, target *string) []error {
|
||||
|
||||
if self.isAnonymous() {
|
||||
return nil
|
||||
}
|
||||
if self.stop != nil {
|
||||
close(self.stop)
|
||||
}
|
||||
|
@ -199,7 +204,8 @@ func (self *HonkAdapter) toMsg(h honk, target *string) Message {
|
|||
}
|
||||
if h.Oonker != "" {
|
||||
r := fmt.Sprintf("%s/bonk/%d", h.Honker, h.ID)
|
||||
msg.Renoter = &h.Oonker
|
||||
fmt.Println(r)
|
||||
msg.Renoter = &h.Honker
|
||||
msg.RenoteId = &r
|
||||
msg.RenoteTime = &tt
|
||||
}
|
||||
|
@ -223,14 +229,70 @@ func (self *HonkAdapter) Fetch(etype string, ids []string) error {
|
|||
return aaa.Fetch(etype, ids)
|
||||
}
|
||||
|
||||
func (self *HonkAdapter) donk(data map[string]string) error {
|
||||
var b bytes.Buffer
|
||||
w := multipart.NewWriter(&b)
|
||||
fw, err := w.CreateFormField("action")
|
||||
io.Copy(fw, strings.NewReader("honk"))
|
||||
fw, err = w.CreateFormField("token")
|
||||
io.Copy(fw, strings.NewReader(self.token))
|
||||
for k, v := range data {
|
||||
if k == "file" {
|
||||
if fw, err = w.CreateFormFile("donk", "donk"); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
fieldName := "noise"
|
||||
switch k {
|
||||
case "desc":
|
||||
fieldName = "donkdesc"
|
||||
case "content":
|
||||
fieldName = "noise"
|
||||
}
|
||||
if fw, err = w.CreateFormField(fieldName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, err := io.Copy(fw, strings.NewReader(v)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
w.Close()
|
||||
|
||||
req, err := http.NewRequest("POST", self.server+"/api", &b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", w.FormDataContentType())
|
||||
c := http.Client{}
|
||||
res, err := c.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.StatusCode < 400 {
|
||||
return nil
|
||||
} else {
|
||||
return errors.New(fmt.Sprintf("status: %d", res.StatusCode))
|
||||
}
|
||||
}
|
||||
|
||||
func (self *HonkAdapter) Do(action string, data map[string]string) error {
|
||||
if self.isAnonymous() {
|
||||
return nil
|
||||
}
|
||||
switch action {
|
||||
case "post":
|
||||
res, err := http.PostForm(self.server+"/api", url.Values{
|
||||
honkForm := url.Values{
|
||||
"action": []string{"honk"},
|
||||
"token": []string{self.token},
|
||||
"noise": []string{data["content"]},
|
||||
})
|
||||
}
|
||||
_, exists := data["file"]
|
||||
if exists {
|
||||
return self.donk(data)
|
||||
}
|
||||
res, err := http.PostForm(self.server+"/api", honkForm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
10
cli/cli.go
10
cli/cli.go
|
@ -105,6 +105,16 @@ func Process(args ...string) error {
|
|||
aa := strings.Split(a, "=")
|
||||
k := aa[0]
|
||||
v := strings.Join(aa[1:], "=")
|
||||
if k == "file" {
|
||||
b, err := ioutil.ReadFile(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v = string(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
data[k] = v
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,11 +89,11 @@ export class DatagramSocket {
|
|||
});
|
||||
}
|
||||
if (data.target) {
|
||||
|
||||
console.log("data has target: " + data.target);
|
||||
let e = document.querySelector(`underbbs-timeline#${data.target}[data-adapter="${data.adapter}"]`);
|
||||
if (e) {
|
||||
console.log("setting latest...")
|
||||
e.setAttribute("data-latest", data.id);
|
||||
e.setAttribute("data-latest", data.renoteId ?? data.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -15,6 +16,13 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
type doRequest struct {
|
||||
Action string `json:"action"`
|
||||
Content *string `json:"content,omitempty"`
|
||||
File *string `json:"file,omitempty"`
|
||||
Desc *string `json:"desc,omitempty"`
|
||||
}
|
||||
|
||||
func getSubscriberKey(req *http.Request) (string, error) {
|
||||
authHeader := req.Header.Get("Authorization")
|
||||
if strings.HasPrefix(authHeader, "Bearer ") {
|
||||
|
@ -114,13 +122,6 @@ func apiConfigureAdapters(next http.Handler, subscribers map[*Subscriber][]adapt
|
|||
})
|
||||
}
|
||||
|
||||
func apiGetAdapters(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
w.WriteHeader(201)
|
||||
next.ServeHTTP(w, req)
|
||||
})
|
||||
}
|
||||
|
||||
type subscribeParams struct {
|
||||
Filter string `json:"filter"`
|
||||
Target *string `json:"target,omitempty"`
|
||||
|
@ -203,6 +204,43 @@ func apiAdapterFetch(next http.Handler, subscribers map[*Subscriber][]adapter.Ad
|
|||
})
|
||||
}
|
||||
|
||||
func apiAdapterDo(next http.Handler, subscribers map[*Subscriber][]adapter.Adapter) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
authHeader := req.Header.Get("Authorization")
|
||||
if strings.HasPrefix(authHeader, "Bearer ") {
|
||||
subscriberKey := strings.Split(authHeader, "Bearer ")[1]
|
||||
s := getSubscriberByKey(subscriberKey, subscribers)
|
||||
if s != nil {
|
||||
apiParams := req.Context().Value("params").(map[string]string)
|
||||
for _, a := range subscribers[s] {
|
||||
if a.Name() == apiParams["adapter_id"] {
|
||||
// request body is json
|
||||
// if we have a `file`, it needs to be transformed from base64 to standard bytes/string
|
||||
doReq := map[string]string{}
|
||||
err := json.NewDecoder(req.Body).Decode(&doReq)
|
||||
if err != nil {
|
||||
w.WriteHeader(422)
|
||||
return
|
||||
}
|
||||
if f, exists := doReq["file"]; exists {
|
||||
rawFile, err := base64.StdEncoding.DecodeString(f)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
doReq["file"] = string(rawFile)
|
||||
}
|
||||
a.Do(doReq["action"], doReq)
|
||||
next.ServeHTTP(w, req)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
})
|
||||
}
|
||||
|
||||
func (self *BBSServer) apiMux() http.Handler {
|
||||
errTemplate, err := template.New("err").Parse("{{ $params := (.Context).Value \"params\" }}<html><body><h1>ERROR {{ $params.ErrorCode }}</h1><p class='error'>{{ $params.ErrorMessage }}</p></body></html>")
|
||||
if err != nil {
|
||||
|
@ -212,17 +250,11 @@ func (self *BBSServer) apiMux() http.Handler {
|
|||
Fallback: *errTemplate,
|
||||
}
|
||||
|
||||
// adapters (POST & GET)
|
||||
rtr.Post("/adapters", ProtectWithSubscriberKey(
|
||||
apiConfigureAdapters(renderer.JSON("data"), self.subscribers),
|
||||
self.subscribers,
|
||||
))
|
||||
rtr.Get("/adapters", ProtectWithSubscriberKey(
|
||||
apiGetAdapters(renderer.JSON("data")),
|
||||
self.subscribers,
|
||||
))
|
||||
|
||||
// adapters/:name/subscribe
|
||||
rtr.Post(`/adapters/(?P<adapter_id>\S+)/subscribe`, ProtectWithSubscriberKey(
|
||||
apiAdapterSubscribe(renderer.JSON("data"), self.subscribers),
|
||||
self.subscribers,
|
||||
|
@ -233,5 +265,10 @@ func (self *BBSServer) apiMux() http.Handler {
|
|||
self.subscribers,
|
||||
))
|
||||
|
||||
rtr.Post(`adapters/(?P<adapter-id>\S+)/do`, ProtectWithSubscriberKey(
|
||||
apiAdapterDo(renderer.JSON("data"), self.subscribers),
|
||||
self.subscribers,
|
||||
))
|
||||
|
||||
return http.HandlerFunc(rtr.ServeHTTP)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue