diff --git a/session/sess_couchbase.go b/session/sess_couchbase.go new file mode 100644 index 00000000..74b2242c --- /dev/null +++ b/session/sess_couchbase.go @@ -0,0 +1,203 @@ +package session + +import ( + "github.com/couchbaselabs/go-couchbase" + "net/http" + "strings" + "sync" +) + +var couchbpder = &CouchbaseProvider{} + +type CouchbaseSessionStore struct { + b *couchbase.Bucket + sid string + lock sync.RWMutex + values map[interface{}]interface{} + maxlifetime int64 +} + +type CouchbaseProvider struct { + maxlifetime int64 + savePath string + pool string + bucket string + b *couchbase.Bucket +} + +func (cs *CouchbaseSessionStore) Set(key, value interface{}) error { + cs.lock.Lock() + defer cs.lock.Unlock() + cs.values[key] = value + return nil +} + +func (cs *CouchbaseSessionStore) Get(key interface{}) interface{} { + cs.lock.RLock() + defer cs.lock.RUnlock() + if v, ok := cs.values[key]; ok { + return v + } else { + return nil + } + return nil +} + +func (cs *CouchbaseSessionStore) Delete(key interface{}) error { + cs.lock.Lock() + defer cs.lock.Unlock() + delete(cs.values, key) + return nil +} + +func (cs *CouchbaseSessionStore) Flush() error { + cs.lock.Lock() + defer cs.lock.Unlock() + cs.values = make(map[interface{}]interface{}) + return nil +} + +func (cs *CouchbaseSessionStore) SessionID() string { + return cs.sid +} + +func (cs *CouchbaseSessionStore) SessionRelease(w http.ResponseWriter) { + defer cs.b.Close() + + // if rs.values is empty, return directly + if len(cs.values) < 1 { + cs.b.Delete(cs.sid) + return + } + + bo, err := encodeGob(cs.values) + if err != nil { + return + } + + cs.b.Set(cs.sid, int(cs.maxlifetime), bo) +} + +func (cp *CouchbaseProvider) getBucket() *couchbase.Bucket { + c, err := couchbase.Connect(cp.savePath) + if err != nil { + return nil + } + + pool, err := c.GetPool(cp.pool) + if err != nil { + return nil + } + + bucket, err := pool.GetBucket(cp.bucket) + if err != nil { + return nil + } + + return bucket +} + +// init couchbase session +// savepath like couchbase server REST/JSON URL +// e.g. http://host:port/, Pool, Bucket +func (cp *CouchbaseProvider) SessionInit(maxlifetime int64, savePath string) error { + cp.maxlifetime = maxlifetime + configs := strings.Split(savePath, ",") + if len(configs) > 0 { + cp.savePath = configs[0] + } + if len(configs) > 1 { + cp.pool = configs[1] + } + if len(configs) > 2 { + cp.bucket = configs[2] + } + + return nil +} + +// read couchbase session by sid +func (cp *CouchbaseProvider) SessionRead(sid string) (SessionStore, error) { + cp.b = cp.getBucket() + + var doc []byte + + err := cp.b.Get(sid, &doc) + var kv map[interface{}]interface{} + if doc == nil { + kv = make(map[interface{}]interface{}) + } else { + kv, err = decodeGob(doc) + if err != nil { + return nil, err + } + } + + cs := &CouchbaseSessionStore{b: cp.b, sid: sid, values: kv, maxlifetime: cp.maxlifetime} + return cs, nil +} + +func (cp *CouchbaseProvider) SessionExist(sid string) bool { + cp.b = cp.getBucket() + defer cp.b.Close() + + var doc []byte + + if err := cp.b.Get(sid, &doc); err != nil || doc == nil { + return false + } else { + return true + } +} + +func (cp *CouchbaseProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) { + cp.b = cp.getBucket() + + var doc []byte + if err := cp.b.Get(oldsid, &doc); err != nil || doc == nil { + cp.b.Set(sid, int(cp.maxlifetime), "") + } else { + err := cp.b.Delete(oldsid) + if err != nil { + return nil, err + } + _, _ = cp.b.Add(sid, int(cp.maxlifetime), doc) + } + + err := cp.b.Get(sid, &doc) + if err != nil { + return nil, err + } + var kv map[interface{}]interface{} + if doc == nil { + kv = make(map[interface{}]interface{}) + } else { + kv, err = decodeGob(doc) + if err != nil { + return nil, err + } + } + + cs := &CouchbaseSessionStore{b: cp.b, sid: sid, values: kv, maxlifetime: cp.maxlifetime} + return cs, nil +} + +func (cp *CouchbaseProvider) SessionDestroy(sid string) error { + cp.b = cp.getBucket() + defer cp.b.Close() + + cp.b.Delete(sid) + return nil +} + +func (cp *CouchbaseProvider) SessionGC() { + return +} + +func (cp *CouchbaseProvider) SessionAll() int { + return 0 +} + +func init() { + Register("couchbase", couchbpder) +}