Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
张磊
/
FileStorageBeego
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
846d7664
authored
2014-02-07 15:34:01 +0800
by
傅小黑
Browse Files
Options
Browse Files
Tag
Download
Plain Diff
Merge branch 'develop' of
git://github.com/astaxie/beego
2 parents
6b5108ef
bbc71142
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
666 additions
and
149 deletions
controller.go
logs/console.go
orm/db.go
orm/db_alias.go
orm/orm.go
orm/orm_queryset.go
orm/orm_raw.go
orm/orm_test.go
orm/types.go
session/sess_cookie.go
session/sess_file.go
session/sess_mem.go
session/sess_mysql.go
session/sess_redis.go
session/session.go
toolbox/debug.go
toolbox/healthcheck.go
toolbox/profile.go
toolbox/statistics.go
toolbox/task.go
controller.go
View file @
846d766
...
...
@@ -45,6 +45,7 @@ type Controller struct {
CruSession
session
.
SessionStore
XSRFExpire
int
AppController
interface
{}
EnableReander
bool
}
// ControllerInterface is an interface to uniform all controller handler.
...
...
@@ -74,6 +75,7 @@ func (c *Controller) Init(ctx *context.Context, controllerName, actionName strin
c
.
Ctx
=
ctx
c
.
TplExt
=
"tpl"
c
.
AppController
=
app
c
.
EnableReander
=
true
}
// Prepare runs after Init before request function execution.
...
...
@@ -123,6 +125,9 @@ func (c *Controller) Options() {
// Render sends the response with rendered template bytes as text/html type.
func
(
c
*
Controller
)
Render
()
error
{
if
!
c
.
EnableReander
{
return
nil
}
rb
,
err
:=
c
.
RenderBytes
()
if
err
!=
nil
{
...
...
@@ -398,6 +403,7 @@ func (c *Controller) SessionRegenerateID() {
// DestroySession cleans session data and session cookie.
func
(
c
*
Controller
)
DestroySession
()
{
c
.
Ctx
.
Input
.
CruSession
.
Flush
()
GlobalSessions
.
SessionDestroy
(
c
.
Ctx
.
ResponseWriter
,
c
.
Ctx
.
Request
)
}
...
...
logs/console.go
View file @
846d766
...
...
@@ -4,8 +4,28 @@ import (
"encoding/json"
"log"
"os"
"runtime"
)
type
Brush
func
(
string
)
string
func
NewBrush
(
color
string
)
Brush
{
pre
:=
"
\0
33["
reset
:=
"
\0
33[0m"
return
func
(
text
string
)
string
{
return
pre
+
color
+
"m"
+
text
+
reset
}
}
var
colors
=
[]
Brush
{
NewBrush
(
"1;36"
),
// Trace cyan
NewBrush
(
"1;34"
),
// Debug blue
NewBrush
(
"1;32"
),
// Info green
NewBrush
(
"1;33"
),
// Warn yellow
NewBrush
(
"1;31"
),
// Error red
NewBrush
(
"1;35"
),
// Critical purple
}
// ConsoleWriter implements LoggerInterface and writes messages to terminal.
type
ConsoleWriter
struct
{
lg
*
log
.
Logger
...
...
@@ -35,7 +55,11 @@ func (c *ConsoleWriter) WriteMsg(msg string, level int) error {
if
level
<
c
.
Level
{
return
nil
}
c
.
lg
.
Println
(
msg
)
if
goos
:=
runtime
.
GOOS
;
goos
==
"windows"
{
c
.
lg
.
Println
(
msg
)
}
else
{
c
.
lg
.
Println
(
colors
[
level
](
msg
))
}
return
nil
}
...
...
orm/db.go
View file @
846d766
...
...
@@ -1350,6 +1350,10 @@ func (d *dbBase) ReadValues(q dbQuerier, qs *querySet, mi *modelInfo, cond *Cond
return
cnt
,
nil
}
func
(
d
*
dbBase
)
RowsTo
(
dbQuerier
,
*
querySet
,
*
modelInfo
,
*
Condition
,
interface
{},
string
,
string
,
*
time
.
Location
)
(
int64
,
error
)
{
return
0
,
nil
}
// flag of update joined record.
func
(
d
*
dbBase
)
SupportUpdateJoin
()
bool
{
return
true
...
...
orm/db_alias.go
View file @
846d766
...
...
@@ -3,7 +3,6 @@ package orm
import
(
"database/sql"
"fmt"
"os"
"reflect"
"sync"
"time"
...
...
@@ -13,11 +12,11 @@ import (
type
DriverType
int
const
(
_
DriverType
=
iota
// int enum type
DR_MySQL
// mysql
DR_Sqlite
// sqlite
DR_Oracle
// oracle
DR_Postgres
// pgsql
_
DriverType
=
iota
// int enum type
DR_MySQL
// mysql
DR_Sqlite
// sqlite
DR_Oracle
// oracle
DR_Postgres
// pgsql
)
// database driver string.
...
...
@@ -96,40 +95,15 @@ type alias struct {
Engine
string
}
// Setting the database connect params. Use the database driver self dataSource args.
func
RegisterDataBase
(
aliasName
,
driverName
,
dataSource
string
,
params
...
int
)
{
al
:=
new
(
alias
)
al
.
Name
=
aliasName
al
.
DriverName
=
driverName
al
.
DataSource
=
dataSource
var
(
err
error
)
if
dr
,
ok
:=
drivers
[
driverName
];
ok
{
al
.
DbBaser
=
dbBasers
[
dr
]
al
.
Driver
=
dr
}
else
{
err
=
fmt
.
Errorf
(
"driver name `%s` have not registered"
,
driverName
)
goto
end
}
if
dataBaseCache
.
add
(
aliasName
,
al
)
==
false
{
err
=
fmt
.
Errorf
(
"db name `%s` already registered, cannot reuse"
,
aliasName
)
goto
end
}
al
.
DB
,
err
=
sql
.
Open
(
driverName
,
dataSource
)
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"register db `%s`, %s"
,
aliasName
,
err
.
Error
())
goto
end
}
func
detectTZ
(
al
*
alias
)
{
// orm timezone system match database
// default use Local
al
.
TZ
=
time
.
Local
if
al
.
DriverName
==
"sphinx"
{
return
}
switch
al
.
Driver
{
case
DR_MySQL
:
row
:=
al
.
DB
.
QueryRow
(
"SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP)"
)
...
...
@@ -173,6 +147,60 @@ func RegisterDataBase(aliasName, driverName, dataSource string, params ...int) {
DebugLog
.
Printf
(
"Detect DB timezone: %s %s
\n
"
,
tz
,
err
.
Error
())
}
}
}
func
addAliasWthDB
(
aliasName
,
driverName
string
,
db
*
sql
.
DB
)
(
*
alias
,
error
)
{
al
:=
new
(
alias
)
al
.
Name
=
aliasName
al
.
DriverName
=
driverName
al
.
DB
=
db
if
dr
,
ok
:=
drivers
[
driverName
];
ok
{
al
.
DbBaser
=
dbBasers
[
dr
]
al
.
Driver
=
dr
}
else
{
return
nil
,
fmt
.
Errorf
(
"driver name `%s` have not registered"
,
driverName
)
}
err
:=
db
.
Ping
()
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"register db Ping `%s`, %s"
,
aliasName
,
err
.
Error
())
}
if
dataBaseCache
.
add
(
aliasName
,
al
)
==
false
{
return
nil
,
fmt
.
Errorf
(
"db name `%s` already registered, cannot reuse"
,
aliasName
)
}
return
al
,
nil
}
func
AddAliasWthDB
(
aliasName
,
driverName
string
,
db
*
sql
.
DB
)
error
{
_
,
err
:=
addAliasWthDB
(
aliasName
,
driverName
,
db
)
return
err
}
// Setting the database connect params. Use the database driver self dataSource args.
func
RegisterDataBase
(
aliasName
,
driverName
,
dataSource
string
,
params
...
int
)
error
{
var
(
err
error
db
*
sql
.
DB
al
*
alias
)
db
,
err
=
sql
.
Open
(
driverName
,
dataSource
)
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"register db `%s`, %s"
,
aliasName
,
err
.
Error
())
goto
end
}
al
,
err
=
addAliasWthDB
(
aliasName
,
driverName
,
db
)
if
err
!=
nil
{
goto
end
}
al
.
DataSource
=
dataSource
detectTZ
(
al
)
for
i
,
v
:=
range
params
{
switch
i
{
...
...
@@ -183,39 +211,37 @@ func RegisterDataBase(aliasName, driverName, dataSource string, params ...int) {
}
}
err
=
al
.
DB
.
Ping
()
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"register db `%s`, %s"
,
aliasName
,
err
.
Error
())
goto
end
}
end
:
if
err
!=
nil
{
fmt
.
Println
(
err
.
Error
())
os
.
Exit
(
2
)
if
db
!=
nil
{
db
.
Close
()
}
DebugLog
.
Println
(
err
.
Error
())
}
return
err
}
// Register a database driver use specify driver name, this can be definition the driver is which database type.
func
RegisterDriver
(
driverName
string
,
typ
DriverType
)
{
func
RegisterDriver
(
driverName
string
,
typ
DriverType
)
error
{
if
t
,
ok
:=
drivers
[
driverName
];
ok
==
false
{
drivers
[
driverName
]
=
typ
}
else
{
if
t
!=
typ
{
fmt
.
Sprintf
(
"driverName `%s` db driver already registered and is other type
\n
"
,
driverName
)
os
.
Exit
(
2
)
return
fmt
.
Errorf
(
"driverName `%s` db driver already registered and is other type
\n
"
,
driverName
)
}
}
return
nil
}
// Change the database default used timezone
func
SetDataBaseTZ
(
aliasName
string
,
tz
*
time
.
Location
)
{
func
SetDataBaseTZ
(
aliasName
string
,
tz
*
time
.
Location
)
error
{
if
al
,
ok
:=
dataBaseCache
.
get
(
aliasName
);
ok
{
al
.
TZ
=
tz
}
else
{
fmt
.
Sprintf
(
"DataBase name `%s` not registered
\n
"
,
aliasName
)
os
.
Exit
(
2
)
return
fmt
.
Errorf
(
"DataBase name `%s` not registered
\n
"
,
aliasName
)
}
return
nil
}
// Change the max idle conns for *sql.DB, use specify database alias name
...
...
orm/orm.go
View file @
846d766
...
...
@@ -74,6 +74,20 @@ func (o *orm) Read(md interface{}, cols ...string) error {
return
nil
}
// Try to read a row from the database, or insert one if it doesn't exist
func
(
o
*
orm
)
ReadOrCreate
(
md
interface
{},
col1
string
,
cols
...
string
)
(
bool
,
int64
,
error
)
{
cols
=
append
([]
string
{
col1
},
cols
...
)
mi
,
ind
:=
o
.
getMiInd
(
md
,
true
)
err
:=
o
.
alias
.
DbBaser
.
Read
(
o
.
db
,
mi
,
ind
,
o
.
alias
.
TZ
,
cols
)
if
err
==
ErrNoRows
{
// Create
id
,
err
:=
o
.
Insert
(
md
)
return
(
err
==
nil
),
id
,
err
}
return
false
,
ind
.
Field
(
mi
.
fields
.
pk
.
fieldIndex
)
.
Int
(),
err
}
// insert model data to database
func
(
o
*
orm
)
Insert
(
md
interface
{})
(
int64
,
error
)
{
mi
,
ind
:=
o
.
getMiInd
(
md
,
true
)
...
...
@@ -425,6 +439,12 @@ func (o *orm) Driver() Driver {
return
driver
(
o
.
alias
.
Name
)
}
func
(
o
*
orm
)
GetDB
()
dbQuerier
{
panic
(
ErrNotImplement
)
// not enough
return
o
.
db
}
// create new orm
func
NewOrm
()
Ormer
{
BootStrap
()
// execute only once
...
...
@@ -436,3 +456,30 @@ func NewOrm() Ormer {
}
return
o
}
// create a new ormer object with specify *sql.DB for query
func
NewOrmWithDB
(
driverName
,
aliasName
string
,
db
*
sql
.
DB
)
(
Ormer
,
error
)
{
var
al
*
alias
if
dr
,
ok
:=
drivers
[
driverName
];
ok
{
al
=
new
(
alias
)
al
.
DbBaser
=
dbBasers
[
dr
]
al
.
Driver
=
dr
}
else
{
return
nil
,
fmt
.
Errorf
(
"driver name `%s` have not registered"
,
driverName
)
}
al
.
Name
=
aliasName
al
.
DriverName
=
driverName
o
:=
new
(
orm
)
o
.
alias
=
al
if
Debug
{
o
.
db
=
newDbQueryLog
(
o
.
alias
,
db
)
}
else
{
o
.
db
=
db
}
return
o
,
nil
}
...
...
orm/orm_queryset.go
View file @
846d766
...
...
@@ -197,6 +197,36 @@ func (o *querySet) ValuesFlat(result *ParamsList, expr string) (int64, error) {
return
o
.
orm
.
alias
.
DbBaser
.
ReadValues
(
o
.
orm
.
db
,
o
,
o
.
mi
,
o
.
cond
,
[]
string
{
expr
},
result
,
o
.
orm
.
alias
.
TZ
)
}
// query all rows into map[string]interface with specify key and value column name.
// keyCol = "name", valueCol = "value"
// table data
// name | value
// total | 100
// found | 200
// to map[string]interface{}{
// "total": 100,
// "found": 200,
// }
func
(
o
*
querySet
)
RowsToMap
(
result
*
Params
,
keyCol
,
valueCol
string
)
(
int64
,
error
)
{
panic
(
ErrNotImplement
)
return
o
.
orm
.
alias
.
DbBaser
.
RowsTo
(
o
.
orm
.
db
,
o
,
o
.
mi
,
o
.
cond
,
result
,
keyCol
,
valueCol
,
o
.
orm
.
alias
.
TZ
)
}
// query all rows into struct with specify key and value column name.
// keyCol = "name", valueCol = "value"
// table data
// name | value
// total | 100
// found | 200
// to struct {
// Total int
// Found int
// }
func
(
o
*
querySet
)
RowsToStruct
(
ptrStruct
interface
{},
keyCol
,
valueCol
string
)
(
int64
,
error
)
{
panic
(
ErrNotImplement
)
return
o
.
orm
.
alias
.
DbBaser
.
RowsTo
(
o
.
orm
.
db
,
o
,
o
.
mi
,
o
.
cond
,
ptrStruct
,
keyCol
,
valueCol
,
o
.
orm
.
alias
.
TZ
)
}
// create new QuerySeter.
func
newQuerySet
(
orm
*
orm
,
mi
*
modelInfo
)
QuerySeter
{
o
:=
new
(
querySet
)
...
...
orm/orm_raw.go
View file @
846d766
...
...
@@ -518,7 +518,7 @@ func (o *rawSet) QueryRows(containers ...interface{}) (int64, error) {
return
cnt
,
nil
}
func
(
o
*
rawSet
)
readValues
(
container
interface
{})
(
int64
,
error
)
{
func
(
o
*
rawSet
)
readValues
(
container
interface
{}
,
needCols
[]
string
)
(
int64
,
error
)
{
var
(
maps
[]
Params
lists
[]
ParamsList
...
...
@@ -552,20 +552,38 @@ func (o *rawSet) readValues(container interface{}) (int64, error) {
defer
rs
.
Close
()
var
(
refs
[]
interface
{}
cnt
int64
cols
[]
string
refs
[]
interface
{}
cnt
int64
cols
[]
string
indexs
[]
int
)
for
rs
.
Next
()
{
if
cnt
==
0
{
if
columns
,
err
:=
rs
.
Columns
();
err
!=
nil
{
return
0
,
err
}
else
{
if
len
(
needCols
)
>
0
{
indexs
=
make
([]
int
,
0
,
len
(
needCols
))
}
else
{
indexs
=
make
([]
int
,
0
,
len
(
columns
))
}
cols
=
columns
refs
=
make
([]
interface
{},
len
(
cols
))
for
i
,
_
:=
range
refs
{
var
ref
sql
.
NullString
refs
[
i
]
=
&
ref
if
len
(
needCols
)
>
0
{
for
_
,
c
:=
range
needCols
{
if
c
==
cols
[
i
]
{
indexs
=
append
(
indexs
,
i
)
}
}
}
else
{
indexs
=
append
(
indexs
,
i
)
}
}
}
}
...
...
@@ -577,7 +595,8 @@ func (o *rawSet) readValues(container interface{}) (int64, error) {
switch
typ
{
case
1
:
params
:=
make
(
Params
,
len
(
cols
))
for
i
,
ref
:=
range
refs
{
for
_
,
i
:=
range
indexs
{
ref
:=
refs
[
i
]
value
:=
reflect
.
Indirect
(
reflect
.
ValueOf
(
ref
))
.
Interface
()
.
(
sql
.
NullString
)
if
value
.
Valid
{
params
[
cols
[
i
]]
=
value
.
String
...
...
@@ -588,7 +607,8 @@ func (o *rawSet) readValues(container interface{}) (int64, error) {
maps
=
append
(
maps
,
params
)
case
2
:
params
:=
make
(
ParamsList
,
0
,
len
(
cols
))
for
_
,
ref
:=
range
refs
{
for
_
,
i
:=
range
indexs
{
ref
:=
refs
[
i
]
value
:=
reflect
.
Indirect
(
reflect
.
ValueOf
(
ref
))
.
Interface
()
.
(
sql
.
NullString
)
if
value
.
Valid
{
params
=
append
(
params
,
value
.
String
)
...
...
@@ -598,7 +618,8 @@ func (o *rawSet) readValues(container interface{}) (int64, error) {
}
lists
=
append
(
lists
,
params
)
case
3
:
for
_
,
ref
:=
range
refs
{
for
_
,
i
:=
range
indexs
{
ref
:=
refs
[
i
]
value
:=
reflect
.
Indirect
(
reflect
.
ValueOf
(
ref
))
.
Interface
()
.
(
sql
.
NullString
)
if
value
.
Valid
{
list
=
append
(
list
,
value
.
String
)
...
...
@@ -623,19 +644,163 @@ func (o *rawSet) readValues(container interface{}) (int64, error) {
return
cnt
,
nil
}
func
(
o
*
rawSet
)
queryRowsTo
(
container
interface
{},
keyCol
,
valueCol
string
)
(
int64
,
error
)
{
var
(
maps
Params
ind
*
reflect
.
Value
)
typ
:=
0
switch
container
.
(
type
)
{
case
*
Params
:
typ
=
1
default
:
typ
=
2
vl
:=
reflect
.
ValueOf
(
container
)
id
:=
reflect
.
Indirect
(
vl
)
if
vl
.
Kind
()
!=
reflect
.
Ptr
||
id
.
Kind
()
!=
reflect
.
Struct
{
panic
(
fmt
.
Errorf
(
"<RawSeter> RowsTo unsupport type `%T` need ptr struct"
,
container
))
}
ind
=
&
id
}
query
:=
o
.
query
o
.
orm
.
alias
.
DbBaser
.
ReplaceMarks
(
&
query
)
args
:=
getFlatParams
(
nil
,
o
.
args
,
o
.
orm
.
alias
.
TZ
)
var
rs
*
sql
.
Rows
if
r
,
err
:=
o
.
orm
.
db
.
Query
(
query
,
args
...
);
err
!=
nil
{
return
0
,
err
}
else
{
rs
=
r
}
defer
rs
.
Close
()
var
(
refs
[]
interface
{}
cnt
int64
cols
[]
string
)
var
(
keyIndex
=
-
1
valueIndex
=
-
1
)
for
rs
.
Next
()
{
if
cnt
==
0
{
if
columns
,
err
:=
rs
.
Columns
();
err
!=
nil
{
return
0
,
err
}
else
{
cols
=
columns
refs
=
make
([]
interface
{},
len
(
cols
))
for
i
,
_
:=
range
refs
{
if
keyCol
==
cols
[
i
]
{
keyIndex
=
i
}
if
typ
==
1
||
keyIndex
==
i
{
var
ref
sql
.
NullString
refs
[
i
]
=
&
ref
}
else
{
var
ref
interface
{}
refs
[
i
]
=
&
ref
}
if
valueCol
==
cols
[
i
]
{
valueIndex
=
i
}
}
if
keyIndex
==
-
1
||
valueIndex
==
-
1
{
panic
(
fmt
.
Errorf
(
"<RawSeter> RowsTo unknown key, value column name `%s: %s`"
,
keyCol
,
valueCol
))
}
}
}
if
err
:=
rs
.
Scan
(
refs
...
);
err
!=
nil
{
return
0
,
err
}
if
cnt
==
0
{
switch
typ
{
case
1
:
maps
=
make
(
Params
)
}
}
key
:=
reflect
.
Indirect
(
reflect
.
ValueOf
(
refs
[
keyIndex
]))
.
Interface
()
.
(
sql
.
NullString
)
.
String
switch
typ
{
case
1
:
value
:=
reflect
.
Indirect
(
reflect
.
ValueOf
(
refs
[
valueIndex
]))
.
Interface
()
.
(
sql
.
NullString
)
if
value
.
Valid
{
maps
[
key
]
=
value
.
String
}
else
{
maps
[
key
]
=
nil
}
default
:
if
id
:=
ind
.
FieldByName
(
camelString
(
key
));
id
.
IsValid
()
{
o
.
setFieldValue
(
id
,
reflect
.
ValueOf
(
refs
[
valueIndex
])
.
Elem
()
.
Interface
())
}
}
cnt
++
}
if
typ
==
1
{
v
,
_
:=
container
.
(
*
Params
)
*
v
=
maps
}
return
cnt
,
nil
}
// query data to []map[string]interface
func
(
o
*
rawSet
)
Values
(
container
*
[]
Params
)
(
int64
,
error
)
{
return
o
.
readValues
(
container
)
func
(
o
*
rawSet
)
Values
(
container
*
[]
Params
,
cols
...
string
)
(
int64
,
error
)
{
return
o
.
readValues
(
container
,
cols
)
}
// query data to [][]interface
func
(
o
*
rawSet
)
ValuesList
(
container
*
[]
ParamsList
)
(
int64
,
error
)
{
return
o
.
readValues
(
container
)
func
(
o
*
rawSet
)
ValuesList
(
container
*
[]
ParamsList
,
cols
...
string
)
(
int64
,
error
)
{
return
o
.
readValues
(
container
,
cols
)
}
// query data to []interface
func
(
o
*
rawSet
)
ValuesFlat
(
container
*
ParamsList
)
(
int64
,
error
)
{
return
o
.
readValues
(
container
)
func
(
o
*
rawSet
)
ValuesFlat
(
container
*
ParamsList
,
cols
...
string
)
(
int64
,
error
)
{
return
o
.
readValues
(
container
,
cols
)
}
// query all rows into map[string]interface with specify key and value column name.
// keyCol = "name", valueCol = "value"
// table data
// name | value
// total | 100
// found | 200
// to map[string]interface{}{
// "total": 100,
// "found": 200,
// }
func
(
o
*
rawSet
)
RowsToMap
(
result
*
Params
,
keyCol
,
valueCol
string
)
(
int64
,
error
)
{
return
o
.
queryRowsTo
(
result
,
keyCol
,
valueCol
)
}
// query all rows into struct with specify key and value column name.
// keyCol = "name", valueCol = "value"
// table data
// name | value
// total | 100
// found | 200
// to struct {
// Total int
// Found int
// }
func
(
o
*
rawSet
)
RowsToStruct
(
ptrStruct
interface
{},
keyCol
,
valueCol
string
)
(
int64
,
error
)
{
return
o
.
queryRowsTo
(
ptrStruct
,
keyCol
,
valueCol
)
}
// return prepared raw statement for used in times.
...
...
orm/orm_test.go
View file @
846d766
...
...
@@ -1642,3 +1642,41 @@ func TestTransaction(t *testing.T) {
throwFail
(
t
,
AssertIs
(
num
,
1
))
}
func
TestReadOrCreate
(
t
*
testing
.
T
)
{
u
:=
&
User
{
UserName
:
"Kyle"
,
Email
:
"kylemcc@gmail.com"
,
Password
:
"other_pass"
,
Status
:
7
,
IsStaff
:
false
,
IsActive
:
true
,
}
created
,
pk
,
err
:=
dORM
.
ReadOrCreate
(
u
,
"UserName"
)
throwFail
(
t
,
err
)
throwFail
(
t
,
AssertIs
(
created
,
true
))
throwFail
(
t
,
AssertIs
(
u
.
UserName
,
"Kyle"
))
throwFail
(
t
,
AssertIs
(
u
.
Email
,
"kylemcc@gmail.com"
))
throwFail
(
t
,
AssertIs
(
u
.
Password
,
"other_pass"
))
throwFail
(
t
,
AssertIs
(
u
.
Status
,
7
))
throwFail
(
t
,
AssertIs
(
u
.
IsStaff
,
false
))
throwFail
(
t
,
AssertIs
(
u
.
IsActive
,
true
))
throwFail
(
t
,
AssertIs
(
u
.
Created
.
In
(
DefaultTimeLoc
),
u
.
Created
.
In
(
DefaultTimeLoc
),
test_Date
))
throwFail
(
t
,
AssertIs
(
u
.
Updated
.
In
(
DefaultTimeLoc
),
u
.
Updated
.
In
(
DefaultTimeLoc
),
test_DateTime
))
nu
:=
&
User
{
UserName
:
u
.
UserName
,
Email
:
"someotheremail@gmail.com"
}
created
,
pk
,
err
=
dORM
.
ReadOrCreate
(
nu
,
"UserName"
)
throwFail
(
t
,
err
)
throwFail
(
t
,
AssertIs
(
created
,
false
))
throwFail
(
t
,
AssertIs
(
nu
.
Id
,
u
.
Id
))
throwFail
(
t
,
AssertIs
(
pk
,
u
.
Id
))
throwFail
(
t
,
AssertIs
(
nu
.
UserName
,
u
.
UserName
))
throwFail
(
t
,
AssertIs
(
nu
.
Email
,
u
.
Email
))
// should contain the value in the table, not the one specified above
throwFail
(
t
,
AssertIs
(
nu
.
Password
,
u
.
Password
))
throwFail
(
t
,
AssertIs
(
nu
.
Status
,
u
.
Status
))
throwFail
(
t
,
AssertIs
(
nu
.
IsStaff
,
u
.
IsStaff
))
throwFail
(
t
,
AssertIs
(
nu
.
IsActive
,
u
.
IsActive
))
dORM
.
Delete
(
u
)
}
...
...
orm/types.go
View file @
846d766
...
...
@@ -23,6 +23,7 @@ type Fielder interface {
// orm struct
type
Ormer
interface
{
Read
(
interface
{},
...
string
)
error
ReadOrCreate
(
interface
{},
string
,
...
string
)
(
bool
,
int64
,
error
)
Insert
(
interface
{})
(
int64
,
error
)
InsertMulti
(
int
,
interface
{})
(
int64
,
error
)
Update
(
interface
{},
...
string
)
(
int64
,
error
)
...
...
@@ -36,6 +37,7 @@ type Ormer interface {
Rollback
()
error
Raw
(
string
,
...
interface
{})
RawSeter
Driver
()
Driver
GetDB
()
dbQuerier
}
// insert prepared statement
...
...
@@ -63,6 +65,8 @@ type QuerySeter interface {
Values
(
*
[]
Params
,
...
string
)
(
int64
,
error
)
ValuesList
(
*
[]
ParamsList
,
...
string
)
(
int64
,
error
)
ValuesFlat
(
*
ParamsList
,
string
)
(
int64
,
error
)
RowsToMap
(
*
Params
,
string
,
string
)
(
int64
,
error
)
RowsToStruct
(
interface
{},
string
,
string
)
(
int64
,
error
)
}
// model to model query struct
...
...
@@ -86,9 +90,11 @@ type RawSeter interface {
QueryRow
(
...
interface
{})
error
QueryRows
(
...
interface
{})
(
int64
,
error
)
SetArgs
(
...
interface
{})
RawSeter
Values
(
*
[]
Params
)
(
int64
,
error
)
ValuesList
(
*
[]
ParamsList
)
(
int64
,
error
)
ValuesFlat
(
*
ParamsList
)
(
int64
,
error
)
Values
(
*
[]
Params
,
...
string
)
(
int64
,
error
)
ValuesList
(
*
[]
ParamsList
,
...
string
)
(
int64
,
error
)
ValuesFlat
(
*
ParamsList
,
...
string
)
(
int64
,
error
)
RowsToMap
(
*
Params
,
string
,
string
)
(
int64
,
error
)
RowsToStruct
(
interface
{},
string
,
string
)
(
int64
,
error
)
Prepare
()
(
RawPreparer
,
error
)
}
...
...
@@ -108,6 +114,14 @@ type dbQuerier interface {
QueryRow
(
query
string
,
args
...
interface
{})
*
sql
.
Row
}
// type DB interface {
// Begin() (*sql.Tx, error)
// Prepare(query string) (stmtQuerier, error)
// Exec(query string, args ...interface{}) (sql.Result, error)
// Query(query string, args ...interface{}) (*sql.Rows, error)
// QueryRow(query string, args ...interface{}) *sql.Row
// }
// transaction beginner
type
txer
interface
{
Begin
()
(
*
sql
.
Tx
,
error
)
...
...
@@ -138,6 +152,7 @@ type dbBaser interface {
GenerateOperatorLeftCol
(
*
fieldInfo
,
string
,
*
string
)
PrepareInsert
(
dbQuerier
,
*
modelInfo
)
(
stmtQuerier
,
string
,
error
)
ReadValues
(
dbQuerier
,
*
querySet
,
*
modelInfo
,
*
Condition
,
[]
string
,
interface
{},
*
time
.
Location
)
(
int64
,
error
)
RowsTo
(
dbQuerier
,
*
querySet
,
*
modelInfo
,
*
Condition
,
interface
{},
string
,
string
,
*
time
.
Location
)
(
int64
,
error
)
MaxLimit
()
uint64
TableQuote
()
string
ReplaceMarks
(
*
string
)
...
...
session/sess_cookie.go
View file @
846d766
...
...
@@ -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
}
...
...
session/sess_file.go
View file @
846d766
...
...
@@ -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
...
...
session/sess_mem.go
View file @
846d766
...
...
@@ -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
()
...
...
session/sess_mysql.go
View file @
846d766
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
()
...
...
session/sess_redis.go
View file @
846d766
...
...
@@ -11,18 +11,21 @@ import (
var
redispder
=
&
RedisProvider
{}
// redis max pool size
var
MAX_POOL_SIZE
=
100
var
redisPool
chan
redis
.
Conn
// redis session store
type
RedisSessionStore
struct
{
c
redis
.
Conn
p
*
redis
.
Pool
sid
string
lock
sync
.
RWMutex
values
map
[
interface
{}]
interface
{}
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,20 +61,31 @@ 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
)
{
defer
rs
.
c
.
Close
()
c
:=
rs
.
p
.
Get
()
defer
c
.
Close
()
// if rs.values is empty, return directly
if
len
(
rs
.
values
)
<
1
{
c
.
Do
(
"DEL"
,
rs
.
sid
)
return
}
b
,
err
:=
encodeGob
(
rs
.
values
)
if
err
!=
nil
{
return
}
rs
.
c
.
Do
(
"SET"
,
rs
.
sid
,
string
(
b
))
rs
.
c
.
Do
(
"EXPIRE"
,
rs
.
sid
,
rs
.
maxlifetime
)
c
.
Do
(
"SET"
,
rs
.
sid
,
string
(
b
),
"EX"
,
rs
.
maxlifetime
)
}
// redis session provider
type
RedisProvider
struct
{
maxlifetime
int64
savePath
string
...
...
@@ -77,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
,
","
)
...
...
@@ -114,12 +132,11 @@ 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
()
if
existed
,
err
:=
redis
.
Int
(
c
.
Do
(
"EXISTS"
,
sid
));
err
!=
nil
||
existed
==
0
{
c
.
Do
(
"SET"
,
sid
)
}
c
.
Do
(
"EXPIRE"
,
sid
,
rp
.
maxlifetime
)
defer
c
.
Close
()
kvs
,
err
:=
redis
.
String
(
c
.
Do
(
"GET"
,
sid
))
var
kv
map
[
interface
{}]
interface
{}
if
len
(
kvs
)
==
0
{
...
...
@@ -130,13 +147,16 @@ func (rp *RedisProvider) SessionRead(sid string) (SessionStore, error) {
return
nil
,
err
}
}
rs
:=
&
RedisSessionStore
{
c
:
c
,
sid
:
sid
,
values
:
kv
,
maxlifetime
:
rp
.
maxlifetime
}
rs
:=
&
RedisSessionStore
{
p
:
rp
.
poollist
,
sid
:
sid
,
values
:
kv
,
maxlifetime
:
rp
.
maxlifetime
}
return
rs
,
nil
}
// check redis session exist by sid
func
(
rp
*
RedisProvider
)
SessionExist
(
sid
string
)
bool
{
c
:=
rp
.
poollist
.
Get
()
defer
c
.
Close
()
if
existed
,
err
:=
redis
.
Int
(
c
.
Do
(
"EXISTS"
,
sid
));
err
!=
nil
||
existed
==
0
{
return
false
}
else
{
...
...
@@ -144,13 +164,21 @@ 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
()
if
existed
,
err
:=
redis
.
Int
(
c
.
Do
(
"EXISTS"
,
oldsid
));
err
!=
nil
||
existed
==
0
{
c
.
Do
(
"SET"
,
oldsid
)
defer
c
.
Close
()
if
existed
,
_
:=
redis
.
Int
(
c
.
Do
(
"EXISTS"
,
oldsid
));
existed
==
0
{
// oldsid doesn't exists, set the new sid directly
// ignore error here, since if it return error
// the existed value will be 0
c
.
Do
(
"SET"
,
sid
,
""
,
"EX"
,
rp
.
maxlifetime
)
}
else
{
c
.
Do
(
"RENAME"
,
oldsid
,
sid
)
c
.
Do
(
"EXPIRE"
,
sid
,
rp
.
maxlifetime
)
}
c
.
Do
(
"RENAME"
,
oldsid
,
sid
)
c
.
Do
(
"EXPIRE"
,
sid
,
rp
.
maxlifetime
)
kvs
,
err
:=
redis
.
String
(
c
.
Do
(
"GET"
,
sid
))
var
kv
map
[
interface
{}]
interface
{}
if
len
(
kvs
)
==
0
{
...
...
@@ -161,24 +189,27 @@ func (rp *RedisProvider) SessionRegenerate(oldsid, sid string) (SessionStore, er
return
nil
,
err
}
}
rs
:=
&
RedisSessionStore
{
c
:
c
,
sid
:
sid
,
values
:
kv
,
maxlifetime
:
rp
.
maxlifetime
}
rs
:=
&
RedisSessionStore
{
p
:
rp
.
poollist
,
sid
:
sid
,
values
:
kv
,
maxlifetime
:
rp
.
maxlifetime
}
return
rs
,
nil
}
// delete redis session by id
func
(
rp
*
RedisProvider
)
SessionDestroy
(
sid
string
)
error
{
c
:=
rp
.
poollist
.
Get
()
defer
c
.
Close
()
c
.
Do
(
"DEL"
,
sid
)
return
nil
}
// Impelment method, no used.
func
(
rp
*
RedisProvider
)
SessionGC
()
{
return
}
//@todo
//
@todo
func
(
rp
*
RedisProvider
)
SessionAll
()
int
{
return
0
}
...
...
session/session.go
View file @
846d766
...
...
@@ -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
{
...
...
toolbox/debug.go
View file @
846d766
...
...
@@ -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
{
...
...
toolbox/healthcheck.go
View file @
846d766
...
...
@@ -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
}
...
...
toolbox/profile.go
View file @
846d766
...
...
@@ -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
:
...
...
toolbox/statistics.go
View file @
846d766
...
...
@@ -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
()
{
...
...
toolbox/task.go
View file @
846d766
...
...
@@ -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
)
}
...
...
Write
Preview
Styling with
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment