2020-11-22 16:10:59 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
2021-05-24 09:12:46 +02:00
|
|
|
"encoding/gob"
|
2021-01-21 17:59:47 +01:00
|
|
|
"encoding/json"
|
2020-11-22 16:10:59 +01:00
|
|
|
"fmt"
|
2021-02-17 08:23:03 +01:00
|
|
|
"io"
|
2020-11-22 16:10:59 +01:00
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"time"
|
2021-06-18 14:32:03 +02:00
|
|
|
|
|
|
|
"git.jlel.se/jlelse/GoBlog/pkgs/contenttype"
|
2020-11-22 16:10:59 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
type apRequest struct {
|
|
|
|
BlogIri, To string
|
|
|
|
Activity []byte
|
|
|
|
Try int
|
|
|
|
}
|
|
|
|
|
2021-06-06 14:39:42 +02:00
|
|
|
func (a *goBlog) initAPSendQueue() {
|
2020-11-22 16:10:59 +01:00
|
|
|
go func() {
|
|
|
|
for {
|
2021-06-06 14:39:42 +02:00
|
|
|
qi, err := a.db.peekQueue("ap")
|
2021-05-24 09:12:46 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Println(err.Error())
|
|
|
|
continue
|
|
|
|
} else if qi != nil {
|
|
|
|
var r apRequest
|
|
|
|
err = gob.NewDecoder(bytes.NewReader(qi.content)).Decode(&r)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err.Error())
|
2021-06-06 14:39:42 +02:00
|
|
|
_ = a.db.dequeue(qi)
|
2020-11-22 16:10:59 +01:00
|
|
|
continue
|
|
|
|
}
|
2021-06-06 14:39:42 +02:00
|
|
|
if err := a.apSendSigned(r.BlogIri, r.To, r.Activity); err != nil {
|
2021-05-24 09:12:46 +02:00
|
|
|
if r.Try++; r.Try < 20 {
|
|
|
|
// Try it again
|
|
|
|
qi.content, _ = r.encode()
|
2021-06-06 14:39:42 +02:00
|
|
|
_ = a.db.reschedule(qi, time.Duration(r.Try)*10*time.Minute)
|
2021-05-24 09:12:46 +02:00
|
|
|
continue
|
2020-11-22 16:10:59 +01:00
|
|
|
} else {
|
2021-05-24 09:12:46 +02:00
|
|
|
log.Printf("Request to %s failed for the 20th time", r.To)
|
|
|
|
log.Println()
|
2021-06-06 14:39:42 +02:00
|
|
|
_ = a.db.apRemoveInbox(r.To)
|
2020-11-22 16:10:59 +01:00
|
|
|
}
|
2021-05-24 09:12:46 +02:00
|
|
|
}
|
2021-06-06 14:39:42 +02:00
|
|
|
err = a.db.dequeue(qi)
|
2021-05-24 09:12:46 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Println(err.Error())
|
2020-11-22 16:10:59 +01:00
|
|
|
}
|
2021-05-24 10:44:43 +02:00
|
|
|
} else {
|
|
|
|
// No item in the queue, wait a moment
|
|
|
|
time.Sleep(15 * time.Second)
|
2020-11-22 16:10:59 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2021-06-06 14:39:42 +02:00
|
|
|
func (db *database) apQueueSendSigned(blogIri, to string, activity interface{}) error {
|
2020-11-22 16:10:59 +01:00
|
|
|
body, err := json.Marshal(activity)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-05-24 09:12:46 +02:00
|
|
|
b, err := (&apRequest{
|
2020-11-22 16:10:59 +01:00
|
|
|
BlogIri: blogIri,
|
|
|
|
To: to,
|
|
|
|
Activity: body,
|
2021-05-24 09:12:46 +02:00
|
|
|
}).encode()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-06-06 14:39:42 +02:00
|
|
|
return db.enqueue("ap", b, time.Now())
|
2021-05-24 09:12:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *apRequest) encode() ([]byte, error) {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
err := gob.NewEncoder(&buf).Encode(r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return buf.Bytes(), nil
|
2020-11-22 16:10:59 +01:00
|
|
|
}
|
|
|
|
|
2021-06-06 14:39:42 +02:00
|
|
|
func (a *goBlog) apSendSigned(blogIri, to string, activity []byte) error {
|
2020-11-22 16:10:59 +01:00
|
|
|
// Create request context with timeout
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
|
|
|
defer cancel()
|
|
|
|
// Create request
|
2021-03-19 14:26:45 +01:00
|
|
|
var requestBuffer bytes.Buffer
|
|
|
|
requestBuffer.Write(activity)
|
|
|
|
r, err := http.NewRequestWithContext(ctx, http.MethodPost, to, &requestBuffer)
|
2020-11-22 16:10:59 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
iri, err := url.Parse(to)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
r.Header.Set("Accept-Charset", "utf-8")
|
|
|
|
r.Header.Set("Date", time.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05")+" GMT")
|
|
|
|
r.Header.Set(userAgent, appUserAgent)
|
2021-06-18 14:32:03 +02:00
|
|
|
r.Header.Set("Accept", contenttype.ASUTF8)
|
|
|
|
r.Header.Set(contentType, contenttype.ASUTF8)
|
2020-11-22 16:10:59 +01:00
|
|
|
r.Header.Set("Host", iri.Host)
|
|
|
|
// Sign request
|
2021-06-06 14:39:42 +02:00
|
|
|
a.apPostSignMutex.Lock()
|
|
|
|
err = a.apPostSigner.SignRequest(a.apPrivateKey, blogIri+"#main-key", r, activity)
|
|
|
|
a.apPostSignMutex.Unlock()
|
2020-11-22 16:10:59 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// Do request
|
2021-06-19 08:37:16 +02:00
|
|
|
resp, err := a.httpClient.Do(r)
|
2020-11-22 16:10:59 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-03-31 09:29:52 +02:00
|
|
|
defer resp.Body.Close()
|
2020-11-22 16:10:59 +01:00
|
|
|
if !apRequestIsSuccess(resp.StatusCode) {
|
2021-02-17 08:23:03 +01:00
|
|
|
body, _ := io.ReadAll(resp.Body)
|
2020-11-22 16:10:59 +01:00
|
|
|
return fmt.Errorf("signed request failed with status %d: %s", resp.StatusCode, string(body))
|
2021-03-31 09:29:52 +02:00
|
|
|
} else {
|
|
|
|
_, _ = io.Copy(io.Discard, resp.Body)
|
2020-11-22 16:10:59 +01:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|