diff --git a/session/sess_cookie.go b/session/sess_cookie.go index 7962be18..ddf1a902 100644 --- a/session/sess_cookie.go +++ b/session/sess_cookie.go @@ -11,12 +11,15 @@ import ( var cookiepder = &CookieProvider{} +// Cookie SessionStore type CookieSessionStore struct { sid string - values map[interface{}]interface{} //session data + values map[interface{}]interface{} // session data lock sync.RWMutex } +// Set value to cookie session. +// the value are encoded as gob with hash block string. func (st *CookieSessionStore) Set(key, value interface{}) error { st.lock.Lock() defer st.lock.Unlock() @@ -24,6 +27,7 @@ func (st *CookieSessionStore) Set(key, value interface{}) error { return nil } +// Get value from cookie session func (st *CookieSessionStore) Get(key interface{}) interface{} { st.lock.RLock() defer st.lock.RUnlock() @@ -35,6 +39,7 @@ func (st *CookieSessionStore) Get(key interface{}) interface{} { return nil } +// Delete value in cookie session func (st *CookieSessionStore) Delete(key interface{}) error { st.lock.Lock() defer st.lock.Unlock() @@ -42,6 +47,7 @@ func (st *CookieSessionStore) Delete(key interface{}) error { return nil } +// Clean all values in cookie session func (st *CookieSessionStore) Flush() error { st.lock.Lock() defer st.lock.Unlock() @@ -49,10 +55,12 @@ func (st *CookieSessionStore) Flush() error { return nil } +// Return id of this cookie session func (st *CookieSessionStore) SessionID() string { return st.sid } +// Write cookie session to http response cookie func (st *CookieSessionStore) SessionRelease(w http.ResponseWriter) { str, err := encodeCookie(cookiepder.block, cookiepder.config.SecurityKey, @@ -79,12 +87,21 @@ type cookieConfig struct { Maxage int `json:"maxage"` } +// Cookie session provider type CookieProvider struct { maxlifetime int64 config *cookieConfig block cipher.Block } +// Init cookie session provider with max lifetime and config json. +// maxlifetime is ignored. +// json config: +// securityKey - hash string +// blockKey - gob encode hash string. it's saved as aes crypto. +// securityName - recognized name in encoded cookie string +// cookieName - cookie name +// maxage - cookie max life time. func (pder *CookieProvider) SessionInit(maxlifetime int64, config string) error { pder.config = &cookieConfig{} err := json.Unmarshal([]byte(config), pder.config) @@ -104,6 +121,8 @@ func (pder *CookieProvider) SessionInit(maxlifetime int64, config string) error return nil } +// Get SessionStore in cooke. +// decode cooke string to map and put into SessionStore with sid. func (pder *CookieProvider) SessionRead(sid string) (SessionStore, error) { maps, _ := decodeCookie(pder.block, pder.config.SecurityKey, @@ -116,26 +135,32 @@ func (pder *CookieProvider) SessionRead(sid string) (SessionStore, error) { return rs, nil } +// Cookie session is always existed func (pder *CookieProvider) SessionExist(sid string) bool { return true } +// Implement method, no used. func (pder *CookieProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) { return nil, nil } +// Implement method, no used. func (pder *CookieProvider) SessionDestroy(sid string) error { return nil } +// Implement method, no used. func (pder *CookieProvider) SessionGC() { return } +// Implement method, return 0. func (pder *CookieProvider) SessionAll() int { return 0 } +// Implement method, no used. func (pder *CookieProvider) SessionUpdate(sid string) error { return nil } diff --git a/session/sess_file.go b/session/sess_file.go index 5d33d0e2..73eec874 100644 --- a/session/sess_file.go +++ b/session/sess_file.go @@ -18,6 +18,7 @@ var ( gcmaxlifetime int64 ) +// File session store type FileSessionStore struct { f *os.File sid string @@ -25,6 +26,7 @@ type FileSessionStore struct { values map[interface{}]interface{} } +// Set value to file session func (fs *FileSessionStore) Set(key, value interface{}) error { fs.lock.Lock() defer fs.lock.Unlock() @@ -32,6 +34,7 @@ func (fs *FileSessionStore) Set(key, value interface{}) error { return nil } +// Get value from file session func (fs *FileSessionStore) Get(key interface{}) interface{} { fs.lock.RLock() defer fs.lock.RUnlock() @@ -43,6 +46,7 @@ func (fs *FileSessionStore) Get(key interface{}) interface{} { return nil } +// Delete value in file session by given key func (fs *FileSessionStore) Delete(key interface{}) error { fs.lock.Lock() defer fs.lock.Unlock() @@ -50,6 +54,7 @@ func (fs *FileSessionStore) Delete(key interface{}) error { return nil } +// Clean all values in file session func (fs *FileSessionStore) Flush() error { fs.lock.Lock() defer fs.lock.Unlock() @@ -57,10 +62,12 @@ func (fs *FileSessionStore) Flush() error { return nil } +// Get file session store id func (fs *FileSessionStore) SessionID() string { return fs.sid } +// Write file session to local file with Gob string func (fs *FileSessionStore) SessionRelease(w http.ResponseWriter) { defer fs.f.Close() b, err := encodeGob(fs.values) @@ -72,17 +79,23 @@ func (fs *FileSessionStore) SessionRelease(w http.ResponseWriter) { fs.f.Write(b) } +// File session provider type FileProvider struct { maxlifetime int64 savePath string } +// Init file session provider. +// savePath sets the session files path. func (fp *FileProvider) SessionInit(maxlifetime int64, savePath string) error { fp.maxlifetime = maxlifetime fp.savePath = savePath return nil } +// Read file session by sid. +// if file is not exist, create it. +// the file path is generated from sid string. func (fp *FileProvider) SessionRead(sid string) (SessionStore, error) { err := os.MkdirAll(path.Join(fp.savePath, string(sid[0]), string(sid[1])), 0777) if err != nil { @@ -117,6 +130,8 @@ func (fp *FileProvider) SessionRead(sid string) (SessionStore, error) { return ss, nil } +// Check file session exist. +// it checkes the file named from sid exist or not. func (fp *FileProvider) SessionExist(sid string) bool { _, err := os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid)) if err == nil { @@ -126,16 +141,20 @@ func (fp *FileProvider) SessionExist(sid string) bool { } } +// Remove all files in this save path func (fp *FileProvider) SessionDestroy(sid string) error { os.Remove(path.Join(fp.savePath)) return nil } +// Recycle files in save path func (fp *FileProvider) SessionGC() { gcmaxlifetime = fp.maxlifetime filepath.Walk(fp.savePath, gcpath) } +// Get active file session number. +// it walks save path to count files. func (fp *FileProvider) SessionAll() int { a := &activeSession{} err := filepath.Walk(fp.savePath, func(path string, f os.FileInfo, err error) error { @@ -148,6 +167,8 @@ func (fp *FileProvider) SessionAll() int { return a.total } +// Generate new sid for file session. +// it delete old file and create new file named from new sid. func (fp *FileProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) { err := os.MkdirAll(path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1])), 0777) if err != nil { @@ -197,6 +218,7 @@ func (fp *FileProvider) SessionRegenerate(oldsid, sid string) (SessionStore, err return ss, nil } +// remove file in save path if expired func gcpath(path string, info os.FileInfo, err error) error { if err != nil { return err diff --git a/session/sess_mem.go b/session/sess_mem.go index c74c2602..33c84717 100644 --- a/session/sess_mem.go +++ b/session/sess_mem.go @@ -9,6 +9,8 @@ import ( var mempder = &MemProvider{list: list.New(), sessions: make(map[string]*list.Element)} +// memory session store. +// it saved sessions in a map in memory. type MemSessionStore struct { sid string //session id timeAccessed time.Time //last access time @@ -16,6 +18,7 @@ type MemSessionStore struct { lock sync.RWMutex } +// set value to memory session func (st *MemSessionStore) Set(key, value interface{}) error { st.lock.Lock() defer st.lock.Unlock() @@ -23,6 +26,7 @@ func (st *MemSessionStore) Set(key, value interface{}) error { return nil } +// get value from memory session by key func (st *MemSessionStore) Get(key interface{}) interface{} { st.lock.RLock() defer st.lock.RUnlock() @@ -34,6 +38,7 @@ func (st *MemSessionStore) Get(key interface{}) interface{} { return nil } +// delete in memory session by key func (st *MemSessionStore) Delete(key interface{}) error { st.lock.Lock() defer st.lock.Unlock() @@ -41,6 +46,7 @@ func (st *MemSessionStore) Delete(key interface{}) error { return nil } +// clear all values in memory session func (st *MemSessionStore) Flush() error { st.lock.Lock() defer st.lock.Unlock() @@ -48,27 +54,31 @@ func (st *MemSessionStore) Flush() error { return nil } +// get this id of memory session store func (st *MemSessionStore) SessionID() string { return st.sid } +// Implement method, no used. func (st *MemSessionStore) SessionRelease(w http.ResponseWriter) { } type MemProvider struct { - lock sync.RWMutex //用来锁 - sessions map[string]*list.Element //用来存储在内存 - list *list.List //用来做gc + lock sync.RWMutex // locker + sessions map[string]*list.Element // map in memory + list *list.List // for gc maxlifetime int64 savePath string } +// init memory session func (pder *MemProvider) SessionInit(maxlifetime int64, savePath string) error { pder.maxlifetime = maxlifetime pder.savePath = savePath return nil } +// get memory session store by sid func (pder *MemProvider) SessionRead(sid string) (SessionStore, error) { pder.lock.RLock() if element, ok := pder.sessions[sid]; ok { @@ -87,6 +97,7 @@ func (pder *MemProvider) SessionRead(sid string) (SessionStore, error) { return nil, nil } +// check session store exist in memory session by sid func (pder *MemProvider) SessionExist(sid string) bool { pder.lock.RLock() defer pder.lock.RUnlock() @@ -97,6 +108,7 @@ func (pder *MemProvider) SessionExist(sid string) bool { } } +// generate new sid for session store in memory session func (pder *MemProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) { pder.lock.RLock() if element, ok := pder.sessions[oldsid]; ok { @@ -120,6 +132,7 @@ func (pder *MemProvider) SessionRegenerate(oldsid, sid string) (SessionStore, er return nil, nil } +// delete session store in memory session by id func (pder *MemProvider) SessionDestroy(sid string) error { pder.lock.Lock() defer pder.lock.Unlock() @@ -131,6 +144,7 @@ func (pder *MemProvider) SessionDestroy(sid string) error { return nil } +// clean expired session stores in memory session func (pder *MemProvider) SessionGC() { pder.lock.RLock() for { @@ -152,10 +166,12 @@ func (pder *MemProvider) SessionGC() { pder.lock.RUnlock() } +// get count number of memory session func (pder *MemProvider) SessionAll() int { return pder.list.Len() } +// expand time of session store by id in memory session func (pder *MemProvider) SessionUpdate(sid string) error { pder.lock.Lock() defer pder.lock.Unlock() diff --git a/session/sess_mysql.go b/session/sess_mysql.go index 7bad9e4a..b471c6c0 100644 --- a/session/sess_mysql.go +++ b/session/sess_mysql.go @@ -1,11 +1,12 @@ package session -//CREATE TABLE `session` ( -// `session_key` char(64) NOT NULL, -// `session_data` blob, -// `session_expiry` int(11) unsigned NOT NULL, -// PRIMARY KEY (`session_key`) -//) ENGINE=MyISAM DEFAULT CHARSET=utf8; +// mysql session support need create table as sql: +// CREATE TABLE `session` ( +// `session_key` char(64) NOT NULL, +// session_data` blob, +// `session_expiry` int(11) unsigned NOT NULL, +// PRIMARY KEY (`session_key`) +// ) ENGINE=MyISAM DEFAULT CHARSET=utf8; import ( "database/sql" @@ -18,6 +19,7 @@ import ( var mysqlpder = &MysqlProvider{} +// mysql session store type MysqlSessionStore struct { c *sql.DB sid string @@ -25,6 +27,8 @@ type MysqlSessionStore struct { values map[interface{}]interface{} } +// set value in mysql session. +// it is temp value in map. func (st *MysqlSessionStore) Set(key, value interface{}) error { st.lock.Lock() defer st.lock.Unlock() @@ -32,6 +36,7 @@ func (st *MysqlSessionStore) Set(key, value interface{}) error { return nil } +// get value from mysql session func (st *MysqlSessionStore) Get(key interface{}) interface{} { st.lock.RLock() defer st.lock.RUnlock() @@ -43,6 +48,7 @@ func (st *MysqlSessionStore) Get(key interface{}) interface{} { return nil } +// delete value in mysql session func (st *MysqlSessionStore) Delete(key interface{}) error { st.lock.Lock() defer st.lock.Unlock() @@ -50,6 +56,7 @@ func (st *MysqlSessionStore) Delete(key interface{}) error { return nil } +// clear all values in mysql session func (st *MysqlSessionStore) Flush() error { st.lock.Lock() defer st.lock.Unlock() @@ -57,10 +64,13 @@ func (st *MysqlSessionStore) Flush() error { return nil } +// get session id of this mysql session store func (st *MysqlSessionStore) SessionID() string { return st.sid } +// save mysql session values to database. +// must call this method to save values to database. func (st *MysqlSessionStore) SessionRelease(w http.ResponseWriter) { defer st.c.Close() b, err := encodeGob(st.values) @@ -72,11 +82,13 @@ func (st *MysqlSessionStore) SessionRelease(w http.ResponseWriter) { } +// mysql session provider type MysqlProvider struct { maxlifetime int64 savePath string } +// connect to mysql func (mp *MysqlProvider) connectInit() *sql.DB { db, e := sql.Open("mysql", mp.savePath) if e != nil { @@ -85,12 +97,15 @@ func (mp *MysqlProvider) connectInit() *sql.DB { return db } +// init mysql session. +// savepath is the connection string of mysql. func (mp *MysqlProvider) SessionInit(maxlifetime int64, savePath string) error { mp.maxlifetime = maxlifetime mp.savePath = savePath return nil } +// get mysql session by sid func (mp *MysqlProvider) SessionRead(sid string) (SessionStore, error) { c := mp.connectInit() row := c.QueryRow("select session_data from session where session_key=?", sid) @@ -113,6 +128,7 @@ func (mp *MysqlProvider) SessionRead(sid string) (SessionStore, error) { return rs, nil } +// check mysql session exist func (mp *MysqlProvider) SessionExist(sid string) bool { c := mp.connectInit() defer c.Close() @@ -126,6 +142,7 @@ func (mp *MysqlProvider) SessionExist(sid string) bool { } } +// generate new sid for mysql session func (mp *MysqlProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) { c := mp.connectInit() row := c.QueryRow("select session_data from session where session_key=?", oldsid) @@ -148,6 +165,7 @@ func (mp *MysqlProvider) SessionRegenerate(oldsid, sid string) (SessionStore, er return rs, nil } +// delete mysql session by sid func (mp *MysqlProvider) SessionDestroy(sid string) error { c := mp.connectInit() c.Exec("DELETE FROM session where session_key=?", sid) @@ -155,6 +173,7 @@ func (mp *MysqlProvider) SessionDestroy(sid string) error { return nil } +// delete expired values in mysql session func (mp *MysqlProvider) SessionGC() { c := mp.connectInit() c.Exec("DELETE from session where session_expiry < ?", time.Now().Unix()-mp.maxlifetime) @@ -162,6 +181,7 @@ func (mp *MysqlProvider) SessionGC() { return } +// count values in mysql session func (mp *MysqlProvider) SessionAll() int { c := mp.connectInit() defer c.Close() diff --git a/session/sess_redis.go b/session/sess_redis.go index b05e4831..3c51b793 100644 --- a/session/sess_redis.go +++ b/session/sess_redis.go @@ -11,10 +11,12 @@ import ( var redispder = &RedisProvider{} +// redis max pool size var MAX_POOL_SIZE = 100 var redisPool chan redis.Conn +// redis session store type RedisSessionStore struct { p *redis.Pool sid string @@ -23,6 +25,7 @@ type RedisSessionStore struct { maxlifetime int64 } +// set value in redis session func (rs *RedisSessionStore) Set(key, value interface{}) error { rs.lock.Lock() defer rs.lock.Unlock() @@ -30,6 +33,7 @@ func (rs *RedisSessionStore) Set(key, value interface{}) error { return nil } +// get value in redis session func (rs *RedisSessionStore) Get(key interface{}) interface{} { rs.lock.RLock() defer rs.lock.RUnlock() @@ -41,6 +45,7 @@ func (rs *RedisSessionStore) Get(key interface{}) interface{} { return nil } +// delete value in redis session func (rs *RedisSessionStore) Delete(key interface{}) error { rs.lock.Lock() defer rs.lock.Unlock() @@ -48,6 +53,7 @@ func (rs *RedisSessionStore) Delete(key interface{}) error { return nil } +// clear all values in redis session func (rs *RedisSessionStore) Flush() error { rs.lock.Lock() defer rs.lock.Unlock() @@ -55,10 +61,12 @@ func (rs *RedisSessionStore) Flush() error { return nil } +// get redis session id func (rs *RedisSessionStore) SessionID() string { return rs.sid } +// save session values to redis func (rs *RedisSessionStore) SessionRelease(w http.ResponseWriter) { c := rs.p.Get() defer c.Close() @@ -77,6 +85,7 @@ func (rs *RedisSessionStore) SessionRelease(w http.ResponseWriter) { c.Do("SET", rs.sid, string(b), "EX", rs.maxlifetime) } +// redis session provider type RedisProvider struct { maxlifetime int64 savePath string @@ -85,8 +94,9 @@ type RedisProvider struct { poollist *redis.Pool } -//savepath like redisserveraddr,poolsize,password -//127.0.0.1:6379,100,astaxie +// init redis session +// savepath like redis server addr,pool size,password +// e.g. 127.0.0.1:6379,100,astaxie func (rp *RedisProvider) SessionInit(maxlifetime int64, savePath string) error { rp.maxlifetime = maxlifetime configs := strings.Split(savePath, ",") @@ -122,6 +132,7 @@ func (rp *RedisProvider) SessionInit(maxlifetime int64, savePath string) error { return nil } +// read redis session by sid func (rp *RedisProvider) SessionRead(sid string) (SessionStore, error) { c := rp.poollist.Get() defer c.Close() @@ -141,6 +152,7 @@ func (rp *RedisProvider) SessionRead(sid string) (SessionStore, error) { return rs, nil } +// check redis session exist by sid func (rp *RedisProvider) SessionExist(sid string) bool { c := rp.poollist.Get() defer c.Close() @@ -152,6 +164,7 @@ func (rp *RedisProvider) SessionExist(sid string) bool { } } +// generate new sid for redis session func (rp *RedisProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) { c := rp.poollist.Get() defer c.Close() @@ -181,6 +194,7 @@ func (rp *RedisProvider) SessionRegenerate(oldsid, sid string) (SessionStore, er return rs, nil } +// delete redis session by id func (rp *RedisProvider) SessionDestroy(sid string) error { c := rp.poollist.Get() defer c.Close() @@ -189,11 +203,12 @@ func (rp *RedisProvider) SessionDestroy(sid string) error { return nil } +// Impelment method, no used. func (rp *RedisProvider) SessionGC() { return } -//@todo +// @todo func (rp *RedisProvider) SessionAll() int { return 0 } diff --git a/session/session.go b/session/session.go index f41ba85b..d1a44538 100644 --- a/session/session.go +++ b/session/session.go @@ -14,6 +14,7 @@ import ( "time" ) +// SessionStore contains all data for one session process with specific id. type SessionStore interface { Set(key, value interface{}) error //set session value Get(key interface{}) interface{} //get session value @@ -23,6 +24,8 @@ type SessionStore interface { Flush() error //delete all data } +// Provider contains global session methods and saved SessionStores. +// it can operate a SessionStore by its id. type Provider interface { SessionInit(gclifetime int64, config string) error SessionRead(sid string) (SessionStore, error) @@ -61,16 +64,24 @@ type managerConfig struct { ProviderConfig string `json:"providerConfig"` } +// Manager contains Provider and its configuration. type Manager struct { provider Provider config *managerConfig } -//options -//1. is https default false -//2. hashfunc default sha1 -//3. hashkey default beegosessionkey -//4. maxage default is none +// Create new Manager with provider name and json config string. +// provider name: +// 1. cookie +// 2. file +// 3. memory +// 4. redis +// 5. mysql +// json config: +// 1. is https default false +// 2. hashfunc default sha1 +// 3. hashkey default beegosessionkey +// 4. maxage default is none func NewManager(provideName, config string) (*Manager, error) { provider, ok := provides[provideName] if !ok { @@ -102,7 +113,8 @@ func NewManager(provideName, config string) (*Manager, error) { }, nil } -//get Session +// Start session. generate or read the session id from http request. +// if session id exists, return SessionStore with this id. func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (session SessionStore) { cookie, err := r.Cookie(manager.config.CookieName) if err != nil || cookie.Value == "" { @@ -144,7 +156,7 @@ func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (se return } -//Destroy sessionid +// Destroy session by its id in http request cookie. func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) { cookie, err := r.Cookie(manager.config.CookieName) if err != nil || cookie.Value == "" { @@ -161,16 +173,20 @@ func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) { } } +// Get SessionStore by its id. func (manager *Manager) GetProvider(sid string) (sessions SessionStore, err error) { sessions, err = manager.provider.SessionRead(sid) return } +// Start session gc process. +// it can do gc in times after gc lifetime. func (manager *Manager) GC() { manager.provider.SessionGC() time.AfterFunc(time.Duration(manager.config.Gclifetime)*time.Second, func() { manager.GC() }) } +// Regenerate a session id for this SessionStore who's id is saving in http request. func (manager *Manager) SessionRegenerateId(w http.ResponseWriter, r *http.Request) (session SessionStore) { sid := manager.sessionId(r) cookie, err := r.Cookie(manager.config.CookieName) @@ -198,20 +214,23 @@ func (manager *Manager) SessionRegenerateId(w http.ResponseWriter, r *http.Reque return } +// Get all active sessions count number. func (manager *Manager) GetActiveSession() int { return manager.provider.SessionAll() } +// Set hash function for generating session id. func (manager *Manager) SetHashFunc(hasfunc, hashkey string) { manager.config.SessionIDHashFunc = hasfunc manager.config.SessionIDHashKey = hashkey } +// Set cookie with https. func (manager *Manager) SetSecure(secure bool) { manager.config.Secure = secure } -//remote_addr cruunixnano randdata +// generate session id with rand string, unix nano time, remote addr by hash function. func (manager *Manager) sessionId(r *http.Request) (sid string) { bs := make([]byte, 24) if _, err := io.ReadFull(rand.Reader, bs); err != nil { diff --git a/toolbox/debug.go b/toolbox/debug.go index 7cb9db4e..c22af04f 100644 --- a/toolbox/debug.go +++ b/toolbox/debug.go @@ -29,16 +29,13 @@ type pointerInfo struct { used []int } -// // print the data in console -// func Display(data ...interface{}) { display(true, data...) } -// -// return string -// + +// return data print string func GetDisplayString(data ...interface{}) string { return display(false, data...) } @@ -67,9 +64,7 @@ func display(displayed bool, data ...interface{}) string { return buf.String() } -// -// return fomateinfo -// +// return data dump and format bytes func fomateinfo(headlen int, data ...interface{}) []byte { var buf = new(bytes.Buffer) @@ -108,6 +103,7 @@ func fomateinfo(headlen int, data ...interface{}) []byte { return buf.Bytes() } +// check data is golang basic type func isSimpleType(val reflect.Value, kind reflect.Kind, pointers **pointerInfo, interfaces *[]reflect.Value) bool { switch kind { case reflect.Bool: @@ -158,6 +154,7 @@ func isSimpleType(val reflect.Value, kind reflect.Kind, pointers **pointerInfo, return false } +// dump value func printKeyValue(buf *bytes.Buffer, val reflect.Value, pointers **pointerInfo, interfaces *[]reflect.Value, structFilter func(string, string) bool, formatOutput bool, indent string, level int) { var t = val.Kind() @@ -367,6 +364,7 @@ func printKeyValue(buf *bytes.Buffer, val reflect.Value, pointers **pointerInfo, } } +// dump pointer value func printPointerInfo(buf *bytes.Buffer, headlen int, pointers *pointerInfo) { var anyused = false var pointerNum = 0 @@ -434,9 +432,7 @@ func printPointerInfo(buf *bytes.Buffer, headlen int, pointers *pointerInfo) { } } -// -// get stack info -// +// get stack bytes func stack(skip int, indent string) []byte { var buf = new(bytes.Buffer) @@ -455,7 +451,7 @@ func stack(skip int, indent string) []byte { return buf.Bytes() } -// function returns, if possible, the name of the function containing the PC. +// return the name of the function containing the PC if possible, func function(pc uintptr) []byte { fn := runtime.FuncForPC(pc) if fn == nil { diff --git a/toolbox/healthcheck.go b/toolbox/healthcheck.go index 224624ad..1540c7c7 100644 --- a/toolbox/healthcheck.go +++ b/toolbox/healthcheck.go @@ -13,12 +13,15 @@ package toolbox //AddHealthCheck("database",&DatabaseCheck{}) +// health checker map var AdminCheckList map[string]HealthChecker +// health checker interface type HealthChecker interface { Check() error } +// add health checker with name string func AddHealthCheck(name string, hc HealthChecker) { AdminCheckList[name] = hc } diff --git a/toolbox/profile.go b/toolbox/profile.go index 07d55d26..41721b09 100644 --- a/toolbox/profile.go +++ b/toolbox/profile.go @@ -19,6 +19,7 @@ func init() { pid = os.Getpid() } +// parse input command string func ProcessInput(input string, w io.Writer) { switch input { case "lookup goroutine": @@ -44,6 +45,7 @@ func ProcessInput(input string, w io.Writer) { } } +// record memory profile in pprof func MemProf() { if f, err := os.Create("mem-" + strconv.Itoa(pid) + ".memprof"); err != nil { log.Fatal("record memory profile failed: %v", err) @@ -54,6 +56,7 @@ func MemProf() { } } +// start cpu profile monitor func StartCPUProfile() { f, err := os.Create("cpu-" + strconv.Itoa(pid) + ".pprof") if err != nil { @@ -62,10 +65,12 @@ func StartCPUProfile() { pprof.StartCPUProfile(f) } +// stop cpu profile monitor func StopCPUProfile() { pprof.StopCPUProfile() } +// print gc information to io.Writer func PrintGCSummary(w io.Writer) { memStats := &runtime.MemStats{} runtime.ReadMemStats(memStats) @@ -114,7 +119,7 @@ func avg(items []time.Duration) time.Duration { return time.Duration(int64(sum) / int64(len(items))) } -// human readable format +// format bytes number friendly func toH(bytes uint64) string { switch { case bytes < 1024: diff --git a/toolbox/statistics.go b/toolbox/statistics.go index b75cfb05..6042197e 100644 --- a/toolbox/statistics.go +++ b/toolbox/statistics.go @@ -7,6 +7,7 @@ import ( "time" ) +// Statistics struct type Statistics struct { RequestUrl string RequestController string @@ -16,12 +17,15 @@ type Statistics struct { TotalTime time.Duration } +// UrlMap contains several statistics struct to log different data type UrlMap struct { lock sync.RWMutex LengthLimit int //limit the urlmap's length if it's equal to 0 there's no limit urlmap map[string]map[string]*Statistics } +// add statistics task. +// it needs request method, request url, request controller and statistics time duration func (m *UrlMap) AddStatistics(requestMethod, requestUrl, requestController string, requesttime time.Duration) { m.lock.Lock() defer m.lock.Unlock() @@ -65,6 +69,7 @@ func (m *UrlMap) AddStatistics(requestMethod, requestUrl, requestController stri } } +// put url statistics result in io.Writer func (m *UrlMap) GetMap(rw io.Writer) { m.lock.RLock() defer m.lock.RUnlock() @@ -78,6 +83,7 @@ func (m *UrlMap) GetMap(rw io.Writer) { } } +// global statistics data map var StatisticsMap *UrlMap func init() { diff --git a/toolbox/task.go b/toolbox/task.go index ce9f56f9..b5558c15 100644 --- a/toolbox/task.go +++ b/toolbox/task.go @@ -53,6 +53,7 @@ const ( starBit = 1 << 63 ) +// time taks schedule type Schedule struct { Second uint64 Minute uint64 @@ -62,8 +63,10 @@ type Schedule struct { Week uint64 } +// task func type type TaskFunc func() error +// task interface type Tasker interface { GetStatus() string Run() error @@ -73,21 +76,24 @@ type Tasker interface { GetPrev() time.Time } +// task error type taskerr struct { t time.Time errinfo string } +// task struct type Task struct { Taskname string Spec *Schedule DoFunc TaskFunc Prev time.Time Next time.Time - Errlist []*taskerr //errtime:errinfo - ErrLimit int //max length for the errlist 0 stand for there' no limit + Errlist []*taskerr // like errtime:errinfo + ErrLimit int // max length for the errlist, 0 stand for no limit } +// add new task with name, time and func func NewTask(tname string, spec string, f TaskFunc) *Task { task := &Task{ @@ -99,6 +105,7 @@ func NewTask(tname string, spec string, f TaskFunc) *Task { return task } +// get current task status func (tk *Task) GetStatus() string { var str string for _, v := range tk.Errlist { @@ -107,6 +114,7 @@ func (tk *Task) GetStatus() string { return str } +// run task func (tk *Task) Run() error { err := tk.DoFunc() if err != nil { @@ -117,53 +125,58 @@ func (tk *Task) Run() error { return err } +// set next time for this task func (tk *Task) SetNext(now time.Time) { tk.Next = tk.Spec.Next(now) } +// get the next call time of this task func (tk *Task) GetNext() time.Time { return tk.Next } + +// set prev time of this task func (tk *Task) SetPrev(now time.Time) { tk.Prev = now } +// get prev time of this task func (tk *Task) GetPrev() time.Time { return tk.Prev } -//前6个字段分别表示: -// 秒钟:0-59 -// 分钟:0-59 -// 小时:1-23 -// 日期:1-31 -// 月份:1-12 -// 星期:0-6(0表示周日) +// six columns mean: +// second:0-59 +// minute:0-59 +// hour:1-23 +// day:1-31 +// month:1-12 +// week:0-6(0 means Sunday) -//还可以用一些特殊符号: -// *: 表示任何时刻 -// ,: 表示分割,如第三段里:2,4,表示2点和4点执行 -//   -:表示一个段,如第三端里: 1-5,就表示1到5点 -// /n : 表示每个n的单位执行一次,如第三段里,*/1, 就表示每隔1个小时执行一次命令。也可以写成1-23/1. +// some signals: +// *: any time +// ,:  separate signal +//   -:duration +// /n : do as n times of time duration ///////////////////////////////////////////////////////// -// 0/30 * * * * * 每30秒 执行 -// 0 43 21 * * * 21:43 执行 -// 0 15 05 * * *    05:15 执行 -// 0 0 17 * * * 17:00 执行 -// 0 0 17 * * 1 每周一的 17:00 执行 -// 0 0,10 17 * * 0,2,3 每周日,周二,周三的 17:00和 17:10 执行 -// 0 0-10 17 1 * * 毎月1日从 17:00到7:10 毎隔1分钟 执行 -// 0 0 0 1,15 * 1 毎月1日和 15日和 一日的 0:00 执行 -// 0 42 4 1 * *     毎月1日的 4:42分 执行 -// 0 0 21 * * 1-6   周一到周六 21:00 执行 -// 0 0,10,20,30,40,50 * * * *  每隔10分 执行 -// 0 */10 * * * *        每隔10分 执行 -// 0 * 1 * * *         从1:0到1:59 每隔1分钟 执行 -// 0 0 1 * * *         1:00 执行 -// 0 0 */1 * * *        毎时0分 每隔1小时 执行 -// 0 0 * * * *         毎时0分 每隔1小时 执行 -// 0 2 8-20/3 * * *       8:02,11:02,14:02,17:02,20:02 执行 -// 0 30 5 1,15 * *       1日 和 15日的 5:30 执行 +// 0/30 * * * * * every 30s +// 0 43 21 * * * 21:43 +// 0 15 05 * * *    05:15 +// 0 0 17 * * * 17:00 +// 0 0 17 * * 1 17:00 in every Monday +// 0 0,10 17 * * 0,2,3 17:00 and 17:10 in every Sunday, Tuesday and Wednesday +// 0 0-10 17 1 * * 17:00 to 17:10 in 1 min duration each time on the first day of month +// 0 0 0 1,15 * 1 0:00 on the 1st day and 15th day of month +// 0 42 4 1 * *     4:42 on the 1st day of month +// 0 0 21 * * 1-6   21:00 from Monday to Saturday +// 0 0,10,20,30,40,50 * * * *  every 10 min duration +// 0 */10 * * * *        every 10 min duration +// 0 * 1 * * *         1:00 to 1:59 in 1 min duration each time +// 0 0 1 * * *         1:00 +// 0 0 */1 * * *        0 min of hour in 1 hour duration +// 0 0 * * * *         0 min of hour in 1 hour duration +// 0 2 8-20/3 * * *       8:02, 11:02, 14:02, 17:02, 20:02 +// 0 30 5 1,15 * *       5:30 on the 1st day and 15th day of month func (t *Task) SetCron(spec string) { t.Spec = t.parse(spec) } @@ -252,6 +265,7 @@ func (t *Task) parseSpec(spec string) *Schedule { return nil } +// set schedule to next time func (s *Schedule) Next(t time.Time) time.Time { // Start at the earliest possible time (the upcoming second). @@ -349,6 +363,7 @@ func dayMatches(s *Schedule, t time.Time) bool { return domMatch || dowMatch } +// start all tasks func StartTask() { go run() } @@ -388,20 +403,23 @@ func run() { } } +// start all tasks func StopTask() { stop <- true } +// add task with name func AddTask(taskname string, t Tasker) { AdminTaskList[taskname] = t } -//sort map for tasker +// sort map for tasker type MapSorter struct { Keys []string Vals []Tasker } +// create new tasker map func NewMapSorter(m map[string]Tasker) *MapSorter { ms := &MapSorter{ Keys: make([]string, 0, len(m)), @@ -414,6 +432,7 @@ func NewMapSorter(m map[string]Tasker) *MapSorter { return ms } +// sort tasker map func (ms *MapSorter) Sort() { sort.Sort(ms) }