From e9e86d6e015c077c253f4e45d106d87ccf95df09 Mon Sep 17 00:00:00 2001 From: Gino Date: Wed, 2 Aug 2023 03:34:13 -0700 Subject: [PATCH] feat: replace amqp w/ nats (#3) --- README.md | 13 ++++------ config.go | 10 ++++---- docker-compose.yml | 20 +++++++-------- go.mod | 20 +++++++++------ go.sum | 64 +++++++++++++++++++++++++++------------------- kantoku.go | 44 ++++++++++++++++++++----------- kantoku.toml | 8 +++--- routes.go | 37 +++++++++++++++------------ 8 files changed, 123 insertions(+), 93 deletions(-) diff --git a/README.md b/README.md index a508b3d..83948dd 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## 📦 Features - super-duper fast -- publishes all interactions to rabbitmq as JSON +- publishes interactions to a NATS subject - interaction testing route ## ⛓️ usage @@ -17,6 +17,9 @@ ### implementing kantoku into your code base +Whenever Discord `POST`s an interaction to `/v1/interactions` Kantoku will request an interaction response on the +configured NATS subject. + _wip_ ###### [Discord Server](https://discord.gg/8R4d8RydT4) @@ -46,16 +49,10 @@ _wip_ -#### Amqp Response - -response body is the response returned to discord. - -**A _Content-Header_ must be supplied** - ## 📜 contributors - [@melike2d](https://github.com/melike2d) -- [@TopiSenpai](https://github.com/TopiSenpai) +- [@Topi314](https://github.com/Topi314) --- diff --git a/config.go b/config.go index d98a1bf..81496fc 100644 --- a/config.go +++ b/config.go @@ -22,7 +22,7 @@ type Config struct { type KantokuConfig struct { PublicKey string `toml:"public_key"` Server ServerConfig `toml:"server"` - Amqp AmqpConfig `toml:"amqp"` + Nats NatsConfig `toml:"nats"` Logging LoggingConfig `toml:"logging"` } @@ -32,10 +32,10 @@ type ServerConfig struct { ExposeTestRoute bool `toml:"expose_test_route"` } -type AmqpConfig struct { - URI string `toml:"uri"` - Group string `toml:"group"` - Event string `toml:"event"` +type NatsConfig struct { + Servers []string `toml:"servers"` + Subject string `toml:"subject"` + NoResponders *interface{} `toml:"no_responders"` } type LoggingConfig struct { diff --git a/docker-compose.yml b/docker-compose.yml index 47c8565..1171647 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,26 +2,26 @@ version: '3.7' services: kantoku: - image: ghcr.io/mixtape-bot/kantoku + image: ghcr.io/dimensional-fun/kantoku container_name: kantoku networks: - - rabbitmq + - nats volumes: - ./kantoku.toml:/opt/kantoku/kantoku.toml restart: unless-stopped depends_on: - - rabbitmq + - nats expose: - 80 - rabbitmq: - image: rabbitmq:management-alpine - container_name: rabbitmq + nats: + image: nats:alpine + container_name: nats restart: unless-stopped expose: - - 5672 + - 4222 networks: - - rabbitmq + - nats networks: - rabbitmq: - name: rabbitmq + nats: + name: nats diff --git a/go.mod b/go.mod index 9834504..ed78f04 100644 --- a/go.mod +++ b/go.mod @@ -3,16 +3,20 @@ module github.com/mixtape-bot/kantoku go 1.18 require ( - github.com/0x4b53/amqp-rpc v1.0.1 github.com/gorilla/mux v1.8.0 - github.com/oasisprotocol/curve25519-voi v0.0.0-20220328075252-7dd334e3daae - github.com/pelletier/go-toml v1.9.4 - github.com/sirupsen/logrus v1.8.1 - github.com/streadway/amqp v1.0.0 + github.com/nats-io/nats.go v1.28.0 + github.com/oasisprotocol/curve25519-voi v0.0.0-20230110094441-db37f07504ce + github.com/pelletier/go-toml v1.9.5 + github.com/sirupsen/logrus v1.9.3 ) require ( - github.com/google/uuid v1.1.1 // indirect - golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 // indirect - golang.org/x/sys v0.0.0-20220325203850-36772127a21f // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/klauspost/compress v1.16.5 // indirect + github.com/nats-io/nats-server/v2 v2.9.20 // indirect + github.com/nats-io/nkeys v0.4.4 // indirect + github.com/nats-io/nuid v1.0.1 // indirect + golang.org/x/crypto v0.11.0 // indirect + golang.org/x/sys v0.10.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect ) diff --git a/go.sum b/go.sum index ec27289..02d6026 100644 --- a/go.sum +++ b/go.sum @@ -1,36 +1,46 @@ -github.com/0x4b53/amqp-rpc v1.0.1 h1:Cgk8D5oeF/oezn/i8agZVnzv/xqZ2d4MrDv5h7wBAlI= -github.com/0x4b53/amqp-rpc v1.0.1/go.mod h1:pDF97rxn75MKdXgRvlscnWPXIB2b0ujGOochPrBDNdM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/oasisprotocol/curve25519-voi v0.0.0-20220328075252-7dd334e3daae h1:7smdlrfdcZic4VfsGKD2ulWL804a4GVphr4s7WZxGiY= -github.com/oasisprotocol/curve25519-voi v0.0.0-20220328075252-7dd334e3daae/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s= -github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= -github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= +github.com/nats-io/jwt/v2 v2.4.1 h1:Y35W1dgbbz2SQUYDPCaclXcuqleVmpbRa7646Jf2EX4= +github.com/nats-io/nats-server/v2 v2.9.20 h1:bt1dW6xsL1hWWwv7Hovm+EJt5L6iplyqlgEFkoEUk0k= +github.com/nats-io/nats-server/v2 v2.9.20/go.mod h1:aTb/xtLCGKhfTFLxP591CMWfkdgBmcUUSkiSOe5A3gw= +github.com/nats-io/nats.go v1.28.0 h1:Th4G6zdsz2d0OqXdfzKLClo6bOfoI/b1kInhRtFIy5c= +github.com/nats-io/nats.go v1.28.0/go.mod h1:XpbWUlOElGwTYbMR7imivs7jJj9GtK7ypv321Wp6pjc= +github.com/nats-io/nkeys v0.4.4 h1:xvBJ8d69TznjcQl9t6//Q5xXuVhyYiSos6RPtvQNTwA= +github.com/nats-io/nkeys v0.4.4/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/oasisprotocol/curve25519-voi v0.0.0-20230110094441-db37f07504ce h1:/pEpMk55wH0X+E5zedGEMOdLuWmV8P4+4W3+LZaM6kg= +github.com/oasisprotocol/curve25519-voi v0.0.0-20230110094441-db37f07504ce/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo= -github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 h1:S25/rfnfsMVgORT4/J61MJ7rdyseOZOyvLIrZEZ7s6s= -golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220325203850-36772127a21f h1:TrmogKRsSOxRMJbLYGrB4SBbW+LJcEllYBLME5Zk5pU= -golang.org/x/sys v0.0.0-20220325203850-36772127a21f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/kantoku.go b/kantoku.go index fe63069..f4b2f9e 100644 --- a/kantoku.go +++ b/kantoku.go @@ -2,15 +2,16 @@ package main import ( "encoding/hex" + "encoding/json" "fmt" "net/http" + "strings" "time" - rpc "github.com/0x4b53/amqp-rpc" "github.com/gorilla/mux" + "github.com/nats-io/nats.go" "github.com/oasisprotocol/curve25519-voi/primitives/ed25519" "github.com/sirupsen/logrus" - "github.com/streadway/amqp" ) const version = "dev" @@ -46,16 +47,28 @@ func main() { k.Logger.Fatal("failed to decode public key: ", err) } - /* setting up RPC using RabbitMQ */ - k.RpcClient = rpc.NewClient(k.Config.Kantoku.Amqp.URI). - WithTimeout(3000 * time.Millisecond). - WithConfirmMode(true). - WithDebugLogger(k.Logger.Debugf). - WithErrorLogger(k.Logger.Errorf) + /* prepare no_responders reply. */ + if k.Config.Kantoku.Nats.NoResponders != nil { + b, err := json.Marshal(map[string]any{ + "type": 4, + "data": k.Config.Kantoku.Nats.NoResponders, + }) - k.RpcClient.OnStarted(func(_, _ *amqp.Connection, inChan, _ *amqp.Channel) { - k.Logger.Infoln("connected to rabbitmq") - }) + if err != nil { + k.Logger.Warnln("unable to encode 'no_responders' reply: ", err) + } else { + k.NoResponders = b + } + } + + /* prepare nats client */ + nc, err := nats.Connect(strings.Join(k.Config.Kantoku.Nats.Servers, ", ")) + if err != nil { + k.Logger.Fatal("connecting to NATS server failed: ", err) + } + + k.NatsConn = nc + k.Logger.Infoln("connected to NATS server!") /* starting Server */ k.Logger.Infof("starting w/ version: %s...", version) @@ -104,8 +117,9 @@ func main() { } type Kantoku struct { - RpcClient *rpc.Client - Config Config - Logger *logrus.Logger - PublicKey ed25519.PublicKey + NatsConn *nats.Conn + NoResponders []byte + Config Config + Logger *logrus.Logger + PublicKey ed25519.PublicKey } diff --git a/kantoku.toml b/kantoku.toml index 4994457..054373e 100644 --- a/kantoku.toml +++ b/kantoku.toml @@ -6,10 +6,10 @@ public_key = "" port = 80 expose_test_route = false - [kantoku.amqp] - uri = "amqp://localhost:5672" - group = "gateway" - event = "INTERACTION_CREATE" + [kantoku.nats] + servers = ["nats://127.0.0.1:4222"] + subject = "gateway.INTERACTION_CREATE" + no_responders = { content = "this command no workery" } [kantoku.logging] time_format = "01-02-06 15:04:05" diff --git a/routes.go b/routes.go index a6cede4..4d9e3d1 100644 --- a/routes.go +++ b/routes.go @@ -3,12 +3,12 @@ package main import ( "encoding/hex" "encoding/json" - "github.com/oasisprotocol/curve25519-voi/primitives/ed25519" - "github.com/streadway/amqp" "io" "net/http" + "time" - rpc "github.com/0x4b53/amqp-rpc" + "github.com/nats-io/nats.go" + "github.com/oasisprotocol/curve25519-voi/primitives/ed25519" ) func (k *Kantoku) GetIndex(w http.ResponseWriter, _ *http.Request) { @@ -85,31 +85,36 @@ func (k *Kantoku) handleInteraction(w http.ResponseWriter, r *http.Request, pk e resp, err := k.publishInteraction(body) if err != nil { + if err == nats.ErrNoResponders && k.NoResponders != nil { + k.reply(w, k.NoResponders, "application/json") + return + } + k.Logger.Errorln("Error publishing interaction:", err) w.WriteHeader(http.StatusBadRequest) k.createJsonResponse(w, err.Error(), false) return } - if resp.ContentType == "" { - _ = resp.Nack(false, false) + contentType := resp.Header.Get("Content-Type") + if contentType == "" { return } - w.Header().Set("Content-Type", resp.ContentType) - if _, err = w.Write(resp.Body); err != nil { + k.reply(w, resp.Data, contentType) +} + +func (k *Kantoku) reply(w http.ResponseWriter, body []byte, contentType string) { + w.Header().Set("Content-Type", contentType) + if _, err := w.Write(body); err != nil { k.Logger.Errorln("Error writing response body:", err.Error()) } } -func (k *Kantoku) publishInteraction(body []byte) (*amqp.Delivery, error) { - /* publish the interaction and wait for a reply */ - req := rpc.NewRequest(). - WithExchange(k.Config.Kantoku.Amqp.Group). - WithRoutingKey(k.Config.Kantoku.Amqp.Event) - - req.Publishing.ContentType = "application/json" - req.Publishing.Body = body +func (k *Kantoku) publishInteraction(body []byte) (*nats.Msg, error) { + msg := nats.NewMsg(k.Config.Kantoku.Nats.Subject) + msg.Data = body + msg.Header.Add("Content-Type", "application/json") - return k.RpcClient.Send(req) + return k.NatsConn.RequestMsg(msg, 3*time.Second) }