Simple tool for handling long polling request on server side.
go get github.com/stanlry/gopolling
package main
import (
"encoding/json"
"github.com/stanlry/gopolling"
"log"
"net/http"
)
var channel = "test"
var mgr = gopolling.New(gopolling.DefaultOption)
func main() {
http.HandleFunc("/message", func(w http.ResponseWriter, r *http.Request) {
resp, _ := mgr.WaitForNotice(r.Context(), channel, nil)
st, _ := json.Marshal(resp)
w.Write(st)
})
http.HandleFunc("/notify", func(w http.ResponseWriter, r *http.Request) {
data := r.URL.Query().Get("data")
mgr.Notify(channel, data, nil)
})
log.Println("start serve on :80")
log.Fatal(http.ListenAndServe(":80", nil))
}
wait for message
curl -s localhsot/message
notify clients
curl -s localhost/notify?data=[your message here]
var mgr = gopolling.New(gopolling.Option{
// message retention time, default is 60s
Retention: 60,
// set the timeout for each request, default 120s
Timeout: 1 * time.Minute,
// message bus, default use goroutine
Bus: adapter.NewRedisAdapter(pool),
// message buffer, default use memory
Buffer: adapter.NewRedisAdapter(pool),
// logger interface, currently support zap and logrus, default will not log any error
Logger: zap.NewExample().Sugar(),
})
wait for notice from listener or notifier
// this function will block until receive a notice or timeout
resp, err := mgr.WaitForNotice(
// request context
r.Context(),
// channel
channel,
// send the data to listener, it will be discarded if no listener exist
"data",
})
only wait for notice with matched selector
resp, err := mgr.WaitForSelectedNotice(
r.Context(),
channel,
"data",
// specify identity in the channel, this selector is essential a string map
gopolling.S{
"id": "xxx",
}
)
Notify everyone that have been waiting in the channel
mgr.Notify(
// channel
channel,
// data being sent
"data",
// selector that specify the receiving side, if no one match the selector, message will be discarded
gopolling.S{
"id": "xxx",
},
)
Listen to event when request was made and reply immediately. The reply message will only notify the one who make the request
// subscribe listener
mgr.SubscribeListener(channel, func(ev gopolling.Event, cb *gopolling.Callback){
// event data
st := ev.Data.(string)
// reply to immediately, you can skip this part if no reply is needed
cb.Reply("reply data")
})
Redis is supported for both message bus and message buffer
pool := &redis.Pool{
MaxIdle: 1,
MaxActive: 100,
IdleTimeout: 5 * time.Minute,
Dial: func() (redis.Conn, error) {
option := redis.DialPassword("password")
con, err := redis.Dial("tcp", "localhost:6379", option)
if err != nil {
return nil, err
}
return con, err
},
}
adapter := adapter.NewRedisAdapter(pool)
mgr := gopolling.New(gopolling.Option{
bus: adapter,
buffer: adapter,
})
GCP Pub/Sub is supported for message bus
client := pubsub.NewClient(context.Background(), "project-id")
adapter := adapter.NewGCPPubSubAdapter(client)
mgr := gopolling.New(gopolling.Option{
bus: adapter,
})