mirror of
https://gitee.com/johng/gf
synced 2026-06-25 09:15:41 +08:00
Merge branch 'master' of https://gitee.com/wenzi1/gf
This commit is contained in:
6
TODO
6
TODO
@ -8,6 +8,11 @@ orm增加更多数据库支持;
|
||||
增加可选择性的orm tag特性,用以数据表记录与struct对象转换的键名属性映射;
|
||||
ghttp.Response增加输出内容后自动退出当前请求机制,不需要用户手动return,参考beego如何实现;
|
||||
Cookie&Session数据池化处理;
|
||||
ghttp.Client增加proxy特性;
|
||||
gtime增加对时区转换的封装,并简化失去转换时对类似+80500时区的支持;
|
||||
改进gf-orm的where查询功能,参考thinkphp 里的where查询语法;
|
||||
gproc进程间通信增加分组特性,不同的进程见可以通过进程ID以及分组名称发送/获取消息;
|
||||
|
||||
|
||||
DONE:
|
||||
1. gconv完善针对不同类型的判断,例如:尽量减少sprintf("%v", xxx)来执行string类型的转换;
|
||||
@ -35,6 +40,7 @@ DONE:
|
||||
23. 平滑重启机制改进,以便于开发阶段调试;
|
||||
24. 对grpool进行优化改进,包括属性原子操作封装采用gtype实现,修正设计BUG:https://github.com/johng-cn/gf/issues/6;
|
||||
25. gredis增加redis密码支持;
|
||||
26. 改进ghttp.Server平滑重启机制,当新进程接管服务后,再使用进程间通信方式通知父进程销毁;
|
||||
|
||||
|
||||
|
||||
|
||||
@ -40,39 +40,40 @@ func NewIntArray(size int, cap ... int) *IntArray {
|
||||
// 获取指定索引的数据项, 调用方注意判断数组边界
|
||||
func (a *IntArray) Get(index int) int {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
value := a.array[index]
|
||||
a.mu.RUnlock()
|
||||
return value
|
||||
}
|
||||
|
||||
// 设置指定索引的数据项, 调用方注意判断数组边界
|
||||
func (a *IntArray) Set(index int, value int) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.RUnlock()
|
||||
a.array[index] = value
|
||||
a.mu.Unlock()
|
||||
}
|
||||
|
||||
// 在当前索引位置前插入一个数据项, 调用方注意判断数组边界
|
||||
func (a *IntArray) Insert(index int, value int) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.RUnlock()
|
||||
rear := append([]int{}, a.array[index : ]...)
|
||||
a.array = append(a.array[0 : index], value)
|
||||
a.array = append(a.array, rear...)
|
||||
a.mu.Unlock()
|
||||
|
||||
}
|
||||
|
||||
// 删除指定索引的数据项, 调用方注意判断数组边界
|
||||
func (a *IntArray) Remove(index int) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.RUnlock()
|
||||
a.array = append(a.array[ : index], a.array[index + 1 : ]...)
|
||||
a.mu.Unlock()
|
||||
}
|
||||
|
||||
// 追加数据项
|
||||
func (a *IntArray) Append(value int) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.RUnlock()
|
||||
a.array = append(a.array, value)
|
||||
a.mu.Unlock()
|
||||
}
|
||||
|
||||
// 数组长度
|
||||
@ -94,12 +95,12 @@ func (a *IntArray) Slice() []int {
|
||||
// 清空数据数组
|
||||
func (a *IntArray) Clear() {
|
||||
a.mu.Lock()
|
||||
defer a.mu.RUnlock()
|
||||
if a.cap > 0 {
|
||||
a.array = make([]int, a.size, a.cap)
|
||||
} else {
|
||||
a.array = make([]int, a.size)
|
||||
}
|
||||
a.mu.Unlock()
|
||||
}
|
||||
|
||||
// 查找指定数值的索引位置,返回索引位置,如果查找不到则返回-1
|
||||
@ -140,13 +141,13 @@ func (a *IntArray) Search(value int) int {
|
||||
// 使用自定义方法执行加锁修改操作
|
||||
func (a *IntArray) LockFunc(f func(array []int)) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
f(a.array)
|
||||
a.mu.Unlock()
|
||||
}
|
||||
|
||||
// 使用自定义方法执行加锁读取操作
|
||||
func (a *IntArray) RLockFunc(f func(array []int)) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.Unlock()
|
||||
f(a.array)
|
||||
a.mu.RUnlock()
|
||||
}
|
||||
}
|
||||
@ -30,32 +30,32 @@ func NewArray(size int, cap ... int) *Array {
|
||||
// 获取指定索引的数据项, 调用方注意判断数组边界
|
||||
func (a *Array) Get(index int) interface{} {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
value := a.array[index]
|
||||
a.mu.RUnlock()
|
||||
return value
|
||||
}
|
||||
|
||||
// 设置指定索引的数据项, 调用方注意判断数组边界
|
||||
func (a *Array) Set(index int, value interface{}) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
a.array[index] = value
|
||||
a.mu.Unlock()
|
||||
}
|
||||
|
||||
// 在当前索引位置前插入一个数据项, 调用方注意判断数组边界
|
||||
func (a *Array) Insert(index int, value interface{}) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
rear := append([]interface{}{}, a.array[index : ]...)
|
||||
a.array = append(a.array[0 : index], value)
|
||||
a.array = append(a.array, rear...)
|
||||
a.mu.Unlock()
|
||||
}
|
||||
|
||||
// 删除指定索引的数据项, 调用方注意判断数组边界
|
||||
func (a *Array) Remove(index int) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
a.array = append(a.array[ : index], a.array[index + 1 : ]...)
|
||||
a.mu.Unlock()
|
||||
}
|
||||
|
||||
// 追加数据项
|
||||
|
||||
@ -70,16 +70,16 @@ func (a *SortedIntArray) Add(value int) {
|
||||
// 获取指定索引的数据项, 调用方注意判断数组边界
|
||||
func (a *SortedIntArray) Get(index int) int {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
value := a.array[index]
|
||||
a.mu.RUnlock()
|
||||
return value
|
||||
}
|
||||
|
||||
// 删除指定索引的数据项, 调用方注意判断数组边界
|
||||
func (a *SortedIntArray) Remove(index int) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
a.array = append(a.array[ : index], a.array[index + 1 : ]...)
|
||||
a.mu.Unlock()
|
||||
}
|
||||
|
||||
// 数组长度
|
||||
|
||||
@ -55,16 +55,16 @@ func (a *SortedArray) Add(value interface{}) {
|
||||
// 获取指定索引的数据项, 调用方注意判断数组边界
|
||||
func (a *SortedArray) Get(index int) interface{} {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
value := a.array[index]
|
||||
a.mu.RUnlock()
|
||||
return value
|
||||
}
|
||||
|
||||
// 删除指定索引的数据项, 调用方注意判断数组边界
|
||||
func (a *SortedArray) Remove(index int) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
a.array = append(a.array[ : index], a.array[index + 1 : ]...)
|
||||
a.mu.Unlock()
|
||||
}
|
||||
|
||||
// 数组长度
|
||||
|
||||
@ -65,16 +65,16 @@ func (a *SortedStringArray) Add(value string) {
|
||||
// 获取指定索引的数据项, 调用方注意判断数组边界
|
||||
func (a *SortedStringArray) Get(index int) string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
value := a.array[index]
|
||||
a.mu.RUnlock()
|
||||
return value
|
||||
}
|
||||
|
||||
// 删除指定索引的数据项, 调用方注意判断数组边界
|
||||
func (a *SortedStringArray) Remove(index int) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
a.array = append(a.array[ : index], a.array[index + 1 : ]...)
|
||||
a.mu.Unlock()
|
||||
}
|
||||
|
||||
// 数组长度
|
||||
|
||||
@ -6,25 +6,24 @@
|
||||
|
||||
// go test *.go -bench=".*"
|
||||
|
||||
package gmap_test
|
||||
package gmap
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"gitee.com/johng/gf/g/container/gmap"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
|
||||
var ibm = gmap.NewIntBoolMap()
|
||||
var iim = gmap.NewIntIntMap()
|
||||
var iifm = gmap.NewIntInterfaceMap()
|
||||
var ism = gmap.NewIntStringMap()
|
||||
var ififm = gmap.NewInterfaceInterfaceMap()
|
||||
var sbm = gmap.NewStringBoolMap()
|
||||
var sim = gmap.NewStringIntMap()
|
||||
var sifm = gmap.NewStringInterfaceMap()
|
||||
var ssm = gmap.NewStringStringMap()
|
||||
var uifm = gmap.NewUintInterfaceMap()
|
||||
var ibm = NewIntBoolMap()
|
||||
var iim = NewIntIntMap()
|
||||
var iifm = NewIntInterfaceMap()
|
||||
var ism = NewIntStringMap()
|
||||
var ififm = NewInterfaceInterfaceMap()
|
||||
var sbm = NewStringBoolMap()
|
||||
var sim = NewStringIntMap()
|
||||
var sifm = NewStringInterfaceMap()
|
||||
var ssm = NewStringStringMap()
|
||||
var uifm = NewUintInterfaceMap()
|
||||
|
||||
func BenchmarkIntBoolMap_Set(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
@ -148,7 +148,7 @@ func (this *IntIntMap) Size() int {
|
||||
// 哈希表是否为空
|
||||
func (this *IntIntMap) IsEmpty() bool {
|
||||
this.mu.RLock()
|
||||
empty := (len(this.m) == 0)
|
||||
empty := len(this.m) == 0
|
||||
this.mu.RUnlock()
|
||||
return empty
|
||||
}
|
||||
|
||||
@ -9,7 +9,6 @@ package gmap
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"gitee.com/johng/gf/g/util/gconv"
|
||||
)
|
||||
|
||||
type IntInterfaceMap struct {
|
||||
@ -81,30 +80,6 @@ func (this *IntInterfaceMap) GetWithDefault(key int, value interface{}) interfac
|
||||
return val
|
||||
}
|
||||
|
||||
func (this *IntInterfaceMap) GetBool(key int) bool {
|
||||
return gconv.Bool(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *IntInterfaceMap) GetInt(key int) int {
|
||||
return gconv.Int(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *IntInterfaceMap) GetUint (key int) uint {
|
||||
return gconv.Uint(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *IntInterfaceMap) GetFloat32 (key int) float32 {
|
||||
return gconv.Float32(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *IntInterfaceMap) GetFloat64 (key int) float64 {
|
||||
return gconv.Float64(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *IntInterfaceMap) GetString (key int) string {
|
||||
return gconv.String(this.Get(key))
|
||||
}
|
||||
|
||||
// 删除键值对
|
||||
func (this *IntInterfaceMap) Remove(key int) {
|
||||
this.mu.Lock()
|
||||
|
||||
@ -9,7 +9,6 @@ package gmap
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"gitee.com/johng/gf/g/util/gconv"
|
||||
)
|
||||
|
||||
type InterfaceInterfaceMap struct {
|
||||
@ -81,30 +80,6 @@ func (this *InterfaceInterfaceMap) GetWithDefault(key interface{}, value interfa
|
||||
return val
|
||||
}
|
||||
|
||||
func (this *InterfaceInterfaceMap) GetBool(key interface{}) bool {
|
||||
return gconv.Bool(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *InterfaceInterfaceMap) GetInt(key interface{}) int {
|
||||
return gconv.Int(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *InterfaceInterfaceMap) GetUint (key interface{}) uint {
|
||||
return gconv.Uint(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *InterfaceInterfaceMap) GetFloat32 (key interface{}) float32 {
|
||||
return gconv.Float32(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *InterfaceInterfaceMap) GetFloat64 (key interface{}) float64 {
|
||||
return gconv.Float64(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *InterfaceInterfaceMap) GetString (key interface{}) string {
|
||||
return gconv.String(this.Get(key))
|
||||
}
|
||||
|
||||
// 删除键值对
|
||||
func (this *InterfaceInterfaceMap) Remove(key interface{}) {
|
||||
this.mu.Lock()
|
||||
|
||||
@ -9,7 +9,6 @@ package gmap
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"gitee.com/johng/gf/g/util/gconv"
|
||||
)
|
||||
|
||||
type StringInterfaceMap struct {
|
||||
@ -81,30 +80,6 @@ func (this *StringInterfaceMap) GetWithDefault(key string, value interface{}) in
|
||||
return val
|
||||
}
|
||||
|
||||
func (this *StringInterfaceMap) GetBool(key string) bool {
|
||||
return gconv.Bool(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *StringInterfaceMap) GetInt(key string) int {
|
||||
return gconv.Int(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *StringInterfaceMap) GetUint (key string) uint {
|
||||
return gconv.Uint(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *StringInterfaceMap) GetFloat32 (key string) float32 {
|
||||
return gconv.Float32(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *StringInterfaceMap) GetFloat64 (key string) float64 {
|
||||
return gconv.Float64(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *StringInterfaceMap) GetString (key string) string {
|
||||
return gconv.String(this.Get(key))
|
||||
}
|
||||
|
||||
// 删除键值对
|
||||
func (this *StringInterfaceMap) Remove(key string) {
|
||||
this.mu.Lock()
|
||||
|
||||
@ -9,7 +9,6 @@ package gmap
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"gitee.com/johng/gf/g/util/gconv"
|
||||
)
|
||||
|
||||
type UintInterfaceMap struct {
|
||||
@ -80,30 +79,6 @@ func (this *UintInterfaceMap) GetWithDefault(key uint, value interface{}) interf
|
||||
return val
|
||||
}
|
||||
|
||||
func (this *UintInterfaceMap) GetBool(key uint) bool {
|
||||
return gconv.Bool(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *UintInterfaceMap) GetInt(key uint) int {
|
||||
return gconv.Int(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *UintInterfaceMap) GetUint (key uint) uint {
|
||||
return gconv.Uint(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *UintInterfaceMap) GetFloat32 (key uint) float32 {
|
||||
return gconv.Float32(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *UintInterfaceMap) GetFloat64 (key uint) float64 {
|
||||
return gconv.Float64(this.Get(key))
|
||||
}
|
||||
|
||||
func (this *UintInterfaceMap) GetString (key uint) string {
|
||||
return gconv.String(this.Get(key))
|
||||
}
|
||||
|
||||
// 删除键值对
|
||||
func (this *UintInterfaceMap) Remove(key uint) {
|
||||
this.mu.Lock()
|
||||
|
||||
@ -234,7 +234,7 @@ func (db *Db) insert(table string, data Map, option uint8) (sql.Result, error) {
|
||||
for k, v := range data {
|
||||
fields = append(fields, db.charl + k + db.charr)
|
||||
values = append(values, "?")
|
||||
params = append(params, v)
|
||||
params = append(params, gconv.String(v))
|
||||
}
|
||||
operation := db.getInsertOperationByOption(option)
|
||||
updatestr := ""
|
||||
@ -247,7 +247,10 @@ func (db *Db) insert(table string, data Map, option uint8) (sql.Result, error) {
|
||||
}
|
||||
return db.Exec(
|
||||
fmt.Sprintf("%s INTO %s%s%s(%s) VALUES(%s) %s",
|
||||
operation, db.charl, table, db.charr, strings.Join(fields, ","), strings.Join(values, ","), updatestr), params...
|
||||
operation, db.charl, table, db.charr, strings.Join(fields, ","),
|
||||
strings.Join(values, ","),
|
||||
updatestr),
|
||||
params...
|
||||
)
|
||||
}
|
||||
|
||||
@ -283,35 +286,43 @@ func (db *Db) batchInsert(table string, list List, batch int, option uint8) (sql
|
||||
keys = append(keys, k)
|
||||
values = append(values, "?")
|
||||
}
|
||||
var kstr = db.charl + strings.Join(keys, db.charl + "," + db.charr) + db.charr
|
||||
keyStr := db.charl + strings.Join(keys, db.charl + "," + db.charr) + db.charr
|
||||
valueHolderStr := "(" + strings.Join(values, ",") + ")"
|
||||
// 操作判断
|
||||
operation := db.getInsertOperationByOption(option)
|
||||
updatestr := ""
|
||||
if option == OPTION_SAVE {
|
||||
var updates []string
|
||||
for _, k := range keys {
|
||||
updates = append(updates, fmt.Sprintf("%s=VALUES(%s)", db.charl, k, db.charr, k))
|
||||
updates = append(updates, fmt.Sprintf("%s%s%s=VALUES(%s)", db.charl, k, db.charr, k))
|
||||
}
|
||||
updatestr = fmt.Sprintf(" ON DUPLICATE KEY UPDATE %s", strings.Join(updates, ","))
|
||||
}
|
||||
// 构造批量写入数据格式(注意map的遍历是无序的)
|
||||
for i := 0; i < size; i++ {
|
||||
for _, k := range keys {
|
||||
params = append(params, list[i][k])
|
||||
params = append(params, gconv.String(list[i][k]))
|
||||
}
|
||||
bvalues = append(bvalues, "(" + strings.Join(values, ",") + ")")
|
||||
bvalues = append(bvalues, valueHolderStr)
|
||||
if len(bvalues) == batch {
|
||||
r, err := db.Exec(fmt.Sprintf("%s INTO %s%s%s(%s) VALUES%s %s", operation, db.charl, table, db.charr, kstr, strings.Join(bvalues, ","), updatestr), params...)
|
||||
r, err := db.Exec(fmt.Sprintf("%s INTO %s%s%s(%s) VALUES%s %s",
|
||||
operation, db.charl, table, db.charr, keyStr, strings.Join(bvalues, ","),
|
||||
updatestr),
|
||||
params...)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
result = r
|
||||
params = params[:0]
|
||||
bvalues = bvalues[:0]
|
||||
}
|
||||
}
|
||||
// 处理最后不构成指定批量的数据
|
||||
if len(bvalues) > 0 {
|
||||
r, err := db.Exec(fmt.Sprintf("%s INTO %s%s%s(%s) VALUES%s %s", operation, db.charl, table, db.charr, kstr, strings.Join(bvalues, ","), updatestr), params...)
|
||||
r, err := db.Exec(fmt.Sprintf("%s INTO %s%s%s(%s) VALUES%s %s",
|
||||
operation, db.charl, table, db.charr, keyStr, strings.Join(bvalues, ","),
|
||||
updatestr),
|
||||
params...)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
@ -169,7 +169,7 @@ func (tx *Tx) insert(table string, data Map, option uint8) (sql.Result, error) {
|
||||
for k, v := range data {
|
||||
keys = append(keys, tx.db.charl + k + tx.db.charr)
|
||||
values = append(values, "?")
|
||||
params = append(params, v)
|
||||
params = append(params, gconv.String(v))
|
||||
}
|
||||
operation := tx.db.getInsertOperationByOption(option)
|
||||
updatestr := ""
|
||||
@ -182,7 +182,10 @@ func (tx *Tx) insert(table string, data Map, option uint8) (sql.Result, error) {
|
||||
}
|
||||
return tx.Exec(
|
||||
fmt.Sprintf("%s INTO %s%s%s(%s) VALUES(%s) %s",
|
||||
operation, tx.db.charl, table, tx.db.charr, strings.Join(keys, ","), strings.Join(values, ","), updatestr), params...
|
||||
operation, tx.db.charl, table, tx.db.charr, strings.Join(keys, ","),
|
||||
strings.Join(values, ","),
|
||||
updatestr),
|
||||
params...
|
||||
)
|
||||
}
|
||||
|
||||
@ -218,35 +221,43 @@ func (tx *Tx) batchInsert(table string, list List, batch int, option uint8) (sql
|
||||
keys = append(keys, k)
|
||||
values = append(values, "?")
|
||||
}
|
||||
var kstr = tx.db.charl + strings.Join(keys, tx.db.charl + "," + tx.db.charr) + tx.db.charr
|
||||
keyStr := tx.db.charl + strings.Join(keys, tx.db.charl + "," + tx.db.charr) + tx.db.charr
|
||||
valueHolderStr := "(" + strings.Join(values, ",") + ")"
|
||||
// 操作判断
|
||||
operation := tx.db.getInsertOperationByOption(option)
|
||||
updatestr := ""
|
||||
if option == OPTION_SAVE {
|
||||
var updates []string
|
||||
for _, k := range keys {
|
||||
updates = append(updates, fmt.Sprintf("%s=VALUES(%s)", tx.db.charl, k, tx.db.charr, k))
|
||||
updates = append(updates, fmt.Sprintf("%s%s%s=VALUES(%s)", tx.db.charl, k, tx.db.charr, k))
|
||||
}
|
||||
updatestr = fmt.Sprintf(" ON DUPLICATE KEY UPDATE %s", strings.Join(updates, ","))
|
||||
}
|
||||
// 构造批量写入数据格式(注意map的遍历是无序的)
|
||||
for i := 0; i < size; i++ {
|
||||
for _, k := range keys {
|
||||
params = append(params, list[i][k])
|
||||
params = append(params, gconv.String(list[i][k]))
|
||||
}
|
||||
bvalues = append(bvalues, "(" + strings.Join(values, ",") + ")")
|
||||
bvalues = append(bvalues, valueHolderStr)
|
||||
if len(bvalues) == batch {
|
||||
r, err := tx.Exec(fmt.Sprintf("%s INTO %s%s%s(%s) VALUES%s %s", operation, tx.db.charl, table, tx.db.charr, kstr, strings.Join(bvalues, ","), updatestr), params...)
|
||||
r, err := tx.Exec(fmt.Sprintf("%s INTO %s%s%s(%s) VALUES%s %s",
|
||||
operation, tx.db.charl, table, tx.db.charr, keyStr, strings.Join(bvalues, ","),
|
||||
updatestr),
|
||||
params...)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
result = r
|
||||
params = params[:0]
|
||||
bvalues = bvalues[:0]
|
||||
}
|
||||
}
|
||||
// 处理最后不构成指定批量的数据
|
||||
if len(bvalues) > 0 {
|
||||
r, err := tx.Exec(fmt.Sprintf("%s INTO %s%s%s(%s) VALUES%s %s", operation, tx.db.charl, table, tx.db.charr, kstr, strings.Join(bvalues, ","), updatestr), params...)
|
||||
r, err := tx.Exec(fmt.Sprintf("%s INTO %s%s%s(%s) VALUES%s %s",
|
||||
operation, tx.db.charl, table, tx.db.charr, keyStr, strings.Join(bvalues, ","),
|
||||
updatestr),
|
||||
params...)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ import (
|
||||
"gitee.com/johng/gf/g/encoding/gyaml"
|
||||
"gitee.com/johng/gf/g/encoding/gtoml"
|
||||
"gitee.com/johng/gf/g/util/gstr"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -32,7 +33,7 @@ type Json struct {
|
||||
mu sync.RWMutex
|
||||
p *interface{} // 注意这是一个指针
|
||||
c byte // 层级分隔符,默认为"."
|
||||
vc bool // 是否执行分隔符冲突检测(默认为true,检测会比较影响检索效率)
|
||||
vc bool // 层级检索是否执行分隔符冲突检测(默认为false,检测会比较影响检索效率)
|
||||
}
|
||||
|
||||
// 将变量转换为Json对象进行处理,该变量至少应当是一个map或者array,否者转换没有意义
|
||||
@ -42,13 +43,13 @@ func New(value interface{}) *Json {
|
||||
return &Json{
|
||||
p : &value,
|
||||
c : byte(gDEFAULT_SPLIT_CHAR),
|
||||
vc : true ,
|
||||
vc : false ,
|
||||
}
|
||||
case []interface{}:
|
||||
return &Json{
|
||||
p : &value,
|
||||
c : byte(gDEFAULT_SPLIT_CHAR),
|
||||
vc : true ,
|
||||
vc : false ,
|
||||
}
|
||||
default:
|
||||
// 这里效率会比较低
|
||||
@ -57,7 +58,7 @@ func New(value interface{}) *Json {
|
||||
return &Json{
|
||||
p : &v,
|
||||
c : byte(gDEFAULT_SPLIT_CHAR),
|
||||
vc : true,
|
||||
vc : false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -101,9 +102,13 @@ func Load (path string) (*Json, error) {
|
||||
}
|
||||
|
||||
// 支持的配置文件格式:xml, json, yaml/yml, toml
|
||||
func LoadContent (data []byte, t string) (*Json, error) {
|
||||
func LoadContent (data []byte, dataType...string) (*Json, error) {
|
||||
var err error
|
||||
var result interface{}
|
||||
t := "json"
|
||||
if len(dataType) > 0 {
|
||||
t = dataType[0]
|
||||
}
|
||||
switch t {
|
||||
case "xml": fallthrough
|
||||
case ".xml":
|
||||
@ -140,7 +145,8 @@ func (j *Json) SetSplitChar(char byte) {
|
||||
j.mu.Unlock()
|
||||
}
|
||||
|
||||
// 设置自定义的层级分隔符号
|
||||
// 设置是否执行层级冲突检查,当键名中存在层级符号时需要开启该特性,默认为关闭。
|
||||
// 开启比较耗性能,也不建议允许键名中存在分隔符,最好在应用端避免这种情况。
|
||||
func (j *Json) SetViolenceCheck(check bool) {
|
||||
j.mu.Lock()
|
||||
j.vc = check
|
||||
@ -201,6 +207,19 @@ func (j *Json) GetString(pattern string) string {
|
||||
return gconv.String(j.Get(pattern))
|
||||
}
|
||||
|
||||
// 返回指定json中的strings(转换为[]string数组)
|
||||
func (j *Json) GetStrings(pattern string) []string {
|
||||
return gconv.Strings(j.Get(pattern))
|
||||
}
|
||||
|
||||
func (j *Json) GetTime(pattern string, format ... string) time.Time {
|
||||
return gconv.Time(j.Get(pattern), format...)
|
||||
}
|
||||
|
||||
func (j *Json) GetTimeDuration(pattern string) time.Duration {
|
||||
return gconv.TimeDuration(j.Get(pattern))
|
||||
}
|
||||
|
||||
// 返回指定json中的bool(false:"", 0, false, off)
|
||||
func (j *Json) GetBool(pattern string) bool {
|
||||
return gconv.Bool(j.Get(pattern))
|
||||
@ -456,18 +475,22 @@ func (j *Json) setPointerWithValue(pointer *interface{}, key string, value inter
|
||||
return pointer
|
||||
}
|
||||
|
||||
// 根据约定字符串方式访问json解析数据,参数形如: "items.name.first", "list.0"
|
||||
// 返回的结果类型的interface{},因此需要自己做类型转换
|
||||
// 如果找不到对应节点的数据,返回nil
|
||||
func (j *Json) Get(pattern string) interface{} {
|
||||
// 根据约定字符串方式访问json解析数据,参数形如: "items.name.first", "list.0"; 当pattern为空时,表示获取所有数据;
|
||||
// 返回的结果类型的interface{},因此需要自己做类型转换;
|
||||
// 如果找不到对应节点的数据,返回nil;
|
||||
func (j *Json) Get(pattern...string) interface{} {
|
||||
j.mu.RLock()
|
||||
defer j.mu.RUnlock()
|
||||
|
||||
queryPattern := ""
|
||||
if len(pattern) > 0 {
|
||||
queryPattern = pattern[0]
|
||||
}
|
||||
var result *interface{}
|
||||
if j.vc {
|
||||
result = j.getPointerByPattern(pattern)
|
||||
result = j.getPointerByPattern(queryPattern)
|
||||
} else {
|
||||
result = j.getPointerByPatternWithoutSplitCharViolenceCheck(pattern)
|
||||
result = j.getPointerByPatternWithoutSplitCharViolenceCheck(queryPattern)
|
||||
}
|
||||
if result != nil {
|
||||
return *result
|
||||
|
||||
@ -9,6 +9,7 @@ package gparser
|
||||
|
||||
import (
|
||||
"gitee.com/johng/gf/g/encoding/gjson"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Parser struct {
|
||||
@ -32,9 +33,9 @@ func Load (path string) (*Parser, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// 支持的配置文件格式:xml, json, yaml/yml, toml
|
||||
func LoadContent (data []byte, fileType string) (*Parser, error) {
|
||||
if j, e := gjson.LoadContent(data, fileType); e == nil {
|
||||
// 支持的数据内容格式:json(默认), xml, yaml/yml, toml
|
||||
func LoadContent (data []byte, dataType...string) (*Parser, error) {
|
||||
if j, e := gjson.LoadContent(data, dataType...); e == nil {
|
||||
return &Parser{j}, nil
|
||||
} else {
|
||||
return nil, e
|
||||
@ -46,9 +47,10 @@ func (p *Parser) SetSplitChar(char byte) {
|
||||
p.json.SetSplitChar(char)
|
||||
}
|
||||
|
||||
// 设置自定义的层级分隔符号
|
||||
// 设置是否执行层级冲突检查,当键名中存在层级符号时需要开启该特性,默认为关闭。
|
||||
// 开启比较耗性能,也不建议允许键名中存在分隔符,最好在应用端避免这种情况。
|
||||
func (p *Parser) SetViolenceCheck(check bool) {
|
||||
p.SetViolenceCheck(check)
|
||||
p.json.SetViolenceCheck(check)
|
||||
}
|
||||
|
||||
// 将指定的json内容转换为指定结构返回,查找失败或者转换失败,目标对象转换为nil
|
||||
@ -74,6 +76,18 @@ func (p *Parser) GetString(pattern string) string {
|
||||
return p.json.GetString(pattern)
|
||||
}
|
||||
|
||||
func (p *Parser) GetStrings(pattern string) []string {
|
||||
return p.json.GetStrings(pattern)
|
||||
}
|
||||
|
||||
func (p *Parser) GetTime(pattern string, format ... string) time.Time {
|
||||
return p.json.GetTime(pattern, format...)
|
||||
}
|
||||
|
||||
func (p *Parser) GetTimeDuration(pattern string) time.Duration {
|
||||
return p.json.GetTimeDuration(pattern)
|
||||
}
|
||||
|
||||
// 返回指定json中的bool(false:"", 0, false, off)
|
||||
func (p *Parser) GetBool(pattern string) bool {
|
||||
return p.json.GetBool(pattern)
|
||||
@ -138,11 +152,11 @@ func (p *Parser) Remove(pattern string) error {
|
||||
return p.json.Remove(pattern)
|
||||
}
|
||||
|
||||
// 根据约定字符串方式访问json解析数据,参数形如: "items.name.first", "list.0"
|
||||
// 返回的结果类型的interface{},因此需要自己做类型转换
|
||||
// 如果找不到对应节点的数据,返回nil
|
||||
func (p *Parser) Get(pattern string) interface{} {
|
||||
return p.json.Get(pattern)
|
||||
// 根据约定字符串方式访问json解析数据,参数形如: "items.name.first", "list.0"; 当pattern为空时,表示获取所有数据
|
||||
// 返回的结果类型的interface{},因此需要自己做类型转换;
|
||||
// 如果找不到对应节点的数据,返回nil;
|
||||
func (p *Parser) Get(pattern...string) interface{} {
|
||||
return p.json.Get(pattern...)
|
||||
}
|
||||
|
||||
// 转换为map[string]interface{}类型,如果转换失败,返回nil
|
||||
|
||||
@ -25,6 +25,8 @@ import (
|
||||
"gitee.com/johng/gf/g/os/gfile"
|
||||
"gitee.com/johng/gf/g/os/genv"
|
||||
"github.com/gorilla/websocket"
|
||||
"gitee.com/johng/gf/g/os/gtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -127,6 +129,8 @@ func init() {
|
||||
|
||||
// 信号量管理操作监听
|
||||
go handleProcessSignal()
|
||||
// 异步监听进程间消息
|
||||
go handleProcessMessage()
|
||||
}
|
||||
|
||||
// 获取/创建一个默认配置的HTTP Server(默认监听端口是80)
|
||||
@ -213,6 +217,13 @@ func (s *Server) Start() error {
|
||||
s.startServer(nil)
|
||||
}
|
||||
|
||||
// 如果是子进程,那么服务开启后通知父进程销毁
|
||||
if gproc.IsChild() {
|
||||
gtime.SetTimeout(2*time.Second, func() {
|
||||
gproc.Send(gproc.PPid(), []byte("exit"))
|
||||
})
|
||||
}
|
||||
|
||||
// 开启异步关闭队列处理循环
|
||||
s.startCloseQueueLoop()
|
||||
return nil
|
||||
|
||||
@ -22,14 +22,15 @@ import (
|
||||
"gitee.com/johng/gf/g/util/gconv"
|
||||
"time"
|
||||
"runtime"
|
||||
"bytes"
|
||||
)
|
||||
|
||||
const (
|
||||
gADMIN_ACTION_INTERVAL_LIMIT = 2000 // (毫秒)服务开启后允许执行管理操作的间隔限制
|
||||
gADMIN_ACTION_RESTARTING = 1
|
||||
gADMIN_ACTION_SHUTINGDOWN = 2
|
||||
gADMIN_ACTION_RELOAD_ENVKEY = "gf.server.reload"
|
||||
gADMIN_ACTION_RESTART_ENVKEY = "gf.server.restart"
|
||||
gADMIN_ACTION_RELOAD_ENVKEY = "GF_SERVER_RELOAD"
|
||||
gADMIN_ACTION_RESTART_ENVKEY = "GF_SERVER_RESTART"
|
||||
)
|
||||
|
||||
// 用于服务管理的对象
|
||||
@ -240,8 +241,6 @@ func restartWebServers(newExeFilePath...string) {
|
||||
})
|
||||
} else {
|
||||
forkReloadProcess(newExeFilePath...)
|
||||
go gracefulShutdownWebServers()
|
||||
doneChan <- struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
@ -278,4 +277,17 @@ func forcedlyCloseWebServers() {
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 异步监听进程间消息
|
||||
func handleProcessMessage() {
|
||||
for {
|
||||
if msg := gproc.Receive(); msg != nil {
|
||||
if bytes.EqualFold(msg.Data, []byte("exit")) {
|
||||
gracefulShutdownWebServers()
|
||||
doneChan <- struct{}{}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,7 +12,6 @@ package ghttp
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
"strings"
|
||||
"net/http"
|
||||
"gitee.com/johng/gf/g/os/gtime"
|
||||
)
|
||||
@ -43,7 +42,7 @@ func GetCookie(r *Request) *Cookie {
|
||||
}
|
||||
c := &Cookie {
|
||||
data : make(map[string]CookieItem),
|
||||
domain : strings.Split(r.Host, ":")[0],
|
||||
domain : r.GetHost(),
|
||||
server : r.Server,
|
||||
request : r,
|
||||
response : r.Response,
|
||||
@ -53,15 +52,13 @@ func GetCookie(r *Request) *Cookie {
|
||||
return c
|
||||
}
|
||||
|
||||
// 从请求流中初始化
|
||||
// 从请求流中初始化,无锁
|
||||
func (c *Cookie) init() {
|
||||
c.mu.Lock()
|
||||
for _, v := range c.request.Cookies() {
|
||||
c.data[v.Name] = CookieItem {
|
||||
v.Value, v.Domain, v.Path, v.Expires.Second(), v.HttpOnly,
|
||||
}
|
||||
}
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
// 获取所有的Cookie并构造成map返回
|
||||
@ -137,6 +134,7 @@ func (c *Cookie) Close() {
|
||||
func (c *Cookie) Output() {
|
||||
c.mu.RLock()
|
||||
for k, v := range c.data {
|
||||
// 只有expire != 0的才是服务端在本地请求中设置的cookie
|
||||
if v.expire == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -86,6 +86,10 @@ func (s *Session) GetUint (k string) uint {
|
||||
return gconv.Uint(s.Get(k))
|
||||
}
|
||||
|
||||
func (s *Session) GetUint8 (k string) uint8 {
|
||||
return gconv.Uint8(s.Get(k))
|
||||
}
|
||||
|
||||
func (s *Session) GetFloat32 (k string) float32 {
|
||||
return gconv.Float32(s.Get(k))
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@ type Config struct {
|
||||
paths *gspath.SPath // 搜索目录路径
|
||||
jsons *gmap.StringInterfaceMap // 配置文件对象
|
||||
closed *gtype.Bool // 是否已经被close
|
||||
vc *gtype.Bool // 层级检索是否执行分隔符冲突检测(默认为false,检测会比较影响检索效率)
|
||||
}
|
||||
|
||||
// 生成一个配置管理对象
|
||||
@ -41,6 +42,7 @@ func New(path string, file...string) *Config {
|
||||
paths : s,
|
||||
jsons : gmap.NewStringInterfaceMap(),
|
||||
closed : gtype.NewBool(),
|
||||
vc : gtype.NewBool(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,6 +64,13 @@ func (c *Config) SetPath(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 设置是否执行层级冲突检查,当键名中存在层级符号时需要开启该特性,默认为关闭。
|
||||
// 开启比较耗性能,也不建议允许键名中存在分隔符,最好在应用端避免这种情况。
|
||||
func (c *Config) SetViolenceCheck(check bool) {
|
||||
c.vc.Set(check)
|
||||
c.Reload()
|
||||
}
|
||||
|
||||
// 添加配置管理器的配置文件搜索路径
|
||||
func (c *Config) AddPath(path string) error {
|
||||
if err := c.paths.Add(path); err != nil {
|
||||
@ -91,6 +100,7 @@ func (c *Config) getJson(file...string) *gjson.Json {
|
||||
return r.(*gjson.Json)
|
||||
}
|
||||
if j, err := gjson.Load(fpath); err == nil {
|
||||
j.SetViolenceCheck(c.vc.Val())
|
||||
c.addMonitor(fpath)
|
||||
c.jsons.Set(fpath, j)
|
||||
return j
|
||||
@ -132,6 +142,13 @@ func (c *Config) GetString(pattern string, file...string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c *Config) GetStrings(pattern string, file...string) []string {
|
||||
if j := c.getJson(file...); j != nil {
|
||||
return j.GetStrings(pattern)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 返回指定json中的bool
|
||||
func (c *Config) GetBool(pattern string, file...string) bool {
|
||||
if j := c.getJson(file...); j != nil {
|
||||
|
||||
@ -110,7 +110,7 @@ func (c *gCmdOption) GetBool(key string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// 绑定命令行参数及对应的命令函数,注意参数是函数的内存地址
|
||||
// 绑定命令行参数及对应的命令函数,注意命令函数参数是函数的内存地址
|
||||
// 如果操作失败返回错误信息
|
||||
func BindHandle (cmd string, f func()) error {
|
||||
if _, ok := cmdFuncMap[cmd]; ok {
|
||||
|
||||
@ -17,8 +17,9 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
gPROC_ENV_KEY_PPID_KEY = "gproc.ppid"
|
||||
gPROC_TEMP_DIR_ENV_KEY = "gproc.tempdir"
|
||||
gPROC_ENV_KEY_PPID_KEY = "GPROC_PPID"
|
||||
gPROC_ENV_KEY_COMM_KEY = "GPROC_COMM_ENABLED"
|
||||
gPROC_TEMP_DIR_ENV_KEY = "GPROC_TEMP_DIR"
|
||||
)
|
||||
|
||||
// 进程开始执行时间
|
||||
@ -36,7 +37,7 @@ func PPid() int {
|
||||
}
|
||||
// gPROC_ENV_KEY_PPID_KEY为gproc包自定义的父进程
|
||||
ppidValue := os.Getenv(gPROC_ENV_KEY_PPID_KEY)
|
||||
if ppidValue != "" {
|
||||
if ppidValue != "" && ppidValue != "0" {
|
||||
return gconv.Int(ppidValue)
|
||||
}
|
||||
return PPidOS()
|
||||
@ -49,7 +50,8 @@ func PPidOS() int {
|
||||
|
||||
// 判断当前进程是否为gproc创建的子进程
|
||||
func IsChild() bool {
|
||||
return os.Getenv(gPROC_ENV_KEY_PPID_KEY) != ""
|
||||
ppidValue := os.Getenv(gPROC_ENV_KEY_PPID_KEY)
|
||||
return ppidValue != "" && ppidValue != "0"
|
||||
}
|
||||
|
||||
// 设置gproc父进程ID,当ppid为0时表示该进程为gproc主进程,否则为gproc子进程
|
||||
|
||||
@ -37,7 +37,10 @@ type sendQueueItem struct {
|
||||
|
||||
// 进程管理/通信初始化操作
|
||||
func init() {
|
||||
go startTcpListening()
|
||||
// 默认下为空("")
|
||||
if os.Getenv(gPROC_ENV_KEY_COMM_KEY) != "0" {
|
||||
go startTcpListening()
|
||||
}
|
||||
}
|
||||
|
||||
// 获取指定进程的通信文件地址
|
||||
@ -47,7 +50,7 @@ func getCommFilePath(pid int) string {
|
||||
|
||||
// 获取进程间通信目录地址
|
||||
func getCommDirPath() string {
|
||||
tempDir := os.Getenv("gproc.tempdir")
|
||||
tempDir := os.Getenv(gPROC_TEMP_DIR_ENV_KEY)
|
||||
if tempDir == "" {
|
||||
tempDir = gfile.TempDir()
|
||||
}
|
||||
|
||||
@ -9,10 +9,7 @@ package gproc
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"os/exec"
|
||||
"gitee.com/johng/gf/g/container/gmap"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// 进程管理器
|
||||
@ -27,40 +24,6 @@ func NewManager() *Manager {
|
||||
}
|
||||
}
|
||||
|
||||
// 创建一个进程(不执行)
|
||||
func NewProcess(path string, args []string, environment []string) *Process {
|
||||
env := make([]string, len(environment) + 1)
|
||||
for k, v := range environment {
|
||||
env[k] = v
|
||||
}
|
||||
env[len(env) - 1] = fmt.Sprintf("%s=%s", gPROC_TEMP_DIR_ENV_KEY, os.TempDir())
|
||||
p := &Process {
|
||||
Manager : nil,
|
||||
PPid : os.Getpid(),
|
||||
Cmd : exec.Cmd {
|
||||
Args : []string{path},
|
||||
Path : path,
|
||||
Stdin : os.Stdin,
|
||||
Stdout : os.Stdout,
|
||||
Stderr : os.Stderr,
|
||||
Env : env,
|
||||
ExtraFiles : make([]*os.File, 0),
|
||||
},
|
||||
}
|
||||
// 当前工作目录
|
||||
if d, err := os.Getwd(); err == nil {
|
||||
p.Dir = d
|
||||
}
|
||||
if len(args) > 0 {
|
||||
start := 0
|
||||
if strings.EqualFold(path, args[0]) {
|
||||
start = 1
|
||||
}
|
||||
p.Args = append(p.Args, args[start : ]...)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// 创建一个进程(不执行)
|
||||
func (m *Manager) NewProcess(path string, args []string, environment []string) *Process {
|
||||
p := NewProcess(path, args, environment)
|
||||
|
||||
@ -11,13 +11,49 @@ import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 子进程
|
||||
type Process struct {
|
||||
exec.Cmd
|
||||
Manager *Manager // 所属进程管理器
|
||||
PPid int // 自定义关联的父进程ID
|
||||
Manager *Manager // 所属进程管理器
|
||||
PPid int // 自定义关联的父进程ID
|
||||
DisableComm bool // 是否关闭TCP通信监听服务
|
||||
}
|
||||
|
||||
// 创建一个进程(不执行)
|
||||
func NewProcess(path string, args []string, environment []string) *Process {
|
||||
env := make([]string, len(environment) + 1)
|
||||
for k, v := range environment {
|
||||
env[k] = v
|
||||
}
|
||||
env[len(env) - 1] = fmt.Sprintf("%s=%s", gPROC_TEMP_DIR_ENV_KEY, os.TempDir())
|
||||
p := &Process {
|
||||
Manager : nil,
|
||||
PPid : os.Getpid(),
|
||||
Cmd : exec.Cmd {
|
||||
Args : []string{path},
|
||||
Path : path,
|
||||
Stdin : os.Stdin,
|
||||
Stdout : os.Stdout,
|
||||
Stderr : os.Stderr,
|
||||
Env : env,
|
||||
ExtraFiles : make([]*os.File, 0),
|
||||
},
|
||||
}
|
||||
// 当前工作目录
|
||||
if d, err := os.Getwd(); err == nil {
|
||||
p.Dir = d
|
||||
}
|
||||
if len(args) > 0 {
|
||||
start := 0
|
||||
if strings.EqualFold(path, args[0]) {
|
||||
start = 1
|
||||
}
|
||||
p.Args = append(p.Args, args[start : ]...)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// 开始执行(非阻塞)
|
||||
@ -25,9 +61,12 @@ func (p *Process) Start() (int, error) {
|
||||
if p.Process != nil {
|
||||
return p.Pid(), nil
|
||||
}
|
||||
if p.PPid > 0 {
|
||||
p.Env = append(p.Env, fmt.Sprintf("%s=%d", gPROC_ENV_KEY_PPID_KEY, p.PPid))
|
||||
commEnabled := 1
|
||||
if p.DisableComm {
|
||||
commEnabled = 0
|
||||
}
|
||||
p.Env = append(p.Env, fmt.Sprintf("%s=%d", gPROC_ENV_KEY_PPID_KEY, p.PPid))
|
||||
p.Env = append(p.Env, fmt.Sprintf("%s=%d", gPROC_ENV_KEY_COMM_KEY, commEnabled))
|
||||
if err := p.Cmd.Start(); err == nil {
|
||||
if p.Manager != nil {
|
||||
p.Manager.processes.Set(p.Process.Pid, p)
|
||||
|
||||
@ -15,6 +15,10 @@ import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
TIME_REAGEX_PATTERN = `(\d{4}-\d{2}-\d{2})[\sT]{0,1}(\d{2}:\d{2}:\d{2}){0,1}\.{0,1}(\d{0,9})([\sZ]{0,1})([\+-]{0,1})([:\d]*)`
|
||||
)
|
||||
|
||||
var (
|
||||
// 用于time.Time转换使用,防止多次Compile
|
||||
timeRegex *regexp.Regexp
|
||||
@ -22,7 +26,7 @@ var (
|
||||
|
||||
func init() {
|
||||
// 使用正则判断会比直接使用ParseInLocation挨个轮训判断要快很多
|
||||
timeRegex, _ = regexp.Compile(`(\d{4}-\d{2}-\d{2})[\sT]{0,1}(\d{2}:\d{2}:\d{2}){0,1}\.{0,1}(\d{0,9})([\sZ]{0,1})([\+-]{0,1})([:\d]*)`)
|
||||
timeRegex, _ = regexp.Compile(TIME_REAGEX_PATTERN)
|
||||
|
||||
}
|
||||
|
||||
@ -88,6 +92,15 @@ func Format(format string, timestamps...int64) string {
|
||||
}
|
||||
|
||||
// 字符串转换为时间对象,需要给定字符串时间格式,format格式形如:2006-01-02 15:04:05
|
||||
// 不传递自定义格式下默认支持的标准时间格式:
|
||||
// "2017-12-14 04:51:34 +0805 LMT",
|
||||
// "2006-01-02T15:04:05Z07:00",
|
||||
// "2014-01-17T01:19:15+08:00",
|
||||
// "2018-02-09T20:46:17.897Z",
|
||||
// "2018-02-09 20:46:17.897",
|
||||
// "2018-02-09T20:46:17Z",
|
||||
// "2018-02-09 20:46:17",
|
||||
// "2018-02-09",
|
||||
func StrToTime(str string, format...string) (time.Time, error) {
|
||||
// 优先使用用户输入日期格式进行转换
|
||||
if len(format) > 0 {
|
||||
|
||||
@ -12,13 +12,14 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
"strconv"
|
||||
"gitee.com/johng/gf/g/encoding/gbinary"
|
||||
"gitee.com/johng/gf/g/util/gstr"
|
||||
"encoding/json"
|
||||
"gitee.com/johng/gf/g/os/gtime"
|
||||
"gitee.com/johng/gf/g/util/gstr"
|
||||
"gitee.com/johng/gf/g/encoding/gbinary"
|
||||
)
|
||||
|
||||
// 将变量i转换为字符串指定的类型t
|
||||
func Convert(i interface{}, t string) interface{} {
|
||||
func Convert(i interface{}, t string, params...interface{}) interface{} {
|
||||
switch t {
|
||||
case "int": return Int(i)
|
||||
case "int8": return Int8(i)
|
||||
@ -35,7 +36,12 @@ func Convert(i interface{}, t string) interface{} {
|
||||
case "bool": return Bool(i)
|
||||
case "string": return String(i)
|
||||
case "[]byte": return Bytes(i)
|
||||
case "time.Time": return Time(i)
|
||||
case "time.Time":
|
||||
if len(params) > 0 {
|
||||
return Time(i, String(params[0]))
|
||||
}
|
||||
return Time(i)
|
||||
|
||||
case "time.Duration": return TimeDuration(i)
|
||||
default:
|
||||
return i
|
||||
@ -106,13 +112,15 @@ func String(i interface{}) string {
|
||||
case uint16: return strconv.FormatUint(uint64(value), 10)
|
||||
case uint32: return strconv.FormatUint(uint64(value), 10)
|
||||
case uint64: return strconv.FormatUint(uint64(value), 10)
|
||||
case float32: return strconv.FormatFloat(float64(value), 'f', -1, 64)
|
||||
case float32: return strconv.FormatFloat(float64(value), 'f', -1, 32)
|
||||
case float64: return strconv.FormatFloat(value, 'f', -1, 64)
|
||||
case bool: return strconv.FormatBool(value)
|
||||
case string: return value
|
||||
case []byte: return string(value)
|
||||
default:
|
||||
return fmt.Sprintf("%v", value)
|
||||
// 默认使用json进行字符串转换
|
||||
jsonContent, _ := json.Marshal(value)
|
||||
return string(jsonContent)
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,7 +297,7 @@ func Float32 (i interface{}) float32 {
|
||||
if v, ok := i.(float32); ok {
|
||||
return v
|
||||
}
|
||||
v, _ := strconv.ParseFloat(String(i), 32)
|
||||
v, _ := strconv.ParseFloat(String(i), 64)
|
||||
return float32(v)
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
clientMax := 10
|
||||
clientMax := 1000
|
||||
requestMax := 1000
|
||||
failureNum := gtype.NewInt64()
|
||||
successNum := gtype.NewInt64()
|
||||
@ -21,7 +21,7 @@ func main() {
|
||||
go func(clientId int) {
|
||||
url := "http://127.0.0.1:8199/"
|
||||
for i := 0; i < requestMax; i++ {
|
||||
url = fmt.Sprintf("http://127.0.0.1:8199/%d_%d", clientId, i)
|
||||
//url = fmt.Sprintf("http://127.0.0.1:8199/%d_%d", clientId, i)
|
||||
if c, e := ghttp.Get(url); e == nil {
|
||||
c.Close()
|
||||
successNum.Add(1)
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
"fmt"
|
||||
"gitee.com/johng/gf/g/encoding/gjson"
|
||||
)
|
||||
|
||||
func main() {
|
||||
t := time.Now().Zone()
|
||||
fmt.Println(z)
|
||||
}
|
||||
content := `[0.00000000059, 1.598877777409]`
|
||||
j, _ := gjson.LoadContent([]byte(content), "json")
|
||||
fmt.Println(j.GetString("0"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user