Skip to content

Commit

Permalink
feat: replace amqp w/ nats (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
viztea committed Aug 2, 2023
1 parent cbb8b31 commit e9e86d6
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 93 deletions.
13 changes: 5 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -46,16 +49,10 @@ _wip_

<https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object>

#### 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)

---

Expand Down
10 changes: 5 additions & 5 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
}

Expand All @@ -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 {
Expand Down
20 changes: 10 additions & 10 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
20 changes: 12 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
64 changes: 37 additions & 27 deletions go.sum
Original file line number Diff line number Diff line change
@@ -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=
44 changes: 29 additions & 15 deletions kantoku.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
8 changes: 4 additions & 4 deletions kantoku.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
37 changes: 21 additions & 16 deletions routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
}

0 comments on commit e9e86d6

Please sign in to comment.