2014-07-10 12:19:39 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2014-07-16 18:57:54 +00:00
|
|
|
"sync"
|
2014-07-10 12:19:39 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type (
|
2014-09-09 08:20:40 +00:00
|
|
|
request struct {
|
|
|
|
queues []string
|
|
|
|
responseCh chan response
|
|
|
|
abort chan bool
|
|
|
|
dead bool
|
2014-07-10 12:19:39 +00:00
|
|
|
}
|
2014-09-09 08:20:40 +00:00
|
|
|
response struct {
|
|
|
|
queue string
|
|
|
|
message message
|
2014-07-10 12:19:39 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2014-07-16 18:57:54 +00:00
|
|
|
pool struct {
|
2014-09-09 08:20:40 +00:00
|
|
|
requests []*request
|
2014-07-16 18:57:54 +00:00
|
|
|
mutex sync.Mutex
|
|
|
|
}
|
2014-07-10 12:19:39 +00:00
|
|
|
)
|
|
|
|
|
2014-09-09 08:20:40 +00:00
|
|
|
func registerPublication(q string, msg message) bool {
|
|
|
|
for _, r := range pool.requests {
|
|
|
|
if r.dead {
|
2014-07-17 13:22:37 +00:00
|
|
|
continue
|
|
|
|
}
|
2014-09-09 08:20:40 +00:00
|
|
|
for _, qname := range r.queues {
|
2014-07-17 13:22:37 +00:00
|
|
|
if qname == q {
|
2014-09-09 08:20:40 +00:00
|
|
|
rsp := response{queue: q, message: msg}
|
|
|
|
ok := r.tryRespond(rsp)
|
2014-07-17 13:22:37 +00:00
|
|
|
if ok {
|
|
|
|
return true
|
|
|
|
}
|
2014-07-10 12:19:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-07-16 17:50:05 +00:00
|
|
|
|
2014-09-09 08:20:40 +00:00
|
|
|
ok := getQueue(q).push(msg)
|
2014-07-16 17:50:05 +00:00
|
|
|
return ok
|
2014-07-10 12:19:39 +00:00
|
|
|
}
|
|
|
|
|
2014-09-09 08:20:40 +00:00
|
|
|
func registerSubscription(r *request) {
|
|
|
|
for _, qname := range r.queues {
|
|
|
|
q := getQueue(qname)
|
|
|
|
msg, ok := q.tryFetch(r.abort)
|
2014-07-12 10:42:26 +00:00
|
|
|
if ok {
|
2014-09-09 08:20:40 +00:00
|
|
|
rsp := response{queue: qname, message: msg}
|
|
|
|
ok := r.tryRespond(rsp)
|
2014-07-17 13:22:37 +00:00
|
|
|
if !ok {
|
2014-09-09 08:20:40 +00:00
|
|
|
q.push(msg)
|
2014-07-17 13:22:37 +00:00
|
|
|
}
|
|
|
|
|
2014-07-10 12:19:39 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2014-07-16 18:57:54 +00:00
|
|
|
|
2014-09-09 08:20:40 +00:00
|
|
|
pool.requests = append(pool.requests, r)
|
2014-07-17 13:22:37 +00:00
|
|
|
}
|
|
|
|
|
2014-09-09 08:20:40 +00:00
|
|
|
func (r *request) tryRespond(rsp response) bool {
|
2014-07-17 13:22:37 +00:00
|
|
|
okch := make(chan bool)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
defer func() {
|
|
|
|
err := recover()
|
2014-07-17 13:49:11 +00:00
|
|
|
if err != nil { // Panic!
|
2014-09-09 08:20:40 +00:00
|
|
|
r.dead = true
|
2014-07-17 13:22:37 +00:00
|
|
|
okch <- false
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2014-09-09 08:20:40 +00:00
|
|
|
r.responseCh <- rsp // If channel is already closed expect a panic
|
2014-07-17 13:22:37 +00:00
|
|
|
okch <- true
|
|
|
|
}()
|
|
|
|
|
|
|
|
ok := <-okch
|
|
|
|
return ok
|
2014-07-10 12:19:39 +00:00
|
|
|
}
|
|
|
|
|
2014-09-09 08:20:40 +00:00
|
|
|
func (r *request) purge() {
|
2014-07-16 18:57:54 +00:00
|
|
|
pool.mutex.Lock()
|
|
|
|
defer pool.mutex.Unlock()
|
|
|
|
|
2014-09-09 08:20:40 +00:00
|
|
|
r.dead = true
|
2014-07-16 18:57:54 +00:00
|
|
|
deleted := 0
|
2014-09-09 08:20:40 +00:00
|
|
|
for i, req := range pool.requests {
|
|
|
|
if req.dead {
|
|
|
|
pool.requests = append(pool.requests[:i-deleted], pool.requests[i-deleted+1:]...)
|
2014-07-16 18:57:54 +00:00
|
|
|
deleted++
|
2014-07-10 12:19:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|