846d7664 by 傅小黑

Merge branch 'develop' of git://github.com/astaxie/beego

2 parents 6b5108ef bbc71142
...@@ -45,6 +45,7 @@ type Controller struct { ...@@ -45,6 +45,7 @@ type Controller struct {
45 CruSession session.SessionStore 45 CruSession session.SessionStore
46 XSRFExpire int 46 XSRFExpire int
47 AppController interface{} 47 AppController interface{}
48 EnableReander bool
48 } 49 }
49 50
50 // ControllerInterface is an interface to uniform all controller handler. 51 // ControllerInterface is an interface to uniform all controller handler.
...@@ -74,6 +75,7 @@ func (c *Controller) Init(ctx *context.Context, controllerName, actionName strin ...@@ -74,6 +75,7 @@ func (c *Controller) Init(ctx *context.Context, controllerName, actionName strin
74 c.Ctx = ctx 75 c.Ctx = ctx
75 c.TplExt = "tpl" 76 c.TplExt = "tpl"
76 c.AppController = app 77 c.AppController = app
78 c.EnableReander = true
77 } 79 }
78 80
79 // Prepare runs after Init before request function execution. 81 // Prepare runs after Init before request function execution.
...@@ -123,6 +125,9 @@ func (c *Controller) Options() { ...@@ -123,6 +125,9 @@ func (c *Controller) Options() {
123 125
124 // Render sends the response with rendered template bytes as text/html type. 126 // Render sends the response with rendered template bytes as text/html type.
125 func (c *Controller) Render() error { 127 func (c *Controller) Render() error {
128 if !c.EnableReander {
129 return nil
130 }
126 rb, err := c.RenderBytes() 131 rb, err := c.RenderBytes()
127 132
128 if err != nil { 133 if err != nil {
...@@ -398,6 +403,7 @@ func (c *Controller) SessionRegenerateID() { ...@@ -398,6 +403,7 @@ func (c *Controller) SessionRegenerateID() {
398 403
399 // DestroySession cleans session data and session cookie. 404 // DestroySession cleans session data and session cookie.
400 func (c *Controller) DestroySession() { 405 func (c *Controller) DestroySession() {
406 c.Ctx.Input.CruSession.Flush()
401 GlobalSessions.SessionDestroy(c.Ctx.ResponseWriter, c.Ctx.Request) 407 GlobalSessions.SessionDestroy(c.Ctx.ResponseWriter, c.Ctx.Request)
402 } 408 }
403 409
......
...@@ -4,8 +4,28 @@ import ( ...@@ -4,8 +4,28 @@ import (
4 "encoding/json" 4 "encoding/json"
5 "log" 5 "log"
6 "os" 6 "os"
7 "runtime"
7 ) 8 )
8 9
10 type Brush func(string) string
11
12 func NewBrush(color string) Brush {
13 pre := "\033["
14 reset := "\033[0m"
15 return func(text string) string {
16 return pre + color + "m" + text + reset
17 }
18 }
19
20 var colors = []Brush{
21 NewBrush("1;36"), // Trace cyan
22 NewBrush("1;34"), // Debug blue
23 NewBrush("1;32"), // Info green
24 NewBrush("1;33"), // Warn yellow
25 NewBrush("1;31"), // Error red
26 NewBrush("1;35"), // Critical purple
27 }
28
9 // ConsoleWriter implements LoggerInterface and writes messages to terminal. 29 // ConsoleWriter implements LoggerInterface and writes messages to terminal.
10 type ConsoleWriter struct { 30 type ConsoleWriter struct {
11 lg *log.Logger 31 lg *log.Logger
...@@ -35,7 +55,11 @@ func (c *ConsoleWriter) WriteMsg(msg string, level int) error { ...@@ -35,7 +55,11 @@ func (c *ConsoleWriter) WriteMsg(msg string, level int) error {
35 if level < c.Level { 55 if level < c.Level {
36 return nil 56 return nil
37 } 57 }
38 c.lg.Println(msg) 58 if goos := runtime.GOOS; goos == "windows" {
59 c.lg.Println(msg)
60 } else {
61 c.lg.Println(colors[level](msg))
62 }
39 return nil 63 return nil
40 } 64 }
41 65
......
...@@ -1350,6 +1350,10 @@ func (d *dbBase) ReadValues(q dbQuerier, qs *querySet, mi *modelInfo, cond *Cond ...@@ -1350,6 +1350,10 @@ func (d *dbBase) ReadValues(q dbQuerier, qs *querySet, mi *modelInfo, cond *Cond
1350 return cnt, nil 1350 return cnt, nil
1351 } 1351 }
1352 1352
1353 func (d *dbBase) RowsTo(dbQuerier, *querySet, *modelInfo, *Condition, interface{}, string, string, *time.Location) (int64, error) {
1354 return 0, nil
1355 }
1356
1353 // flag of update joined record. 1357 // flag of update joined record.
1354 func (d *dbBase) SupportUpdateJoin() bool { 1358 func (d *dbBase) SupportUpdateJoin() bool {
1355 return true 1359 return true
......
...@@ -3,7 +3,6 @@ package orm ...@@ -3,7 +3,6 @@ package orm
3 import ( 3 import (
4 "database/sql" 4 "database/sql"
5 "fmt" 5 "fmt"
6 "os"
7 "reflect" 6 "reflect"
8 "sync" 7 "sync"
9 "time" 8 "time"
...@@ -13,11 +12,11 @@ import ( ...@@ -13,11 +12,11 @@ import (
13 type DriverType int 12 type DriverType int
14 13
15 const ( 14 const (
16 _ DriverType = iota // int enum type 15 _ DriverType = iota // int enum type
17 DR_MySQL // mysql 16 DR_MySQL // mysql
18 DR_Sqlite // sqlite 17 DR_Sqlite // sqlite
19 DR_Oracle // oracle 18 DR_Oracle // oracle
20 DR_Postgres // pgsql 19 DR_Postgres // pgsql
21 ) 20 )
22 21
23 // database driver string. 22 // database driver string.
...@@ -96,40 +95,15 @@ type alias struct { ...@@ -96,40 +95,15 @@ type alias struct {
96 Engine string 95 Engine string
97 } 96 }
98 97
99 // Setting the database connect params. Use the database driver self dataSource args. 98 func detectTZ(al *alias) {
100 func RegisterDataBase(aliasName, driverName, dataSource string, params ...int) {
101 al := new(alias)
102 al.Name = aliasName
103 al.DriverName = driverName
104 al.DataSource = dataSource
105
106 var (
107 err error
108 )
109
110 if dr, ok := drivers[driverName]; ok {
111 al.DbBaser = dbBasers[dr]
112 al.Driver = dr
113 } else {
114 err = fmt.Errorf("driver name `%s` have not registered", driverName)
115 goto end
116 }
117
118 if dataBaseCache.add(aliasName, al) == false {
119 err = fmt.Errorf("db name `%s` already registered, cannot reuse", aliasName)
120 goto end
121 }
122
123 al.DB, err = sql.Open(driverName, dataSource)
124 if err != nil {
125 err = fmt.Errorf("register db `%s`, %s", aliasName, err.Error())
126 goto end
127 }
128
129 // orm timezone system match database 99 // orm timezone system match database
130 // default use Local 100 // default use Local
131 al.TZ = time.Local 101 al.TZ = time.Local
132 102
103 if al.DriverName == "sphinx" {
104 return
105 }
106
133 switch al.Driver { 107 switch al.Driver {
134 case DR_MySQL: 108 case DR_MySQL:
135 row := al.DB.QueryRow("SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP)") 109 row := al.DB.QueryRow("SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP)")
...@@ -173,6 +147,60 @@ func RegisterDataBase(aliasName, driverName, dataSource string, params ...int) { ...@@ -173,6 +147,60 @@ func RegisterDataBase(aliasName, driverName, dataSource string, params ...int) {
173 DebugLog.Printf("Detect DB timezone: %s %s\n", tz, err.Error()) 147 DebugLog.Printf("Detect DB timezone: %s %s\n", tz, err.Error())
174 } 148 }
175 } 149 }
150 }
151
152 func addAliasWthDB(aliasName, driverName string, db *sql.DB) (*alias, error) {
153 al := new(alias)
154 al.Name = aliasName
155 al.DriverName = driverName
156 al.DB = db
157
158 if dr, ok := drivers[driverName]; ok {
159 al.DbBaser = dbBasers[dr]
160 al.Driver = dr
161 } else {
162 return nil, fmt.Errorf("driver name `%s` have not registered", driverName)
163 }
164
165 err := db.Ping()
166 if err != nil {
167 return nil, fmt.Errorf("register db Ping `%s`, %s", aliasName, err.Error())
168 }
169
170 if dataBaseCache.add(aliasName, al) == false {
171 return nil, fmt.Errorf("db name `%s` already registered, cannot reuse", aliasName)
172 }
173
174 return al, nil
175 }
176
177 func AddAliasWthDB(aliasName, driverName string, db *sql.DB) error {
178 _, err := addAliasWthDB(aliasName, driverName, db)
179 return err
180 }
181
182 // Setting the database connect params. Use the database driver self dataSource args.
183 func RegisterDataBase(aliasName, driverName, dataSource string, params ...int) error {
184 var (
185 err error
186 db *sql.DB
187 al *alias
188 )
189
190 db, err = sql.Open(driverName, dataSource)
191 if err != nil {
192 err = fmt.Errorf("register db `%s`, %s", aliasName, err.Error())
193 goto end
194 }
195
196 al, err = addAliasWthDB(aliasName, driverName, db)
197 if err != nil {
198 goto end
199 }
200
201 al.DataSource = dataSource
202
203 detectTZ(al)
176 204
177 for i, v := range params { 205 for i, v := range params {
178 switch i { 206 switch i {
...@@ -183,39 +211,37 @@ func RegisterDataBase(aliasName, driverName, dataSource string, params ...int) { ...@@ -183,39 +211,37 @@ func RegisterDataBase(aliasName, driverName, dataSource string, params ...int) {
183 } 211 }
184 } 212 }
185 213
186 err = al.DB.Ping()
187 if err != nil {
188 err = fmt.Errorf("register db `%s`, %s", aliasName, err.Error())
189 goto end
190 }
191
192 end: 214 end:
193 if err != nil { 215 if err != nil {
194 fmt.Println(err.Error()) 216 if db != nil {
195 os.Exit(2) 217 db.Close()
218 }
219 DebugLog.Println(err.Error())
196 } 220 }
221
222 return err
197 } 223 }
198 224
199 // Register a database driver use specify driver name, this can be definition the driver is which database type. 225 // Register a database driver use specify driver name, this can be definition the driver is which database type.
200 func RegisterDriver(driverName string, typ DriverType) { 226 func RegisterDriver(driverName string, typ DriverType) error {
201 if t, ok := drivers[driverName]; ok == false { 227 if t, ok := drivers[driverName]; ok == false {
202 drivers[driverName] = typ 228 drivers[driverName] = typ
203 } else { 229 } else {
204 if t != typ { 230 if t != typ {
205 fmt.Sprintf("driverName `%s` db driver already registered and is other type\n", driverName) 231 return fmt.Errorf("driverName `%s` db driver already registered and is other type\n", driverName)
206 os.Exit(2)
207 } 232 }
208 } 233 }
234 return nil
209 } 235 }
210 236
211 // Change the database default used timezone 237 // Change the database default used timezone
212 func SetDataBaseTZ(aliasName string, tz *time.Location) { 238 func SetDataBaseTZ(aliasName string, tz *time.Location) error {
213 if al, ok := dataBaseCache.get(aliasName); ok { 239 if al, ok := dataBaseCache.get(aliasName); ok {
214 al.TZ = tz 240 al.TZ = tz
215 } else { 241 } else {
216 fmt.Sprintf("DataBase name `%s` not registered\n", aliasName) 242 return fmt.Errorf("DataBase name `%s` not registered\n", aliasName)
217 os.Exit(2)
218 } 243 }
244 return nil
219 } 245 }
220 246
221 // Change the max idle conns for *sql.DB, use specify database alias name 247 // Change the max idle conns for *sql.DB, use specify database alias name
......
...@@ -74,6 +74,20 @@ func (o *orm) Read(md interface{}, cols ...string) error { ...@@ -74,6 +74,20 @@ func (o *orm) Read(md interface{}, cols ...string) error {
74 return nil 74 return nil
75 } 75 }
76 76
77 // Try to read a row from the database, or insert one if it doesn't exist
78 func (o *orm) ReadOrCreate(md interface{}, col1 string, cols ...string) (bool, int64, error) {
79 cols = append([]string{col1}, cols...)
80 mi, ind := o.getMiInd(md, true)
81 err := o.alias.DbBaser.Read(o.db, mi, ind, o.alias.TZ, cols)
82 if err == ErrNoRows {
83 // Create
84 id, err := o.Insert(md)
85 return (err == nil), id, err
86 }
87
88 return false, ind.Field(mi.fields.pk.fieldIndex).Int(), err
89 }
90
77 // insert model data to database 91 // insert model data to database
78 func (o *orm) Insert(md interface{}) (int64, error) { 92 func (o *orm) Insert(md interface{}) (int64, error) {
79 mi, ind := o.getMiInd(md, true) 93 mi, ind := o.getMiInd(md, true)
...@@ -425,6 +439,12 @@ func (o *orm) Driver() Driver { ...@@ -425,6 +439,12 @@ func (o *orm) Driver() Driver {
425 return driver(o.alias.Name) 439 return driver(o.alias.Name)
426 } 440 }
427 441
442 func (o *orm) GetDB() dbQuerier {
443 panic(ErrNotImplement)
444 // not enough
445 return o.db
446 }
447
428 // create new orm 448 // create new orm
429 func NewOrm() Ormer { 449 func NewOrm() Ormer {
430 BootStrap() // execute only once 450 BootStrap() // execute only once
...@@ -436,3 +456,30 @@ func NewOrm() Ormer { ...@@ -436,3 +456,30 @@ func NewOrm() Ormer {
436 } 456 }
437 return o 457 return o
438 } 458 }
459
460 // create a new ormer object with specify *sql.DB for query
461 func NewOrmWithDB(driverName, aliasName string, db *sql.DB) (Ormer, error) {
462 var al *alias
463
464 if dr, ok := drivers[driverName]; ok {
465 al = new(alias)
466 al.DbBaser = dbBasers[dr]
467 al.Driver = dr
468 } else {
469 return nil, fmt.Errorf("driver name `%s` have not registered", driverName)
470 }
471
472 al.Name = aliasName
473 al.DriverName = driverName
474
475 o := new(orm)
476 o.alias = al
477
478 if Debug {
479 o.db = newDbQueryLog(o.alias, db)
480 } else {
481 o.db = db
482 }
483
484 return o, nil
485 }
......
...@@ -197,6 +197,36 @@ func (o *querySet) ValuesFlat(result *ParamsList, expr string) (int64, error) { ...@@ -197,6 +197,36 @@ func (o *querySet) ValuesFlat(result *ParamsList, expr string) (int64, error) {
197 return o.orm.alias.DbBaser.ReadValues(o.orm.db, o, o.mi, o.cond, []string{expr}, result, o.orm.alias.TZ) 197 return o.orm.alias.DbBaser.ReadValues(o.orm.db, o, o.mi, o.cond, []string{expr}, result, o.orm.alias.TZ)
198 } 198 }
199 199
200 // query all rows into map[string]interface with specify key and value column name.
201 // keyCol = "name", valueCol = "value"
202 // table data
203 // name | value
204 // total | 100
205 // found | 200
206 // to map[string]interface{}{
207 // "total": 100,
208 // "found": 200,
209 // }
210 func (o *querySet) RowsToMap(result *Params, keyCol, valueCol string) (int64, error) {
211 panic(ErrNotImplement)
212 return o.orm.alias.DbBaser.RowsTo(o.orm.db, o, o.mi, o.cond, result, keyCol, valueCol, o.orm.alias.TZ)
213 }
214
215 // query all rows into struct with specify key and value column name.
216 // keyCol = "name", valueCol = "value"
217 // table data
218 // name | value
219 // total | 100
220 // found | 200
221 // to struct {
222 // Total int
223 // Found int
224 // }
225 func (o *querySet) RowsToStruct(ptrStruct interface{}, keyCol, valueCol string) (int64, error) {
226 panic(ErrNotImplement)
227 return o.orm.alias.DbBaser.RowsTo(o.orm.db, o, o.mi, o.cond, ptrStruct, keyCol, valueCol, o.orm.alias.TZ)
228 }
229
200 // create new QuerySeter. 230 // create new QuerySeter.
201 func newQuerySet(orm *orm, mi *modelInfo) QuerySeter { 231 func newQuerySet(orm *orm, mi *modelInfo) QuerySeter {
202 o := new(querySet) 232 o := new(querySet)
......
...@@ -518,7 +518,7 @@ func (o *rawSet) QueryRows(containers ...interface{}) (int64, error) { ...@@ -518,7 +518,7 @@ func (o *rawSet) QueryRows(containers ...interface{}) (int64, error) {
518 return cnt, nil 518 return cnt, nil
519 } 519 }
520 520
521 func (o *rawSet) readValues(container interface{}) (int64, error) { 521 func (o *rawSet) readValues(container interface{}, needCols []string) (int64, error) {
522 var ( 522 var (
523 maps []Params 523 maps []Params
524 lists []ParamsList 524 lists []ParamsList
...@@ -552,20 +552,38 @@ func (o *rawSet) readValues(container interface{}) (int64, error) { ...@@ -552,20 +552,38 @@ func (o *rawSet) readValues(container interface{}) (int64, error) {
552 defer rs.Close() 552 defer rs.Close()
553 553
554 var ( 554 var (
555 refs []interface{} 555 refs []interface{}
556 cnt int64 556 cnt int64
557 cols []string 557 cols []string
558 indexs []int
558 ) 559 )
560
559 for rs.Next() { 561 for rs.Next() {
560 if cnt == 0 { 562 if cnt == 0 {
561 if columns, err := rs.Columns(); err != nil { 563 if columns, err := rs.Columns(); err != nil {
562 return 0, err 564 return 0, err
563 } else { 565 } else {
566 if len(needCols) > 0 {
567 indexs = make([]int, 0, len(needCols))
568 } else {
569 indexs = make([]int, 0, len(columns))
570 }
571
564 cols = columns 572 cols = columns
565 refs = make([]interface{}, len(cols)) 573 refs = make([]interface{}, len(cols))
566 for i, _ := range refs { 574 for i, _ := range refs {
567 var ref sql.NullString 575 var ref sql.NullString
568 refs[i] = &ref 576 refs[i] = &ref
577
578 if len(needCols) > 0 {
579 for _, c := range needCols {
580 if c == cols[i] {
581 indexs = append(indexs, i)
582 }
583 }
584 } else {
585 indexs = append(indexs, i)
586 }
569 } 587 }
570 } 588 }
571 } 589 }
...@@ -577,7 +595,8 @@ func (o *rawSet) readValues(container interface{}) (int64, error) { ...@@ -577,7 +595,8 @@ func (o *rawSet) readValues(container interface{}) (int64, error) {
577 switch typ { 595 switch typ {
578 case 1: 596 case 1:
579 params := make(Params, len(cols)) 597 params := make(Params, len(cols))
580 for i, ref := range refs { 598 for _, i := range indexs {
599 ref := refs[i]
581 value := reflect.Indirect(reflect.ValueOf(ref)).Interface().(sql.NullString) 600 value := reflect.Indirect(reflect.ValueOf(ref)).Interface().(sql.NullString)
582 if value.Valid { 601 if value.Valid {
583 params[cols[i]] = value.String 602 params[cols[i]] = value.String
...@@ -588,7 +607,8 @@ func (o *rawSet) readValues(container interface{}) (int64, error) { ...@@ -588,7 +607,8 @@ func (o *rawSet) readValues(container interface{}) (int64, error) {
588 maps = append(maps, params) 607 maps = append(maps, params)
589 case 2: 608 case 2:
590 params := make(ParamsList, 0, len(cols)) 609 params := make(ParamsList, 0, len(cols))
591 for _, ref := range refs { 610 for _, i := range indexs {
611 ref := refs[i]
592 value := reflect.Indirect(reflect.ValueOf(ref)).Interface().(sql.NullString) 612 value := reflect.Indirect(reflect.ValueOf(ref)).Interface().(sql.NullString)
593 if value.Valid { 613 if value.Valid {
594 params = append(params, value.String) 614 params = append(params, value.String)
...@@ -598,7 +618,8 @@ func (o *rawSet) readValues(container interface{}) (int64, error) { ...@@ -598,7 +618,8 @@ func (o *rawSet) readValues(container interface{}) (int64, error) {
598 } 618 }
599 lists = append(lists, params) 619 lists = append(lists, params)
600 case 3: 620 case 3:
601 for _, ref := range refs { 621 for _, i := range indexs {
622 ref := refs[i]
602 value := reflect.Indirect(reflect.ValueOf(ref)).Interface().(sql.NullString) 623 value := reflect.Indirect(reflect.ValueOf(ref)).Interface().(sql.NullString)
603 if value.Valid { 624 if value.Valid {
604 list = append(list, value.String) 625 list = append(list, value.String)
...@@ -623,19 +644,163 @@ func (o *rawSet) readValues(container interface{}) (int64, error) { ...@@ -623,19 +644,163 @@ func (o *rawSet) readValues(container interface{}) (int64, error) {
623 return cnt, nil 644 return cnt, nil
624 } 645 }
625 646
647 func (o *rawSet) queryRowsTo(container interface{}, keyCol, valueCol string) (int64, error) {
648 var (
649 maps Params
650 ind *reflect.Value
651 )
652
653 typ := 0
654 switch container.(type) {
655 case *Params:
656 typ = 1
657 default:
658 typ = 2
659 vl := reflect.ValueOf(container)
660 id := reflect.Indirect(vl)
661 if vl.Kind() != reflect.Ptr || id.Kind() != reflect.Struct {
662 panic(fmt.Errorf("<RawSeter> RowsTo unsupport type `%T` need ptr struct", container))
663 }
664
665 ind = &id
666 }
667
668 query := o.query
669 o.orm.alias.DbBaser.ReplaceMarks(&query)
670
671 args := getFlatParams(nil, o.args, o.orm.alias.TZ)
672
673 var rs *sql.Rows
674 if r, err := o.orm.db.Query(query, args...); err != nil {
675 return 0, err
676 } else {
677 rs = r
678 }
679
680 defer rs.Close()
681
682 var (
683 refs []interface{}
684 cnt int64
685 cols []string
686 )
687
688 var (
689 keyIndex = -1
690 valueIndex = -1
691 )
692
693 for rs.Next() {
694 if cnt == 0 {
695 if columns, err := rs.Columns(); err != nil {
696 return 0, err
697 } else {
698 cols = columns
699 refs = make([]interface{}, len(cols))
700 for i, _ := range refs {
701 if keyCol == cols[i] {
702 keyIndex = i
703 }
704
705 if typ == 1 || keyIndex == i {
706 var ref sql.NullString
707 refs[i] = &ref
708 } else {
709 var ref interface{}
710 refs[i] = &ref
711 }
712
713 if valueCol == cols[i] {
714 valueIndex = i
715 }
716 }
717
718 if keyIndex == -1 || valueIndex == -1 {
719 panic(fmt.Errorf("<RawSeter> RowsTo unknown key, value column name `%s: %s`", keyCol, valueCol))
720 }
721 }
722 }
723
724 if err := rs.Scan(refs...); err != nil {
725 return 0, err
726 }
727
728 if cnt == 0 {
729 switch typ {
730 case 1:
731 maps = make(Params)
732 }
733 }
734
735 key := reflect.Indirect(reflect.ValueOf(refs[keyIndex])).Interface().(sql.NullString).String
736
737 switch typ {
738 case 1:
739 value := reflect.Indirect(reflect.ValueOf(refs[valueIndex])).Interface().(sql.NullString)
740 if value.Valid {
741 maps[key] = value.String
742 } else {
743 maps[key] = nil
744 }
745
746 default:
747 if id := ind.FieldByName(camelString(key)); id.IsValid() {
748 o.setFieldValue(id, reflect.ValueOf(refs[valueIndex]).Elem().Interface())
749 }
750 }
751
752 cnt++
753 }
754
755 if typ == 1 {
756 v, _ := container.(*Params)
757 *v = maps
758 }
759
760 return cnt, nil
761 }
762
626 // query data to []map[string]interface 763 // query data to []map[string]interface
627 func (o *rawSet) Values(container *[]Params) (int64, error) { 764 func (o *rawSet) Values(container *[]Params, cols ...string) (int64, error) {
628 return o.readValues(container) 765 return o.readValues(container, cols)
629 } 766 }
630 767
631 // query data to [][]interface 768 // query data to [][]interface
632 func (o *rawSet) ValuesList(container *[]ParamsList) (int64, error) { 769 func (o *rawSet) ValuesList(container *[]ParamsList, cols ...string) (int64, error) {
633 return o.readValues(container) 770 return o.readValues(container, cols)
634 } 771 }
635 772
636 // query data to []interface 773 // query data to []interface
637 func (o *rawSet) ValuesFlat(container *ParamsList) (int64, error) { 774 func (o *rawSet) ValuesFlat(container *ParamsList, cols ...string) (int64, error) {
638 return o.readValues(container) 775 return o.readValues(container, cols)
776 }
777
778 // query all rows into map[string]interface with specify key and value column name.
779 // keyCol = "name", valueCol = "value"
780 // table data
781 // name | value
782 // total | 100
783 // found | 200
784 // to map[string]interface{}{
785 // "total": 100,
786 // "found": 200,
787 // }
788 func (o *rawSet) RowsToMap(result *Params, keyCol, valueCol string) (int64, error) {
789 return o.queryRowsTo(result, keyCol, valueCol)
790 }
791
792 // query all rows into struct with specify key and value column name.
793 // keyCol = "name", valueCol = "value"
794 // table data
795 // name | value
796 // total | 100
797 // found | 200
798 // to struct {
799 // Total int
800 // Found int
801 // }
802 func (o *rawSet) RowsToStruct(ptrStruct interface{}, keyCol, valueCol string) (int64, error) {
803 return o.queryRowsTo(ptrStruct, keyCol, valueCol)
639 } 804 }
640 805
641 // return prepared raw statement for used in times. 806 // return prepared raw statement for used in times.
......
...@@ -1642,3 +1642,41 @@ func TestTransaction(t *testing.T) { ...@@ -1642,3 +1642,41 @@ func TestTransaction(t *testing.T) {
1642 throwFail(t, AssertIs(num, 1)) 1642 throwFail(t, AssertIs(num, 1))
1643 1643
1644 } 1644 }
1645
1646 func TestReadOrCreate(t *testing.T) {
1647 u := &User{
1648 UserName: "Kyle",
1649 Email: "kylemcc@gmail.com",
1650 Password: "other_pass",
1651 Status: 7,
1652 IsStaff: false,
1653 IsActive: true,
1654 }
1655
1656 created, pk, err := dORM.ReadOrCreate(u, "UserName")
1657 throwFail(t, err)
1658 throwFail(t, AssertIs(created, true))
1659 throwFail(t, AssertIs(u.UserName, "Kyle"))
1660 throwFail(t, AssertIs(u.Email, "kylemcc@gmail.com"))
1661 throwFail(t, AssertIs(u.Password, "other_pass"))
1662 throwFail(t, AssertIs(u.Status, 7))
1663 throwFail(t, AssertIs(u.IsStaff, false))
1664 throwFail(t, AssertIs(u.IsActive, true))
1665 throwFail(t, AssertIs(u.Created.In(DefaultTimeLoc), u.Created.In(DefaultTimeLoc), test_Date))
1666 throwFail(t, AssertIs(u.Updated.In(DefaultTimeLoc), u.Updated.In(DefaultTimeLoc), test_DateTime))
1667
1668 nu := &User{UserName: u.UserName, Email: "someotheremail@gmail.com"}
1669 created, pk, err = dORM.ReadOrCreate(nu, "UserName")
1670 throwFail(t, err)
1671 throwFail(t, AssertIs(created, false))
1672 throwFail(t, AssertIs(nu.Id, u.Id))
1673 throwFail(t, AssertIs(pk, u.Id))
1674 throwFail(t, AssertIs(nu.UserName, u.UserName))
1675 throwFail(t, AssertIs(nu.Email, u.Email)) // should contain the value in the table, not the one specified above
1676 throwFail(t, AssertIs(nu.Password, u.Password))
1677 throwFail(t, AssertIs(nu.Status, u.Status))
1678 throwFail(t, AssertIs(nu.IsStaff, u.IsStaff))
1679 throwFail(t, AssertIs(nu.IsActive, u.IsActive))
1680
1681 dORM.Delete(u)
1682 }
......
...@@ -23,6 +23,7 @@ type Fielder interface { ...@@ -23,6 +23,7 @@ type Fielder interface {
23 // orm struct 23 // orm struct
24 type Ormer interface { 24 type Ormer interface {
25 Read(interface{}, ...string) error 25 Read(interface{}, ...string) error
26 ReadOrCreate(interface{}, string, ...string) (bool, int64, error)
26 Insert(interface{}) (int64, error) 27 Insert(interface{}) (int64, error)
27 InsertMulti(int, interface{}) (int64, error) 28 InsertMulti(int, interface{}) (int64, error)
28 Update(interface{}, ...string) (int64, error) 29 Update(interface{}, ...string) (int64, error)
...@@ -36,6 +37,7 @@ type Ormer interface { ...@@ -36,6 +37,7 @@ type Ormer interface {
36 Rollback() error 37 Rollback() error
37 Raw(string, ...interface{}) RawSeter 38 Raw(string, ...interface{}) RawSeter
38 Driver() Driver 39 Driver() Driver
40 GetDB() dbQuerier
39 } 41 }
40 42
41 // insert prepared statement 43 // insert prepared statement
...@@ -63,6 +65,8 @@ type QuerySeter interface { ...@@ -63,6 +65,8 @@ type QuerySeter interface {
63 Values(*[]Params, ...string) (int64, error) 65 Values(*[]Params, ...string) (int64, error)
64 ValuesList(*[]ParamsList, ...string) (int64, error) 66 ValuesList(*[]ParamsList, ...string) (int64, error)
65 ValuesFlat(*ParamsList, string) (int64, error) 67 ValuesFlat(*ParamsList, string) (int64, error)
68 RowsToMap(*Params, string, string) (int64, error)
69 RowsToStruct(interface{}, string, string) (int64, error)
66 } 70 }
67 71
68 // model to model query struct 72 // model to model query struct
...@@ -86,9 +90,11 @@ type RawSeter interface { ...@@ -86,9 +90,11 @@ type RawSeter interface {
86 QueryRow(...interface{}) error 90 QueryRow(...interface{}) error
87 QueryRows(...interface{}) (int64, error) 91 QueryRows(...interface{}) (int64, error)
88 SetArgs(...interface{}) RawSeter 92 SetArgs(...interface{}) RawSeter
89 Values(*[]Params) (int64, error) 93 Values(*[]Params, ...string) (int64, error)
90 ValuesList(*[]ParamsList) (int64, error) 94 ValuesList(*[]ParamsList, ...string) (int64, error)
91 ValuesFlat(*ParamsList) (int64, error) 95 ValuesFlat(*ParamsList, ...string) (int64, error)
96 RowsToMap(*Params, string, string) (int64, error)
97 RowsToStruct(interface{}, string, string) (int64, error)
92 Prepare() (RawPreparer, error) 98 Prepare() (RawPreparer, error)
93 } 99 }
94 100
...@@ -108,6 +114,14 @@ type dbQuerier interface { ...@@ -108,6 +114,14 @@ type dbQuerier interface {
108 QueryRow(query string, args ...interface{}) *sql.Row 114 QueryRow(query string, args ...interface{}) *sql.Row
109 } 115 }
110 116
117 // type DB interface {
118 // Begin() (*sql.Tx, error)
119 // Prepare(query string) (stmtQuerier, error)
120 // Exec(query string, args ...interface{}) (sql.Result, error)
121 // Query(query string, args ...interface{}) (*sql.Rows, error)
122 // QueryRow(query string, args ...interface{}) *sql.Row
123 // }
124
111 // transaction beginner 125 // transaction beginner
112 type txer interface { 126 type txer interface {
113 Begin() (*sql.Tx, error) 127 Begin() (*sql.Tx, error)
...@@ -138,6 +152,7 @@ type dbBaser interface { ...@@ -138,6 +152,7 @@ type dbBaser interface {
138 GenerateOperatorLeftCol(*fieldInfo, string, *string) 152 GenerateOperatorLeftCol(*fieldInfo, string, *string)
139 PrepareInsert(dbQuerier, *modelInfo) (stmtQuerier, string, error) 153 PrepareInsert(dbQuerier, *modelInfo) (stmtQuerier, string, error)
140 ReadValues(dbQuerier, *querySet, *modelInfo, *Condition, []string, interface{}, *time.Location) (int64, error) 154 ReadValues(dbQuerier, *querySet, *modelInfo, *Condition, []string, interface{}, *time.Location) (int64, error)
155 RowsTo(dbQuerier, *querySet, *modelInfo, *Condition, interface{}, string, string, *time.Location) (int64, error)
141 MaxLimit() uint64 156 MaxLimit() uint64
142 TableQuote() string 157 TableQuote() string
143 ReplaceMarks(*string) 158 ReplaceMarks(*string)
......
...@@ -11,12 +11,15 @@ import ( ...@@ -11,12 +11,15 @@ import (
11 11
12 var cookiepder = &CookieProvider{} 12 var cookiepder = &CookieProvider{}
13 13
14 // Cookie SessionStore
14 type CookieSessionStore struct { 15 type CookieSessionStore struct {
15 sid string 16 sid string
16 values map[interface{}]interface{} //session data 17 values map[interface{}]interface{} // session data
17 lock sync.RWMutex 18 lock sync.RWMutex
18 } 19 }
19 20
21 // Set value to cookie session.
22 // the value are encoded as gob with hash block string.
20 func (st *CookieSessionStore) Set(key, value interface{}) error { 23 func (st *CookieSessionStore) Set(key, value interface{}) error {
21 st.lock.Lock() 24 st.lock.Lock()
22 defer st.lock.Unlock() 25 defer st.lock.Unlock()
...@@ -24,6 +27,7 @@ func (st *CookieSessionStore) Set(key, value interface{}) error { ...@@ -24,6 +27,7 @@ func (st *CookieSessionStore) Set(key, value interface{}) error {
24 return nil 27 return nil
25 } 28 }
26 29
30 // Get value from cookie session
27 func (st *CookieSessionStore) Get(key interface{}) interface{} { 31 func (st *CookieSessionStore) Get(key interface{}) interface{} {
28 st.lock.RLock() 32 st.lock.RLock()
29 defer st.lock.RUnlock() 33 defer st.lock.RUnlock()
...@@ -35,6 +39,7 @@ func (st *CookieSessionStore) Get(key interface{}) interface{} { ...@@ -35,6 +39,7 @@ func (st *CookieSessionStore) Get(key interface{}) interface{} {
35 return nil 39 return nil
36 } 40 }
37 41
42 // Delete value in cookie session
38 func (st *CookieSessionStore) Delete(key interface{}) error { 43 func (st *CookieSessionStore) Delete(key interface{}) error {
39 st.lock.Lock() 44 st.lock.Lock()
40 defer st.lock.Unlock() 45 defer st.lock.Unlock()
...@@ -42,6 +47,7 @@ func (st *CookieSessionStore) Delete(key interface{}) error { ...@@ -42,6 +47,7 @@ func (st *CookieSessionStore) Delete(key interface{}) error {
42 return nil 47 return nil
43 } 48 }
44 49
50 // Clean all values in cookie session
45 func (st *CookieSessionStore) Flush() error { 51 func (st *CookieSessionStore) Flush() error {
46 st.lock.Lock() 52 st.lock.Lock()
47 defer st.lock.Unlock() 53 defer st.lock.Unlock()
...@@ -49,10 +55,12 @@ func (st *CookieSessionStore) Flush() error { ...@@ -49,10 +55,12 @@ func (st *CookieSessionStore) Flush() error {
49 return nil 55 return nil
50 } 56 }
51 57
58 // Return id of this cookie session
52 func (st *CookieSessionStore) SessionID() string { 59 func (st *CookieSessionStore) SessionID() string {
53 return st.sid 60 return st.sid
54 } 61 }
55 62
63 // Write cookie session to http response cookie
56 func (st *CookieSessionStore) SessionRelease(w http.ResponseWriter) { 64 func (st *CookieSessionStore) SessionRelease(w http.ResponseWriter) {
57 str, err := encodeCookie(cookiepder.block, 65 str, err := encodeCookie(cookiepder.block,
58 cookiepder.config.SecurityKey, 66 cookiepder.config.SecurityKey,
...@@ -79,12 +87,21 @@ type cookieConfig struct { ...@@ -79,12 +87,21 @@ type cookieConfig struct {
79 Maxage int `json:"maxage"` 87 Maxage int `json:"maxage"`
80 } 88 }
81 89
90 // Cookie session provider
82 type CookieProvider struct { 91 type CookieProvider struct {
83 maxlifetime int64 92 maxlifetime int64
84 config *cookieConfig 93 config *cookieConfig
85 block cipher.Block 94 block cipher.Block
86 } 95 }
87 96
97 // Init cookie session provider with max lifetime and config json.
98 // maxlifetime is ignored.
99 // json config:
100 // securityKey - hash string
101 // blockKey - gob encode hash string. it's saved as aes crypto.
102 // securityName - recognized name in encoded cookie string
103 // cookieName - cookie name
104 // maxage - cookie max life time.
88 func (pder *CookieProvider) SessionInit(maxlifetime int64, config string) error { 105 func (pder *CookieProvider) SessionInit(maxlifetime int64, config string) error {
89 pder.config = &cookieConfig{} 106 pder.config = &cookieConfig{}
90 err := json.Unmarshal([]byte(config), pder.config) 107 err := json.Unmarshal([]byte(config), pder.config)
...@@ -104,6 +121,8 @@ func (pder *CookieProvider) SessionInit(maxlifetime int64, config string) error ...@@ -104,6 +121,8 @@ func (pder *CookieProvider) SessionInit(maxlifetime int64, config string) error
104 return nil 121 return nil
105 } 122 }
106 123
124 // Get SessionStore in cooke.
125 // decode cooke string to map and put into SessionStore with sid.
107 func (pder *CookieProvider) SessionRead(sid string) (SessionStore, error) { 126 func (pder *CookieProvider) SessionRead(sid string) (SessionStore, error) {
108 maps, _ := decodeCookie(pder.block, 127 maps, _ := decodeCookie(pder.block,
109 pder.config.SecurityKey, 128 pder.config.SecurityKey,
...@@ -116,26 +135,32 @@ func (pder *CookieProvider) SessionRead(sid string) (SessionStore, error) { ...@@ -116,26 +135,32 @@ func (pder *CookieProvider) SessionRead(sid string) (SessionStore, error) {
116 return rs, nil 135 return rs, nil
117 } 136 }
118 137
138 // Cookie session is always existed
119 func (pder *CookieProvider) SessionExist(sid string) bool { 139 func (pder *CookieProvider) SessionExist(sid string) bool {
120 return true 140 return true
121 } 141 }
122 142
143 // Implement method, no used.
123 func (pder *CookieProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) { 144 func (pder *CookieProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) {
124 return nil, nil 145 return nil, nil
125 } 146 }
126 147
148 // Implement method, no used.
127 func (pder *CookieProvider) SessionDestroy(sid string) error { 149 func (pder *CookieProvider) SessionDestroy(sid string) error {
128 return nil 150 return nil
129 } 151 }
130 152
153 // Implement method, no used.
131 func (pder *CookieProvider) SessionGC() { 154 func (pder *CookieProvider) SessionGC() {
132 return 155 return
133 } 156 }
134 157
158 // Implement method, return 0.
135 func (pder *CookieProvider) SessionAll() int { 159 func (pder *CookieProvider) SessionAll() int {
136 return 0 160 return 0
137 } 161 }
138 162
163 // Implement method, no used.
139 func (pder *CookieProvider) SessionUpdate(sid string) error { 164 func (pder *CookieProvider) SessionUpdate(sid string) error {
140 return nil 165 return nil
141 } 166 }
......
...@@ -18,6 +18,7 @@ var ( ...@@ -18,6 +18,7 @@ var (
18 gcmaxlifetime int64 18 gcmaxlifetime int64
19 ) 19 )
20 20
21 // File session store
21 type FileSessionStore struct { 22 type FileSessionStore struct {
22 f *os.File 23 f *os.File
23 sid string 24 sid string
...@@ -25,6 +26,7 @@ type FileSessionStore struct { ...@@ -25,6 +26,7 @@ type FileSessionStore struct {
25 values map[interface{}]interface{} 26 values map[interface{}]interface{}
26 } 27 }
27 28
29 // Set value to file session
28 func (fs *FileSessionStore) Set(key, value interface{}) error { 30 func (fs *FileSessionStore) Set(key, value interface{}) error {
29 fs.lock.Lock() 31 fs.lock.Lock()
30 defer fs.lock.Unlock() 32 defer fs.lock.Unlock()
...@@ -32,6 +34,7 @@ func (fs *FileSessionStore) Set(key, value interface{}) error { ...@@ -32,6 +34,7 @@ func (fs *FileSessionStore) Set(key, value interface{}) error {
32 return nil 34 return nil
33 } 35 }
34 36
37 // Get value from file session
35 func (fs *FileSessionStore) Get(key interface{}) interface{} { 38 func (fs *FileSessionStore) Get(key interface{}) interface{} {
36 fs.lock.RLock() 39 fs.lock.RLock()
37 defer fs.lock.RUnlock() 40 defer fs.lock.RUnlock()
...@@ -43,6 +46,7 @@ func (fs *FileSessionStore) Get(key interface{}) interface{} { ...@@ -43,6 +46,7 @@ func (fs *FileSessionStore) Get(key interface{}) interface{} {
43 return nil 46 return nil
44 } 47 }
45 48
49 // Delete value in file session by given key
46 func (fs *FileSessionStore) Delete(key interface{}) error { 50 func (fs *FileSessionStore) Delete(key interface{}) error {
47 fs.lock.Lock() 51 fs.lock.Lock()
48 defer fs.lock.Unlock() 52 defer fs.lock.Unlock()
...@@ -50,6 +54,7 @@ func (fs *FileSessionStore) Delete(key interface{}) error { ...@@ -50,6 +54,7 @@ func (fs *FileSessionStore) Delete(key interface{}) error {
50 return nil 54 return nil
51 } 55 }
52 56
57 // Clean all values in file session
53 func (fs *FileSessionStore) Flush() error { 58 func (fs *FileSessionStore) Flush() error {
54 fs.lock.Lock() 59 fs.lock.Lock()
55 defer fs.lock.Unlock() 60 defer fs.lock.Unlock()
...@@ -57,10 +62,12 @@ func (fs *FileSessionStore) Flush() error { ...@@ -57,10 +62,12 @@ func (fs *FileSessionStore) Flush() error {
57 return nil 62 return nil
58 } 63 }
59 64
65 // Get file session store id
60 func (fs *FileSessionStore) SessionID() string { 66 func (fs *FileSessionStore) SessionID() string {
61 return fs.sid 67 return fs.sid
62 } 68 }
63 69
70 // Write file session to local file with Gob string
64 func (fs *FileSessionStore) SessionRelease(w http.ResponseWriter) { 71 func (fs *FileSessionStore) SessionRelease(w http.ResponseWriter) {
65 defer fs.f.Close() 72 defer fs.f.Close()
66 b, err := encodeGob(fs.values) 73 b, err := encodeGob(fs.values)
...@@ -72,17 +79,23 @@ func (fs *FileSessionStore) SessionRelease(w http.ResponseWriter) { ...@@ -72,17 +79,23 @@ func (fs *FileSessionStore) SessionRelease(w http.ResponseWriter) {
72 fs.f.Write(b) 79 fs.f.Write(b)
73 } 80 }
74 81
82 // File session provider
75 type FileProvider struct { 83 type FileProvider struct {
76 maxlifetime int64 84 maxlifetime int64
77 savePath string 85 savePath string
78 } 86 }
79 87
88 // Init file session provider.
89 // savePath sets the session files path.
80 func (fp *FileProvider) SessionInit(maxlifetime int64, savePath string) error { 90 func (fp *FileProvider) SessionInit(maxlifetime int64, savePath string) error {
81 fp.maxlifetime = maxlifetime 91 fp.maxlifetime = maxlifetime
82 fp.savePath = savePath 92 fp.savePath = savePath
83 return nil 93 return nil
84 } 94 }
85 95
96 // Read file session by sid.
97 // if file is not exist, create it.
98 // the file path is generated from sid string.
86 func (fp *FileProvider) SessionRead(sid string) (SessionStore, error) { 99 func (fp *FileProvider) SessionRead(sid string) (SessionStore, error) {
87 err := os.MkdirAll(path.Join(fp.savePath, string(sid[0]), string(sid[1])), 0777) 100 err := os.MkdirAll(path.Join(fp.savePath, string(sid[0]), string(sid[1])), 0777)
88 if err != nil { 101 if err != nil {
...@@ -117,6 +130,8 @@ func (fp *FileProvider) SessionRead(sid string) (SessionStore, error) { ...@@ -117,6 +130,8 @@ func (fp *FileProvider) SessionRead(sid string) (SessionStore, error) {
117 return ss, nil 130 return ss, nil
118 } 131 }
119 132
133 // Check file session exist.
134 // it checkes the file named from sid exist or not.
120 func (fp *FileProvider) SessionExist(sid string) bool { 135 func (fp *FileProvider) SessionExist(sid string) bool {
121 _, err := os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid)) 136 _, err := os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
122 if err == nil { 137 if err == nil {
...@@ -126,16 +141,20 @@ func (fp *FileProvider) SessionExist(sid string) bool { ...@@ -126,16 +141,20 @@ func (fp *FileProvider) SessionExist(sid string) bool {
126 } 141 }
127 } 142 }
128 143
144 // Remove all files in this save path
129 func (fp *FileProvider) SessionDestroy(sid string) error { 145 func (fp *FileProvider) SessionDestroy(sid string) error {
130 os.Remove(path.Join(fp.savePath)) 146 os.Remove(path.Join(fp.savePath))
131 return nil 147 return nil
132 } 148 }
133 149
150 // Recycle files in save path
134 func (fp *FileProvider) SessionGC() { 151 func (fp *FileProvider) SessionGC() {
135 gcmaxlifetime = fp.maxlifetime 152 gcmaxlifetime = fp.maxlifetime
136 filepath.Walk(fp.savePath, gcpath) 153 filepath.Walk(fp.savePath, gcpath)
137 } 154 }
138 155
156 // Get active file session number.
157 // it walks save path to count files.
139 func (fp *FileProvider) SessionAll() int { 158 func (fp *FileProvider) SessionAll() int {
140 a := &activeSession{} 159 a := &activeSession{}
141 err := filepath.Walk(fp.savePath, func(path string, f os.FileInfo, err error) error { 160 err := filepath.Walk(fp.savePath, func(path string, f os.FileInfo, err error) error {
...@@ -148,6 +167,8 @@ func (fp *FileProvider) SessionAll() int { ...@@ -148,6 +167,8 @@ func (fp *FileProvider) SessionAll() int {
148 return a.total 167 return a.total
149 } 168 }
150 169
170 // Generate new sid for file session.
171 // it delete old file and create new file named from new sid.
151 func (fp *FileProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) { 172 func (fp *FileProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) {
152 err := os.MkdirAll(path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1])), 0777) 173 err := os.MkdirAll(path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1])), 0777)
153 if err != nil { 174 if err != nil {
...@@ -197,6 +218,7 @@ func (fp *FileProvider) SessionRegenerate(oldsid, sid string) (SessionStore, err ...@@ -197,6 +218,7 @@ func (fp *FileProvider) SessionRegenerate(oldsid, sid string) (SessionStore, err
197 return ss, nil 218 return ss, nil
198 } 219 }
199 220
221 // remove file in save path if expired
200 func gcpath(path string, info os.FileInfo, err error) error { 222 func gcpath(path string, info os.FileInfo, err error) error {
201 if err != nil { 223 if err != nil {
202 return err 224 return err
......
...@@ -9,6 +9,8 @@ import ( ...@@ -9,6 +9,8 @@ import (
9 9
10 var mempder = &MemProvider{list: list.New(), sessions: make(map[string]*list.Element)} 10 var mempder = &MemProvider{list: list.New(), sessions: make(map[string]*list.Element)}
11 11
12 // memory session store.
13 // it saved sessions in a map in memory.
12 type MemSessionStore struct { 14 type MemSessionStore struct {
13 sid string //session id 15 sid string //session id
14 timeAccessed time.Time //last access time 16 timeAccessed time.Time //last access time
...@@ -16,6 +18,7 @@ type MemSessionStore struct { ...@@ -16,6 +18,7 @@ type MemSessionStore struct {
16 lock sync.RWMutex 18 lock sync.RWMutex
17 } 19 }
18 20
21 // set value to memory session
19 func (st *MemSessionStore) Set(key, value interface{}) error { 22 func (st *MemSessionStore) Set(key, value interface{}) error {
20 st.lock.Lock() 23 st.lock.Lock()
21 defer st.lock.Unlock() 24 defer st.lock.Unlock()
...@@ -23,6 +26,7 @@ func (st *MemSessionStore) Set(key, value interface{}) error { ...@@ -23,6 +26,7 @@ func (st *MemSessionStore) Set(key, value interface{}) error {
23 return nil 26 return nil
24 } 27 }
25 28
29 // get value from memory session by key
26 func (st *MemSessionStore) Get(key interface{}) interface{} { 30 func (st *MemSessionStore) Get(key interface{}) interface{} {
27 st.lock.RLock() 31 st.lock.RLock()
28 defer st.lock.RUnlock() 32 defer st.lock.RUnlock()
...@@ -34,6 +38,7 @@ func (st *MemSessionStore) Get(key interface{}) interface{} { ...@@ -34,6 +38,7 @@ func (st *MemSessionStore) Get(key interface{}) interface{} {
34 return nil 38 return nil
35 } 39 }
36 40
41 // delete in memory session by key
37 func (st *MemSessionStore) Delete(key interface{}) error { 42 func (st *MemSessionStore) Delete(key interface{}) error {
38 st.lock.Lock() 43 st.lock.Lock()
39 defer st.lock.Unlock() 44 defer st.lock.Unlock()
...@@ -41,6 +46,7 @@ func (st *MemSessionStore) Delete(key interface{}) error { ...@@ -41,6 +46,7 @@ func (st *MemSessionStore) Delete(key interface{}) error {
41 return nil 46 return nil
42 } 47 }
43 48
49 // clear all values in memory session
44 func (st *MemSessionStore) Flush() error { 50 func (st *MemSessionStore) Flush() error {
45 st.lock.Lock() 51 st.lock.Lock()
46 defer st.lock.Unlock() 52 defer st.lock.Unlock()
...@@ -48,27 +54,31 @@ func (st *MemSessionStore) Flush() error { ...@@ -48,27 +54,31 @@ func (st *MemSessionStore) Flush() error {
48 return nil 54 return nil
49 } 55 }
50 56
57 // get this id of memory session store
51 func (st *MemSessionStore) SessionID() string { 58 func (st *MemSessionStore) SessionID() string {
52 return st.sid 59 return st.sid
53 } 60 }
54 61
62 // Implement method, no used.
55 func (st *MemSessionStore) SessionRelease(w http.ResponseWriter) { 63 func (st *MemSessionStore) SessionRelease(w http.ResponseWriter) {
56 } 64 }
57 65
58 type MemProvider struct { 66 type MemProvider struct {
59 lock sync.RWMutex //用来锁 67 lock sync.RWMutex // locker
60 sessions map[string]*list.Element //用来存储在内存 68 sessions map[string]*list.Element // map in memory
61 list *list.List //用来做gc 69 list *list.List // for gc
62 maxlifetime int64 70 maxlifetime int64
63 savePath string 71 savePath string
64 } 72 }
65 73
74 // init memory session
66 func (pder *MemProvider) SessionInit(maxlifetime int64, savePath string) error { 75 func (pder *MemProvider) SessionInit(maxlifetime int64, savePath string) error {
67 pder.maxlifetime = maxlifetime 76 pder.maxlifetime = maxlifetime
68 pder.savePath = savePath 77 pder.savePath = savePath
69 return nil 78 return nil
70 } 79 }
71 80
81 // get memory session store by sid
72 func (pder *MemProvider) SessionRead(sid string) (SessionStore, error) { 82 func (pder *MemProvider) SessionRead(sid string) (SessionStore, error) {
73 pder.lock.RLock() 83 pder.lock.RLock()
74 if element, ok := pder.sessions[sid]; ok { 84 if element, ok := pder.sessions[sid]; ok {
...@@ -87,6 +97,7 @@ func (pder *MemProvider) SessionRead(sid string) (SessionStore, error) { ...@@ -87,6 +97,7 @@ func (pder *MemProvider) SessionRead(sid string) (SessionStore, error) {
87 return nil, nil 97 return nil, nil
88 } 98 }
89 99
100 // check session store exist in memory session by sid
90 func (pder *MemProvider) SessionExist(sid string) bool { 101 func (pder *MemProvider) SessionExist(sid string) bool {
91 pder.lock.RLock() 102 pder.lock.RLock()
92 defer pder.lock.RUnlock() 103 defer pder.lock.RUnlock()
...@@ -97,6 +108,7 @@ func (pder *MemProvider) SessionExist(sid string) bool { ...@@ -97,6 +108,7 @@ func (pder *MemProvider) SessionExist(sid string) bool {
97 } 108 }
98 } 109 }
99 110
111 // generate new sid for session store in memory session
100 func (pder *MemProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) { 112 func (pder *MemProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) {
101 pder.lock.RLock() 113 pder.lock.RLock()
102 if element, ok := pder.sessions[oldsid]; ok { 114 if element, ok := pder.sessions[oldsid]; ok {
...@@ -120,6 +132,7 @@ func (pder *MemProvider) SessionRegenerate(oldsid, sid string) (SessionStore, er ...@@ -120,6 +132,7 @@ func (pder *MemProvider) SessionRegenerate(oldsid, sid string) (SessionStore, er
120 return nil, nil 132 return nil, nil
121 } 133 }
122 134
135 // delete session store in memory session by id
123 func (pder *MemProvider) SessionDestroy(sid string) error { 136 func (pder *MemProvider) SessionDestroy(sid string) error {
124 pder.lock.Lock() 137 pder.lock.Lock()
125 defer pder.lock.Unlock() 138 defer pder.lock.Unlock()
...@@ -131,6 +144,7 @@ func (pder *MemProvider) SessionDestroy(sid string) error { ...@@ -131,6 +144,7 @@ func (pder *MemProvider) SessionDestroy(sid string) error {
131 return nil 144 return nil
132 } 145 }
133 146
147 // clean expired session stores in memory session
134 func (pder *MemProvider) SessionGC() { 148 func (pder *MemProvider) SessionGC() {
135 pder.lock.RLock() 149 pder.lock.RLock()
136 for { 150 for {
...@@ -152,10 +166,12 @@ func (pder *MemProvider) SessionGC() { ...@@ -152,10 +166,12 @@ func (pder *MemProvider) SessionGC() {
152 pder.lock.RUnlock() 166 pder.lock.RUnlock()
153 } 167 }
154 168
169 // get count number of memory session
155 func (pder *MemProvider) SessionAll() int { 170 func (pder *MemProvider) SessionAll() int {
156 return pder.list.Len() 171 return pder.list.Len()
157 } 172 }
158 173
174 // expand time of session store by id in memory session
159 func (pder *MemProvider) SessionUpdate(sid string) error { 175 func (pder *MemProvider) SessionUpdate(sid string) error {
160 pder.lock.Lock() 176 pder.lock.Lock()
161 defer pder.lock.Unlock() 177 defer pder.lock.Unlock()
......
1 package session 1 package session
2 2
3 //CREATE TABLE `session` ( 3 // mysql session support need create table as sql:
4 // `session_key` char(64) NOT NULL, 4 // CREATE TABLE `session` (
5 // `session_data` blob, 5 // `session_key` char(64) NOT NULL,
6 // `session_expiry` int(11) unsigned NOT NULL, 6 // session_data` blob,
7 // PRIMARY KEY (`session_key`) 7 // `session_expiry` int(11) unsigned NOT NULL,
8 //) ENGINE=MyISAM DEFAULT CHARSET=utf8; 8 // PRIMARY KEY (`session_key`)
9 // ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
9 10
10 import ( 11 import (
11 "database/sql" 12 "database/sql"
...@@ -18,6 +19,7 @@ import ( ...@@ -18,6 +19,7 @@ import (
18 19
19 var mysqlpder = &MysqlProvider{} 20 var mysqlpder = &MysqlProvider{}
20 21
22 // mysql session store
21 type MysqlSessionStore struct { 23 type MysqlSessionStore struct {
22 c *sql.DB 24 c *sql.DB
23 sid string 25 sid string
...@@ -25,6 +27,8 @@ type MysqlSessionStore struct { ...@@ -25,6 +27,8 @@ type MysqlSessionStore struct {
25 values map[interface{}]interface{} 27 values map[interface{}]interface{}
26 } 28 }
27 29
30 // set value in mysql session.
31 // it is temp value in map.
28 func (st *MysqlSessionStore) Set(key, value interface{}) error { 32 func (st *MysqlSessionStore) Set(key, value interface{}) error {
29 st.lock.Lock() 33 st.lock.Lock()
30 defer st.lock.Unlock() 34 defer st.lock.Unlock()
...@@ -32,6 +36,7 @@ func (st *MysqlSessionStore) Set(key, value interface{}) error { ...@@ -32,6 +36,7 @@ func (st *MysqlSessionStore) Set(key, value interface{}) error {
32 return nil 36 return nil
33 } 37 }
34 38
39 // get value from mysql session
35 func (st *MysqlSessionStore) Get(key interface{}) interface{} { 40 func (st *MysqlSessionStore) Get(key interface{}) interface{} {
36 st.lock.RLock() 41 st.lock.RLock()
37 defer st.lock.RUnlock() 42 defer st.lock.RUnlock()
...@@ -43,6 +48,7 @@ func (st *MysqlSessionStore) Get(key interface{}) interface{} { ...@@ -43,6 +48,7 @@ func (st *MysqlSessionStore) Get(key interface{}) interface{} {
43 return nil 48 return nil
44 } 49 }
45 50
51 // delete value in mysql session
46 func (st *MysqlSessionStore) Delete(key interface{}) error { 52 func (st *MysqlSessionStore) Delete(key interface{}) error {
47 st.lock.Lock() 53 st.lock.Lock()
48 defer st.lock.Unlock() 54 defer st.lock.Unlock()
...@@ -50,6 +56,7 @@ func (st *MysqlSessionStore) Delete(key interface{}) error { ...@@ -50,6 +56,7 @@ func (st *MysqlSessionStore) Delete(key interface{}) error {
50 return nil 56 return nil
51 } 57 }
52 58
59 // clear all values in mysql session
53 func (st *MysqlSessionStore) Flush() error { 60 func (st *MysqlSessionStore) Flush() error {
54 st.lock.Lock() 61 st.lock.Lock()
55 defer st.lock.Unlock() 62 defer st.lock.Unlock()
...@@ -57,10 +64,13 @@ func (st *MysqlSessionStore) Flush() error { ...@@ -57,10 +64,13 @@ func (st *MysqlSessionStore) Flush() error {
57 return nil 64 return nil
58 } 65 }
59 66
67 // get session id of this mysql session store
60 func (st *MysqlSessionStore) SessionID() string { 68 func (st *MysqlSessionStore) SessionID() string {
61 return st.sid 69 return st.sid
62 } 70 }
63 71
72 // save mysql session values to database.
73 // must call this method to save values to database.
64 func (st *MysqlSessionStore) SessionRelease(w http.ResponseWriter) { 74 func (st *MysqlSessionStore) SessionRelease(w http.ResponseWriter) {
65 defer st.c.Close() 75 defer st.c.Close()
66 b, err := encodeGob(st.values) 76 b, err := encodeGob(st.values)
...@@ -72,11 +82,13 @@ func (st *MysqlSessionStore) SessionRelease(w http.ResponseWriter) { ...@@ -72,11 +82,13 @@ func (st *MysqlSessionStore) SessionRelease(w http.ResponseWriter) {
72 82
73 } 83 }
74 84
85 // mysql session provider
75 type MysqlProvider struct { 86 type MysqlProvider struct {
76 maxlifetime int64 87 maxlifetime int64
77 savePath string 88 savePath string
78 } 89 }
79 90
91 // connect to mysql
80 func (mp *MysqlProvider) connectInit() *sql.DB { 92 func (mp *MysqlProvider) connectInit() *sql.DB {
81 db, e := sql.Open("mysql", mp.savePath) 93 db, e := sql.Open("mysql", mp.savePath)
82 if e != nil { 94 if e != nil {
...@@ -85,12 +97,15 @@ func (mp *MysqlProvider) connectInit() *sql.DB { ...@@ -85,12 +97,15 @@ func (mp *MysqlProvider) connectInit() *sql.DB {
85 return db 97 return db
86 } 98 }
87 99
100 // init mysql session.
101 // savepath is the connection string of mysql.
88 func (mp *MysqlProvider) SessionInit(maxlifetime int64, savePath string) error { 102 func (mp *MysqlProvider) SessionInit(maxlifetime int64, savePath string) error {
89 mp.maxlifetime = maxlifetime 103 mp.maxlifetime = maxlifetime
90 mp.savePath = savePath 104 mp.savePath = savePath
91 return nil 105 return nil
92 } 106 }
93 107
108 // get mysql session by sid
94 func (mp *MysqlProvider) SessionRead(sid string) (SessionStore, error) { 109 func (mp *MysqlProvider) SessionRead(sid string) (SessionStore, error) {
95 c := mp.connectInit() 110 c := mp.connectInit()
96 row := c.QueryRow("select session_data from session where session_key=?", sid) 111 row := c.QueryRow("select session_data from session where session_key=?", sid)
...@@ -113,6 +128,7 @@ func (mp *MysqlProvider) SessionRead(sid string) (SessionStore, error) { ...@@ -113,6 +128,7 @@ func (mp *MysqlProvider) SessionRead(sid string) (SessionStore, error) {
113 return rs, nil 128 return rs, nil
114 } 129 }
115 130
131 // check mysql session exist
116 func (mp *MysqlProvider) SessionExist(sid string) bool { 132 func (mp *MysqlProvider) SessionExist(sid string) bool {
117 c := mp.connectInit() 133 c := mp.connectInit()
118 defer c.Close() 134 defer c.Close()
...@@ -126,6 +142,7 @@ func (mp *MysqlProvider) SessionExist(sid string) bool { ...@@ -126,6 +142,7 @@ func (mp *MysqlProvider) SessionExist(sid string) bool {
126 } 142 }
127 } 143 }
128 144
145 // generate new sid for mysql session
129 func (mp *MysqlProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) { 146 func (mp *MysqlProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) {
130 c := mp.connectInit() 147 c := mp.connectInit()
131 row := c.QueryRow("select session_data from session where session_key=?", oldsid) 148 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 ...@@ -148,6 +165,7 @@ func (mp *MysqlProvider) SessionRegenerate(oldsid, sid string) (SessionStore, er
148 return rs, nil 165 return rs, nil
149 } 166 }
150 167
168 // delete mysql session by sid
151 func (mp *MysqlProvider) SessionDestroy(sid string) error { 169 func (mp *MysqlProvider) SessionDestroy(sid string) error {
152 c := mp.connectInit() 170 c := mp.connectInit()
153 c.Exec("DELETE FROM session where session_key=?", sid) 171 c.Exec("DELETE FROM session where session_key=?", sid)
...@@ -155,6 +173,7 @@ func (mp *MysqlProvider) SessionDestroy(sid string) error { ...@@ -155,6 +173,7 @@ func (mp *MysqlProvider) SessionDestroy(sid string) error {
155 return nil 173 return nil
156 } 174 }
157 175
176 // delete expired values in mysql session
158 func (mp *MysqlProvider) SessionGC() { 177 func (mp *MysqlProvider) SessionGC() {
159 c := mp.connectInit() 178 c := mp.connectInit()
160 c.Exec("DELETE from session where session_expiry < ?", time.Now().Unix()-mp.maxlifetime) 179 c.Exec("DELETE from session where session_expiry < ?", time.Now().Unix()-mp.maxlifetime)
...@@ -162,6 +181,7 @@ func (mp *MysqlProvider) SessionGC() { ...@@ -162,6 +181,7 @@ func (mp *MysqlProvider) SessionGC() {
162 return 181 return
163 } 182 }
164 183
184 // count values in mysql session
165 func (mp *MysqlProvider) SessionAll() int { 185 func (mp *MysqlProvider) SessionAll() int {
166 c := mp.connectInit() 186 c := mp.connectInit()
167 defer c.Close() 187 defer c.Close()
......
...@@ -11,18 +11,21 @@ import ( ...@@ -11,18 +11,21 @@ import (
11 11
12 var redispder = &RedisProvider{} 12 var redispder = &RedisProvider{}
13 13
14 // redis max pool size
14 var MAX_POOL_SIZE = 100 15 var MAX_POOL_SIZE = 100
15 16
16 var redisPool chan redis.Conn 17 var redisPool chan redis.Conn
17 18
19 // redis session store
18 type RedisSessionStore struct { 20 type RedisSessionStore struct {
19 c redis.Conn 21 p *redis.Pool
20 sid string 22 sid string
21 lock sync.RWMutex 23 lock sync.RWMutex
22 values map[interface{}]interface{} 24 values map[interface{}]interface{}
23 maxlifetime int64 25 maxlifetime int64
24 } 26 }
25 27
28 // set value in redis session
26 func (rs *RedisSessionStore) Set(key, value interface{}) error { 29 func (rs *RedisSessionStore) Set(key, value interface{}) error {
27 rs.lock.Lock() 30 rs.lock.Lock()
28 defer rs.lock.Unlock() 31 defer rs.lock.Unlock()
...@@ -30,6 +33,7 @@ func (rs *RedisSessionStore) Set(key, value interface{}) error { ...@@ -30,6 +33,7 @@ func (rs *RedisSessionStore) Set(key, value interface{}) error {
30 return nil 33 return nil
31 } 34 }
32 35
36 // get value in redis session
33 func (rs *RedisSessionStore) Get(key interface{}) interface{} { 37 func (rs *RedisSessionStore) Get(key interface{}) interface{} {
34 rs.lock.RLock() 38 rs.lock.RLock()
35 defer rs.lock.RUnlock() 39 defer rs.lock.RUnlock()
...@@ -41,6 +45,7 @@ func (rs *RedisSessionStore) Get(key interface{}) interface{} { ...@@ -41,6 +45,7 @@ func (rs *RedisSessionStore) Get(key interface{}) interface{} {
41 return nil 45 return nil
42 } 46 }
43 47
48 // delete value in redis session
44 func (rs *RedisSessionStore) Delete(key interface{}) error { 49 func (rs *RedisSessionStore) Delete(key interface{}) error {
45 rs.lock.Lock() 50 rs.lock.Lock()
46 defer rs.lock.Unlock() 51 defer rs.lock.Unlock()
...@@ -48,6 +53,7 @@ func (rs *RedisSessionStore) Delete(key interface{}) error { ...@@ -48,6 +53,7 @@ func (rs *RedisSessionStore) Delete(key interface{}) error {
48 return nil 53 return nil
49 } 54 }
50 55
56 // clear all values in redis session
51 func (rs *RedisSessionStore) Flush() error { 57 func (rs *RedisSessionStore) Flush() error {
52 rs.lock.Lock() 58 rs.lock.Lock()
53 defer rs.lock.Unlock() 59 defer rs.lock.Unlock()
...@@ -55,20 +61,31 @@ func (rs *RedisSessionStore) Flush() error { ...@@ -55,20 +61,31 @@ func (rs *RedisSessionStore) Flush() error {
55 return nil 61 return nil
56 } 62 }
57 63
64 // get redis session id
58 func (rs *RedisSessionStore) SessionID() string { 65 func (rs *RedisSessionStore) SessionID() string {
59 return rs.sid 66 return rs.sid
60 } 67 }
61 68
69 // save session values to redis
62 func (rs *RedisSessionStore) SessionRelease(w http.ResponseWriter) { 70 func (rs *RedisSessionStore) SessionRelease(w http.ResponseWriter) {
63 defer rs.c.Close() 71 c := rs.p.Get()
72 defer c.Close()
73
74 // if rs.values is empty, return directly
75 if len(rs.values) < 1 {
76 c.Do("DEL", rs.sid)
77 return
78 }
79
64 b, err := encodeGob(rs.values) 80 b, err := encodeGob(rs.values)
65 if err != nil { 81 if err != nil {
66 return 82 return
67 } 83 }
68 rs.c.Do("SET", rs.sid, string(b)) 84
69 rs.c.Do("EXPIRE", rs.sid, rs.maxlifetime) 85 c.Do("SET", rs.sid, string(b), "EX", rs.maxlifetime)
70 } 86 }
71 87
88 // redis session provider
72 type RedisProvider struct { 89 type RedisProvider struct {
73 maxlifetime int64 90 maxlifetime int64
74 savePath string 91 savePath string
...@@ -77,8 +94,9 @@ type RedisProvider struct { ...@@ -77,8 +94,9 @@ type RedisProvider struct {
77 poollist *redis.Pool 94 poollist *redis.Pool
78 } 95 }
79 96
80 //savepath like redisserveraddr,poolsize,password 97 // init redis session
81 //127.0.0.1:6379,100,astaxie 98 // savepath like redis server addr,pool size,password
99 // e.g. 127.0.0.1:6379,100,astaxie
82 func (rp *RedisProvider) SessionInit(maxlifetime int64, savePath string) error { 100 func (rp *RedisProvider) SessionInit(maxlifetime int64, savePath string) error {
83 rp.maxlifetime = maxlifetime 101 rp.maxlifetime = maxlifetime
84 configs := strings.Split(savePath, ",") 102 configs := strings.Split(savePath, ",")
...@@ -114,12 +132,11 @@ func (rp *RedisProvider) SessionInit(maxlifetime int64, savePath string) error { ...@@ -114,12 +132,11 @@ func (rp *RedisProvider) SessionInit(maxlifetime int64, savePath string) error {
114 return nil 132 return nil
115 } 133 }
116 134
135 // read redis session by sid
117 func (rp *RedisProvider) SessionRead(sid string) (SessionStore, error) { 136 func (rp *RedisProvider) SessionRead(sid string) (SessionStore, error) {
118 c := rp.poollist.Get() 137 c := rp.poollist.Get()
119 if existed, err := redis.Int(c.Do("EXISTS", sid)); err != nil || existed == 0 { 138 defer c.Close()
120 c.Do("SET", sid) 139
121 }
122 c.Do("EXPIRE", sid, rp.maxlifetime)
123 kvs, err := redis.String(c.Do("GET", sid)) 140 kvs, err := redis.String(c.Do("GET", sid))
124 var kv map[interface{}]interface{} 141 var kv map[interface{}]interface{}
125 if len(kvs) == 0 { 142 if len(kvs) == 0 {
...@@ -130,13 +147,16 @@ func (rp *RedisProvider) SessionRead(sid string) (SessionStore, error) { ...@@ -130,13 +147,16 @@ func (rp *RedisProvider) SessionRead(sid string) (SessionStore, error) {
130 return nil, err 147 return nil, err
131 } 148 }
132 } 149 }
133 rs := &RedisSessionStore{c: c, sid: sid, values: kv, maxlifetime: rp.maxlifetime} 150
151 rs := &RedisSessionStore{p: rp.poollist, sid: sid, values: kv, maxlifetime: rp.maxlifetime}
134 return rs, nil 152 return rs, nil
135 } 153 }
136 154
155 // check redis session exist by sid
137 func (rp *RedisProvider) SessionExist(sid string) bool { 156 func (rp *RedisProvider) SessionExist(sid string) bool {
138 c := rp.poollist.Get() 157 c := rp.poollist.Get()
139 defer c.Close() 158 defer c.Close()
159
140 if existed, err := redis.Int(c.Do("EXISTS", sid)); err != nil || existed == 0 { 160 if existed, err := redis.Int(c.Do("EXISTS", sid)); err != nil || existed == 0 {
141 return false 161 return false
142 } else { 162 } else {
...@@ -144,13 +164,21 @@ func (rp *RedisProvider) SessionExist(sid string) bool { ...@@ -144,13 +164,21 @@ func (rp *RedisProvider) SessionExist(sid string) bool {
144 } 164 }
145 } 165 }
146 166
167 // generate new sid for redis session
147 func (rp *RedisProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) { 168 func (rp *RedisProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) {
148 c := rp.poollist.Get() 169 c := rp.poollist.Get()
149 if existed, err := redis.Int(c.Do("EXISTS", oldsid)); err != nil || existed == 0 { 170 defer c.Close()
150 c.Do("SET", oldsid) 171
172 if existed, _ := redis.Int(c.Do("EXISTS", oldsid)); existed == 0 {
173 // oldsid doesn't exists, set the new sid directly
174 // ignore error here, since if it return error
175 // the existed value will be 0
176 c.Do("SET", sid, "", "EX", rp.maxlifetime)
177 } else {
178 c.Do("RENAME", oldsid, sid)
179 c.Do("EXPIRE", sid, rp.maxlifetime)
151 } 180 }
152 c.Do("RENAME", oldsid, sid) 181
153 c.Do("EXPIRE", sid, rp.maxlifetime)
154 kvs, err := redis.String(c.Do("GET", sid)) 182 kvs, err := redis.String(c.Do("GET", sid))
155 var kv map[interface{}]interface{} 183 var kv map[interface{}]interface{}
156 if len(kvs) == 0 { 184 if len(kvs) == 0 {
...@@ -161,24 +189,27 @@ func (rp *RedisProvider) SessionRegenerate(oldsid, sid string) (SessionStore, er ...@@ -161,24 +189,27 @@ func (rp *RedisProvider) SessionRegenerate(oldsid, sid string) (SessionStore, er
161 return nil, err 189 return nil, err
162 } 190 }
163 } 191 }
164 rs := &RedisSessionStore{c: c, sid: sid, values: kv, maxlifetime: rp.maxlifetime} 192
193 rs := &RedisSessionStore{p: rp.poollist, sid: sid, values: kv, maxlifetime: rp.maxlifetime}
165 return rs, nil 194 return rs, nil
166 } 195 }
167 196
197 // delete redis session by id
168 func (rp *RedisProvider) SessionDestroy(sid string) error { 198 func (rp *RedisProvider) SessionDestroy(sid string) error {
169 c := rp.poollist.Get() 199 c := rp.poollist.Get()
170 defer c.Close() 200 defer c.Close()
201
171 c.Do("DEL", sid) 202 c.Do("DEL", sid)
172 return nil 203 return nil
173 } 204 }
174 205
206 // Impelment method, no used.
175 func (rp *RedisProvider) SessionGC() { 207 func (rp *RedisProvider) SessionGC() {
176 return 208 return
177 } 209 }
178 210
179 //@todo 211 // @todo
180 func (rp *RedisProvider) SessionAll() int { 212 func (rp *RedisProvider) SessionAll() int {
181
182 return 0 213 return 0
183 } 214 }
184 215
......
...@@ -14,6 +14,7 @@ import ( ...@@ -14,6 +14,7 @@ import (
14 "time" 14 "time"
15 ) 15 )
16 16
17 // SessionStore contains all data for one session process with specific id.
17 type SessionStore interface { 18 type SessionStore interface {
18 Set(key, value interface{}) error //set session value 19 Set(key, value interface{}) error //set session value
19 Get(key interface{}) interface{} //get session value 20 Get(key interface{}) interface{} //get session value
...@@ -23,6 +24,8 @@ type SessionStore interface { ...@@ -23,6 +24,8 @@ type SessionStore interface {
23 Flush() error //delete all data 24 Flush() error //delete all data
24 } 25 }
25 26
27 // Provider contains global session methods and saved SessionStores.
28 // it can operate a SessionStore by its id.
26 type Provider interface { 29 type Provider interface {
27 SessionInit(gclifetime int64, config string) error 30 SessionInit(gclifetime int64, config string) error
28 SessionRead(sid string) (SessionStore, error) 31 SessionRead(sid string) (SessionStore, error)
...@@ -61,16 +64,24 @@ type managerConfig struct { ...@@ -61,16 +64,24 @@ type managerConfig struct {
61 ProviderConfig string `json:"providerConfig"` 64 ProviderConfig string `json:"providerConfig"`
62 } 65 }
63 66
67 // Manager contains Provider and its configuration.
64 type Manager struct { 68 type Manager struct {
65 provider Provider 69 provider Provider
66 config *managerConfig 70 config *managerConfig
67 } 71 }
68 72
69 //options 73 // Create new Manager with provider name and json config string.
70 //1. is https default false 74 // provider name:
71 //2. hashfunc default sha1 75 // 1. cookie
72 //3. hashkey default beegosessionkey 76 // 2. file
73 //4. maxage default is none 77 // 3. memory
78 // 4. redis
79 // 5. mysql
80 // json config:
81 // 1. is https default false
82 // 2. hashfunc default sha1
83 // 3. hashkey default beegosessionkey
84 // 4. maxage default is none
74 func NewManager(provideName, config string) (*Manager, error) { 85 func NewManager(provideName, config string) (*Manager, error) {
75 provider, ok := provides[provideName] 86 provider, ok := provides[provideName]
76 if !ok { 87 if !ok {
...@@ -102,7 +113,8 @@ func NewManager(provideName, config string) (*Manager, error) { ...@@ -102,7 +113,8 @@ func NewManager(provideName, config string) (*Manager, error) {
102 }, nil 113 }, nil
103 } 114 }
104 115
105 //get Session 116 // Start session. generate or read the session id from http request.
117 // if session id exists, return SessionStore with this id.
106 func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (session SessionStore) { 118 func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (session SessionStore) {
107 cookie, err := r.Cookie(manager.config.CookieName) 119 cookie, err := r.Cookie(manager.config.CookieName)
108 if err != nil || cookie.Value == "" { 120 if err != nil || cookie.Value == "" {
...@@ -144,7 +156,7 @@ func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (se ...@@ -144,7 +156,7 @@ func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (se
144 return 156 return
145 } 157 }
146 158
147 //Destroy sessionid 159 // Destroy session by its id in http request cookie.
148 func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) { 160 func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) {
149 cookie, err := r.Cookie(manager.config.CookieName) 161 cookie, err := r.Cookie(manager.config.CookieName)
150 if err != nil || cookie.Value == "" { 162 if err != nil || cookie.Value == "" {
...@@ -161,16 +173,20 @@ func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) { ...@@ -161,16 +173,20 @@ func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) {
161 } 173 }
162 } 174 }
163 175
176 // Get SessionStore by its id.
164 func (manager *Manager) GetProvider(sid string) (sessions SessionStore, err error) { 177 func (manager *Manager) GetProvider(sid string) (sessions SessionStore, err error) {
165 sessions, err = manager.provider.SessionRead(sid) 178 sessions, err = manager.provider.SessionRead(sid)
166 return 179 return
167 } 180 }
168 181
182 // Start session gc process.
183 // it can do gc in times after gc lifetime.
169 func (manager *Manager) GC() { 184 func (manager *Manager) GC() {
170 manager.provider.SessionGC() 185 manager.provider.SessionGC()
171 time.AfterFunc(time.Duration(manager.config.Gclifetime)*time.Second, func() { manager.GC() }) 186 time.AfterFunc(time.Duration(manager.config.Gclifetime)*time.Second, func() { manager.GC() })
172 } 187 }
173 188
189 // Regenerate a session id for this SessionStore who's id is saving in http request.
174 func (manager *Manager) SessionRegenerateId(w http.ResponseWriter, r *http.Request) (session SessionStore) { 190 func (manager *Manager) SessionRegenerateId(w http.ResponseWriter, r *http.Request) (session SessionStore) {
175 sid := manager.sessionId(r) 191 sid := manager.sessionId(r)
176 cookie, err := r.Cookie(manager.config.CookieName) 192 cookie, err := r.Cookie(manager.config.CookieName)
...@@ -198,20 +214,23 @@ func (manager *Manager) SessionRegenerateId(w http.ResponseWriter, r *http.Reque ...@@ -198,20 +214,23 @@ func (manager *Manager) SessionRegenerateId(w http.ResponseWriter, r *http.Reque
198 return 214 return
199 } 215 }
200 216
217 // Get all active sessions count number.
201 func (manager *Manager) GetActiveSession() int { 218 func (manager *Manager) GetActiveSession() int {
202 return manager.provider.SessionAll() 219 return manager.provider.SessionAll()
203 } 220 }
204 221
222 // Set hash function for generating session id.
205 func (manager *Manager) SetHashFunc(hasfunc, hashkey string) { 223 func (manager *Manager) SetHashFunc(hasfunc, hashkey string) {
206 manager.config.SessionIDHashFunc = hasfunc 224 manager.config.SessionIDHashFunc = hasfunc
207 manager.config.SessionIDHashKey = hashkey 225 manager.config.SessionIDHashKey = hashkey
208 } 226 }
209 227
228 // Set cookie with https.
210 func (manager *Manager) SetSecure(secure bool) { 229 func (manager *Manager) SetSecure(secure bool) {
211 manager.config.Secure = secure 230 manager.config.Secure = secure
212 } 231 }
213 232
214 //remote_addr cruunixnano randdata 233 // generate session id with rand string, unix nano time, remote addr by hash function.
215 func (manager *Manager) sessionId(r *http.Request) (sid string) { 234 func (manager *Manager) sessionId(r *http.Request) (sid string) {
216 bs := make([]byte, 24) 235 bs := make([]byte, 24)
217 if _, err := io.ReadFull(rand.Reader, bs); err != nil { 236 if _, err := io.ReadFull(rand.Reader, bs); err != nil {
......
...@@ -29,16 +29,13 @@ type pointerInfo struct { ...@@ -29,16 +29,13 @@ type pointerInfo struct {
29 used []int 29 used []int
30 } 30 }
31 31
32 //
33 // print the data in console 32 // print the data in console
34 //
35 func Display(data ...interface{}) { 33 func Display(data ...interface{}) {
36 display(true, data...) 34 display(true, data...)
37 } 35 }
38 36
39 // 37
40 // return string 38 // return data print string
41 //
42 func GetDisplayString(data ...interface{}) string { 39 func GetDisplayString(data ...interface{}) string {
43 return display(false, data...) 40 return display(false, data...)
44 } 41 }
...@@ -67,9 +64,7 @@ func display(displayed bool, data ...interface{}) string { ...@@ -67,9 +64,7 @@ func display(displayed bool, data ...interface{}) string {
67 return buf.String() 64 return buf.String()
68 } 65 }
69 66
70 // 67 // return data dump and format bytes
71 // return fomateinfo
72 //
73 func fomateinfo(headlen int, data ...interface{}) []byte { 68 func fomateinfo(headlen int, data ...interface{}) []byte {
74 var buf = new(bytes.Buffer) 69 var buf = new(bytes.Buffer)
75 70
...@@ -108,6 +103,7 @@ func fomateinfo(headlen int, data ...interface{}) []byte { ...@@ -108,6 +103,7 @@ func fomateinfo(headlen int, data ...interface{}) []byte {
108 return buf.Bytes() 103 return buf.Bytes()
109 } 104 }
110 105
106 // check data is golang basic type
111 func isSimpleType(val reflect.Value, kind reflect.Kind, pointers **pointerInfo, interfaces *[]reflect.Value) bool { 107 func isSimpleType(val reflect.Value, kind reflect.Kind, pointers **pointerInfo, interfaces *[]reflect.Value) bool {
112 switch kind { 108 switch kind {
113 case reflect.Bool: 109 case reflect.Bool:
...@@ -158,6 +154,7 @@ func isSimpleType(val reflect.Value, kind reflect.Kind, pointers **pointerInfo, ...@@ -158,6 +154,7 @@ func isSimpleType(val reflect.Value, kind reflect.Kind, pointers **pointerInfo,
158 return false 154 return false
159 } 155 }
160 156
157 // dump value
161 func printKeyValue(buf *bytes.Buffer, val reflect.Value, pointers **pointerInfo, interfaces *[]reflect.Value, structFilter func(string, string) bool, formatOutput bool, indent string, level int) { 158 func printKeyValue(buf *bytes.Buffer, val reflect.Value, pointers **pointerInfo, interfaces *[]reflect.Value, structFilter func(string, string) bool, formatOutput bool, indent string, level int) {
162 var t = val.Kind() 159 var t = val.Kind()
163 160
...@@ -367,6 +364,7 @@ func printKeyValue(buf *bytes.Buffer, val reflect.Value, pointers **pointerInfo, ...@@ -367,6 +364,7 @@ func printKeyValue(buf *bytes.Buffer, val reflect.Value, pointers **pointerInfo,
367 } 364 }
368 } 365 }
369 366
367 // dump pointer value
370 func printPointerInfo(buf *bytes.Buffer, headlen int, pointers *pointerInfo) { 368 func printPointerInfo(buf *bytes.Buffer, headlen int, pointers *pointerInfo) {
371 var anyused = false 369 var anyused = false
372 var pointerNum = 0 370 var pointerNum = 0
...@@ -434,9 +432,7 @@ func printPointerInfo(buf *bytes.Buffer, headlen int, pointers *pointerInfo) { ...@@ -434,9 +432,7 @@ func printPointerInfo(buf *bytes.Buffer, headlen int, pointers *pointerInfo) {
434 } 432 }
435 } 433 }
436 434
437 // 435 // get stack bytes
438 // get stack info
439 //
440 func stack(skip int, indent string) []byte { 436 func stack(skip int, indent string) []byte {
441 var buf = new(bytes.Buffer) 437 var buf = new(bytes.Buffer)
442 438
...@@ -455,7 +451,7 @@ func stack(skip int, indent string) []byte { ...@@ -455,7 +451,7 @@ func stack(skip int, indent string) []byte {
455 return buf.Bytes() 451 return buf.Bytes()
456 } 452 }
457 453
458 // function returns, if possible, the name of the function containing the PC. 454 // return the name of the function containing the PC if possible,
459 func function(pc uintptr) []byte { 455 func function(pc uintptr) []byte {
460 fn := runtime.FuncForPC(pc) 456 fn := runtime.FuncForPC(pc)
461 if fn == nil { 457 if fn == nil {
......
...@@ -13,12 +13,15 @@ package toolbox ...@@ -13,12 +13,15 @@ package toolbox
13 13
14 //AddHealthCheck("database",&DatabaseCheck{}) 14 //AddHealthCheck("database",&DatabaseCheck{})
15 15
16 // health checker map
16 var AdminCheckList map[string]HealthChecker 17 var AdminCheckList map[string]HealthChecker
17 18
19 // health checker interface
18 type HealthChecker interface { 20 type HealthChecker interface {
19 Check() error 21 Check() error
20 } 22 }
21 23
24 // add health checker with name string
22 func AddHealthCheck(name string, hc HealthChecker) { 25 func AddHealthCheck(name string, hc HealthChecker) {
23 AdminCheckList[name] = hc 26 AdminCheckList[name] = hc
24 } 27 }
......
...@@ -19,6 +19,7 @@ func init() { ...@@ -19,6 +19,7 @@ func init() {
19 pid = os.Getpid() 19 pid = os.Getpid()
20 } 20 }
21 21
22 // parse input command string
22 func ProcessInput(input string, w io.Writer) { 23 func ProcessInput(input string, w io.Writer) {
23 switch input { 24 switch input {
24 case "lookup goroutine": 25 case "lookup goroutine":
...@@ -44,6 +45,7 @@ func ProcessInput(input string, w io.Writer) { ...@@ -44,6 +45,7 @@ func ProcessInput(input string, w io.Writer) {
44 } 45 }
45 } 46 }
46 47
48 // record memory profile in pprof
47 func MemProf() { 49 func MemProf() {
48 if f, err := os.Create("mem-" + strconv.Itoa(pid) + ".memprof"); err != nil { 50 if f, err := os.Create("mem-" + strconv.Itoa(pid) + ".memprof"); err != nil {
49 log.Fatal("record memory profile failed: %v", err) 51 log.Fatal("record memory profile failed: %v", err)
...@@ -54,6 +56,7 @@ func MemProf() { ...@@ -54,6 +56,7 @@ func MemProf() {
54 } 56 }
55 } 57 }
56 58
59 // start cpu profile monitor
57 func StartCPUProfile() { 60 func StartCPUProfile() {
58 f, err := os.Create("cpu-" + strconv.Itoa(pid) + ".pprof") 61 f, err := os.Create("cpu-" + strconv.Itoa(pid) + ".pprof")
59 if err != nil { 62 if err != nil {
...@@ -62,10 +65,12 @@ func StartCPUProfile() { ...@@ -62,10 +65,12 @@ func StartCPUProfile() {
62 pprof.StartCPUProfile(f) 65 pprof.StartCPUProfile(f)
63 } 66 }
64 67
68 // stop cpu profile monitor
65 func StopCPUProfile() { 69 func StopCPUProfile() {
66 pprof.StopCPUProfile() 70 pprof.StopCPUProfile()
67 } 71 }
68 72
73 // print gc information to io.Writer
69 func PrintGCSummary(w io.Writer) { 74 func PrintGCSummary(w io.Writer) {
70 memStats := &runtime.MemStats{} 75 memStats := &runtime.MemStats{}
71 runtime.ReadMemStats(memStats) 76 runtime.ReadMemStats(memStats)
...@@ -114,7 +119,7 @@ func avg(items []time.Duration) time.Duration { ...@@ -114,7 +119,7 @@ func avg(items []time.Duration) time.Duration {
114 return time.Duration(int64(sum) / int64(len(items))) 119 return time.Duration(int64(sum) / int64(len(items)))
115 } 120 }
116 121
117 // human readable format 122 // format bytes number friendly
118 func toH(bytes uint64) string { 123 func toH(bytes uint64) string {
119 switch { 124 switch {
120 case bytes < 1024: 125 case bytes < 1024:
......
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
7 "time" 7 "time"
8 ) 8 )
9 9
10 // Statistics struct
10 type Statistics struct { 11 type Statistics struct {
11 RequestUrl string 12 RequestUrl string
12 RequestController string 13 RequestController string
...@@ -16,12 +17,15 @@ type Statistics struct { ...@@ -16,12 +17,15 @@ type Statistics struct {
16 TotalTime time.Duration 17 TotalTime time.Duration
17 } 18 }
18 19
20 // UrlMap contains several statistics struct to log different data
19 type UrlMap struct { 21 type UrlMap struct {
20 lock sync.RWMutex 22 lock sync.RWMutex
21 LengthLimit int //limit the urlmap's length if it's equal to 0 there's no limit 23 LengthLimit int //limit the urlmap's length if it's equal to 0 there's no limit
22 urlmap map[string]map[string]*Statistics 24 urlmap map[string]map[string]*Statistics
23 } 25 }
24 26
27 // add statistics task.
28 // it needs request method, request url, request controller and statistics time duration
25 func (m *UrlMap) AddStatistics(requestMethod, requestUrl, requestController string, requesttime time.Duration) { 29 func (m *UrlMap) AddStatistics(requestMethod, requestUrl, requestController string, requesttime time.Duration) {
26 m.lock.Lock() 30 m.lock.Lock()
27 defer m.lock.Unlock() 31 defer m.lock.Unlock()
...@@ -65,6 +69,7 @@ func (m *UrlMap) AddStatistics(requestMethod, requestUrl, requestController stri ...@@ -65,6 +69,7 @@ func (m *UrlMap) AddStatistics(requestMethod, requestUrl, requestController stri
65 } 69 }
66 } 70 }
67 71
72 // put url statistics result in io.Writer
68 func (m *UrlMap) GetMap(rw io.Writer) { 73 func (m *UrlMap) GetMap(rw io.Writer) {
69 m.lock.RLock() 74 m.lock.RLock()
70 defer m.lock.RUnlock() 75 defer m.lock.RUnlock()
...@@ -78,6 +83,7 @@ func (m *UrlMap) GetMap(rw io.Writer) { ...@@ -78,6 +83,7 @@ func (m *UrlMap) GetMap(rw io.Writer) {
78 } 83 }
79 } 84 }
80 85
86 // global statistics data map
81 var StatisticsMap *UrlMap 87 var StatisticsMap *UrlMap
82 88
83 func init() { 89 func init() {
......
...@@ -53,6 +53,7 @@ const ( ...@@ -53,6 +53,7 @@ const (
53 starBit = 1 << 63 53 starBit = 1 << 63
54 ) 54 )
55 55
56 // time taks schedule
56 type Schedule struct { 57 type Schedule struct {
57 Second uint64 58 Second uint64
58 Minute uint64 59 Minute uint64
...@@ -62,8 +63,10 @@ type Schedule struct { ...@@ -62,8 +63,10 @@ type Schedule struct {
62 Week uint64 63 Week uint64
63 } 64 }
64 65
66 // task func type
65 type TaskFunc func() error 67 type TaskFunc func() error
66 68
69 // task interface
67 type Tasker interface { 70 type Tasker interface {
68 GetStatus() string 71 GetStatus() string
69 Run() error 72 Run() error
...@@ -73,21 +76,24 @@ type Tasker interface { ...@@ -73,21 +76,24 @@ type Tasker interface {
73 GetPrev() time.Time 76 GetPrev() time.Time
74 } 77 }
75 78
79 // task error
76 type taskerr struct { 80 type taskerr struct {
77 t time.Time 81 t time.Time
78 errinfo string 82 errinfo string
79 } 83 }
80 84
85 // task struct
81 type Task struct { 86 type Task struct {
82 Taskname string 87 Taskname string
83 Spec *Schedule 88 Spec *Schedule
84 DoFunc TaskFunc 89 DoFunc TaskFunc
85 Prev time.Time 90 Prev time.Time
86 Next time.Time 91 Next time.Time
87 Errlist []*taskerr //errtime:errinfo 92 Errlist []*taskerr // like errtime:errinfo
88 ErrLimit int //max length for the errlist 0 stand for there' no limit 93 ErrLimit int // max length for the errlist, 0 stand for no limit
89 } 94 }
90 95
96 // add new task with name, time and func
91 func NewTask(tname string, spec string, f TaskFunc) *Task { 97 func NewTask(tname string, spec string, f TaskFunc) *Task {
92 98
93 task := &Task{ 99 task := &Task{
...@@ -99,6 +105,7 @@ func NewTask(tname string, spec string, f TaskFunc) *Task { ...@@ -99,6 +105,7 @@ func NewTask(tname string, spec string, f TaskFunc) *Task {
99 return task 105 return task
100 } 106 }
101 107
108 // get current task status
102 func (tk *Task) GetStatus() string { 109 func (tk *Task) GetStatus() string {
103 var str string 110 var str string
104 for _, v := range tk.Errlist { 111 for _, v := range tk.Errlist {
...@@ -107,6 +114,7 @@ func (tk *Task) GetStatus() string { ...@@ -107,6 +114,7 @@ func (tk *Task) GetStatus() string {
107 return str 114 return str
108 } 115 }
109 116
117 // run task
110 func (tk *Task) Run() error { 118 func (tk *Task) Run() error {
111 err := tk.DoFunc() 119 err := tk.DoFunc()
112 if err != nil { 120 if err != nil {
...@@ -117,53 +125,58 @@ func (tk *Task) Run() error { ...@@ -117,53 +125,58 @@ func (tk *Task) Run() error {
117 return err 125 return err
118 } 126 }
119 127
128 // set next time for this task
120 func (tk *Task) SetNext(now time.Time) { 129 func (tk *Task) SetNext(now time.Time) {
121 tk.Next = tk.Spec.Next(now) 130 tk.Next = tk.Spec.Next(now)
122 } 131 }
123 132
133 // get the next call time of this task
124 func (tk *Task) GetNext() time.Time { 134 func (tk *Task) GetNext() time.Time {
125 return tk.Next 135 return tk.Next
126 } 136 }
137
138 // set prev time of this task
127 func (tk *Task) SetPrev(now time.Time) { 139 func (tk *Task) SetPrev(now time.Time) {
128 tk.Prev = now 140 tk.Prev = now
129 } 141 }
130 142
143 // get prev time of this task
131 func (tk *Task) GetPrev() time.Time { 144 func (tk *Task) GetPrev() time.Time {
132 return tk.Prev 145 return tk.Prev
133 } 146 }
134 147
135 //前6个字段分别表示 148 // six columns mean
136 // 秒钟:0-59 149 // second:0-59
137 // 分钟:0-59 150 // minute:0-59
138 // 小时:1-23 151 // hour:1-23
139 // 日期:1-31 152 // day:1-31
140 // 月份:1-12 153 // month:1-12
141 // 星期:0-6(0表示周日 154 // week:0-6(0 means Sunday
142 155
143 //还可以用一些特殊符号 156 // some signals
144 // *: 表示任何时刻 157 // *: any time
145 // ,: 表示分割,如第三段里:2,4,表示2点和4点执行 158 // ,:  separate signal
146 //   -:表示一个段,如第三端里: 1-5,就表示1到5点 159 //   -:duration
147 // /n : 表示每个n的单位执行一次,如第三段里,*/1, 就表示每隔1个小时执行一次命令。也可以写成1-23/1. 160 // /n : do as n times of time duration
148 ///////////////////////////////////////////////////////// 161 /////////////////////////////////////////////////////////
149 // 0/30 * * * * * 每30秒 执行 162 // 0/30 * * * * * every 30s
150 // 0 43 21 * * * 21:43 执行 163 // 0 43 21 * * * 21:43
151 // 0 15 05 * * *    05:15 执行 164 // 0 15 05 * * *    05:15
152 // 0 0 17 * * * 17:00 执行 165 // 0 0 17 * * * 17:00
153 // 0 0 17 * * 1 每周一的 17:00 执行 166 // 0 0 17 * * 1 17:00 in every Monday
154 // 0 0,10 17 * * 0,2,3 每周日,周二,周三的 17:00和 17:10 执行 167 // 0 0,10 17 * * 0,2,3 17:00 and 17:10 in every Sunday, Tuesday and Wednesday
155 // 0 0-10 17 1 * * 毎月1日从 17:00到7:10 毎隔1分钟 执行 168 // 0 0-10 17 1 * * 17:00 to 17:10 in 1 min duration each time on the first day of month
156 // 0 0 0 1,15 * 1 毎月1日和 15日和 一日的 0:00 执行 169 // 0 0 0 1,15 * 1 0:00 on the 1st day and 15th day of month
157 // 0 42 4 1 * *     毎月1日的 4:42分 执行 170 // 0 42 4 1 * *     4:42 on the 1st day of month
158 // 0 0 21 * * 1-6   周一到周六 21:00 执行 171 // 0 0 21 * * 1-6   21:00 from Monday to Saturday
159 // 0 0,10,20,30,40,50 * * * *  每隔10分 执行 172 // 0 0,10,20,30,40,50 * * * *  every 10 min duration
160 // 0 */10 * * * *        每隔10分 执行 173 // 0 */10 * * * *        every 10 min duration
161 // 0 * 1 * * *         从1:0到1:59 每隔1分钟 执行 174 // 0 * 1 * * *         1:00 to 1:59 in 1 min duration each time
162 // 0 0 1 * * *         1:00 执行 175 // 0 0 1 * * *         1:00
163 // 0 0 */1 * * *        毎时0分 每隔1小时 执行 176 // 0 0 */1 * * *        0 min of hour in 1 hour duration
164 // 0 0 * * * *         毎时0分 每隔1小时 执行 177 // 0 0 * * * *         0 min of hour in 1 hour duration
165 // 0 2 8-20/3 * * *       8:02,11:02,14:02,17:02,20:02 执行 178 // 0 2 8-20/3 * * *       8:02, 11:02, 14:02, 17:02, 20:02
166 // 0 30 5 1,15 * *       1日 和 15日的 5:30 执行 179 // 0 30 5 1,15 * *       5:30 on the 1st day and 15th day of month
167 func (t *Task) SetCron(spec string) { 180 func (t *Task) SetCron(spec string) {
168 t.Spec = t.parse(spec) 181 t.Spec = t.parse(spec)
169 } 182 }
...@@ -252,6 +265,7 @@ func (t *Task) parseSpec(spec string) *Schedule { ...@@ -252,6 +265,7 @@ func (t *Task) parseSpec(spec string) *Schedule {
252 return nil 265 return nil
253 } 266 }
254 267
268 // set schedule to next time
255 func (s *Schedule) Next(t time.Time) time.Time { 269 func (s *Schedule) Next(t time.Time) time.Time {
256 270
257 // Start at the earliest possible time (the upcoming second). 271 // Start at the earliest possible time (the upcoming second).
...@@ -349,6 +363,7 @@ func dayMatches(s *Schedule, t time.Time) bool { ...@@ -349,6 +363,7 @@ func dayMatches(s *Schedule, t time.Time) bool {
349 return domMatch || dowMatch 363 return domMatch || dowMatch
350 } 364 }
351 365
366 // start all tasks
352 func StartTask() { 367 func StartTask() {
353 go run() 368 go run()
354 } 369 }
...@@ -388,20 +403,23 @@ func run() { ...@@ -388,20 +403,23 @@ func run() {
388 } 403 }
389 } 404 }
390 405
406 // start all tasks
391 func StopTask() { 407 func StopTask() {
392 stop <- true 408 stop <- true
393 } 409 }
394 410
411 // add task with name
395 func AddTask(taskname string, t Tasker) { 412 func AddTask(taskname string, t Tasker) {
396 AdminTaskList[taskname] = t 413 AdminTaskList[taskname] = t
397 } 414 }
398 415
399 //sort map for tasker 416 // sort map for tasker
400 type MapSorter struct { 417 type MapSorter struct {
401 Keys []string 418 Keys []string
402 Vals []Tasker 419 Vals []Tasker
403 } 420 }
404 421
422 // create new tasker map
405 func NewMapSorter(m map[string]Tasker) *MapSorter { 423 func NewMapSorter(m map[string]Tasker) *MapSorter {
406 ms := &MapSorter{ 424 ms := &MapSorter{
407 Keys: make([]string, 0, len(m)), 425 Keys: make([]string, 0, len(m)),
...@@ -414,6 +432,7 @@ func NewMapSorter(m map[string]Tasker) *MapSorter { ...@@ -414,6 +432,7 @@ func NewMapSorter(m map[string]Tasker) *MapSorter {
414 return ms 432 return ms
415 } 433 }
416 434
435 // sort tasker map
417 func (ms *MapSorter) Sort() { 436 func (ms *MapSorter) Sort() {
418 sort.Sort(ms) 437 sort.Sort(ms)
419 } 438 }
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!