diff options
Diffstat (limited to 'session_store.go')
-rw-r--r-- | session_store.go | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/session_store.go b/session_store.go new file mode 100644 index 0000000..b2e1538 --- /dev/null +++ b/session_store.go @@ -0,0 +1,206 @@ +// +// rhimportd +// +// The Radio Helsinki Rivendell Import Daemon +// +// +// Copyright (C) 2015 Christian Pointner <equinox@helsinki.at> +// +// This file is part of rhimportd. +// +// rhimportd is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// rhimportd is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with rhimportd. If not, see <http://www.gnu.org/licenses/>. +// + +package rhimport + +import ( + "encoding/base32" + "fmt" + "github.com/satori/go.uuid" + "strings" +) + +type newSessionResponse struct { + id string + session *SessionChan + err error +} + +type newSessionRequest struct { + ctx *ImportContext + response chan newSessionResponse +} + +type getSessionResponse struct { + session *SessionChan + err error +} + +type getSessionRequest struct { + user string + id string + response chan getSessionResponse +} + +type removeSessionResponse struct { + err error +} + +type removeSessionRequest struct { + user string + id string + response chan removeSessionResponse +} + +type SessionStoreChan struct { + newChan chan<- newSessionRequest + getChan chan<- getSessionRequest + removeChan chan<- removeSessionRequest +} + +type SessionStore struct { + store map[string]map[string]*Session + quit chan bool + done chan bool + newChan chan newSessionRequest + getChan chan getSessionRequest + removeChan chan removeSessionRequest +} + +func (self *SessionStore) new(ctx *ImportContext) (resp newSessionResponse) { + b := uuid.NewV4().Bytes() + resp.id = strings.ToLower(strings.TrimRight(base32.StdEncoding.EncodeToString(b), "=")) + if _, exists := self.store[ctx.UserName]; !exists { + self.store[ctx.UserName] = make(map[string]*Session) + } + self.store[ctx.UserName][resp.id] = NewSession(ctx) + resp.session = self.store[ctx.UserName][resp.id].getInterface() + rhdl.Printf("SessionStore: created session for '%s' -> %s", ctx.UserName, resp.id) + return +} + +func (self *SessionStoreChan) New(ctx *ImportContext) (string, *SessionChan, error) { + res_ch := make(chan newSessionResponse) + req := newSessionRequest{} + req.ctx = ctx + req.response = res_ch + self.newChan <- req + + res := <-res_ch + if res.err != nil { + return "", nil, res.err + } + return res.id, res.session, nil +} + +func (self *SessionStore) get(user, id string) (resp getSessionResponse) { + if session, exists := self.store[user][id]; exists { + resp.session = session.getInterface() + } else { + resp.err = fmt.Errorf("SessionStore: session '%s/%s' not found", user, id) + } + return +} + +func (self *SessionStoreChan) Get(user, id string) (*SessionChan, error) { + res_ch := make(chan getSessionResponse) + req := getSessionRequest{} + req.user = user + req.id = id + req.response = res_ch + self.getChan <- req + + res := <-res_ch + if res.err != nil { + return nil, res.err + } + return res.session, nil +} + +func (self *SessionStore) remove(user, id string) (resp removeSessionResponse) { + if session, exists := self.store[user][id]; exists { + session.Cleanup() + delete(self.store[user], id) + rhdl.Printf("SessionStore: removed session '%s/%s'", user, id) + if userstore, exists := self.store[user]; exists { + if len(userstore) == 0 { + delete(self.store, user) + rhdl.Printf("SessionStore: removed user '%s'", user) + } + } + } else { + resp.err = fmt.Errorf("SessionStore: session '%s/%s' not found", user, id) + } + return +} + +func (self *SessionStoreChan) Remove(user, id string) error { + res_ch := make(chan removeSessionResponse) + req := removeSessionRequest{} + req.user = user + req.id = id + req.response = res_ch + self.removeChan <- req + + res := <-res_ch + return res.err +} + +func (self *SessionStore) dispatchRequests() { + defer func() { self.done <- true }() + for { + select { + case <-self.quit: + return + case req := <-self.newChan: + req.response <- self.new(req.ctx) + case req := <-self.getChan: + req.response <- self.get(req.user, req.id) + case req := <-self.removeChan: + req.response <- self.remove(req.user, req.id) + } + } +} + +func (self *SessionStore) GetInterface() *SessionStoreChan { + ch := &SessionStoreChan{} + ch.newChan = self.newChan + ch.getChan = self.getChan + ch.removeChan = self.removeChan + return ch +} + +func (self *SessionStore) Cleanup() { + self.quit <- true + <-self.done + close(self.quit) + close(self.done) + close(self.newChan) + close(self.getChan) + close(self.removeChan) +} + +func NewSessionStore(conf *Config) (store *SessionStore, err error) { + store = new(SessionStore) + + store.quit = make(chan bool) + store.done = make(chan bool) + store.store = make(map[string]map[string]*Session) + store.newChan = make(chan newSessionRequest) + store.getChan = make(chan getSessionRequest) + store.removeChan = make(chan removeSessionRequest) + + go store.dispatchRequests() + return +} |