server: add long-polling support
This commit is contained in:
parent
94823e104d
commit
1ddbcb3636
@ -158,7 +158,7 @@ func ProcessEvent(globals AsinkGlobals, event *asink.Event) {
|
|||||||
event.Status |= asink.ON_SERVER
|
event.Status |= asink.ON_SERVER
|
||||||
err = DatabaseUpdateEvent(globals.db, event)
|
err = DatabaseUpdateEvent(globals.db, event)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err) //TODO probably, definitely, none of these should panic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
76
server/longpolling.go
Normal file
76
server/longpolling.go
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"asink"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LongPollGroup struct {
|
||||||
|
channels []*chan *asink.Event
|
||||||
|
lock sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
type PollingManager struct {
|
||||||
|
lock sync.RWMutex
|
||||||
|
groups map[string]*LongPollGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
var pm *PollingManager
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
pm = new(PollingManager)
|
||||||
|
pm.groups = make(map[string]*LongPollGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addPoller(uid string, channel *chan *asink.Event) {
|
||||||
|
pm.lock.RLock()
|
||||||
|
|
||||||
|
group := pm.groups[uid]
|
||||||
|
if group != nil {
|
||||||
|
group.lock.Lock()
|
||||||
|
pm.lock.RUnlock()
|
||||||
|
group.channels = append(group.channels, channel)
|
||||||
|
group.lock.Unlock()
|
||||||
|
} else {
|
||||||
|
pm.lock.RUnlock()
|
||||||
|
pm.lock.Lock()
|
||||||
|
group = new(LongPollGroup)
|
||||||
|
group.channels = append(group.channels, channel)
|
||||||
|
pm.groups[uid] = group
|
||||||
|
pm.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
//set timer to call function after one minute
|
||||||
|
timeout := time.Duration(1)*time.Minute
|
||||||
|
time.AfterFunc(timeout, func() {
|
||||||
|
group.lock.Lock()
|
||||||
|
for i, c := range group.channels {
|
||||||
|
if c == channel {
|
||||||
|
copy(group.channels[i:], group.channels[i+1:])
|
||||||
|
group.channels = group.channels[:len(group.channels)-1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
group.lock.Unlock()
|
||||||
|
close(*channel)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func broadcastToPollers(uid string, event *asink.Event) {
|
||||||
|
//store off the long polling group we're trying to send to and remove
|
||||||
|
//it from PollingManager.groups
|
||||||
|
pm.lock.Lock()
|
||||||
|
group := pm.groups[uid]
|
||||||
|
pm.groups[uid] = nil
|
||||||
|
pm.lock.Unlock()
|
||||||
|
|
||||||
|
//send event down each of group's channels
|
||||||
|
if group != nil {
|
||||||
|
group.lock.Lock()
|
||||||
|
for _, c := range group.channels {
|
||||||
|
*c <- event
|
||||||
|
}
|
||||||
|
group.lock.Unlock()
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//global variables
|
||||||
var eventsRegexp *regexp.Regexp
|
var eventsRegexp *regexp.Regexp
|
||||||
var port int = 8080
|
var port int = 8080
|
||||||
var db *sql.DB
|
var db *sql.DB
|
||||||
@ -80,7 +81,15 @@ func getEvents(w http.ResponseWriter, r *http.Request, nextEvent uint64) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO long-poll here if events is empty
|
//long-poll if events is empty
|
||||||
|
if len(events) == 0 {
|
||||||
|
c := make(chan *asink.Event)
|
||||||
|
addPoller("aclindsa", &c) //TODO support more than one user
|
||||||
|
e, ok := <-c
|
||||||
|
if ok {
|
||||||
|
events = append(events, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func putEvents(w http.ResponseWriter, r *http.Request) {
|
func putEvents(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -119,6 +128,8 @@ func putEvents(w http.ResponseWriter, r *http.Request) {
|
|||||||
for _, event := range events.Events {
|
for _, event := range events.Events {
|
||||||
DatabaseAddEvent(db, event)
|
DatabaseAddEvent(db, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
broadcastToPollers("aclindsa", events.Events[0]) //TODO support more than one user
|
||||||
}
|
}
|
||||||
|
|
||||||
func eventHandler(w http.ResponseWriter, r *http.Request) {
|
func eventHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
Loading…
Reference in New Issue
Block a user