makes PostActivity fully async

This commit is contained in:
Christian Beutel
2025-07-10 14:46:12 +02:00
parent d577ac209e
commit d6e08e6d80

View File

@@ -27,13 +27,22 @@ import (
) )
func PostActivity(app core.App, actor *core.Record, activity *pub.Activity, recipients []string) error { func PostActivity(app core.App, actor *core.Record, activity *pub.Activity, recipients []string) error {
go func() {
defer func() {
if r := recover(); r != nil {
app.Logger().Error(fmt.Sprintf("Recovered from panic in PostActivity: %v", r))
}
}()
encryptionKey := os.Getenv("POCKETBASE_ENCRYPTION_KEY") encryptionKey := os.Getenv("POCKETBASE_ENCRYPTION_KEY")
if len(encryptionKey) == 0 { if len(encryptionKey) == 0 {
return fmt.Errorf("POCKETBASE_ENCRYPTION_KEY not set") app.Logger().Error("POCKETBASE_ENCRYPTION_KEY not set")
return
} }
origin := os.Getenv("ORIGIN") origin := os.Getenv("ORIGIN")
if origin == "" { if origin == "" {
return fmt.Errorf("ORIGIN not set") app.Logger().Error("ORIGIN not set")
return
} }
algs := []httpsig.Algorithm{httpsig.RSA_SHA256} algs := []httpsig.Algorithm{httpsig.RSA_SHA256}
@@ -45,35 +54,37 @@ func PostActivity(app core.App, actor *core.Record, activity *pub.Activity, reci
jsonld.IRI(pub.SecurityContextURI), jsonld.IRI(pub.SecurityContextURI),
).Marshal(activity) ).Marshal(activity)
if err != nil { if err != nil {
return err app.Logger().Error(fmt.Sprintf("Failed to marshal activity: %s", err))
return
} }
decryptedPrivateKey, err := security.Decrypt(actor.GetString("private_key"), encryptionKey) decryptedPrivateKey, err := security.Decrypt(actor.GetString("private_key"), encryptionKey)
if err != nil { if err != nil {
return err app.Logger().Error(fmt.Sprintf("Failed to decrypt key: %s", err))
return
} }
privateKey, err := x509.ParsePKCS1PrivateKey(decryptedPrivateKey) privateKey, err := x509.ParsePKCS1PrivateKey(decryptedPrivateKey)
if err != nil { if err != nil {
return err app.Logger().Error(fmt.Sprintf("Failed to parse private key: %s", err))
return
} }
pubID := actor.GetString("iri") + "#main-key" pubID := actor.GetString("iri") + "#main-key"
client := &http.Client{} client := &http.Client{}
var wg sync.WaitGroup sem := semaphore.NewWeighted(5)
sem := semaphore.NewWeighted(5) // Limit to 5 concurrent sends
slices.Sort(recipients) slices.Sort(recipients)
uniqueRecipients := slices.Compact(recipients) uniqueRecipients := slices.Compact(recipients)
var wg sync.WaitGroup
for _, v := range uniqueRecipients { for _, v := range uniqueRecipients {
wg.Add(1) wg.Add(1)
go func(inbox string) { go func(inbox string) {
defer wg.Done() defer wg.Done()
signer, _, err := httpsig.NewSigner(algs, httpsig.DigestSha256, postHeaders, httpsig.Signature, int64(expiresIn)) signer, _, err := httpsig.NewSigner(algs, httpsig.DigestSha256, postHeaders, httpsig.Signature, int64(expiresIn))
if err != nil { if err != nil {
app.Logger().Error(fmt.Sprintf("Signer creation failed: %s", err))
return return
} }
@@ -83,8 +94,7 @@ func PostActivity(app core.App, actor *core.Record, activity *pub.Activity, reci
} }
defer sem.Release(1) defer sem.Release(1)
buf := bytes.NewBuffer(body) req, err := http.NewRequest(http.MethodPost, inbox, bytes.NewBuffer(body))
req, err := http.NewRequest(http.MethodPost, inbox, buf)
if err != nil { if err != nil {
app.Logger().Error(fmt.Sprintf("Request creation failed: %s", err)) app.Logger().Error(fmt.Sprintf("Request creation failed: %s", err))
return return
@@ -100,22 +110,21 @@ func PostActivity(app core.App, actor *core.Record, activity *pub.Activity, reci
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
app.Logger().Error(fmt.Sprintf("Error sending request to inbox %s: %s", inbox, err)) app.Logger().Error(fmt.Sprintf("Error sending to inbox %s: %s", inbox, err))
return return
} }
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted { if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted {
body, _ := io.ReadAll(resp.Body) respBody, _ := io.ReadAll(resp.Body)
app.Logger().Error(fmt.Sprintf("Inbox %s responded with %d: %s", inbox, resp.StatusCode, body)) app.Logger().Error(fmt.Sprintf("Inbox %s responded with %d: %s", inbox, resp.StatusCode, respBody))
} else { } else {
app.Logger().Info(fmt.Sprintf("Sent %s to %s", activity.Type, inbox), "activity", activity) app.Logger().Info(fmt.Sprintf("Sent %s to %s", activity.Type, inbox), "activity", activity)
} }
}(v) }(v)
} }
wg.Wait() wg.Wait()
}()
return nil return nil
} }