summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rhimport/session_store.go186
1 files changed, 126 insertions, 60 deletions
diff --git a/rhimport/session_store.go b/rhimport/session_store.go
index f744f50..f25a297 100644
--- a/rhimport/session_store.go
+++ b/rhimport/session_store.go
@@ -60,6 +60,13 @@ type getSessionRequest struct {
response chan getSessionResponse
}
+type SessionsUpdateCB func(added, removed map[string]string, userdata interface{}) bool
+
+type SessionsListCB struct {
+ cb SessionsUpdateCB
+ userdata interface{}
+}
+
type listSessionsResponse struct {
sessions map[string]string
responsecode int
@@ -70,6 +77,8 @@ type listSessionsRequest struct {
user string
password string
trusted bool
+ callback SessionsUpdateCB
+ userdata interface{}
response chan listSessionsResponse
}
@@ -84,13 +93,42 @@ type removeSessionRequest struct {
response chan removeSessionResponse
}
-type SessionStoreElement struct {
+type SessionStoreSessionElement struct {
s *Session
refId string
}
+type SessionStoreUserElement struct {
+ sessions map[string]*SessionStoreSessionElement
+ updateCBs []SessionsListCB
+}
+
+func (user *SessionStoreUserElement) callUpdateHandler(added, removed map[string]string) {
+ var keptCBs []SessionsListCB
+ for _, cb := range user.updateCBs {
+ if cb.cb != nil {
+ if keep := cb.cb(added, removed, cb.userdata); keep {
+ keptCBs = append(keptCBs, cb)
+ }
+ }
+ }
+ user.updateCBs = keptCBs
+}
+
+func (user *SessionStoreUserElement) callUpdateHandlerAdd(id, refId string) {
+ added := make(map[string]string)
+ added[id] = refId
+ user.callUpdateHandler(added, nil)
+}
+
+func (user *SessionStoreUserElement) callUpdateHandlerRemove(id, refId string) {
+ removed := make(map[string]string)
+ removed[id] = refId
+ user.callUpdateHandler(nil, removed)
+}
+
type SessionStore struct {
- store map[string]map[string]*SessionStoreElement
+ store map[string]*SessionStoreUserElement
conf *Config
db *rddb.DBChan
quit chan bool
@@ -109,11 +147,11 @@ func generateSessionId() (string, error) {
return base64.RawStdEncoding.EncodeToString(b[:]), nil
}
-func (self *SessionStore) new(ctx *Context, refId string) (resp newSessionResponse) {
+func (store *SessionStore) new(ctx *Context, refId string) (resp newSessionResponse) {
resp.responsecode = http.StatusOK
resp.errorstring = "OK"
if !ctx.Trusted {
- if ok, err := self.db.CheckPassword(ctx.UserName, ctx.Password); err != nil {
+ if ok, err := store.db.CheckPassword(ctx.UserName, ctx.Password); err != nil {
resp.responsecode = http.StatusInternalServerError
resp.errorstring = err.Error()
return
@@ -128,23 +166,33 @@ func (self *SessionStore) new(ctx *Context, refId string) (resp newSessionRespon
resp.errorstring = err.Error()
} else {
resp.id = id
- if _, exists := self.store[ctx.UserName]; !exists {
- self.store[ctx.UserName] = make(map[string]*SessionStoreElement)
+ if _, exists := store.store[ctx.UserName]; !exists {
+ newuser := &SessionStoreUserElement{}
+ newuser.sessions = make(map[string]*SessionStoreSessionElement)
+ store.store[ctx.UserName] = newuser
}
- ctx.conf = self.conf
- ctx.db = self.db
- s := &SessionStoreElement{newSession(ctx, func() { self.GetInterface().Remove(ctx.UserName, resp.id) }), refId}
- self.store[ctx.UserName][resp.id] = s
- resp.session = self.store[ctx.UserName][resp.id].s.getInterface()
+ ctx.conf = store.conf
+ ctx.db = store.db
+ s := &SessionStoreSessionElement{newSession(ctx, func() { store.GetInterface().Remove(ctx.UserName, resp.id) }), refId}
+ store.store[ctx.UserName].sessions[resp.id] = s
+ resp.session = store.store[ctx.UserName].sessions[resp.id].s.getInterface()
rhdl.Printf("SessionStore: created session for '%s' -> %s", ctx.UserName, resp.id)
+ store.store[ctx.UserName].callUpdateHandlerAdd(resp.id, refId)
}
return
}
-func (self *SessionStore) get(user, id string) (resp getSessionResponse) {
+func (store *SessionStore) get(username, id string) (resp getSessionResponse) {
resp.responsecode = http.StatusOK
resp.errorstring = "OK"
- if session, exists := self.store[user][id]; exists {
+
+ user, exists := store.store[username]
+ if !exists {
+ resp.responsecode = http.StatusNotFound
+ resp.errorstring = fmt.Sprintf("SessionStore: session '%s/%s' not found", user, id)
+ }
+
+ if session, exists := user.sessions[id]; exists {
resp.session = session.s.getInterface()
resp.refId = session.refId
} else {
@@ -154,11 +202,11 @@ func (self *SessionStore) get(user, id string) (resp getSessionResponse) {
return
}
-func (self *SessionStore) list(user, password string, trusted bool) (resp listSessionsResponse) {
+func (store *SessionStore) list(username, password string, trusted bool, userdata interface{}, cb SessionsUpdateCB) (resp listSessionsResponse) {
resp.responsecode = http.StatusOK
resp.errorstring = "OK"
if !trusted {
- if ok, err := self.db.CheckPassword(user, password); err != nil {
+ if ok, err := store.db.CheckPassword(username, password); err != nil {
resp.responsecode = http.StatusInternalServerError
resp.errorstring = err.Error()
return
@@ -169,26 +217,42 @@ func (self *SessionStore) list(user, password string, trusted bool) (resp listSe
}
}
resp.sessions = make(map[string]string)
- if sessions, exists := self.store[user]; exists {
- for id, e := range sessions {
+ if user, exists := store.store[username]; exists {
+ for id, e := range user.sessions {
resp.sessions[id] = e.refId
}
+ if cb != nil {
+ user.updateCBs = append(user.updateCBs, SessionsListCB{cb, userdata})
+ }
+ } else if cb != nil {
+ newuser := &SessionStoreUserElement{}
+ newuser.sessions = make(map[string]*SessionStoreSessionElement)
+ newuser.updateCBs = []SessionsListCB{SessionsListCB{cb, userdata}}
+ store.store[username] = newuser
}
return
}
-func (self *SessionStore) remove(user, id string) (resp removeSessionResponse) {
+func (store *SessionStore) remove(username, id string) (resp removeSessionResponse) {
resp.responsecode = http.StatusOK
resp.errorstring = "OK"
- if session, exists := self.store[user][id]; exists {
+
+ user, exists := store.store[username]
+ if !exists {
+ resp.responsecode = http.StatusNotFound
+ resp.errorstring = fmt.Sprintf("SessionStore: session '%s/%s' not found", user, id)
+ }
+
+ if session, exists := user.sessions[id]; exists {
go session.s.cleanup() // cleanup could take a while -> don't block all the other stuff
- 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)
- }
+ refId := session.refId
+ delete(user.sessions, id)
+ rhdl.Printf("SessionStore: removed session '%s/%s'", username, id)
+ user.callUpdateHandlerRemove(id, refId)
+
+ if len(user.sessions) == 0 && len(user.updateCBs) == 0 {
+ delete(store.store, username)
+ rhdl.Printf("SessionStore: removed user '%s'", username)
}
} else {
resp.responsecode = http.StatusNotFound
@@ -197,20 +261,20 @@ func (self *SessionStore) remove(user, id string) (resp removeSessionResponse) {
return
}
-func (self *SessionStore) dispatchRequests() {
- defer func() { self.done <- true }()
+func (store *SessionStore) dispatchRequests() {
+ defer func() { store.done <- true }()
for {
select {
- case <-self.quit:
+ case <-store.quit:
return
- case req := <-self.newChan:
- req.response <- self.new(req.ctx, req.refId)
- case req := <-self.getChan:
- req.response <- self.get(req.user, req.id)
- case req := <-self.listChan:
- req.response <- self.list(req.user, req.password, req.trusted)
- case req := <-self.removeChan:
- req.response <- self.remove(req.user, req.id)
+ case req := <-store.newChan:
+ req.response <- store.new(req.ctx, req.refId)
+ case req := <-store.getChan:
+ req.response <- store.get(req.user, req.id)
+ case req := <-store.listChan:
+ req.response <- store.list(req.user, req.password, req.trusted, req.userdata, req.callback)
+ case req := <-store.removeChan:
+ req.response <- store.remove(req.user, req.id)
}
}
}
@@ -225,73 +289,75 @@ type SessionStoreChan struct {
removeChan chan<- removeSessionRequest
}
-func (self *SessionStoreChan) New(ctx *Context, refId string) (string, *SessionChan, int, string) {
+func (store *SessionStoreChan) New(ctx *Context, refId string) (string, *SessionChan, int, string) {
resCh := make(chan newSessionResponse)
req := newSessionRequest{}
req.ctx = ctx
req.refId = refId
req.response = resCh
- self.newChan <- req
+ store.newChan <- req
res := <-resCh
return res.id, res.session, res.responsecode, res.errorstring
}
-func (self *SessionStoreChan) Get(user, id string) (*SessionChan, string, int, string) {
+func (store *SessionStoreChan) Get(user, id string) (*SessionChan, string, int, string) {
resCh := make(chan getSessionResponse)
req := getSessionRequest{}
req.user = user
req.id = id
req.response = resCh
- self.getChan <- req
+ store.getChan <- req
res := <-resCh
return res.session, res.refId, res.responsecode, res.errorstring
}
-func (self *SessionStoreChan) List(user, password string, trusted bool) (map[string]string, int, string) {
+func (store *SessionStoreChan) List(user, password string, trusted bool, userdata interface{}, cb SessionsUpdateCB) (map[string]string, int, string) {
resCh := make(chan listSessionsResponse)
req := listSessionsRequest{}
req.user = user
req.password = password
req.trusted = trusted
req.response = resCh
- self.listChan <- req
+ req.callback = cb
+ req.userdata = userdata
+ store.listChan <- req
res := <-resCh
return res.sessions, res.responsecode, res.errorstring
}
-func (self *SessionStoreChan) Remove(user, id string) (int, string) {
+func (store *SessionStoreChan) Remove(user, id string) (int, string) {
resCh := make(chan removeSessionResponse)
req := removeSessionRequest{}
req.user = user
req.id = id
req.response = resCh
- self.removeChan <- req
+ store.removeChan <- req
res := <-resCh
return res.responsecode, res.errorstring
}
-func (self *SessionStore) GetInterface() *SessionStoreChan {
+func (store *SessionStore) GetInterface() *SessionStoreChan {
ch := &SessionStoreChan{}
- ch.newChan = self.newChan
- ch.getChan = self.getChan
- ch.listChan = self.listChan
- ch.removeChan = self.removeChan
+ ch.newChan = store.newChan
+ ch.getChan = store.getChan
+ ch.listChan = store.listChan
+ ch.removeChan = store.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.listChan)
- close(self.removeChan)
+func (store *SessionStore) Cleanup() {
+ store.quit <- true
+ <-store.done
+ close(store.quit)
+ close(store.done)
+ close(store.newChan)
+ close(store.getChan)
+ close(store.listChan)
+ close(store.removeChan)
}
func NewSessionStore(conf *Config, db *rddb.DBChan) (store *SessionStore, err error) {
@@ -300,7 +366,7 @@ func NewSessionStore(conf *Config, db *rddb.DBChan) (store *SessionStore, err er
store.db = db
store.quit = make(chan bool)
store.done = make(chan bool)
- store.store = make(map[string]map[string]*SessionStoreElement)
+ store.store = make(map[string]*SessionStoreUserElement)
store.newChan = make(chan newSessionRequest, 10)
store.getChan = make(chan getSessionRequest, 10)
store.listChan = make(chan listSessionsRequest, 10)