rabbitmq auto reconnect after connection lost
parent
cd6bb93e99
commit
eb1a18d03a
1
go.mod
1
go.mod
|
@ -3,6 +3,7 @@ module clickandjoin.app/websocketserver
|
||||||
go 1.19
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.23 // indirect
|
||||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||||
github.com/fasthttp/websocket v1.5.0 // indirect
|
github.com/fasthttp/websocket v1.5.0 // indirect
|
||||||
github.com/gocql/gocql v1.3.1 // indirect
|
github.com/gocql/gocql v1.3.1 // indirect
|
||||||
|
|
40
go.sum
40
go.sum
|
@ -1,3 +1,43 @@
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.4 h1:LdnXOQ+rxyb3F0UsUB8PCe2rj13HF7rPU9/AI6XEE2Y=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.4/go.mod h1:TnJVKLDZ8l/2HFeU6yzSGrxa1A9g4IpXlpLMqbgxnvo=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.5 h1:zDfrB0gutr3XOHBLbWjH1D51d+4QLgr8VNbGYbBCkbg=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.5/go.mod h1:TnJVKLDZ8l/2HFeU6yzSGrxa1A9g4IpXlpLMqbgxnvo=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.6 h1:RLJUVs8EfmhlU9IWHTpqnd/65m58yloJ8vb7geHFOOU=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.6/go.mod h1:TnJVKLDZ8l/2HFeU6yzSGrxa1A9g4IpXlpLMqbgxnvo=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.7 h1:PLdOzcnNxyrnHOg8pRGUJ9lZ+YIB/J16Vspuoytqx3I=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.7/go.mod h1:TnJVKLDZ8l/2HFeU6yzSGrxa1A9g4IpXlpLMqbgxnvo=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.8 h1:uMFmtiaOy8jiqW0HpZ9/9O2tpXplvOjYXIB/spuDib4=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.8/go.mod h1:TnJVKLDZ8l/2HFeU6yzSGrxa1A9g4IpXlpLMqbgxnvo=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.9 h1:yU7apejSLPdNyUNi/k6/Ix+QbSjyDLMgxsX2r9dFPrM=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.9/go.mod h1:TnJVKLDZ8l/2HFeU6yzSGrxa1A9g4IpXlpLMqbgxnvo=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.10 h1:lzYHPbLKuSe6Uh7fifvRcWy/6ZkszZ9/vAKrhHsBRE0=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.10/go.mod h1:TnJVKLDZ8l/2HFeU6yzSGrxa1A9g4IpXlpLMqbgxnvo=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.11 h1:CcdPpf2DcdZiCJ1oGj4ExN3VGMeubmZBdjVmLAFQUdA=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.11/go.mod h1:TnJVKLDZ8l/2HFeU6yzSGrxa1A9g4IpXlpLMqbgxnvo=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.12 h1:/KZI3TdUGp8kMb+0xbafvvnvU3lorieJetnKE8KMEmE=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.12/go.mod h1:TnJVKLDZ8l/2HFeU6yzSGrxa1A9g4IpXlpLMqbgxnvo=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.13 h1:IKEIiXplAyutn/tMUjLkF5lbfmeWpL9rMcLYaMS0uDM=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.13/go.mod h1:TnJVKLDZ8l/2HFeU6yzSGrxa1A9g4IpXlpLMqbgxnvo=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.14 h1:lfjHLJVILSYhHSIMensVOqlhUrAmISSmEEtpZh8QJAk=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.14/go.mod h1:KPbHNtFhttE/TtXZcorq6LKpCigkTaF0qzmB2p7nFsg=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.15 h1:QVZrkx+/gTt/E7DtGYwGnI9hQ66/D/F3YWwFdBPdtyg=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.15/go.mod h1:KPbHNtFhttE/TtXZcorq6LKpCigkTaF0qzmB2p7nFsg=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.16 h1:i9+wrkOQQbhuRU1xMaWTr2Y4JFdOQamTS/BZO8pCMjc=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.16/go.mod h1:KPbHNtFhttE/TtXZcorq6LKpCigkTaF0qzmB2p7nFsg=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.17 h1:Xh62QbcYLj/07r2hoR+Dz9K0vkbuP8oZ2NdspCfXPmc=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.17/go.mod h1:KPbHNtFhttE/TtXZcorq6LKpCigkTaF0qzmB2p7nFsg=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.18 h1:7WzhKv+b/leJoqa9h/kPlEcN3zijHXD88aPYtCboWhY=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.18/go.mod h1:KPbHNtFhttE/TtXZcorq6LKpCigkTaF0qzmB2p7nFsg=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.19 h1:RDvCD1EtTMe+eDWitGnyA6DwlmO10NqfXLRvGw1Ieho=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.19/go.mod h1:KPbHNtFhttE/TtXZcorq6LKpCigkTaF0qzmB2p7nFsg=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.20 h1:0fFXnoqdnzXxmLRBf3Rnp9UTuUT0zmrnIxO7OA+IZao=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.20/go.mod h1:KPbHNtFhttE/TtXZcorq6LKpCigkTaF0qzmB2p7nFsg=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.21 h1:6VgGO8GsrPtBfS6tcamw2OFRt4XplIKAY6zpgNbCvdg=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.21/go.mod h1:KPbHNtFhttE/TtXZcorq6LKpCigkTaF0qzmB2p7nFsg=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.22 h1:26wm+XTVNsoQxg8RHzkwS/s5ZKSjTvjQXg2GTM7Pwgw=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.22/go.mod h1:KPbHNtFhttE/TtXZcorq6LKpCigkTaF0qzmB2p7nFsg=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.23 h1:FYMFWE9gXAXtvLzyVmv9yp/AmQos1OfTuVZy6DnQrEw=
|
||||||
|
git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client v1.0.23/go.mod h1:KPbHNtFhttE/TtXZcorq6LKpCigkTaF0qzmB2p7nFsg=
|
||||||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
|
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
|
||||||
|
|
|
@ -0,0 +1,220 @@
|
||||||
|
package rabbitmq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"clickandjoin.app/websocketserver/modules/structs"
|
||||||
|
"clickandjoin.app/websocketserver/modules/utils"
|
||||||
|
"clickandjoin.app/websocketserver/socketclients"
|
||||||
|
gorabbitmqclient "git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
amqp "github.com/rabbitmq/amqp091-go"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PublishClientMessage(rabbitMqMessage structs.RabbitMqMessage) error {
|
||||||
|
msg, err := json.Marshal(rabbitMqMessage)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorln("Failed to marshal rabbitMqMessage, err:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = WebsocketClient.PushExchangeMessage(rabbitMqMessage.Rec, msg)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorln("Failed to publish client msg, err:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each user a queue is created in the websocket exchange channel where he receives his messages
|
||||||
|
func CreateWSClientBinding(socketClient *structs.SocketClient, id string) (err error) {
|
||||||
|
msgs, err := createWSClientQueueAndBindingConsumer(socketClient, id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorln("Failed to create ws client queue and binding consumer, err:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// canceled when websocket client disconnects
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
socketClient.CancelFunc = cancel
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
logrus.Println("DONE!")
|
||||||
|
return
|
||||||
|
case <-WebSocketChannelClosedChannel:
|
||||||
|
// This case handles the event of closed channel e.g. abnormal shutdown
|
||||||
|
msgs, err = createWSClientQueueAndBindingConsumer(socketClient, id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// If the AMQP channel is not ready, it will continue the loop. Next
|
||||||
|
// iteration will enter this case because chClosedCh is closed by the
|
||||||
|
// library
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugln("Re-set ws client channel", socketClient.RabbitMqConsumerId)
|
||||||
|
|
||||||
|
// Re-set channel to receive notifications
|
||||||
|
// The library closes this channel after abnormal shutdown
|
||||||
|
WebSocketChannelClosedChannel = make(chan *amqp.Error, 1)
|
||||||
|
WebsocketClient.Channel.NotifyClose(WebSocketChannelClosedChannel)
|
||||||
|
|
||||||
|
case msg := <-msgs:
|
||||||
|
var receivedMessage structs.ReceivedMessage
|
||||||
|
|
||||||
|
err = utils.UnmarshalReceivedMessage(msg.Body, &receivedMessage)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorln("Failed to unmarshal received msg, err:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugln("RABBITMQ RECEIVED MESSAGE:", receivedMessage)
|
||||||
|
|
||||||
|
err = socketClient.SendMessage(structs.SendSocketMessage{Cmd: receivedMessage.Cmd, Body: receivedMessage.Body})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorln("Failed to send message to client, err:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createWSClientQueueAndBindingConsumer(socketClient *structs.SocketClient, id string) (msgs <-chan amqp.Delivery, err error) {
|
||||||
|
q, err := WebsocketClient.QueueDeclare(gorabbitmqclient.QueueDeclareSettings{
|
||||||
|
Name: "",
|
||||||
|
Durable: false,
|
||||||
|
DeleteWhenUnused: false,
|
||||||
|
Exclusive: true,
|
||||||
|
NoWait: false,
|
||||||
|
Arguments: nil,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return msgs, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// set an ID for the consumer to delete the consumer after the socket user has disconnected
|
||||||
|
socketClient.RabbitMqConsumerId = uuid.New().String()
|
||||||
|
|
||||||
|
// store queue name in the client to delete it when the client disconnects from the websocket
|
||||||
|
socketClient.RabbitMqQueueName = q.Name
|
||||||
|
|
||||||
|
err = WebsocketClient.QueueBind(gorabbitmqclient.QueueBindSettings{
|
||||||
|
QueueName: q.Name,
|
||||||
|
RoutingKey: id,
|
||||||
|
Exchange: exchangeWebsocketMessages,
|
||||||
|
NoWait: false,
|
||||||
|
Arguments: nil,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorln("Failed to bind queue, err:", err)
|
||||||
|
return msgs, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return WebsocketClient.ConsumeChannelMessages(gorabbitmqclient.ChannelConsumeSettings{
|
||||||
|
QueueName: q.Name,
|
||||||
|
Consumer: socketClient.RabbitMqConsumerId,
|
||||||
|
AutoAck: true,
|
||||||
|
Exclusive: false,
|
||||||
|
NoLocal: false,
|
||||||
|
NoWait: false,
|
||||||
|
Arguments: nil,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteWSClient(consumerId string, qName string) error {
|
||||||
|
// delete consumer
|
||||||
|
err := WebsocketClient.Channel.Cancel(consumerId, false)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorln("Failed to delete consumer, err:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete queue and queue binding
|
||||||
|
_, err = WebsocketClient.Channel.QueueDelete(qName, false, true, false)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorln("Failed to delete queue, err:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Println("deleted", consumerId, qName)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ApiBroadcastMessagesHandling() {
|
||||||
|
msgs, err := apiBroadcastMessagesConsumer()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorln("Failed to create api broadcast message consumer, err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
channelClosedChannel := make(chan *amqp.Error, 1)
|
||||||
|
ApiBroadcastClient.Channel.NotifyClose(channelClosedChannel)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-channelClosedChannel:
|
||||||
|
// This case handles the event of closed channel e.g. abnormal shutdown
|
||||||
|
msgs, err = apiBroadcastMessagesConsumer()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// If the AMQP channel is not ready, it will continue the loop. Next
|
||||||
|
// iteration will enter this case because chClosedCh is closed by the
|
||||||
|
// library
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugln("Re-set api broadcast channel")
|
||||||
|
|
||||||
|
// Re-set channel to receive notifications
|
||||||
|
// The library closes this channel after abnormal shutdown
|
||||||
|
channelClosedChannel = make(chan *amqp.Error, 1)
|
||||||
|
WebsocketClient.Channel.NotifyClose(channelClosedChannel)
|
||||||
|
|
||||||
|
case msg := <-msgs:
|
||||||
|
var receivedMessage structs.ReceivedMessage
|
||||||
|
|
||||||
|
err = utils.UnmarshalReceivedMessage(msg.Body, &receivedMessage)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorln("Failed to unmarshal received msg, err:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugln("RABBITMQ RECEIVED BROADCAST MESSAGE:", receivedMessage)
|
||||||
|
|
||||||
|
socketclients.BroadcastMessage(structs.SendSocketMessage{Cmd: receivedMessage.Cmd, Body: receivedMessage.Body})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func apiBroadcastMessagesConsumer() (msgs <-chan amqp.Delivery, err error) {
|
||||||
|
return ApiBroadcastClient.ConsumeChannelMessages(gorabbitmqclient.ChannelConsumeSettings{
|
||||||
|
QueueName: ApiBroadcastClient.AssignedQueueName,
|
||||||
|
Consumer: "",
|
||||||
|
AutoAck: true,
|
||||||
|
Exclusive: false,
|
||||||
|
NoLocal: false,
|
||||||
|
NoWait: false,
|
||||||
|
Arguments: nil,
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,300 +1,101 @@
|
||||||
package rabbitmq
|
package rabbitmq
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"clickandjoin.app/websocketserver/modules/config"
|
"clickandjoin.app/websocketserver/modules/config"
|
||||||
"clickandjoin.app/websocketserver/modules/structs"
|
gorabbitmqclient "git.clickandjoin.umbach.dev/ClickandJoin/go-rabbitmq-client"
|
||||||
"clickandjoin.app/websocketserver/modules/utils"
|
|
||||||
"clickandjoin.app/websocketserver/socketclients"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
amqp "github.com/rabbitmq/amqp091-go"
|
amqp "github.com/rabbitmq/amqp091-go"
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var Conn *amqp.Connection
|
|
||||||
var Channel *amqp.Channel
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
exchangeWebsocketMessages = "cnj.websocketserver.messages"
|
exchangeWebsocketMessages = "cnj.websocketserver.messages"
|
||||||
exchangeBroadcastMessages = "cnj.api.broadcast.messages"
|
exchangeBroadcastMessages = "cnj.api.broadcast.messages"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getConnectionString() string {
|
var (
|
||||||
cfg := &config.Cfg.RabbitMq
|
WebsocketClient *gorabbitmqclient.Client
|
||||||
|
ApiBroadcastClient *gorabbitmqclient.Client
|
||||||
return fmt.Sprintf("amqp://%s:%s@%s/", cfg.Username, cfg.Password, cfg.Host)
|
ConnectionAddress string
|
||||||
}
|
WebSocketChannelClosedChannel chan *amqp.Error // informs when the connection has been lost
|
||||||
|
)
|
||||||
|
|
||||||
func Init() {
|
func Init() {
|
||||||
conn, err := amqp.Dial(getConnectionString())
|
cfg := config.Cfg
|
||||||
|
|
||||||
if err != nil {
|
ConnectionAddress = gorabbitmqclient.GetConnectionString(cfg.RabbitMq.Username, cfg.RabbitMq.Password, cfg.RabbitMq.Host)
|
||||||
logrus.Fatalln("RabbitMQ connection failed, err:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ch, err := conn.Channel()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logrus.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
Channel = ch
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* websocketserver messages
|
* websocketserver messages
|
||||||
*/
|
*/
|
||||||
// creates a new exchange if one does not already exist
|
WebsocketClient = gorabbitmqclient.NewClient(
|
||||||
|
cfg.Debug,
|
||||||
err = ch.ExchangeDeclare(
|
gorabbitmqclient.ExchangeSettings{
|
||||||
exchangeWebsocketMessages, // name
|
Name: exchangeWebsocketMessages,
|
||||||
"direct", // type
|
Type: "direct",
|
||||||
true, // durable
|
Durable: true,
|
||||||
false, // auto-deleted
|
AutoDeleted: false,
|
||||||
false, // internal
|
Internal: false,
|
||||||
false, // no-wait
|
NoWait: false,
|
||||||
nil, // arguments
|
Arguments: nil,
|
||||||
)
|
ExchangePublishSettings: gorabbitmqclient.ExchangePublishSettings{
|
||||||
|
Mandatory: false,
|
||||||
if err != nil {
|
Immediate: false,
|
||||||
logrus.Fatalln("Failed to declare exchange, err:", err)
|
ContentType: gorabbitmqclient.ContentTypeJson,
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
gorabbitmqclient.QueueSettings{},
|
||||||
|
gorabbitmqclient.ChannelQosSettingsDefault,
|
||||||
|
gorabbitmqclient.Config{
|
||||||
|
ReconnectDelay: 1 * time.Second,
|
||||||
|
ReInitDelay: 1 * time.Second,
|
||||||
|
ResendDelay: 5 * time.Second,
|
||||||
|
},
|
||||||
|
ConnectionAddress)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* api broadcast messages
|
* api broadcast messages
|
||||||
*/
|
*/
|
||||||
|
|
||||||
q, err := ch.QueueDeclare(
|
ApiBroadcastClient = gorabbitmqclient.NewClient(
|
||||||
"", // name
|
cfg.Debug,
|
||||||
false, // durable
|
gorabbitmqclient.ExchangeSettings{},
|
||||||
false, // delete when unused
|
gorabbitmqclient.QueueSettings{
|
||||||
true, // exclusive
|
Name: "",
|
||||||
false, // no-wait
|
Durable: false,
|
||||||
nil, // arguments
|
DeleteWhenUnused: false,
|
||||||
)
|
Exclusive: true,
|
||||||
|
NoWait: false,
|
||||||
|
Arguments: nil,
|
||||||
|
QueueBindSettings: gorabbitmqclient.QueueBindSettings{
|
||||||
|
Enabled: true,
|
||||||
|
QueueName: gorabbitmqclient.SetQueueNameToAutomaticallyAssignedQueueName,
|
||||||
|
RoutingKey: "",
|
||||||
|
Exchange: exchangeBroadcastMessages,
|
||||||
|
NoWait: false,
|
||||||
|
Arguments: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
gorabbitmqclient.ChannelQosSettingsDefault,
|
||||||
|
gorabbitmqclient.Config{
|
||||||
|
ReconnectDelay: 1 * time.Second,
|
||||||
|
ReInitDelay: 1 * time.Second,
|
||||||
|
ResendDelay: 5 * time.Second,
|
||||||
|
},
|
||||||
|
ConnectionAddress)
|
||||||
|
|
||||||
if err != nil {
|
// give the connection sometime to setup
|
||||||
logrus.Fatalln("Failed to declare queue, err:", err)
|
<-time.After(time.Second)
|
||||||
}
|
|
||||||
|
|
||||||
err = ch.QueueBind(
|
/*
|
||||||
q.Name, // queue name
|
* websocketserver messages
|
||||||
"", // routing key
|
*/
|
||||||
exchangeBroadcastMessages, // exchange
|
WebSocketChannelClosedChannel = make(chan *amqp.Error, 1)
|
||||||
false,
|
WebsocketClient.Channel.NotifyClose(WebSocketChannelClosedChannel)
|
||||||
nil,
|
|
||||||
)
|
|
||||||
|
|
||||||
if err != nil {
|
/*
|
||||||
logrus.Fatalln("Failed to declare queue, err:", err)
|
* api broadcast messages
|
||||||
}
|
*/
|
||||||
|
|
||||||
msgs, err := ch.Consume(
|
|
||||||
q.Name, // queue
|
|
||||||
"", // consumer
|
|
||||||
true, // auto-ack
|
|
||||||
false, // exclusive
|
|
||||||
false, // no-local
|
|
||||||
false, // no-wait
|
|
||||||
nil, // args
|
|
||||||
)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logrus.Fatalln("Failed to register consumer, err:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for d := range msgs {
|
|
||||||
var receivedMessage structs.ReceivedMessage
|
|
||||||
|
|
||||||
err = utils.UnmarshalReceivedMessage(d.Body, &receivedMessage)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorln("Failed to unmarshal received msg, err:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugln("RABBITMQ RECEIVED BROADCAST MESSAGE:", receivedMessage)
|
|
||||||
|
|
||||||
socketclients.BroadcastMessage(structs.SendSocketMessage{Cmd: receivedMessage.Cmd, Body: receivedMessage.Body})
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
|
go ApiBroadcastMessagesHandling()
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateClientBinding(socketClient *structs.SocketClient, id string) (queueName string, err error) {
|
|
||||||
q, err := Channel.QueueDeclare(
|
|
||||||
"", // name
|
|
||||||
false, // durable
|
|
||||||
false, // delete when unused
|
|
||||||
true, // exclusive
|
|
||||||
false, // no-wait
|
|
||||||
nil, // arguments
|
|
||||||
)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorln("Failed to declare queue, err:", err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = Channel.QueueBind(
|
|
||||||
q.Name, // name
|
|
||||||
id, // key
|
|
||||||
exchangeWebsocketMessages, // exchange
|
|
||||||
false, // no-wait
|
|
||||||
nil, // arguments
|
|
||||||
)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorln("Failed to bind queue, err:", err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
// set an ID for the consumer to delete the consumer after the socket user has disconnected
|
|
||||||
socketClient.RabbitMqConsumerId = uuid.New().String()
|
|
||||||
|
|
||||||
msgs, err := Channel.Consume(
|
|
||||||
q.Name, // queue
|
|
||||||
socketClient.RabbitMqConsumerId, // consumer
|
|
||||||
true, // auto ack
|
|
||||||
false, // exclusive
|
|
||||||
false, // no local
|
|
||||||
false, // no wait
|
|
||||||
nil, // args
|
|
||||||
)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorln("Failed to register consumer, err:", err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for d := range msgs {
|
|
||||||
var receivedMessage structs.ReceivedMessage
|
|
||||||
|
|
||||||
err = utils.UnmarshalReceivedMessage(d.Body, &receivedMessage)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorln("Failed to unmarshal received msg, err:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugln("RABBITMQ RECEIVED MESSAGE:", receivedMessage)
|
|
||||||
|
|
||||||
err = socketClient.SendMessage(structs.SendSocketMessage{Cmd: receivedMessage.Cmd, Body: receivedMessage.Body})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorln("Failed to send message to client, err:", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return q.Name, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteClient(consumerId string, qName string) error {
|
|
||||||
// delete consumer
|
|
||||||
err := Channel.Cancel(consumerId, false)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorln("Failed to delete consumer, err:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete queue and queue binding
|
|
||||||
_, err = Channel.QueueDelete(qName, false, true, false)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorln("Failed to delete queue, err:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func PublishClientMessage(rabbitMqMessage structs.RabbitMqMessage) error {
|
|
||||||
msg, err := json.Marshal(rabbitMqMessage)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorln("Failed to marshal rabbitMqMessage, err:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
err = Channel.PublishWithContext(ctx,
|
|
||||||
exchangeWebsocketMessages, // exchange
|
|
||||||
rabbitMqMessage.Rec, // routing key
|
|
||||||
false, // mandatory
|
|
||||||
false, // immediate
|
|
||||||
amqp.Publishing{
|
|
||||||
ContentType: "application/json",
|
|
||||||
Body: msg,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorln("Failed to publish client msg, err:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
func PublishBroadcastMessage(rabbitMqMessage structs.RabbitMqMessage) error {
|
|
||||||
msg, err := json.Marshal(rabbitMqMessage)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorln("Failed to marshal rabbitMqMessage, err:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = publishMessage(msg, MessagesQueue.Name)
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func publishMessage(body []byte, channelName string) error {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
err := Channel.PublishWithContext(ctx,
|
|
||||||
"messages", // exchange
|
|
||||||
"", // routing key
|
|
||||||
false, // mandatory
|
|
||||||
false, // immediate
|
|
||||||
amqp.Publishing{
|
|
||||||
ContentType: "application/json",
|
|
||||||
Body: body,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorln("Failed to publish a message, err:", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Printf("[x] Sent %s\n", body)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
} */
|
|
||||||
|
|
||||||
/*
|
|
||||||
func declareQueue(channel *amqp.Channel, name string, queue *amqp.Queue) {
|
|
||||||
q, err := channel.QueueDeclare(
|
|
||||||
name, // name
|
|
||||||
true, // durable
|
|
||||||
false, // delete when unused
|
|
||||||
false, // exclusive
|
|
||||||
false, // no-wait
|
|
||||||
nil, // arguments
|
|
||||||
)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("Failed to declare a queue", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
*queue = q
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package structs
|
package structs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
@ -13,6 +14,7 @@ type SocketClient struct {
|
||||||
connMu sync.Mutex
|
connMu sync.Mutex
|
||||||
RabbitMqQueueName string
|
RabbitMqQueueName string
|
||||||
RabbitMqConsumerId string
|
RabbitMqConsumerId string
|
||||||
|
CancelFunc context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
type SocketMessage struct {
|
type SocketMessage struct {
|
||||||
|
|
|
@ -21,15 +21,13 @@ func RunHub() {
|
||||||
case newSocketClient := <-register:
|
case newSocketClient := <-register:
|
||||||
uuid := uuid.New().String()
|
uuid := uuid.New().String()
|
||||||
|
|
||||||
queueName, err := rabbitmq.CreateClientBinding(newSocketClient, uuid)
|
err := rabbitmq.CreateWSClientBinding(newSocketClient, uuid)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorln("Failed to create client binding, err:", err)
|
logrus.Errorln("Failed to create client binding, err:", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
newSocketClient.RabbitMqQueueName = queueName
|
|
||||||
|
|
||||||
cache.SocketClients[uuid] = newSocketClient
|
cache.SocketClients[uuid] = newSocketClient
|
||||||
|
|
||||||
logrus.Debugln("REGISTER CLIENT:", uuid)
|
logrus.Debugln("REGISTER CLIENT:", uuid)
|
||||||
|
@ -79,7 +77,8 @@ func RunHub() {
|
||||||
logrus.Debugln("UNREGISTER CLIENT:", id)
|
logrus.Debugln("UNREGISTER CLIENT:", id)
|
||||||
delete(cache.SocketClients, id)
|
delete(cache.SocketClients, id)
|
||||||
|
|
||||||
rabbitmq.DeleteClient(client.RabbitMqConsumerId, client.RabbitMqQueueName)
|
client.CancelFunc()
|
||||||
|
rabbitmq.DeleteWSClient(client.RabbitMqConsumerId, client.RabbitMqQueueName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue