Adopt community codestyle
This commit is contained in:
		
							parent
							
								
									56c1ec2300
								
							
						
					
					
						commit
						49acb0076f
					
				
							
								
								
									
										12
									
								
								config.go
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								config.go
									
									
									
									
									
								
							@ -5,14 +5,14 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	Config struct {
 | 
			
		||||
		Storage string
 | 
			
		||||
		Port    int
 | 
			
		||||
	config struct {
 | 
			
		||||
		storage string
 | 
			
		||||
		port    int
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func SetupConfig() {
 | 
			
		||||
	flag.StringVar(&Config.Storage, "storage", "-", "Kyoto Cabinet storage path (e.g. burlesque.kch#dfunit=8#msiz=512M)")
 | 
			
		||||
	flag.IntVar(&Config.Port, "port", 4401, "Server HTTP port")
 | 
			
		||||
func setupConfig() {
 | 
			
		||||
	flag.StringVar(&config.storage, "storage", "-", "Kyoto Cabinet storage path (e.g. burlesque.kch#dfunit=8#msiz=512M)")
 | 
			
		||||
	flag.IntVar(&config.port, "port", 4401, "Server HTTP port")
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										42
									
								
								counter.go
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								counter.go
									
									
									
									
									
								
							@ -5,64 +5,64 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	MaxIndex = ^uint(0)
 | 
			
		||||
	maxIndex = ^uint(0)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
	// Counter is responsible for operating queue read and write indexes
 | 
			
		||||
	Counter struct {
 | 
			
		||||
		WriteIndex uint // Number of the record last written to the queue
 | 
			
		||||
		ReadIndex  uint // Number of the record last read from the queue
 | 
			
		||||
	counter struct {
 | 
			
		||||
		writeIndex uint // Number of the record last written to the queue
 | 
			
		||||
		readIndex  uint // Number of the record last read from the queue
 | 
			
		||||
		// If WriteIndex is greater than ReadIndex then there are unread messages
 | 
			
		||||
		// If WriteIndex is less tham ReadIndex then MaxIndex was reached
 | 
			
		||||
 | 
			
		||||
		Read      chan uint
 | 
			
		||||
		read      chan uint
 | 
			
		||||
		mutex     sync.Mutex
 | 
			
		||||
		streaming *sync.Cond
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func NewCounter(wi, ri uint) *Counter {
 | 
			
		||||
func newCounter(wi, ri uint) *counter {
 | 
			
		||||
	m := &sync.Mutex{}
 | 
			
		||||
	m.Lock()
 | 
			
		||||
 | 
			
		||||
	c := &Counter{
 | 
			
		||||
		WriteIndex: wi,
 | 
			
		||||
		ReadIndex:  ri,
 | 
			
		||||
		Read:       make(chan uint),
 | 
			
		||||
	c := &counter{
 | 
			
		||||
		writeIndex: wi,
 | 
			
		||||
		readIndex:  ri,
 | 
			
		||||
		read:       make(chan uint),
 | 
			
		||||
		streaming:  sync.NewCond(m),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	go c.Stream()
 | 
			
		||||
	go c.stream()
 | 
			
		||||
	return c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Counter) Write(proc func(i uint) bool) {
 | 
			
		||||
func (c *counter) write(proc func(i uint) bool) {
 | 
			
		||||
	c.mutex.Lock()
 | 
			
		||||
	defer c.mutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	ok := proc(c.WriteIndex + 1)
 | 
			
		||||
	ok := proc(c.writeIndex + 1)
 | 
			
		||||
	if ok {
 | 
			
		||||
		c.WriteIndex++
 | 
			
		||||
		c.writeIndex++
 | 
			
		||||
		c.streaming.Signal()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Counter) Distance() uint {
 | 
			
		||||
	d := c.WriteIndex - c.ReadIndex
 | 
			
		||||
func (c *counter) distance() uint {
 | 
			
		||||
	d := c.writeIndex - c.readIndex
 | 
			
		||||
	if d < 0 {
 | 
			
		||||
		d += MaxIndex
 | 
			
		||||
		d += maxIndex
 | 
			
		||||
	}
 | 
			
		||||
	return d
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Counter) Stream() {
 | 
			
		||||
func (c *counter) stream() {
 | 
			
		||||
	for {
 | 
			
		||||
		if c.Distance() == 0 {
 | 
			
		||||
		if c.distance() == 0 {
 | 
			
		||||
			c.streaming.Wait()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		c.Read <- c.ReadIndex + 1
 | 
			
		||||
		c.ReadIndex++
 | 
			
		||||
		c.read <- c.readIndex + 1
 | 
			
		||||
		c.readIndex++
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								logging.go
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								logging.go
									
									
									
									
									
								
							@ -1,29 +1,29 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"log"
 | 
			
		||||
	loglib "log"
 | 
			
		||||
	"os"
 | 
			
		||||
	"runtime"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	logger *log.Logger
 | 
			
		||||
	logger *loglib.Logger
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func SetupLogging() {
 | 
			
		||||
	logger = log.New(os.Stdout, "", log.Ldate|log.Lmicroseconds)
 | 
			
		||||
func setupLogging() {
 | 
			
		||||
	logger = loglib.New(os.Stdout, "", loglib.Ldate|loglib.Lmicroseconds)
 | 
			
		||||
 | 
			
		||||
	Log("Burlesque v%s started", Version)
 | 
			
		||||
	Log("GOMAXPROCS is set to %d", runtime.GOMAXPROCS(-1))
 | 
			
		||||
	Log("Storage path: %s", Config.Storage)
 | 
			
		||||
	Log("Server is running at http://127.0.0.1:%d", Config.Port)
 | 
			
		||||
	log("Burlesque v%s started", version)
 | 
			
		||||
	log("GOMAXPROCS is set to %d", runtime.GOMAXPROCS(-1))
 | 
			
		||||
	log("Storage path: %s", config.storage)
 | 
			
		||||
	log("Server is running at http://127.0.0.1:%d", config.port)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Log(format string, args ...interface{}) {
 | 
			
		||||
func log(format string, args ...interface{}) {
 | 
			
		||||
	logger.Printf("[INFO]  "+format, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Error(err error, format string, args ...interface{}) {
 | 
			
		||||
func alert(err error, format string, args ...interface{}) {
 | 
			
		||||
	logger.Printf("[ERROR] "+format, args...)
 | 
			
		||||
	logger.Printf("        %s", err.Error())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										28
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								main.go
									
									
									
									
									
								
							@ -7,33 +7,33 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	Version = "0.1.3"
 | 
			
		||||
	version = "0.1.3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func HandleShutdown() {
 | 
			
		||||
func handleShutdown() {
 | 
			
		||||
	ch := make(chan os.Signal)
 | 
			
		||||
	signal.Notify(ch, os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGINT)
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		<-ch
 | 
			
		||||
 | 
			
		||||
		SaveState()
 | 
			
		||||
		Log("State successfully persisted")
 | 
			
		||||
		saveState()
 | 
			
		||||
		log("State successfully persisted")
 | 
			
		||||
 | 
			
		||||
		CloseStorage()
 | 
			
		||||
		closeStorage()
 | 
			
		||||
 | 
			
		||||
		Log("Stopped")
 | 
			
		||||
		log("Stopped")
 | 
			
		||||
		os.Exit(0)
 | 
			
		||||
	}()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	SetupConfig()
 | 
			
		||||
	SetupLogging()
 | 
			
		||||
	SetupStorage()
 | 
			
		||||
	SetupServer()
 | 
			
		||||
	HandleShutdown()
 | 
			
		||||
	LoadState()
 | 
			
		||||
	go KeepStatePersisted()
 | 
			
		||||
	StartServer()
 | 
			
		||||
	setupConfig()
 | 
			
		||||
	setupLogging()
 | 
			
		||||
	setupStorage()
 | 
			
		||||
	setupServer()
 | 
			
		||||
	handleShutdown()
 | 
			
		||||
	loadState()
 | 
			
		||||
	go keepStatePersisted()
 | 
			
		||||
	startServer()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										52
									
								
								queue.go
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								queue.go
									
									
									
									
									
								
							@ -1,24 +1,24 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
	Queue struct {
 | 
			
		||||
		Name    string
 | 
			
		||||
		Counter *Counter
 | 
			
		||||
	queue struct {
 | 
			
		||||
		name    string
 | 
			
		||||
		counter *counter
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	queues = make(map[string]*Queue)
 | 
			
		||||
	queues = make(map[string]*queue)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (q *Queue) Push(msg Message) bool {
 | 
			
		||||
func (q *queue) push(msg message) bool {
 | 
			
		||||
	var err error
 | 
			
		||||
 | 
			
		||||
	q.Counter.Write(func(i uint) bool {
 | 
			
		||||
		key := NewKey(q.Name, i)
 | 
			
		||||
	q.counter.write(func(i uint) bool {
 | 
			
		||||
		key := newKey(q.name, i)
 | 
			
		||||
		err = storage.Set(key, msg)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			Error(err, "Failed to write %d bytes to record '%s'", len(msg), key)
 | 
			
		||||
			alert(err, "Failed to write %d bytes to record '%s'", len(msg), key)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return (err == nil)
 | 
			
		||||
@ -27,49 +27,49 @@ func (q *Queue) Push(msg Message) bool {
 | 
			
		||||
	return (err == nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (q *Queue) TryFetch(abort chan bool) (Message, bool) {
 | 
			
		||||
	if q.Counter.Distance() > 0 {
 | 
			
		||||
		return q.Fetch(abort)
 | 
			
		||||
func (q *queue) tryFetch(abort chan bool) (message, bool) {
 | 
			
		||||
	if q.counter.distance() > 0 {
 | 
			
		||||
		return q.fetch(abort)
 | 
			
		||||
	} else {
 | 
			
		||||
		return Message{}, false
 | 
			
		||||
		return message{}, false
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (q *Queue) Fetch(abort chan bool) (Message, bool) {
 | 
			
		||||
func (q *queue) fetch(abort chan bool) (message, bool) {
 | 
			
		||||
	var i uint
 | 
			
		||||
 | 
			
		||||
	select {
 | 
			
		||||
	case i = <-q.Counter.Read:
 | 
			
		||||
	case i = <-q.counter.read:
 | 
			
		||||
	case <-abort:
 | 
			
		||||
		return Message{}, false
 | 
			
		||||
		return message{}, false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	key := NewKey(q.Name, i)
 | 
			
		||||
	msg, err := storage.Get(key)
 | 
			
		||||
	k := newKey(q.name, i)
 | 
			
		||||
	msg, err := storage.Get(k)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		Error(err, "Failed to read record '%s'", key)
 | 
			
		||||
		alert(err, "Failed to read record '%s'", k)
 | 
			
		||||
		return msg, false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = storage.Remove(key)
 | 
			
		||||
	err = storage.Remove(k)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		Error(err, "Failed to delete record '%s'", key)
 | 
			
		||||
		alert(err, "Failed to delete record '%s'", k)
 | 
			
		||||
		return msg, false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return msg, true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetQueue(name string) *Queue {
 | 
			
		||||
func getQueue(name string) *queue {
 | 
			
		||||
	if _, ok := queues[name]; !ok {
 | 
			
		||||
		RegisterQueue(name, 0, 0)
 | 
			
		||||
		registerQueue(name, 0, 0)
 | 
			
		||||
	}
 | 
			
		||||
	return queues[name]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RegisterQueue(name string, wi, ri uint) {
 | 
			
		||||
	queues[name] = &Queue{
 | 
			
		||||
		Name:    name,
 | 
			
		||||
		Counter: NewCounter(wi, ri),
 | 
			
		||||
func registerQueue(name string, wi, ri uint) {
 | 
			
		||||
	queues[name] = &queue{
 | 
			
		||||
		name:    name,
 | 
			
		||||
		counter: newCounter(wi, ri),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										64
									
								
								request.go
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								request.go
									
									
									
									
									
								
							@ -5,34 +5,34 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
	Request struct {
 | 
			
		||||
		Queues     []string
 | 
			
		||||
		ResponseCh chan Response
 | 
			
		||||
		Abort      chan bool
 | 
			
		||||
		Dead       bool
 | 
			
		||||
	request struct {
 | 
			
		||||
		queues     []string
 | 
			
		||||
		responseCh chan response
 | 
			
		||||
		abort      chan bool
 | 
			
		||||
		dead       bool
 | 
			
		||||
	}
 | 
			
		||||
	Response struct {
 | 
			
		||||
		Queue   string
 | 
			
		||||
		Message Message
 | 
			
		||||
	response struct {
 | 
			
		||||
		queue   string
 | 
			
		||||
		message message
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	pool struct {
 | 
			
		||||
		Requests []*Request
 | 
			
		||||
		requests []*request
 | 
			
		||||
		mutex    sync.Mutex
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func RegisterPublication(q string, msg Message) bool {
 | 
			
		||||
	for _, r := range pool.Requests {
 | 
			
		||||
		if r.Dead {
 | 
			
		||||
func registerPublication(q string, msg message) bool {
 | 
			
		||||
	for _, r := range pool.requests {
 | 
			
		||||
		if r.dead {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		for _, qname := range r.Queues {
 | 
			
		||||
		for _, qname := range r.queues {
 | 
			
		||||
			if qname == q {
 | 
			
		||||
				rsp := Response{Queue: q, Message: msg}
 | 
			
		||||
				ok := r.TryRespond(rsp)
 | 
			
		||||
				rsp := response{queue: q, message: msg}
 | 
			
		||||
				ok := r.tryRespond(rsp)
 | 
			
		||||
				if ok {
 | 
			
		||||
					return true
 | 
			
		||||
				}
 | 
			
		||||
@ -40,41 +40,41 @@ func RegisterPublication(q string, msg Message) bool {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ok := GetQueue(q).Push(msg)
 | 
			
		||||
	ok := getQueue(q).push(msg)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RegisterSubscription(r *Request) {
 | 
			
		||||
	for _, qname := range r.Queues {
 | 
			
		||||
		q := GetQueue(qname)
 | 
			
		||||
		msg, ok := q.TryFetch(r.Abort)
 | 
			
		||||
func registerSubscription(r *request) {
 | 
			
		||||
	for _, qname := range r.queues {
 | 
			
		||||
		q := getQueue(qname)
 | 
			
		||||
		msg, ok := q.tryFetch(r.abort)
 | 
			
		||||
		if ok {
 | 
			
		||||
			rsp := Response{Queue: qname, Message: msg}
 | 
			
		||||
			ok := r.TryRespond(rsp)
 | 
			
		||||
			rsp := response{queue: qname, message: msg}
 | 
			
		||||
			ok := r.tryRespond(rsp)
 | 
			
		||||
			if !ok {
 | 
			
		||||
				q.Push(msg)
 | 
			
		||||
				q.push(msg)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pool.Requests = append(pool.Requests, r)
 | 
			
		||||
	pool.requests = append(pool.requests, r)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *Request) TryRespond(rsp Response) bool {
 | 
			
		||||
func (r *request) tryRespond(rsp response) bool {
 | 
			
		||||
	okch := make(chan bool)
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		defer func() {
 | 
			
		||||
			err := recover()
 | 
			
		||||
			if err != nil { // Panic!
 | 
			
		||||
				r.Dead = true
 | 
			
		||||
				r.dead = true
 | 
			
		||||
				okch <- false
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
 | 
			
		||||
		r.ResponseCh <- rsp // If channel is already closed expect a panic
 | 
			
		||||
		r.responseCh <- rsp // If channel is already closed expect a panic
 | 
			
		||||
		okch <- true
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
@ -82,15 +82,15 @@ func (r *Request) TryRespond(rsp Response) bool {
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *Request) Purge() {
 | 
			
		||||
func (r *request) purge() {
 | 
			
		||||
	pool.mutex.Lock()
 | 
			
		||||
	defer pool.mutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	r.Dead = true
 | 
			
		||||
	r.dead = true
 | 
			
		||||
	deleted := 0
 | 
			
		||||
	for i, req := range pool.Requests {
 | 
			
		||||
		if req.Dead {
 | 
			
		||||
			pool.Requests = append(pool.Requests[:i-deleted], pool.Requests[i-deleted+1:]...)
 | 
			
		||||
	for i, req := range pool.requests {
 | 
			
		||||
		if req.dead {
 | 
			
		||||
			pool.requests = append(pool.requests[:i-deleted], pool.requests[i-deleted+1:]...)
 | 
			
		||||
			deleted++
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										58
									
								
								server.go
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								server.go
									
									
									
									
									
								
							@ -10,26 +10,26 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func StartServer() {
 | 
			
		||||
	port := fmt.Sprintf(":%d", Config.Port)
 | 
			
		||||
func startServer() {
 | 
			
		||||
	port := fmt.Sprintf(":%d", config.port)
 | 
			
		||||
	err := http.ListenAndServe(port, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		Error(err, "Error starting server on port %d", Config.Port)
 | 
			
		||||
		alert(err, "Error starting server on port %d", config.port)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func StatusHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
func statusHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	info := make(map[string]map[string]uint)
 | 
			
		||||
 | 
			
		||||
	for _, q := range queues {
 | 
			
		||||
		info[q.Name] = map[string]uint{
 | 
			
		||||
			"messages":      q.Counter.Distance(),
 | 
			
		||||
		info[q.name] = map[string]uint{
 | 
			
		||||
			"messages":      q.counter.distance(),
 | 
			
		||||
			"subscriptions": 0,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, r := range pool.Requests {
 | 
			
		||||
		for _, q := range r.Queues {
 | 
			
		||||
	for _, r := range pool.requests {
 | 
			
		||||
		for _, q := range r.queues {
 | 
			
		||||
			info[q]["subscriptions"]++
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@ -38,14 +38,14 @@ func StatusHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	w.Write(jsn)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DebugHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
func debugHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	info := make(map[string]interface{})
 | 
			
		||||
	info["version"] = Version
 | 
			
		||||
	info["version"] = version
 | 
			
		||||
	info["goroutines"] = runtime.NumGoroutine()
 | 
			
		||||
 | 
			
		||||
	s, err := storage.Status()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		Error(err, "Failed to get Kyoto Cabinet status")
 | 
			
		||||
		alert(err, "Failed to get Kyoto Cabinet status")
 | 
			
		||||
	}
 | 
			
		||||
	s = s[:len(s)-1] // Removing trailing new line
 | 
			
		||||
 | 
			
		||||
@ -66,15 +66,15 @@ func DebugHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	w.Write(jsn)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func PublishHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
func publishHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	defer r.Body.Close()
 | 
			
		||||
	msg, _ := ioutil.ReadAll(r.Body)
 | 
			
		||||
	if len(msg) == 0 {
 | 
			
		||||
		msg = Message(r.FormValue("msg"))
 | 
			
		||||
		msg = message(r.FormValue("msg"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	qname := r.FormValue("queue")
 | 
			
		||||
	ok := RegisterPublication(qname, msg)
 | 
			
		||||
	ok := registerPublication(qname, msg)
 | 
			
		||||
 | 
			
		||||
	if ok {
 | 
			
		||||
		w.Write([]byte("OK"))
 | 
			
		||||
@ -83,15 +83,15 @@ func PublishHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SubscriptionHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	rch := make(chan Response)
 | 
			
		||||
func subscriptionHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	rch := make(chan response)
 | 
			
		||||
	abort := make(chan bool, 1)
 | 
			
		||||
	req := &Request{
 | 
			
		||||
		Queues:     strings.Split(r.FormValue("queues"), ","),
 | 
			
		||||
		ResponseCh: rch,
 | 
			
		||||
		Abort:      abort,
 | 
			
		||||
	req := &request{
 | 
			
		||||
		queues:     strings.Split(r.FormValue("queues"), ","),
 | 
			
		||||
		responseCh: rch,
 | 
			
		||||
		abort:      abort,
 | 
			
		||||
	}
 | 
			
		||||
	go RegisterSubscription(req)
 | 
			
		||||
	go registerSubscription(req)
 | 
			
		||||
 | 
			
		||||
	disconnected := w.(http.CloseNotifier).CloseNotify()
 | 
			
		||||
	finished := make(chan bool)
 | 
			
		||||
@ -102,7 +102,7 @@ func SubscriptionHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
			abort <- true
 | 
			
		||||
		case <-finished:
 | 
			
		||||
		}
 | 
			
		||||
		req.Purge()
 | 
			
		||||
		req.purge()
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	res, ok := <-rch
 | 
			
		||||
@ -110,15 +110,15 @@ func SubscriptionHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	w.Header().Set("Queue", res.Queue)
 | 
			
		||||
	w.Write(res.Message)
 | 
			
		||||
	w.Header().Set("Queue", res.queue)
 | 
			
		||||
	w.Write(res.message)
 | 
			
		||||
 | 
			
		||||
	finished <- true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SetupServer() {
 | 
			
		||||
	http.HandleFunc("/status", StatusHandler)
 | 
			
		||||
	http.HandleFunc("/debug", DebugHandler)
 | 
			
		||||
	http.HandleFunc("/publish", PublishHandler)
 | 
			
		||||
	http.HandleFunc("/subscribe", SubscriptionHandler)
 | 
			
		||||
func setupServer() {
 | 
			
		||||
	http.HandleFunc("/status", statusHandler)
 | 
			
		||||
	http.HandleFunc("/debug", debugHandler)
 | 
			
		||||
	http.HandleFunc("/publish", publishHandler)
 | 
			
		||||
	http.HandleFunc("/subscribe", subscriptionHandler)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										49
									
								
								state.go
									
									
									
									
									
								
							
							
						
						
									
										49
									
								
								state.go
									
									
									
									
									
								
							@ -6,63 +6,64 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
	QueueState  map[string]uint
 | 
			
		||||
	ServerState map[string]QueueState
 | 
			
		||||
	queueState  map[string]uint
 | 
			
		||||
	serverState map[string]queueState
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	StateMetaKey      = "state"
 | 
			
		||||
	StateSaveInterval = 1 // seconds
 | 
			
		||||
	stateMetaKey      = "state"
 | 
			
		||||
	stateSaveInterval = 1 // seconds
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func SaveState() {
 | 
			
		||||
	state := make(ServerState)
 | 
			
		||||
func saveState() {
 | 
			
		||||
	state := make(serverState)
 | 
			
		||||
	for _, q := range queues {
 | 
			
		||||
		state[q.Name] = QueueState{
 | 
			
		||||
			"wi": q.Counter.WriteIndex,
 | 
			
		||||
			"ri": q.Counter.ReadIndex,
 | 
			
		||||
		state[q.name] = queueState{
 | 
			
		||||
			"wi": q.counter.writeIndex,
 | 
			
		||||
			"ri": q.counter.readIndex,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	jsn, _ := json.Marshal(state)
 | 
			
		||||
	key := Key(StateMetaKey)
 | 
			
		||||
	if err := storage.Set(key, jsn); err != nil {
 | 
			
		||||
		Error(err, "Failed to persist state")
 | 
			
		||||
	k := key(stateMetaKey)
 | 
			
		||||
	if err := storage.Set(k, jsn); err != nil {
 | 
			
		||||
		alert(err, "Failed to persist state")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func LoadState() {
 | 
			
		||||
	state := make(ServerState)
 | 
			
		||||
	key := Key(StateMetaKey)
 | 
			
		||||
func loadState() {
 | 
			
		||||
	state := make(serverState)
 | 
			
		||||
	k := key(stateMetaKey)
 | 
			
		||||
 | 
			
		||||
	jsn, err := storage.Get(key)
 | 
			
		||||
	jsn, err := storage.Get(k)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		Log("State not found")
 | 
			
		||||
		log("State not found")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = json.Unmarshal(jsn, &state)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		Log("Failed to load state")
 | 
			
		||||
		log("Failed to load state")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for qname, meta := range state {
 | 
			
		||||
		RegisterQueue(qname, meta["wi"], meta["ri"])
 | 
			
		||||
		registerQueue(qname, meta["wi"], meta["ri"])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Log("State successfully loaded")
 | 
			
		||||
	log("State successfully loaded")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func KeepStatePersisted() {
 | 
			
		||||
	t := time.NewTicker(StateSaveInterval * time.Second)
 | 
			
		||||
func keepStatePersisted() {
 | 
			
		||||
	t := time.NewTicker(stateSaveInterval * time.Second)
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		<-t.C
 | 
			
		||||
		SaveState()
 | 
			
		||||
		saveState()
 | 
			
		||||
		err := storage.Sync(false)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			Error(err, "Failed to sync storage")
 | 
			
		||||
			alert(err, "Failed to sync storage")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										27
									
								
								storage.go
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								storage.go
									
									
									
									
									
								
							@ -8,41 +8,42 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
	Message []byte
 | 
			
		||||
	Key     []byte
 | 
			
		||||
	message []byte
 | 
			
		||||
	key     []byte
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	storage = cabinet.New()
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func NewKey(queue string, index uint) Key {
 | 
			
		||||
func newKey(queue string, index uint) key {
 | 
			
		||||
	istr := strconv.FormatUint(uint64(index), 10)
 | 
			
		||||
	key := strings.Join([]string{queue, istr}, "_")
 | 
			
		||||
	return Key(key)
 | 
			
		||||
	k := strings.Join([]string{queue, istr}, "_")
 | 
			
		||||
 | 
			
		||||
	return key(k)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SetupStorage() {
 | 
			
		||||
	err := storage.Open(Config.Storage, cabinet.KCOWRITER|cabinet.KCOCREATE)
 | 
			
		||||
func setupStorage() {
 | 
			
		||||
	err := storage.Open(config.storage, cabinet.KCOWRITER|cabinet.KCOCREATE)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		Error(err, "Failed to open database '%s'", Config.Storage)
 | 
			
		||||
		alert(err, "Failed to open database '%s'", config.storage)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CloseStorage() {
 | 
			
		||||
func closeStorage() {
 | 
			
		||||
	var err error
 | 
			
		||||
 | 
			
		||||
	err = storage.Sync(true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		Error(err, "Failed to sync storage (hard)")
 | 
			
		||||
		alert(err, "Failed to sync storage (hard)")
 | 
			
		||||
	} else {
 | 
			
		||||
		Log("Storage synchronized")
 | 
			
		||||
		log("Storage synchronized")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = storage.Close()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		Error(err, "Failed to close storage")
 | 
			
		||||
		alert(err, "Failed to close storage")
 | 
			
		||||
	} else {
 | 
			
		||||
		Log("Storage closed")
 | 
			
		||||
		log("Storage closed")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user