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
|
package adapter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
. "forge.lightcrystal.systems/nilix/underbbs/models"
|
. "forge.lightcrystal.systems/nilix/underbbs/models"
|
||||||
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
@ -111,7 +114,9 @@ func (self *HonkAdapter) Stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *HonkAdapter) Subscribe(filter string, target *string) []error {
|
func (self *HonkAdapter) Subscribe(filter string, target *string) []error {
|
||||||
|
if self.isAnonymous() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if self.stop != nil {
|
if self.stop != nil {
|
||||||
close(self.stop)
|
close(self.stop)
|
||||||
}
|
}
|
||||||
|
@ -199,7 +204,8 @@ func (self *HonkAdapter) toMsg(h honk, target *string) Message {
|
||||||
}
|
}
|
||||||
if h.Oonker != "" {
|
if h.Oonker != "" {
|
||||||
r := fmt.Sprintf("%s/bonk/%d", h.Honker, h.ID)
|
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.RenoteId = &r
|
||||||
msg.RenoteTime = &tt
|
msg.RenoteTime = &tt
|
||||||
}
|
}
|
||||||
|
@ -223,14 +229,70 @@ func (self *HonkAdapter) Fetch(etype string, ids []string) error {
|
||||||
return aaa.Fetch(etype, ids)
|
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 {
|
func (self *HonkAdapter) Do(action string, data map[string]string) error {
|
||||||
|
if self.isAnonymous() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
switch action {
|
switch action {
|
||||||
case "post":
|
case "post":
|
||||||
res, err := http.PostForm(self.server+"/api", url.Values{
|
honkForm := url.Values{
|
||||||
"action": []string{"honk"},
|
"action": []string{"honk"},
|
||||||
"token": []string{self.token},
|
"token": []string{self.token},
|
||||||
"noise": []string{data["content"]},
|
"noise": []string{data["content"]},
|
||||||
})
|
}
|
||||||
|
_, exists := data["file"]
|
||||||
|
if exists {
|
||||||
|
return self.donk(data)
|
||||||
|
}
|
||||||
|
res, err := http.PostForm(self.server+"/api", honkForm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
10
cli/cli.go
10
cli/cli.go
|
@ -105,6 +105,16 @@ func Process(args ...string) error {
|
||||||
aa := strings.Split(a, "=")
|
aa := strings.Split(a, "=")
|
||||||
k := aa[0]
|
k := aa[0]
|
||||||
v := strings.Join(aa[1:], "=")
|
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
|
data[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,11 +89,11 @@ export class DatagramSocket {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (data.target) {
|
if (data.target) {
|
||||||
|
|
||||||
console.log("data has target: " + data.target);
|
console.log("data has target: " + data.target);
|
||||||
let e = document.querySelector(`underbbs-timeline#${data.target}[data-adapter="${data.adapter}"]`);
|
let e = document.querySelector(`underbbs-timeline#${data.target}[data-adapter="${data.adapter}"]`);
|
||||||
if (e) {
|
if (e) {
|
||||||
console.log("setting latest...")
|
e.setAttribute("data-latest", data.renoteId ?? data.id);
|
||||||
e.setAttribute("data-latest", data.id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -15,6 +16,13 @@ import (
|
||||||
"strings"
|
"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) {
|
func getSubscriberKey(req *http.Request) (string, error) {
|
||||||
authHeader := req.Header.Get("Authorization")
|
authHeader := req.Header.Get("Authorization")
|
||||||
if strings.HasPrefix(authHeader, "Bearer ") {
|
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 {
|
type subscribeParams struct {
|
||||||
Filter string `json:"filter"`
|
Filter string `json:"filter"`
|
||||||
Target *string `json:"target,omitempty"`
|
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 {
|
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>")
|
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 {
|
if err != nil {
|
||||||
|
@ -212,17 +250,11 @@ func (self *BBSServer) apiMux() http.Handler {
|
||||||
Fallback: *errTemplate,
|
Fallback: *errTemplate,
|
||||||
}
|
}
|
||||||
|
|
||||||
// adapters (POST & GET)
|
|
||||||
rtr.Post("/adapters", ProtectWithSubscriberKey(
|
rtr.Post("/adapters", ProtectWithSubscriberKey(
|
||||||
apiConfigureAdapters(renderer.JSON("data"), self.subscribers),
|
apiConfigureAdapters(renderer.JSON("data"), self.subscribers),
|
||||||
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(
|
rtr.Post(`/adapters/(?P<adapter_id>\S+)/subscribe`, ProtectWithSubscriberKey(
|
||||||
apiAdapterSubscribe(renderer.JSON("data"), self.subscribers),
|
apiAdapterSubscribe(renderer.JSON("data"), self.subscribers),
|
||||||
self.subscribers,
|
self.subscribers,
|
||||||
|
@ -233,5 +265,10 @@ func (self *BBSServer) apiMux() http.Handler {
|
||||||
self.subscribers,
|
self.subscribers,
|
||||||
))
|
))
|
||||||
|
|
||||||
|
rtr.Post(`adapters/(?P<adapter-id>\S+)/do`, ProtectWithSubscriberKey(
|
||||||
|
apiAdapterDo(renderer.JSON("data"), self.subscribers),
|
||||||
|
self.subscribers,
|
||||||
|
))
|
||||||
|
|
||||||
return http.HandlerFunc(rtr.ServeHTTP)
|
return http.HandlerFunc(rtr.ServeHTTP)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue