Move worker to deliver.

This commit is contained in:
Naoki Kosaka
2021-06-18 22:02:49 +09:00
parent 99f870e0f2
commit aafac21664
12 changed files with 180 additions and 148 deletions

93
deliver/deriver.go Normal file
View File

@ -0,0 +1,93 @@
package deliver
import (
"fmt"
"net/http"
"net/url"
"os"
"time"
"github.com/RichardKnop/machinery/v1"
"github.com/RichardKnop/machinery/v1/log"
"github.com/go-redis/redis"
uuid "github.com/satori/go.uuid"
"github.com/yukimochi/Activity-Relay/models"
)
var (
version string
globalConfig *models.RelayConfig
// Actor : Relay's Actor
Actor models.Actor
redisClient *redis.Client
machineryServer *machinery.Server
httpClient *http.Client
)
func relayActivity(args ...string) error {
inboxURL := args[0]
body := args[1]
err := sendActivity(inboxURL, Actor.ID, []byte(body), globalConfig.ActorKey())
if err != nil {
domain, _ := url.Parse(inboxURL)
eval_script := "local change = redis.call('HSETNX',KEYS[1], 'last_error', ARGV[1]); if change == 1 then redis.call('EXPIRE', KEYS[1], ARGV[2]) end;"
redisClient.Eval(eval_script, []string{"relay:statistics:" + domain.Host}, err.Error(), 60).Result()
}
return err
}
func registorActivity(args ...string) error {
inboxURL := args[0]
body := args[1]
err := sendActivity(inboxURL, Actor.ID, []byte(body), globalConfig.ActorKey())
return err
}
func Entrypoint(g *models.RelayConfig, v string) error {
var err error
globalConfig = g
version = v
err = initialize(globalConfig)
if err != nil {
return err
}
err = machineryServer.RegisterTask("registor", registorActivity)
if err != nil {
return err
}
err = machineryServer.RegisterTask("relay", relayActivity)
if err != nil {
return err
}
workerID := uuid.NewV4()
worker := machineryServer.NewWorker(workerID.String(), globalConfig.JobConcurrency())
err = worker.Launch()
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
return nil
}
func initialize(globalConfig *models.RelayConfig) error {
var err error
redisClient = globalConfig.RedisClient()
machineryServer, err = models.NewMachineryServer(globalConfig)
if err != nil {
return err
}
httpClient = &http.Client{Timeout: time.Duration(5) * time.Second}
Actor = models.NewActivityPubActorFromSelfKey(globalConfig)
newNullLogger := NewNullLogger()
log.DEBUG = newNullLogger
return nil
}

140
deliver/deriver_test.go Normal file
View File

@ -0,0 +1,140 @@
package deliver
import (
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"os"
"testing"
"github.com/spf13/viper"
"github.com/yukimochi/Activity-Relay/models"
)
func TestMain(m *testing.M) {
var err error
testConfigPath := "../misc/config.yml"
file, _ := os.Open(testConfigPath)
defer file.Close()
viper.SetConfigType("yaml")
viper.ReadConfig(file)
viper.Set("ACTOR_PEM", "../misc/testKey.pem")
viper.BindEnv("REDIS_URL")
globalConfig, err = models.NewRelayConfig()
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
err = initialize(globalConfig)
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
redisClient.FlushAll().Result()
code := m.Run()
os.Exit(code)
}
func TestRelayActivity(t *testing.T) {
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
data, _ := ioutil.ReadAll(r.Body)
if string(data) != "data" || r.Header.Get("Content-Type") != "application/activity+json" {
w.WriteHeader(500)
w.Write(nil)
} else {
w.WriteHeader(202)
w.Write(nil)
}
}))
defer s.Close()
err := relayActivity(s.URL, "data")
if err != nil {
t.Fatal("Failed - Data transfar not collect")
}
}
func TestRelayActivityNoHost(t *testing.T) {
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
}))
defer s.Close()
err := relayActivity("http://nohost.example.jp", "data")
if err == nil {
t.Fatal("Failed - Error not reported.")
}
domain, _ := url.Parse("http://nohost.example.jp")
data, _ := redisClient.HGet("relay:statistics:"+domain.Host, "last_error").Result()
if data == "" {
t.Fatal("Failed - Error not cached.")
}
}
func TestRelayActivityResp500(t *testing.T) {
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
w.Write(nil)
}))
defer s.Close()
err := relayActivity(s.URL, "data")
if err == nil {
t.Fatal("Failed - Error not reported.")
}
domain, _ := url.Parse(s.URL)
data, _ := redisClient.HGet("relay:statistics:"+domain.Host, "last_error").Result()
if data == "" {
t.Fatal("Failed - Error not cached.")
}
}
func TestRegistorActivity(t *testing.T) {
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
data, _ := ioutil.ReadAll(r.Body)
if string(data) != "data" || r.Header.Get("Content-Type") != "application/activity+json" {
w.WriteHeader(500)
w.Write(nil)
} else {
w.WriteHeader(202)
w.Write(nil)
}
}))
defer s.Close()
err := registorActivity(s.URL, "data")
if err != nil {
t.Fatal("Failed - Data transfar not collect")
}
}
func TestRegistorActivityNoHost(t *testing.T) {
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
}))
defer s.Close()
err := registorActivity("http://nohost.example.jp", "data")
if err == nil {
t.Fatal("Failed - Error not reported.")
}
}
func TestRegistorActivityResp500(t *testing.T) {
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
w.Write(nil)
}))
defer s.Close()
err := registorActivity(s.URL, "data")
if err == nil {
t.Fatal("Failed - Error not reported.")
}
}

30
deliver/logger.go Normal file
View File

@ -0,0 +1,30 @@
package deliver
// NullLogger : Null logger for debug output
type NullLogger struct {
}
// NewNullLogger : Create Nulllogger
func NewNullLogger() *NullLogger {
var newNullLogger NullLogger
return &newNullLogger
}
func (l *NullLogger) Print(v ...interface{}) {
}
func (l *NullLogger) Printf(format string, v ...interface{}) {
}
func (l *NullLogger) Println(v ...interface{}) {
}
func (l *NullLogger) Fatal(v ...interface{}) {
}
func (l *NullLogger) Fatalf(format string, v ...interface{}) {
}
func (l *NullLogger) Fatalln(v ...interface{}) {
}
func (l *NullLogger) Panic(v ...interface{}) {
}
func (l *NullLogger) Panicf(format string, v ...interface{}) {
}
func (l *NullLogger) Panicln(v ...interface{}) {
}

53
deliver/sender.go Normal file
View File

@ -0,0 +1,53 @@
package deliver
import (
"bytes"
"crypto/rsa"
"crypto/sha256"
"encoding/base64"
"errors"
"fmt"
"net/http"
"time"
httpdate "github.com/Songmu/go-httpdate"
"github.com/yukimochi/httpsig"
)
func appendSignature(request *http.Request, body *[]byte, KeyID string, publicKey *rsa.PrivateKey) error {
hash := sha256.New()
hash.Write(*body)
b := hash.Sum(nil)
request.Header.Set("Digest", "SHA-256="+base64.StdEncoding.EncodeToString(b))
request.Header.Set("Host", request.Host)
signer, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, []string{httpsig.RequestTarget, "Host", "Date", "Digest", "Content-Type"}, httpsig.Signature)
if err != nil {
return err
}
err = signer.SignRequest(publicKey, KeyID, request)
if err != nil {
return err
}
return nil
}
func sendActivity(inboxURL string, KeyID string, body []byte, publicKey *rsa.PrivateKey) error {
req, _ := http.NewRequest("POST", inboxURL, bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/activity+json")
req.Header.Set("User-Agent", fmt.Sprintf("%s (golang net/http; Activity-Relay %s; %s)", globalConfig.ServerServicename(), version, globalConfig.ServerHostname().Host))
req.Header.Set("Date", httpdate.Time2Str(time.Now()))
appendSignature(req, &body, KeyID, publicKey)
resp, err := httpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
fmt.Println(inboxURL, resp.StatusCode)
if resp.StatusCode/100 != 2 {
return errors.New("Post " + inboxURL + ": " + resp.Status)
}
return nil
}