2017-06-03 19:15:20 +00:00
|
|
|
package msgbus
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
|
|
|
|
"golang.org/x/net/websocket"
|
|
|
|
|
|
|
|
"github.com/julienschmidt/httprouter"
|
|
|
|
)
|
|
|
|
|
2017-06-08 04:53:21 +00:00
|
|
|
// Server ...
|
|
|
|
type Server struct {
|
|
|
|
bind string
|
|
|
|
bus *MessageBus
|
|
|
|
router *httprouter.Router
|
|
|
|
}
|
|
|
|
|
2017-06-03 19:15:20 +00:00
|
|
|
// IndexHandler ...
|
2017-06-08 04:53:21 +00:00
|
|
|
func (s *Server) IndexHandler() httprouter.Handle {
|
|
|
|
return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
|
|
fmt.Fprint(w, "Welcome!\n")
|
|
|
|
}
|
2017-06-03 19:15:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// PushHandler ...
|
2017-06-08 04:53:21 +00:00
|
|
|
func (s *Server) PushHandler() httprouter.Handle {
|
|
|
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
topic := p.ByName("topic")
|
|
|
|
websocket.Handler(s.PushWebSocketHandler(topic)).ServeHTTP(w, r)
|
|
|
|
}
|
2017-06-03 19:15:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// PullHandler ...
|
2017-06-08 04:53:21 +00:00
|
|
|
func (s *Server) PullHandler() httprouter.Handle {
|
|
|
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
topic := p.ByName("topic")
|
|
|
|
message, ok := s.bus.Get(topic)
|
|
|
|
if !ok {
|
|
|
|
http.Error(w, "Not Found", http.StatusNotFound)
|
|
|
|
return
|
|
|
|
}
|
2017-06-03 19:15:20 +00:00
|
|
|
|
2017-06-08 04:53:21 +00:00
|
|
|
out, err := json.Marshal(message)
|
|
|
|
if err != nil {
|
|
|
|
http.Error(w, "Internal Error", http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
2017-06-03 19:15:20 +00:00
|
|
|
|
2017-06-08 04:53:21 +00:00
|
|
|
w.Write(out)
|
|
|
|
}
|
2017-06-03 19:15:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// PutHandler ...
|
2017-06-08 04:53:21 +00:00
|
|
|
func (s *Server) PutHandler() httprouter.Handle {
|
|
|
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
|
|
topic := p.ByName("topic")
|
|
|
|
body, err := ioutil.ReadAll(r.Body)
|
|
|
|
if err != nil {
|
|
|
|
http.Error(w, "Internal Error", http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
2017-06-03 19:15:20 +00:00
|
|
|
|
2017-06-08 04:53:21 +00:00
|
|
|
s.bus.Put(topic, s.bus.NewMessage(body))
|
|
|
|
}
|
2017-06-03 19:15:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// PushWebSocketHandler ...
|
2017-06-08 04:53:21 +00:00
|
|
|
func (s *Server) PushWebSocketHandler(topic string) websocket.Handler {
|
2017-06-03 19:15:20 +00:00
|
|
|
return func(conn *websocket.Conn) {
|
|
|
|
id := conn.Request().RemoteAddr
|
2017-06-08 04:53:21 +00:00
|
|
|
ch := s.bus.Subscribe(id, topic)
|
2017-06-03 19:15:20 +00:00
|
|
|
defer func() {
|
2017-06-08 04:53:21 +00:00
|
|
|
s.bus.Unsubscribe(id, topic)
|
2017-06-03 19:15:20 +00:00
|
|
|
}()
|
|
|
|
|
|
|
|
var (
|
|
|
|
err error
|
2017-06-08 04:53:21 +00:00
|
|
|
ack Ack
|
2017-06-03 19:15:20 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
for {
|
|
|
|
msg := <-ch
|
|
|
|
err = websocket.JSON.Send(conn, msg)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Error sending msg to %s", id)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
err = websocket.JSON.Receive(conn, &ack)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Error receiving ack from %s", id)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("message %v acked %v by %s", msg, ack, id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-08 04:53:21 +00:00
|
|
|
func (s *Server) ListenAndServe() {
|
|
|
|
log.Fatal(http.ListenAndServe(s.bind, s.router))
|
2017-06-03 19:15:20 +00:00
|
|
|
}
|
|
|
|
|
2017-06-08 04:53:21 +00:00
|
|
|
func (s *Server) initRoutes() {
|
|
|
|
s.router.GET("/", s.IndexHandler())
|
|
|
|
s.router.GET("/push/:topic", s.PushHandler())
|
|
|
|
s.router.GET("/pull/:topic", s.PullHandler())
|
|
|
|
s.router.PUT("/:topic", s.PutHandler())
|
2017-06-03 19:15:20 +00:00
|
|
|
}
|
|
|
|
|
2017-06-08 04:53:21 +00:00
|
|
|
// NewServer ...
|
|
|
|
func NewServer(bind string) *Server {
|
|
|
|
server := &Server{
|
|
|
|
bind: bind,
|
|
|
|
bus: NewMessageBus(),
|
|
|
|
router: httprouter.New(),
|
|
|
|
}
|
2017-06-03 19:15:20 +00:00
|
|
|
|
2017-06-08 04:53:21 +00:00
|
|
|
server.initRoutes()
|
|
|
|
|
|
|
|
return server
|
2017-06-03 19:15:20 +00:00
|
|
|
}
|