You've already forked microservices
mirror of
https://github.com/ebosas/microservices.git
synced 2025-06-24 22:26:56 +02:00
218 lines
4.8 KiB
Go
218 lines
4.8 KiB
Go
![]() |
package main
|
||
|
|
||
|
import (
|
||
|
"embed"
|
||
|
"fmt"
|
||
|
"html/template"
|
||
|
"log"
|
||
|
"net/http"
|
||
|
"time"
|
||
|
|
||
|
"github.com/ebosas/microservices/config"
|
||
|
"github.com/gorilla/websocket"
|
||
|
"github.com/streadway/amqp"
|
||
|
)
|
||
|
|
||
|
//go:embed template.html
|
||
|
var files embed.FS
|
||
|
|
||
|
//go:embed static
|
||
|
var static embed.FS
|
||
|
|
||
|
var (
|
||
|
conf = config.New()
|
||
|
upgrader = websocket.Upgrader{} // use default options
|
||
|
)
|
||
|
|
||
|
func main() {
|
||
|
log.SetFlags(0)
|
||
|
|
||
|
conn, err := amqp.Dial(conf.RabbitURL)
|
||
|
if err != nil {
|
||
|
log.Fatalf("Failed to connect to RabbitMQ: %s", err)
|
||
|
}
|
||
|
defer conn.Close()
|
||
|
|
||
|
ch, err := conn.Channel()
|
||
|
if err != nil {
|
||
|
log.Fatalf("Failed to open a channel: %s", err)
|
||
|
}
|
||
|
defer ch.Close()
|
||
|
|
||
|
err = ch.ExchangeDeclare(
|
||
|
conf.Exchange, // name
|
||
|
"topic", // type
|
||
|
true, // durable
|
||
|
false, // auto-deleted
|
||
|
false, // internal
|
||
|
false, // no-wait
|
||
|
nil, // arguments
|
||
|
)
|
||
|
if err != nil {
|
||
|
log.Fatalf("Failed to declare an exchange: %s", err)
|
||
|
}
|
||
|
|
||
|
_, err = ch.QueueDeclare(
|
||
|
conf.QueueBack, // name
|
||
|
true, // durable
|
||
|
false, // delete when unused
|
||
|
false, // exclusive
|
||
|
false, // no-wait
|
||
|
nil, // arguments
|
||
|
)
|
||
|
if err != nil {
|
||
|
log.Fatalf("Failed to declare a backend queue: %s", err)
|
||
|
}
|
||
|
|
||
|
err = ch.QueueBind(
|
||
|
conf.QueueBack, // queue name
|
||
|
fmt.Sprintf("#.%s.#", conf.KeyBack), // routing key
|
||
|
conf.Exchange, // exchange
|
||
|
false, // no-wait
|
||
|
nil, // arguments
|
||
|
)
|
||
|
if err != nil {
|
||
|
log.Fatalf("Failed to bind a backend queue: %s", err)
|
||
|
}
|
||
|
|
||
|
// files := http.FileServer(http.Dir("./static"))
|
||
|
// http.Handle("/static/", http.StripPrefix("/static/", files))
|
||
|
// http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(static))))
|
||
|
http.Handle("/static/", http.FileServer(http.FS(static)))
|
||
|
|
||
|
http.HandleFunc("/", handleHome)
|
||
|
http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
|
||
|
handleWs(w, r, conn)
|
||
|
})
|
||
|
|
||
|
log.Fatal(http.ListenAndServe(conf.ServerAddr, nil))
|
||
|
}
|
||
|
|
||
|
func handleHome(w http.ResponseWriter, r *http.Request) {
|
||
|
// t, _ := template.ParseFiles("template.html")
|
||
|
t, _ := template.ParseFS(files, "template.html")
|
||
|
t.Execute(w, nil)
|
||
|
}
|
||
|
|
||
|
func handleWs(w http.ResponseWriter, r *http.Request, c *amqp.Connection) {
|
||
|
ws, err := upgrader.Upgrade(w, r, nil)
|
||
|
if err != nil {
|
||
|
log.Printf("Failed to upgrade WebSocket: %s", err)
|
||
|
return
|
||
|
}
|
||
|
defer ws.Close()
|
||
|
|
||
|
done := make(chan bool)
|
||
|
|
||
|
go wsWriter(ws, c, done)
|
||
|
go wsReader(ws, c, done)
|
||
|
|
||
|
<-done
|
||
|
}
|
||
|
|
||
|
// wsWriter reads messages from a Rabbit exchange
|
||
|
// and writes to a websocket
|
||
|
func wsWriter(ws *websocket.Conn, c *amqp.Connection, done chan bool) {
|
||
|
defer func() {
|
||
|
done <- true
|
||
|
}()
|
||
|
|
||
|
ch, err := c.Channel()
|
||
|
if err != nil {
|
||
|
log.Printf("Failed to open a channel: %s", err)
|
||
|
return
|
||
|
}
|
||
|
defer ch.Close()
|
||
|
|
||
|
q, err := ch.QueueDeclare(
|
||
|
"", // name
|
||
|
false, // durable
|
||
|
true, // delete when unused
|
||
|
true, // exclusive
|
||
|
false, // no-wait
|
||
|
nil, // arguments
|
||
|
)
|
||
|
if err != nil {
|
||
|
log.Printf("Failed to create a frontend queue: %s", err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
err = ch.QueueBind(
|
||
|
q.Name, // queue name
|
||
|
fmt.Sprintf("#.%s.#", conf.KeyFront), // routing key
|
||
|
conf.Exchange, // exchange
|
||
|
false, // no-wait
|
||
|
nil, // arguments
|
||
|
)
|
||
|
if err != nil {
|
||
|
log.Printf("Failed to bind a frontend queue: %s", err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
msgs, err := ch.Consume(
|
||
|
q.Name, // queue name
|
||
|
"", // consumer
|
||
|
false, // auto-ack
|
||
|
false, // exclusive
|
||
|
false, // no-local
|
||
|
false, // no-wait
|
||
|
nil, // args
|
||
|
)
|
||
|
if err != nil {
|
||
|
log.Printf("Failed to register a consumer: %s", err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
for msg := range msgs {
|
||
|
ws.SetWriteDeadline(time.Now().Add(10 * time.Second))
|
||
|
err = ws.WriteMessage(websocket.TextMessage, []byte(msg.Body))
|
||
|
if err != nil {
|
||
|
log.Printf("Failed to write to WebSocket: %s", err)
|
||
|
break
|
||
|
}
|
||
|
|
||
|
msg.Ack(false)
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// wsReader reads messages from a websocket and writes
|
||
|
// to a Rabbit exchange
|
||
|
func wsReader(ws *websocket.Conn, c *amqp.Connection, done chan bool) {
|
||
|
defer func() {
|
||
|
done <- true
|
||
|
}()
|
||
|
|
||
|
ch, err := c.Channel()
|
||
|
if err != nil {
|
||
|
log.Printf("Failed to open a channel: %s", err)
|
||
|
return
|
||
|
}
|
||
|
defer ch.Close()
|
||
|
|
||
|
for {
|
||
|
_, message, err := ws.ReadMessage()
|
||
|
if err != nil {
|
||
|
log.Printf("Failed to read a message: %s", err)
|
||
|
break
|
||
|
}
|
||
|
|
||
|
err = ch.Publish(
|
||
|
conf.Exchange, // exchane name
|
||
|
conf.KeyBack+"."+conf.KeyDB, // routing key
|
||
|
false, // mandatory
|
||
|
false, // immediate
|
||
|
amqp.Publishing{
|
||
|
Timestamp: time.Now(),
|
||
|
ContentType: "text/plain",
|
||
|
Body: []byte(message),
|
||
|
},
|
||
|
)
|
||
|
if err != nil {
|
||
|
log.Printf("Failed to publish a message: %s", err)
|
||
|
break
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|