I m using golang in the back end and mongodb is my database. I wanted to store the user session(betwen login and logout )of my web application in the mongodb for the persistence.Since there is provider available only for mysql not for mongodb,I edited it to support mongodb.But when i try to use it im getting the invalid memory address or nil pointer dereference. The code is as follows and please if there is any better way to code please let me know.Thanks
type (
SessionStore struct {
c *mgo.Session
sid string
lock sync.RWMutex
values map[interface{}]interface{}
}
)
var mgopder = &Provider{}
func (st *SessionStore) Set(key, value interface{}) error {
st.lock.Lock()
defer st.lock.Unlock()
st.values[key] = value
return nil
}
// Get value from mongodb session
func (st *SessionStore) Get(key interface{}) interface{} {
st.lock.RLock()
defer st.lock.RUnlock()
if v, ok := st.values[key]; ok {
return v
}
return nil
}
// Delete value in mongodb session
func (st *SessionStore) Delete(key interface{}) error {
st.lock.Lock()
defer st.lock.Unlock()
delete(st.values, key)
return nil
}
// Flush clear all values in mongodb session
func (st *SessionStore) Flush() error {
st.lock.Lock()
defer st.lock.Unlock()
st.values = make(map[interface{}]interface{})
return nil
}
// SessionID get session id of this mongodb session store
func (st *SessionStore) SessionID() string {
return st.sid
}
// SessionRelease save mongodb session values to database.
// must call this method to save values to database.
func (st *SessionStore) SessionRelease(w http.ResponseWriter) {
defer st.c.Close()
b, err := session.EncodeGob(st.values)
if err != nil {
return
}
st.c.DB("Employee").C("Sessions").Update(nil, bson.M{"$set": bson.M{
"session_data": b,
"session_expiry": time.Now().Unix(),
"session_key": st.sid,
},
},
)
/*st.c.Exec("UPDATE "+TableName+" set `session_data`=?, `session_expiry`=? where session_key=?",
b, time.Now().Unix(), st.sid)*/
}
type Provider struct {
maxlifetime int64
savePath string
Database string
}
// connect to mongodb
func (mp *Provider) connectInit() *mgo.Session {
ds, err := mgo.Dial("Employee")
if err != nil {
return nil
}
return ds
}
// SessionInit init mongodb session.
// savepath is the connection string of mongodb
func (mp *Provider) SessionInit(maxlifetime int64, savePath string) error {
mp.maxlifetime = maxlifetime
mp.savePath = savePath
mp.Database = "Employee"
return nil
}
// SessionRead get mysql session by sid
func (mp *Provider) SessionRead(sid string) (session.Store, error) {
var sessiondata []byte
ds := mp.connectInit()
defer ds.Close()
c := ds.DB(mp.Database).C("Session")
err := c.Find(bson.M{
"session_key": sid,
}).Select(bson.M{"session_data": 1}).All(&sessiondata)
if err != nil {
if err.Error() == "not found" {
c.Insert(bson.M{
"session_key": sid,
"session_data": " ",
"session_expiry": time.Now().Unix(),
})
}
}
var kv map[interface{}]interface{}
if len(sessiondata) == 0 {
kv = make(map[interface{}]interface{})
} else {
kv, err = session.DecodeGob(sessiondata)
if err != nil {
return nil, err
}
}
rs := &SessionStore{c: ds, sid: sid, values: kv}
return rs, nil
}
// SessionExist check mongodb session exist
func (mp *Provider) SessionExist(sid string) bool {
var sessiondata []byte
ds := mp.connectInit()
defer ds.Close()
c := ds.DB("Employee").C("Sessions")
err := c.Find(bson.M{
"session_key": sid,
}).Select(bson.M{
"session_data": 1,
}).One(&sessiondata)
if err != nil {
if err.Error() == "not found" {
return false
}
}
return true
}
// SessionRegenerate generate new sid for mysql session
func (mp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) {
var sessiondata []byte
ds := mp.connectInit()
defer ds.Close()
c := ds.DB("Employee").C("Sessions")
err := c.Find(bson.M{
"session_key": oldsid,
}).Select(bson.M{
"session_data": 1,
}).One(&sessiondata)
if err != nil {
if err.Error() == "not found" {
c.Insert(bson.M{
"sessoin_key": oldsid,
"session_data": " ",
"session_expiry": time.Now().Unix(),
})
}
}
/* row := c.QueryRow("select session_data from "+TableName+" where session_key=?", oldsid)
err := row.Scan(&sessiondata)
c.Update(bson.M{"sessoin_key": oldsid}, bson.M{
"$set": bson.M{
"session_key": sid,
},
})
/*c.Exec("update "+TableName+" set `session_key`=? where session_key=?", sid, oldsid)
*/
var kv map[interface{}]interface{}
if len(sessiondata) == 0 {
kv = make(map[interface{}]interface{})
} else {
kv, err = session.DecodeGob(sessiondata)
if err != nil {
return nil, err
}
}
rs := &SessionStore{c: ds, sid: sid, values: kv}
return rs, nil
}
// SessionDestroy delete mysql session by sid
func (mp *Provider) SessionDestroy(sid string) error {
ds := mp.connectInit()
defer ds.Close()
c := ds.DB("Employee").C("Sessions")
c.Remove(bson.M{
"session_key": sid,
})
return nil
}
// SessionGC delete expired values in mysql session
func (mp *Provider) SessionGC() {
ds := mp.connectInit()
defer ds.Close()
c := ds.DB("Employee").C("Sessions")
c.Remove(bson.M{
"session_expiry": bson.M{
"$lt": time.Now().Unix() - mp.maxlifetime,
},
})
return
}
// SessionAll count values in mysql session
func (mp *Provider) SessionAll() int {
var total int
ds := mp.connectInit()
defer ds.Close()
c := ds.DB("Employee").C("Sessions")
total, err := c.Count()
if err != nil {
return 0
}
return total
}
func init() {
session.Register("mongodb", mgopder)
}
Error:
panic: runtime error: invalid memory address or nil pointer dereference
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x1 addr=0x0 pc=0x6db254]
goroutine 6 [running]:
panic(0xa2f560, 0xc0820080b0)
C:/Go/src/runtime/panic.go:481 +0x3f4
gopkg.in/mgo%2ev2.(*Session).Close(0x0)
C:/Projects/Go/src/gopkg.in/mgo.v2/session.go:1612 +0x144
panic(0xa2f560, 0xc0820080b0)
C:/Go/src/runtime/panic.go:443 +0x4f7
gopkg.in/mgo%2ev2.(*Session).acquireSocket(0x0, 0xc082290000, 0x0, 0x0, 0x0)
C:/Projects/Go/src/gopkg.in/mgo.v2/session.go:4409 +0x4ba
gopkg.in/mgo%2ev2.(*Collection).writeOp(0xc082279f30, 0x8feb80, 0xc082326060, 0xc082326001, 0x0, 0x0, 0x0)
C:/Projects/Go/src/gopkg.in/mgo.v2/session.go:4604 +0xe7
gopkg.in/mgo%2ev2.(*Collection).Remove(0xc082279f30, 0x9d4700, 0xc082326030, 0x0, 0x0)
C:/Projects/Go/src/gopkg.in/mgo.v2/session.go:2586 +0x15c
sample/models.(*Provider).SessionGC(0xe2f5a0)
C:/Projects/Go/src/sample/models/model.go:234 +0x3dc
github.com/astaxie/beego/session.(*Manager).GC(0xc082258b20)
C:/Projects/Go/src/github.com/astaxie/beego/session/session.go:271 +0x48
created by github.com/astaxie/beego.registerSession
C:/Projects/Go/src/github.com/astaxie/beego/hooks.go:68 +0x31d
This is what i normally do.
package mongo
import (
"time"
"gopkg.in/mgo.v2"
)
// DataStore containing a pointer to a mgo session
type DataStore struct {
Session *mgo.Session
}
// ConnectToTagserver is a helper method that connections to pubgears' tagserver
// database
func (ds *DataStore) ConnectToTagserver() {
mongoDBDialInfo := &mgo.DialInfo{
Addrs: []string{"some IP"},
Timeout: 60 * time.Second,
Database: "some db",
}
sess, err := mgo.DialWithInfo(mongoDBDialInfo)
if err != nil {
panic(err)
}
sess.SetMode(mgo.Monotonic, true)
ds.Session = sess
}
// Close is a helper method that ensures the session is properly terminated
func (ds *DataStore) Close() {
ds.Session.Close()
}
Then in my models package I do something like this
package models
import (
"./mongo"
"gopkg.in/mgo.v2/bson"
)
// AdSize represents the data object stucture that is returned by querying
// mongo's account collection
type AdSize struct {
ID bson.ObjectId `bson:"_id,omitempty"`
Providers []string `bson:"providers"`
Size string `bson:"size"`
}
// GetAllAdsizes is a helper function designed to retrieve all the objects in the
// adsize collection
func GetAllAdsizes() ([]AdSize, error) {
ds := mongo.DataStore{}
ds.ConnectToTagserver()
defer ds.Close()
adSizes := []AdSize{}
adSizeCollection := ds.Session.DB("some database").C("some collection")
err := adSizeCollection.Find(bson.M{}).Sort("name").All(&adSizes)
return adSizes, err
}
So I created a session wrapper in the mongo file, then create a session object in the models file, then lastly in some route file i call the method GetAllAdsizes(), which handled my mongo session. The session is keep alive until the the end of the GetAllAdsizes() method, as it was closed on defer. However something like this can be modified, where you handle all the user stuff and then close the session if user logs out. Also take a look here Best practice to maintain a mgo session , where you can see a similar type of logic.
Not sure about your code, here is a sample of a package file that create a session to mongodb in go and used it.
package mydb
import (
"fmt"
"os"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
var Db *mgo.Session
type DbLink struct {
DbName string
}
func NewDbSession(url string) {
var e error
Db, e = mgo.Dial(url)
if e != nil {
panic(e)
os.Exit(-1)
}
}
Then in your main package:
package main
import (
"fmt"
"os"
"mydb"
)
func main() {
// <user> the user to access the db
// <pwd> the database user password
// <host> hostname or ip address of the database server (localhost i.e.)
// <port> the port where the database server is listening (usually 27016).
mydb.NewDbSession("mongodb://<user>:<pwd>@<host>:<port>/?authSource=<db_name>")
session := mydb.Db.Copy()
defer session.Close()
col := session.DB("my_db_schema").C("my_collection_name")
// row is a list of struct depends on collection
err := col.Find(bson.M{"field_name": "value"}).All(&row)
if err != nil {
fmt.Printf("%s\n", err)
}
}
This is a very trivial example that should help you to start.
Consider that MongoDB it's very different from MySQL, as it is a NoSQL and schema less database management system.
Please refer to the documentation of the mgo package for details.
Your user session struct have some issues:
type SessionStore struct {
c *mgo.Session
sid string
lock sync.RWMutex
values map[interface{}]interface{}
}
First you have to use capital letters to export the key.
For example instead of c you should use C , and so on with Sid , Lock and Values .
type SessionStore struct {
C *mgo.Session `json:"C" bson:"c"`
Sid string `json:"Sid" bson:"sid,omitempty"`
Lock sync.RWMutex `json:"Lock" bson:"lock,omitempty"`
Values map[interface{}]interface{} `json:"Values" bson:"values,omitempty"`
}
I don't think that is going to work with pointers.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.