mirror of
https://gitee.com/johng/gf
synced 2026-07-06 05:42:20 +08:00
improve process communication feature for gproc; add more slice converting functions for gconv
This commit is contained in:
@ -1,6 +1,3 @@
|
||||
// 多进程通信示例,
|
||||
// 子进程每个1秒向父进程发送当前时间,
|
||||
// 父进程监听进程消息,收到后打印到终端。
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
@ -5,9 +5,8 @@ import (
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
)
|
||||
|
||||
// 使用gproc kill指定其他进程(清确保运行该程序的用户有足够权限)
|
||||
func main() {
|
||||
pid := 14746
|
||||
pid := 32556
|
||||
m := gproc.NewManager()
|
||||
m.AddProcess(pid)
|
||||
err := m.KillAll()
|
||||
12
.example/os/gproc/gproc_sleep.go
Normal file
12
.example/os/gproc/gproc_sleep.go
Normal file
@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(gproc.Pid())
|
||||
err := gproc.ShellRun("sleep 99999s")
|
||||
fmt.Println(err)
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
[database]
|
||||
debug = true
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test?parseTime=true&loc=Local"
|
||||
@ -1,42 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("")
|
||||
|
||||
// 前景 背景 颜色
|
||||
// ---------------------------------------
|
||||
// 30 40 黑色
|
||||
// 31 41 红色
|
||||
// 32 42 绿色
|
||||
// 33 43 黄色
|
||||
// 34 44 蓝色
|
||||
// 35 45 紫红色
|
||||
// 36 46 青蓝色
|
||||
// 37 47 白色
|
||||
//
|
||||
// 代码 意义
|
||||
// -------------------------
|
||||
// 0 终端默认设置
|
||||
// 1 高亮显示
|
||||
// 4 使用下划线
|
||||
// 5 闪烁
|
||||
// 7 反白显示
|
||||
// 8 不可见
|
||||
|
||||
// 背景色彩 = 40-47
|
||||
for b := 40; b <= 47; b++ {
|
||||
// 前景色彩 = 30-37
|
||||
for f := 30; f <= 37; f++ {
|
||||
// 显示方式 = 0,1,4,5,7,8
|
||||
for _, d := range []int{0, 1, 4, 5, 7, 8} {
|
||||
fmt.Printf(" %c[%d;%d;%dm%s(f=%d,b=%d,d=%d)%c[0m ", 0x1B, d, b, f, "", f, b, d, 0x1B)
|
||||
}
|
||||
fmt.Println("")
|
||||
}
|
||||
fmt.Println("")
|
||||
}
|
||||
}
|
||||
@ -1,18 +1,69 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/encoding/gjson"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
|
||||
group.ALL("/test", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.GetRequest("nickname"))
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
type Detail struct {
|
||||
Mall_coupon_id int64 `json:"mall_coupon_id"` //店铺优惠券id
|
||||
Mall_coupon_discount_pct int `json:"mall_coupon_discount_pct"` //店铺折扣
|
||||
Mall_coupon_min_order_amount int `json:"mall_coupon_min_order_amount"` //最小使用金额
|
||||
Mall_coupon_max_discount_amount int `json:"mall_coupon_max_discount_amount"` //最大使用金额
|
||||
Mall_coupon_total_quantity int64 `json:"mall_coupon_total_quantity"` //店铺券总量
|
||||
Mall_coupon_remain_quantity int64 `json:"mall_coupon_remain_quantity"` //店铺券余量
|
||||
Mall_coupon_start_time int64 `json:"mall_coupon_start_time"` //店铺券使用开始时间
|
||||
Mall_coupon_end_time int64 `json:"mall_coupon_end_time"` //店铺券使用结束时间
|
||||
Goods_id int64 `json:"goods_id"` //参与多多进宝的商品ID
|
||||
Goods_name string `json:"goods_name"` //参与多多进宝的商品标题
|
||||
Goods_desc string `json:"goods_desc"` //参与多多进宝的商品描述
|
||||
Goods_image_url string `json:"goods_image_url"` //多多进宝商品主图
|
||||
Goods_gallery_urls []string `json:"goods_gallery_urls"` //商品轮播图
|
||||
Min_group_price int64 `json:"min_group_price"` //最低价sku的拼团价,单位为分
|
||||
Min_normal_price int64 `json:"min_normal_price"` //最低价sku的单买价,单位为分
|
||||
Mall_name string `json:"mall_name"` //店铺名称
|
||||
Opt_id int64 `json:"opt_id"` //商品标签ID,使用pdd.goods.opt.get接口获取
|
||||
Opt_name string `json:"opt_name"` //商品标签名称
|
||||
Opt_ids []int `json:"opt_ids"` //商品标签ID
|
||||
Cat_ids []int `json:"cat_ids"` //商品一~四级类目ID列表
|
||||
Coupon_min_order_amount int64 `json:"coupon_min_order_amount"` //优惠券门槛金额,单位为分
|
||||
Coupon_discount int64 `json:"coupon_discount"` //优惠券面额,单位为分
|
||||
Coupon_total_quantity int64 `json:"coupon_total_quantity"` //优惠券总数量
|
||||
Coupon_remain_quantity int64 `json:"coupon_remain_quantity"` //优惠券剩余数量
|
||||
Coupon_start_time int64 `json:"coupon_start_time"` //优惠券生效时间,UNIX时间戳
|
||||
Coupon_end_time int64 `json:"coupon_end_time"` //优惠券失效时间,UNIX时间戳
|
||||
Promotion_rate int64 `json:"promotion_rate"` //佣金比例,千分比
|
||||
Goods_eval_count int64 `json:"goods_eval_count"` //商品评价数
|
||||
Cat_id int64 `json:"cat_id"` //商品类目ID,使用pdd.goods.cats.get接口获取
|
||||
Sales_tip string `json:"sales_tip"` //已售卖件数
|
||||
Mall_id int64 `json:"mall_id"` //商家id
|
||||
Service_tags []int64 `json:"service_tags"` // 服务标签: 4-送货入户并安装,5-送货入户,6-电子发票,9-坏果包赔 ...
|
||||
Clt_cpn_batch_sn string `json:"clt_cpn_batch_sn"` //店铺收藏券id
|
||||
Clt_cpn_start_time int64 `json:"clt_cpn_start_time"` //店铺收藏券起始时间
|
||||
Clt_cpn_end_time int64 `json:"clt_cpn_end_time"` //店铺收藏券截止时间
|
||||
Clt_cpn_quantity int64 `json:"clt_cpn_quantity"` //店铺收藏券总量
|
||||
Clt_cpn_remain_quantity int64 `json:"clt_cpn_remain_quantity"` //店铺收藏券剩余量
|
||||
Clt_cpn_discount int64 `json:"clt_cpn_discount"` //店铺收藏券面额,单位为分
|
||||
Clt_cpn_min_amt int64 `json:"clt_cpn_min_amt"` //店铺收藏券使用门槛价格,单位为分
|
||||
Desc_txt string `json:"desc_txt"` //描述分
|
||||
Serv_txt string `json:"serv_txt"` //服务分
|
||||
Lgst_txt string `json:"lgst_txt"` //物流分
|
||||
Plan_type int `json:"plan_type"` //推广计划类型
|
||||
Zs_duo_id int64 `json:"zs_duo_id"` //招商团长id
|
||||
Only_scene_auth int `json:"only_scene_auth"` //快手专享
|
||||
}
|
||||
|
||||
s := `{"goods_detail_response":{"goods_details":[{"category_name":"百货","clt_cpn_end_time":null,"clt_cpn_min_amt":null,"coupon_remain_quantity":7000,"clt_cpn_remain_quantity":null,"promotion_rate":110,"coupon_id":3248825612,"service_tags":[24,13],"mall_id":983152922,"mall_name":"唯美之恋麻雀专卖店","mall_coupon_end_time":0,"clt_cpn_batch_sn":null,"lgst_txt":"高","goods_name":"【40卷32卷12卷】家用实惠卫生纸无芯卷纸批发纸巾厕纸卷筒纸手纸","clt_cpn_discount":null,"goods_id":9133961778,"goods_gallery_urls":["https://t00img.yangkeduo.com/goods/images/2019-08-18/e05846e8-f317-47bf-987d-5ccc0864e60d.jpg","https://t00img.yangkeduo.com/goods/images/2019-12-06/91756ca8-f001-4394-87d3-e7a67dc81d5a.jpg","https://t00img.yangkeduo.com/goods/images/2019-12-07/14c8abe5-cc27-4265-a683-7e2b089bb82e.jpg","https://t00img.yangkeduo.com/goods/images/2019-08-18/c4d338c0-1922-463f-bfcd-accd02018e44.jpg","https://t00img.yangkeduo.com/goods/images/2019-08-18/2b7f67f8-7738-4462-8f27-243594401ecd.jpg","https://t00img.yangkeduo.com/goods/images/2019-08-18/9b9bf86c-a3a7-4de1-9169-8b25c756ed01.jpg","https://t00img.yangkeduo.com/goods/images/2019-12-01/e373de68-c8a4-4752-adbc-d26b1040f8b7.jpg","https://t00img.yangkeduo.com/goods/images/2019-11-25/e622ef70-d917-4606-86af-a238db8c2fce.jpg","https://t00img.yangkeduo.com/goods/images/2019-11-25/9dd92cdd-1a07-4261-9584-cfafb0ddd421.jpg","https://t00img.yangkeduo.com/goods/images/2019-12-03/f7088db8-02f9-412b-a96c-5b452f41d9e3.jpg"],"goods_desc":"本产品原材料精选原生木浆制造,先进喷浆制造工艺,纸质更柔软细腻,没有纸屑,更有韧劲。嘉禾纸业建厂15年,两大自主品牌纸语和唯美之恋,年产能两万万余吨,拥有先进的造纸设备,采用巴西进口制浆制作制造而成,纸质柔软细腻,吸水性强,致力于打造国内孕婴卫生纸首选品牌,深受广大消费者好评。","opt_name":"百货","opt_ids":[17665,10116,10696,330,12619,12,11212,8590,10702,8591,15,13903,8592,17680,12691,22102,13911,12696,22105,21915,223,292,12581,13926,360,10730,12586,20527,11187,8569,12729,17657,8570,8571,10110,10111],"goods_image_url":"https://t00img.yangkeduo.com/goods/images/2019-08-18/e05846e8-f317-47bf-987d-5ccc0864e60d.jpg","has_mall_coupon":false,"min_group_price":720,"coupon_start_time":1575820800,"coupon_discount":200,"coupon_end_time":1575993599,"zs_duo_id":0,"mall_coupon_remain_quantity":0,"plan_type":2,"clt_cpn_quantity":null,"crt_rf_ordr_rto1m":0.03807085638781072,"cat_ids":[17285,17297,17402],"coupon_min_order_amount":200,"category_id":17657,"mall_coupon_discount_pct":0,"cat_id":null,"coupon_total_quantity":12000,"mall_coupon_min_order_amount":0,"merchant_type":4,"clt_cpn_start_time":null,"sales_tip":"4.2万","plan_type_all":4,"only_scene_auth":true,"mall_coupon_id":0,"desc_txt":"高","goods_thumbnail_url":"https://t00img.yangkeduo.com/goods/images/2019-11-20/0b0d078822c6e777ed1eb4ac2cdc930a.jpeg","opt_id":17657,"search_id":null,"min_normal_price":1190,"has_coupon":true,"mall_coupon_start_time":0,"serv_txt":"高","mall_rate":110,"mall_coupon_total_quantity":0,"create_at":null,"mall_coupon_max_discount_amount":0,"mall_cps":1}],"request_id":"15758638812810680"}}`
|
||||
if j, err := gjson.DecodeToJson([]byte(s)); err != nil {
|
||||
glog.Error(err)
|
||||
} else {
|
||||
|
||||
inter := j.GetInterfaces("goods_detail_response.goods_details.0")
|
||||
fmt.Println("接口:", inter)
|
||||
detail := Detail{}
|
||||
err := j.GetStruct("goods_detail_response.goods_details.0", &detail)
|
||||
fmt.Println("结构体:", err, detail)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
"log"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
process := gproc.NewProcessCmd("go run test.go")
|
||||
if pid, err := process.Start(); err != nil {
|
||||
log.Print("Build failed:", err)
|
||||
return
|
||||
} else {
|
||||
log.Printf("Build running: pid: %d", pid)
|
||||
type User struct {
|
||||
Scores []int64
|
||||
}
|
||||
|
||||
user := new(User)
|
||||
err := gconv.Struct(g.Map{"scores": []interface{}{1, 2, 3}}, user)
|
||||
fmt.Println(err)
|
||||
fmt.Println(user)
|
||||
}
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
g.TryCatch(func() {
|
||||
glog.Println("hello")
|
||||
g.Throw("exception")
|
||||
glog.Println("world")
|
||||
})
|
||||
|
||||
g.TryCatch(func() {
|
||||
glog.Println("hello")
|
||||
g.Throw("exception")
|
||||
glog.Println("world")
|
||||
}, func(exception interface{}) {
|
||||
glog.Error(exception)
|
||||
})
|
||||
}
|
||||
@ -74,6 +74,7 @@ type ServerConfig struct {
|
||||
FormParsingMemory int64 // Other: Max memory in bytes which can be used for parsing multimedia form.
|
||||
NameToUriType int // Other: Type for converting struct method name to URI when registering routes.
|
||||
DumpRouterMap bool // Other: Whether automatically dump router map when server starts.
|
||||
Graceful bool // Other: Enable graceful reload feature for all servers of the process.
|
||||
}
|
||||
|
||||
// defaultServerConfig is the default configuration object for server.
|
||||
@ -108,6 +109,7 @@ var defaultServerConfig = ServerConfig{
|
||||
DumpRouterMap: true,
|
||||
FormParsingMemory: 100 * 1024 * 1024, // 100MB
|
||||
Rewrites: make(map[string]string),
|
||||
Graceful: true,
|
||||
}
|
||||
|
||||
// Config returns the default ServerConfig object.
|
||||
@ -140,6 +142,7 @@ func (s *Server) SetConfig(c ServerConfig) error {
|
||||
if c.TLSConfig == nil && c.HTTPSCertPath != "" {
|
||||
s.EnableHTTPS(c.HTTPSCertPath, c.HTTPSKeyPath)
|
||||
}
|
||||
SetGraceful(c.Graceful)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@ -161,13 +161,14 @@ func getPkgOption(option ...PkgOption) (*PkgOption, error) {
|
||||
case 3:
|
||||
pkgOption.MaxDataSize = 0xFFFFFF
|
||||
case 4:
|
||||
pkgOption.MaxDataSize = 0xFFFFFFFF
|
||||
// math.MaxInt32 not math.MaxUint32
|
||||
pkgOption.MaxDataSize = 0x7FFFFFFF
|
||||
}
|
||||
}
|
||||
if pkgOption.MaxDataSize > 0xFFFFFFFF {
|
||||
if pkgOption.MaxDataSize > 0x7FFFFFFF {
|
||||
return nil, fmt.Errorf(
|
||||
`package data size %d definition exceeds allowed max data size %d`,
|
||||
pkgOption.MaxDataSize, 0xFFFFFFFF,
|
||||
pkgOption.MaxDataSize, 0x7FFFFFFF,
|
||||
)
|
||||
}
|
||||
return &pkgOption, nil
|
||||
|
||||
@ -23,7 +23,7 @@ type PoolConn struct {
|
||||
}
|
||||
|
||||
const (
|
||||
gDEFAULT_POOL_EXPIRE = 30000 // (Millisecond) Default TTL for connection in the pool.
|
||||
gDEFAULT_POOL_EXPIRE = 10000 // (Millisecond) Default TTL for connection in the pool.
|
||||
gCONN_STATUS_UNKNOWN = 0 // Means it is unknown it's connective or not.
|
||||
gCONN_STATUS_ACTIVE = 1 // Means it is now connective.
|
||||
gCONN_STATUS_ERROR = 2 // Means it should be closed and removed from pool.
|
||||
@ -36,27 +36,18 @@ var (
|
||||
|
||||
// NewPoolConn creates and returns a connection with pool feature.
|
||||
func NewPoolConn(addr string, timeout ...time.Duration) (*PoolConn, error) {
|
||||
var pool *gpool.Pool
|
||||
if v := addressPoolMap.Get(addr); v == nil {
|
||||
addressPoolMap.LockFunc(func(m map[string]interface{}) {
|
||||
if v, ok := m[addr]; ok {
|
||||
pool = v.(*gpool.Pool)
|
||||
v := addressPoolMap.GetOrSetFuncLock(addr, func() interface{} {
|
||||
var pool *gpool.Pool
|
||||
pool = gpool.New(gDEFAULT_POOL_EXPIRE, func() (interface{}, error) {
|
||||
if conn, err := NewConn(addr, timeout...); err == nil {
|
||||
return &PoolConn{conn, pool, gCONN_STATUS_ACTIVE}, nil
|
||||
} else {
|
||||
pool = gpool.New(gDEFAULT_POOL_EXPIRE, func() (interface{}, error) {
|
||||
if conn, err := NewConn(addr, timeout...); err == nil {
|
||||
return &PoolConn{conn, pool, gCONN_STATUS_ACTIVE}, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
})
|
||||
m[addr] = pool
|
||||
return nil, err
|
||||
}
|
||||
})
|
||||
} else {
|
||||
pool = v.(*gpool.Pool)
|
||||
}
|
||||
|
||||
if v, err := pool.Get(); err == nil {
|
||||
return pool
|
||||
})
|
||||
if v, err := v.(*gpool.Pool).Get(); err == nil {
|
||||
return v.(*PoolConn), nil
|
||||
} else {
|
||||
return nil, err
|
||||
@ -65,6 +56,9 @@ func NewPoolConn(addr string, timeout ...time.Duration) (*PoolConn, error) {
|
||||
|
||||
// Close puts back the connection to the pool if it's active,
|
||||
// or closes the connection if it's not active.
|
||||
//
|
||||
// Note that, if <c> calls Close function closing itself, <c> should not
|
||||
// be used again.
|
||||
func (c *PoolConn) Close() error {
|
||||
if c.pool != nil && c.status == gCONN_STATUS_ACTIVE {
|
||||
c.status = gCONN_STATUS_UNKNOWN
|
||||
@ -78,8 +72,8 @@ func (c *PoolConn) Close() error {
|
||||
// Send writes data to the connection. It retrieves a new connection from its pool if it fails
|
||||
// writing data.
|
||||
func (c *PoolConn) Send(data []byte, retry ...Retry) error {
|
||||
var err error
|
||||
if err = c.Conn.Send(data, retry...); err != nil && c.status == gCONN_STATUS_UNKNOWN {
|
||||
err := c.Conn.Send(data, retry...)
|
||||
if err != nil && c.status == gCONN_STATUS_UNKNOWN {
|
||||
if v, e := c.pool.Get(); e == nil {
|
||||
c.Conn = v.(*PoolConn).Conn
|
||||
err = c.Send(data, retry...)
|
||||
|
||||
21
net/gtcp/gtcp_unit_init_test.go
Normal file
21
net/gtcp/gtcp_unit_init_test.go
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gtcp_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/container/garray"
|
||||
)
|
||||
|
||||
var (
|
||||
ports = garray.NewIntArray(true)
|
||||
)
|
||||
|
||||
func init() {
|
||||
for i := 9000; i <= 10000; i++ {
|
||||
ports.Append(i)
|
||||
}
|
||||
}
|
||||
@ -8,7 +8,6 @@ package gtcp_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/net/gtcp"
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
@ -16,16 +15,6 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
ports = garray.NewIntArray(true)
|
||||
)
|
||||
|
||||
func init() {
|
||||
for i := 9000; i <= 10000; i++ {
|
||||
ports.Append(i)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Package_Basic(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
|
||||
172
net/gtcp/gtcp_unit_pool_pkg_test.go
Normal file
172
net/gtcp/gtcp_unit_pool_pkg_test.go
Normal file
@ -0,0 +1,172 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gtcp_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/net/gtcp"
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Test_Pool_Package_Basic(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
|
||||
defer conn.Close()
|
||||
for {
|
||||
data, err := conn.RecvPkg()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
conn.SendPkg(data)
|
||||
}
|
||||
})
|
||||
go s.Run()
|
||||
defer s.Close()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
// SendPkg
|
||||
gtest.Case(t, func() {
|
||||
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
|
||||
gtest.Assert(err, nil)
|
||||
defer conn.Close()
|
||||
for i := 0; i < 100; i++ {
|
||||
err := conn.SendPkg([]byte(gconv.String(i)))
|
||||
gtest.Assert(err, nil)
|
||||
}
|
||||
for i := 0; i < 100; i++ {
|
||||
err := conn.SendPkgWithTimeout([]byte(gconv.String(i)), time.Second)
|
||||
gtest.Assert(err, nil)
|
||||
}
|
||||
})
|
||||
// SendPkg with big data - failure.
|
||||
gtest.Case(t, func() {
|
||||
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
|
||||
gtest.Assert(err, nil)
|
||||
defer conn.Close()
|
||||
data := make([]byte, 65536)
|
||||
err = conn.SendPkg(data)
|
||||
gtest.AssertNE(err, nil)
|
||||
})
|
||||
// SendRecvPkg
|
||||
gtest.Case(t, func() {
|
||||
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
|
||||
gtest.Assert(err, nil)
|
||||
defer conn.Close()
|
||||
for i := 100; i < 200; i++ {
|
||||
data := []byte(gconv.String(i))
|
||||
result, err := conn.SendRecvPkg(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result, data)
|
||||
}
|
||||
for i := 100; i < 200; i++ {
|
||||
data := []byte(gconv.String(i))
|
||||
result, err := conn.SendRecvPkgWithTimeout(data, time.Second)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result, data)
|
||||
}
|
||||
})
|
||||
// SendRecvPkg with big data - failure.
|
||||
gtest.Case(t, func() {
|
||||
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
|
||||
gtest.Assert(err, nil)
|
||||
defer conn.Close()
|
||||
data := make([]byte, 65536)
|
||||
result, err := conn.SendRecvPkg(data)
|
||||
gtest.AssertNE(err, nil)
|
||||
gtest.Assert(result, nil)
|
||||
})
|
||||
// SendRecvPkg with big data - success.
|
||||
gtest.Case(t, func() {
|
||||
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
|
||||
gtest.Assert(err, nil)
|
||||
defer conn.Close()
|
||||
data := make([]byte, 65500)
|
||||
data[100] = byte(65)
|
||||
data[65400] = byte(85)
|
||||
result, err := conn.SendRecvPkg(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result, data)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Pool_Package_Timeout(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
|
||||
defer conn.Close()
|
||||
for {
|
||||
data, err := conn.RecvPkg()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
gtest.Assert(conn.SendPkg(data), nil)
|
||||
}
|
||||
})
|
||||
go s.Run()
|
||||
defer s.Close()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
gtest.Case(t, func() {
|
||||
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
|
||||
gtest.Assert(err, nil)
|
||||
defer conn.Close()
|
||||
data := []byte("10000")
|
||||
result, err := conn.SendRecvPkgWithTimeout(data, time.Millisecond*500)
|
||||
gtest.AssertNE(err, nil)
|
||||
gtest.Assert(result, nil)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
|
||||
gtest.Assert(err, nil)
|
||||
defer conn.Close()
|
||||
data := []byte("10000")
|
||||
result, err := conn.SendRecvPkgWithTimeout(data, time.Second*2)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result, data)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Pool_Package_Option(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
|
||||
defer conn.Close()
|
||||
option := gtcp.PkgOption{HeaderSize: 1}
|
||||
for {
|
||||
data, err := conn.RecvPkg(option)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
gtest.Assert(conn.SendPkg(data, option), nil)
|
||||
}
|
||||
})
|
||||
go s.Run()
|
||||
defer s.Close()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
// SendRecvPkg with big data - failure.
|
||||
gtest.Case(t, func() {
|
||||
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
|
||||
gtest.Assert(err, nil)
|
||||
defer conn.Close()
|
||||
data := make([]byte, 0xFF+1)
|
||||
result, err := conn.SendRecvPkg(data, gtcp.PkgOption{HeaderSize: 1})
|
||||
gtest.AssertNE(err, nil)
|
||||
gtest.Assert(result, nil)
|
||||
})
|
||||
// SendRecvPkg with big data - success.
|
||||
gtest.Case(t, func() {
|
||||
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
|
||||
gtest.Assert(err, nil)
|
||||
defer conn.Close()
|
||||
data := make([]byte, 0xFF)
|
||||
data[100] = byte(65)
|
||||
data[200] = byte(85)
|
||||
result, err := conn.SendRecvPkg(data, gtcp.PkgOption{HeaderSize: 1})
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result, data)
|
||||
})
|
||||
}
|
||||
65
net/gtcp/gtcp_unit_pool_test.go
Normal file
65
net/gtcp/gtcp_unit_pool_test.go
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gtcp_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/net/gtcp"
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Test_Pool_Basic1(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
|
||||
defer conn.Close()
|
||||
for {
|
||||
data, err := conn.RecvPkg()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
conn.SendPkg(data)
|
||||
}
|
||||
})
|
||||
go s.Run()
|
||||
defer s.Close()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
gtest.Case(t, func() {
|
||||
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
|
||||
gtest.Assert(err, nil)
|
||||
defer conn.Close()
|
||||
data := []byte("9999")
|
||||
err = conn.SendPkg(data)
|
||||
gtest.Assert(err, nil)
|
||||
err = conn.SendPkgWithTimeout(data, time.Second)
|
||||
gtest.Assert(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Pool_Basic2(t *testing.T) {
|
||||
p := ports.PopRand()
|
||||
s := gtcp.NewServer(fmt.Sprintf(`:%d`, p), func(conn *gtcp.Conn) {
|
||||
conn.Close()
|
||||
})
|
||||
go s.Run()
|
||||
defer s.Close()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
gtest.Case(t, func() {
|
||||
conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", p))
|
||||
gtest.Assert(err, nil)
|
||||
defer conn.Close()
|
||||
data := []byte("9999")
|
||||
err = conn.SendPkg(data)
|
||||
gtest.Assert(err, nil)
|
||||
err = conn.SendPkgWithTimeout(data, time.Second)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
_, err = conn.SendRecv(data, -1)
|
||||
gtest.AssertNE(err, nil)
|
||||
})
|
||||
}
|
||||
@ -36,8 +36,16 @@ var (
|
||||
// The absolute file path for main package.
|
||||
// It can be only checked and set once.
|
||||
mainPkgPath = gtype.NewString()
|
||||
// Temporary directory of system.
|
||||
tempDir = "/tmp"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if !Exists(tempDir) {
|
||||
tempDir = os.TempDir()
|
||||
}
|
||||
}
|
||||
|
||||
// Mkdir creates directories recursively with given <path>.
|
||||
// The parameter <path> is suggested to be absolute path.
|
||||
func Mkdir(path string) error {
|
||||
@ -511,5 +519,5 @@ func homeWindows() (string, error) {
|
||||
|
||||
// See os.TempDir().
|
||||
func TempDir() string {
|
||||
return os.TempDir()
|
||||
return tempDir
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ package gproc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
@ -21,15 +22,14 @@ import (
|
||||
|
||||
const (
|
||||
gPROC_ENV_KEY_PPID_KEY = "GPROC_PPID"
|
||||
gPROC_TEMP_DIR_ENV_KEY = "GPROC_TEMP_DIR"
|
||||
)
|
||||
|
||||
var (
|
||||
// 进程开始执行时间
|
||||
// processStartTime is the start time of current process.
|
||||
processStartTime = time.Now()
|
||||
)
|
||||
|
||||
// 获取当前进程ID
|
||||
// Pid returns the pid of current process.
|
||||
func Pid() int {
|
||||
return os.Getpid()
|
||||
}
|
||||
@ -39,7 +39,6 @@ func PPid() int {
|
||||
if !IsChild() {
|
||||
return Pid()
|
||||
}
|
||||
// gPROC_ENV_KEY_PPID_KEY为gproc包自定义的父进程
|
||||
ppidValue := os.Getenv(gPROC_ENV_KEY_PPID_KEY)
|
||||
if ppidValue != "" && ppidValue != "0" {
|
||||
return gconv.Int(ppidValue)
|
||||
@ -114,11 +113,11 @@ func checkEnvKey(env []string, key string) bool {
|
||||
func getShell() string {
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
return searchBinFromEnvPath("cmd.exe")
|
||||
return SearchBinary("cmd.exe")
|
||||
default:
|
||||
path := searchBinFromEnvPath("bash")
|
||||
path := SearchBinary("bash")
|
||||
if path == "" {
|
||||
path = searchBinFromEnvPath("sh")
|
||||
path = SearchBinary("sh")
|
||||
}
|
||||
return path
|
||||
}
|
||||
@ -135,24 +134,25 @@ func getShellOption() string {
|
||||
}
|
||||
|
||||
// 从环境变量PATH中搜索可执行文件
|
||||
func searchBinFromEnvPath(file string) string {
|
||||
// 如果是绝对路径,或者相对路径下存在,那么直接返回
|
||||
func SearchBinary(file string) string {
|
||||
// Check if it's absolute path of exists at current working directory.
|
||||
if gfile.Exists(file) {
|
||||
return file
|
||||
}
|
||||
array := ([]string)(nil)
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
array = strings.Split(os.Getenv("Path"), ";")
|
||||
array = gstr.SplitAndTrim(os.Getenv("Path"), ";")
|
||||
if gfile.Ext(file) != ".exe" {
|
||||
file += ".exe"
|
||||
}
|
||||
default:
|
||||
array = strings.Split(os.Getenv("PATH"), ":")
|
||||
array = gstr.SplitAndTrim(os.Getenv("PATH"), ":")
|
||||
}
|
||||
if len(array) > 0 {
|
||||
path := ""
|
||||
for _, v := range array {
|
||||
path := v + gfile.Separator + file
|
||||
path = v + gfile.Separator + file
|
||||
if gfile.Exists(path) {
|
||||
return path
|
||||
}
|
||||
|
||||
@ -3,42 +3,81 @@
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
// "不要通过共享内存来通信,而应该通过通信来共享内存"
|
||||
|
||||
package gproc
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
"github.com/gogf/gf/net/gtcp"
|
||||
"github.com/gogf/gf/os/gfcache"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
// 进程通信数据结构
|
||||
type Msg struct {
|
||||
SendPid int `json:"spid"` // 发送进程ID
|
||||
RecvPid int `json:"rpid"` // 接收进程ID
|
||||
Group string `json:"group"` // 分组名称
|
||||
Data []byte `json:"data"` // 原始数据
|
||||
// MsgRequest is the request structure for process communication.
|
||||
type MsgRequest struct {
|
||||
SendPid int // Sender PID.
|
||||
RecvPid int // Receiver PID.
|
||||
Group string // Message group name.
|
||||
Data []byte // Request data.
|
||||
}
|
||||
|
||||
// 本地进程通信接收消息队列(按照分组进行构建的map,键值为*gqueue.Queue对象)
|
||||
var commReceiveQueues = gmap.NewStrAnyMap(true)
|
||||
|
||||
// (用于发送)已建立的PID对应的Conn通信对象,键值为一个Pool,防止并行使用同一个通信对象造成数据重叠
|
||||
var commPidConnMap = gmap.NewIntAnyMap(true)
|
||||
|
||||
// 获取指定进程的通信文件地址
|
||||
func getCommFilePath(pid int) string {
|
||||
return getCommDirPath() + gfile.Separator + gconv.String(pid)
|
||||
// MsgResponse is the response structure for process communication.
|
||||
type MsgResponse struct {
|
||||
Code int // 1: OK; Other: Error.
|
||||
Message string // Response message.
|
||||
Data []byte // Response data.
|
||||
}
|
||||
|
||||
// 获取进程间通信目录地址
|
||||
func getCommDirPath() string {
|
||||
tempDir := os.Getenv(gPROC_TEMP_DIR_ENV_KEY)
|
||||
if tempDir == "" {
|
||||
tempDir = gfile.TempDir()
|
||||
const (
|
||||
gPROC_COMM_DEFAULT_GRUOP_NAME = "" // Default group name.
|
||||
gPROC_DEFAULT_TCP_PORT = 10000 // Starting port number for receiver listening.
|
||||
gPROC_MSG_QUEUE_MAX_LENGTH = 10000 // Max size for each message queue of the group.
|
||||
)
|
||||
|
||||
var (
|
||||
// commReceiveQueues is the group name to queue map for storing received data.
|
||||
// The value of the map is type of *gqueue.Queue.
|
||||
commReceiveQueues = gmap.NewStrAnyMap(true)
|
||||
|
||||
// commPidFolderPath specifies the folder path storing pid to port mapping files.
|
||||
commPidFolderPath = gfile.Join(gfile.TempDir(), "gproc")
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Automatically create the storage folder.
|
||||
if !gfile.Exists(commPidFolderPath) {
|
||||
err := gfile.Mkdir(commPidFolderPath)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf(`create gproc folder failed: %v`, err))
|
||||
}
|
||||
}
|
||||
return tempDir + gfile.Separator + "gproc"
|
||||
}
|
||||
|
||||
// getConnByPid creates and returns a TCP connection for specified pid.
|
||||
func getConnByPid(pid int) (*gtcp.Conn, error) {
|
||||
port := getPortByPid(pid)
|
||||
if port > 0 {
|
||||
if conn, err := gtcp.NewConn(fmt.Sprintf("127.0.0.1:%d", port)); err == nil {
|
||||
return conn, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nil, errors.New(fmt.Sprintf("could not find port for pid: %d", pid))
|
||||
}
|
||||
|
||||
// getPortByPid returns the listening port for specified pid.
|
||||
// It returns 0 if no port found for the specified pid.
|
||||
func getPortByPid(pid int) int {
|
||||
path := getCommFilePath(pid)
|
||||
content := gfcache.GetContents(path)
|
||||
return gconv.Int(content)
|
||||
}
|
||||
|
||||
// getCommFilePath returns the pid to port mapping file path for given pid.
|
||||
func getCommFilePath(pid int) string {
|
||||
return gfile.Join(commPidFolderPath, gconv.String(pid))
|
||||
}
|
||||
|
||||
@ -21,50 +21,39 @@ import (
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
const (
|
||||
gPROC_DEFAULT_TCP_PORT = 10000 // 默认开始监听的TCP端口号,如果占用则递增
|
||||
gPROC_MSG_QUEUE_MAX_LENGTH = 10000 // 进程消息队列最大长度(每个分组)
|
||||
)
|
||||
|
||||
var (
|
||||
// 是否已开启TCP端口监听服务
|
||||
// tcpListened marks whether the receiving listening service started.
|
||||
tcpListened = gtype.NewBool()
|
||||
)
|
||||
|
||||
// 获取其他进程传递到当前进程的消息包,阻塞执行。
|
||||
// 进程只有在执行该方法后才会打开请求端口,默认情况下不允许进程间通信。
|
||||
func Receive(group ...string) *Msg {
|
||||
// 一个进程只能开启一个监听goroutine
|
||||
if !tcpListened.Val() && tcpListened.Set(true) == false {
|
||||
go startTcpListening()
|
||||
// Receive blocks and receives message from other process using local TCP listening.
|
||||
// Note that, it only enables the TCP listening service when this function called.
|
||||
func Receive(group ...string) *MsgRequest {
|
||||
// Use atomic operations to guarantee only one receiver goroutine listening.
|
||||
if tcpListened.Cas(false, true) {
|
||||
go receiveTcpListening()
|
||||
}
|
||||
queue := (*gqueue.Queue)(nil)
|
||||
groupName := gPROC_COMM_DEFAULT_GRUOP_NAME
|
||||
var groupName string
|
||||
if len(group) > 0 {
|
||||
groupName = group[0]
|
||||
}
|
||||
if v := commReceiveQueues.Get(groupName); v == nil {
|
||||
commReceiveQueues.LockFunc(func(m map[string]interface{}) {
|
||||
if v, ok := m[groupName]; ok {
|
||||
queue = v.(*gqueue.Queue)
|
||||
} else {
|
||||
queue = gqueue.New(gPROC_MSG_QUEUE_MAX_LENGTH)
|
||||
m[groupName] = queue
|
||||
}
|
||||
})
|
||||
} else {
|
||||
queue = v.(*gqueue.Queue)
|
||||
groupName = gPROC_COMM_DEFAULT_GRUOP_NAME
|
||||
}
|
||||
queue := commReceiveQueues.GetOrSetFuncLock(groupName, func() interface{} {
|
||||
return gqueue.New(gPROC_MSG_QUEUE_MAX_LENGTH)
|
||||
}).(*gqueue.Queue)
|
||||
|
||||
// Blocking receiving.
|
||||
if v := queue.Pop(); v != nil {
|
||||
return v.(*Msg)
|
||||
return v.(*MsgRequest)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 创建本地进程TCP通信服务
|
||||
func startTcpListening() {
|
||||
// receiveTcpListening scans local for available port and starts listening.
|
||||
func receiveTcpListening() {
|
||||
var listen *net.TCPListener
|
||||
// Scan the available port for listening.
|
||||
for i := gPROC_DEFAULT_TCP_PORT; ; i++ {
|
||||
addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("127.0.0.1:%d", i))
|
||||
if err != nil {
|
||||
@ -74,57 +63,55 @@ func startTcpListening() {
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
// 将监听的端口保存到通信文件中(字符串类型存放)
|
||||
// Save the port to the pid file.
|
||||
if err := gfile.PutContents(getCommFilePath(Pid()), gconv.String(i)); err != nil {
|
||||
glog.Error(err)
|
||||
glog.Panic(err)
|
||||
}
|
||||
break
|
||||
}
|
||||
// Start listening.
|
||||
for {
|
||||
if conn, err := listen.Accept(); err != nil {
|
||||
glog.Error(err)
|
||||
} else if conn != nil {
|
||||
go tcpServiceHandler(gtcp.NewConnByNetConn(conn))
|
||||
go receiveTcpHandler(gtcp.NewConnByNetConn(conn))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TCP数据通信处理回调函数
|
||||
func tcpServiceHandler(conn *gtcp.Conn) {
|
||||
option := gtcp.PkgOption{
|
||||
Retry: gtcp.Retry{
|
||||
Count: 3,
|
||||
Interval: 10,
|
||||
},
|
||||
}
|
||||
// receiveTcpHandler is the connection handler for receiving data.
|
||||
func receiveTcpHandler(conn *gtcp.Conn) {
|
||||
var result []byte
|
||||
var response MsgResponse
|
||||
for {
|
||||
var result []byte
|
||||
buffer, err := conn.RecvPkg(option)
|
||||
buffer, err := conn.RecvPkg()
|
||||
if len(buffer) > 0 {
|
||||
msg := new(Msg)
|
||||
msg := new(MsgRequest)
|
||||
if err := json.Unmarshal(buffer, msg); err != nil {
|
||||
glog.Error(err)
|
||||
continue
|
||||
}
|
||||
if v := commReceiveQueues.Get(msg.Group); v == nil {
|
||||
result = []byte(fmt.Sprintf("group [%s] does not exist", msg.Group))
|
||||
break
|
||||
response.Code = 0
|
||||
response.Message = fmt.Sprintf("group [%s] does not exist", msg.Group)
|
||||
} else {
|
||||
result = []byte("ok")
|
||||
if v := commReceiveQueues.Get(msg.Group); v != nil {
|
||||
v.(*gqueue.Queue).Push(msg)
|
||||
}
|
||||
response.Code = 1
|
||||
v.(*gqueue.Queue).Push(msg)
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if err := conn.SendPkg(result, option); err != nil {
|
||||
result, err = json.Marshal(response)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
if err := conn.SendPkg(result); err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
} else {
|
||||
if err := conn.Close(); err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
return
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,28 +7,15 @@
|
||||
package gproc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/net/gtcp"
|
||||
"github.com/gogf/gf/os/gfcache"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
gPROC_COMM_FAILURE_RETRY_COUNT = 3 // 失败重试次数
|
||||
gPROC_COMM_FAILURE_RETRY_TIMEOUT = 1000 // (毫秒)失败重试间隔
|
||||
gPROC_COMM_SEND_TIMEOUT = 5000 // (毫秒)发送超时时间
|
||||
gPROC_COMM_DEFAULT_GRUOP_NAME = "" // 默认分组名称
|
||||
)
|
||||
|
||||
// 向指定gproc进程发送数据.
|
||||
// Send sends data to specified process of given pid.
|
||||
func Send(pid int, data []byte, group ...string) error {
|
||||
msg := Msg{
|
||||
msg := MsgRequest{
|
||||
SendPid: Pid(),
|
||||
RecvPid: pid,
|
||||
Group: gPROC_COMM_DEFAULT_GRUOP_NAME,
|
||||
@ -41,49 +28,27 @@ func Send(pid int, data []byte, group ...string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var buf []byte
|
||||
var conn *gtcp.PoolConn
|
||||
// 循环获取连接TCP对象
|
||||
for i := gPROC_COMM_FAILURE_RETRY_COUNT; i > 0; i-- {
|
||||
if conn, err = getConnByPid(pid); err == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(gPROC_COMM_FAILURE_RETRY_TIMEOUT * time.Millisecond)
|
||||
}
|
||||
if conn == nil {
|
||||
var conn *gtcp.Conn
|
||||
conn, err = getConnByPid(pid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
// 执行数据发送
|
||||
buf, err = conn.SendRecvPkgWithTimeout(msgBytes, gPROC_COMM_SEND_TIMEOUT*time.Millisecond)
|
||||
if len(buf) > 0 {
|
||||
if !bytes.EqualFold(buf, []byte("ok")) {
|
||||
err = errors.New(string(buf))
|
||||
// Do the sending.
|
||||
var result []byte
|
||||
result, err = conn.SendRecvPkg(msgBytes)
|
||||
if len(result) > 0 {
|
||||
response := new(MsgResponse)
|
||||
err = json.Unmarshal(result, response)
|
||||
if err == nil {
|
||||
if response.Code != 1 {
|
||||
err = errors.New(response.Message)
|
||||
}
|
||||
}
|
||||
}
|
||||
// EOF不算异常错误
|
||||
// EOF is not really an error.
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 获取指定进程的TCP通信对象
|
||||
func getConnByPid(pid int) (*gtcp.PoolConn, error) {
|
||||
port := getPortByPid(pid)
|
||||
if port > 0 {
|
||||
if conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", port)); err == nil {
|
||||
return conn, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nil, errors.New(fmt.Sprintf("could not find port for pid: %d", pid))
|
||||
}
|
||||
|
||||
// 获取指定进程监听的端口号
|
||||
func getPortByPid(pid int) int {
|
||||
path := getCommFilePath(pid)
|
||||
content := gfcache.GetContents(path)
|
||||
return gconv.Int(content)
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// 进程管理.
|
||||
package gproc
|
||||
|
||||
import (
|
||||
|
||||
@ -25,15 +25,12 @@ type Process struct {
|
||||
func NewProcess(path string, args []string, environment ...[]string) *Process {
|
||||
var env []string
|
||||
if len(environment) > 0 {
|
||||
env = make([]string, 0)
|
||||
for _, v := range environment[0] {
|
||||
env = append(env, v)
|
||||
}
|
||||
env = make([]string, len(environment[0]))
|
||||
copy(env, environment[0])
|
||||
} else {
|
||||
env = os.Environ()
|
||||
}
|
||||
env = append(env, fmt.Sprintf("%s=%s", gPROC_TEMP_DIR_ENV_KEY, os.TempDir()))
|
||||
p := &Process{
|
||||
process := &Process{
|
||||
Manager: nil,
|
||||
PPid: os.Getpid(),
|
||||
Cmd: exec.Cmd{
|
||||
@ -46,18 +43,16 @@ func NewProcess(path string, args []string, environment ...[]string) *Process {
|
||||
ExtraFiles: make([]*os.File, 0),
|
||||
},
|
||||
}
|
||||
// 当前工作目录
|
||||
if d, err := os.Getwd(); err == nil {
|
||||
p.Dir = d
|
||||
}
|
||||
process.Dir, _ = os.Getwd()
|
||||
if len(args) > 0 {
|
||||
// Exclude of current binary path.
|
||||
start := 0
|
||||
if strings.EqualFold(path, args[0]) {
|
||||
start = 1
|
||||
}
|
||||
p.Args = append(p.Args, args[start:]...)
|
||||
process.Args = append(process.Args, args[start:]...)
|
||||
}
|
||||
return p
|
||||
return process
|
||||
}
|
||||
|
||||
// NewProcessCmd creates and returns a process with given command and optional environment variable array.
|
||||
|
||||
@ -49,7 +49,7 @@ var (
|
||||
)
|
||||
|
||||
// Convert converts the variable <i> to the type <t>, the type <t> is specified by string.
|
||||
// The unnecessary parameter <params> is used for additional parameter passing.
|
||||
// The optional parameter <params> is used for additional parameter passing.
|
||||
func Convert(i interface{}, t string, params ...interface{}) interface{} {
|
||||
switch t {
|
||||
case "int":
|
||||
@ -84,6 +84,20 @@ func Convert(i interface{}, t string, params ...interface{}) interface{} {
|
||||
return Bytes(i)
|
||||
case "[]int":
|
||||
return Ints(i)
|
||||
case "[]int32":
|
||||
return Int32s(i)
|
||||
case "[]int64":
|
||||
return Int64s(i)
|
||||
case "[]uint":
|
||||
return Uints(i)
|
||||
case "[]uint32":
|
||||
return Uint32s(i)
|
||||
case "[]uint64":
|
||||
return Uint64s(i)
|
||||
case "[]float32":
|
||||
return Float32s(i)
|
||||
case "[]float64":
|
||||
return Float64s(i)
|
||||
case "[]string":
|
||||
return Strings(i)
|
||||
|
||||
@ -188,8 +202,6 @@ func String(i interface{}) string {
|
||||
return value
|
||||
case []byte:
|
||||
return string(value)
|
||||
case []rune:
|
||||
return string(value)
|
||||
case *time.Time:
|
||||
if value == nil {
|
||||
return ""
|
||||
|
||||
@ -10,35 +10,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/internal/utilstr"
|
||||
)
|
||||
|
||||
// SliceInt is alias of Ints.
|
||||
func SliceInt(i interface{}) []int {
|
||||
return Ints(i)
|
||||
}
|
||||
|
||||
// SliceUint is alias of Uints.
|
||||
func SliceUint(i interface{}) []uint {
|
||||
return Uints(i)
|
||||
}
|
||||
|
||||
// SliceStr is alias of Strings.
|
||||
func SliceStr(i interface{}) []string {
|
||||
return Strings(i)
|
||||
}
|
||||
|
||||
// SliceAny is alias of Interfaces.
|
||||
func SliceAny(i interface{}) []interface{} {
|
||||
return Interfaces(i)
|
||||
}
|
||||
|
||||
// SliceFloat is alias of Floats.
|
||||
func SliceFloat(i interface{}) []float64 {
|
||||
return Floats(i)
|
||||
}
|
||||
|
||||
// SliceMap is alias of Maps.
|
||||
func SliceMap(i interface{}) []map[string]interface{} {
|
||||
return Maps(i)
|
||||
@ -59,489 +32,6 @@ func SliceStructDeep(params interface{}, pointer interface{}, mapping ...map[str
|
||||
return StructsDeep(params, pointer, mapping...)
|
||||
}
|
||||
|
||||
// Ints converts <i> to []int.
|
||||
func Ints(i interface{}) []int {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
if r, ok := i.([]int); ok {
|
||||
return r
|
||||
} else {
|
||||
var array []int
|
||||
switch value := i.(type) {
|
||||
case []string:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int(v)
|
||||
}
|
||||
case []int8:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int(v)
|
||||
}
|
||||
case []int16:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int(v)
|
||||
}
|
||||
case []int32:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int(v)
|
||||
}
|
||||
case []int64:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int(v)
|
||||
}
|
||||
case []uint:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int(v)
|
||||
}
|
||||
case []uint8:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int(v)
|
||||
}
|
||||
case []uint16:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int(v)
|
||||
}
|
||||
case []uint32:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int(v)
|
||||
}
|
||||
case []uint64:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int(v)
|
||||
}
|
||||
case []bool:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
if v {
|
||||
array[k] = 1
|
||||
} else {
|
||||
array[k] = 0
|
||||
}
|
||||
}
|
||||
case []float32:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int(v)
|
||||
}
|
||||
case []float64:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int(v)
|
||||
}
|
||||
case []interface{}:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int(v)
|
||||
}
|
||||
case [][]byte:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int(v)
|
||||
}
|
||||
default:
|
||||
return []int{Int(i)}
|
||||
}
|
||||
return array
|
||||
}
|
||||
}
|
||||
|
||||
// Uints converts <i> to []uint.
|
||||
func Uints(i interface{}) []uint {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
if r, ok := i.([]uint); ok {
|
||||
return r
|
||||
} else {
|
||||
var array []uint
|
||||
switch value := i.(type) {
|
||||
case []string:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint(v)
|
||||
}
|
||||
case []int8:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint(v)
|
||||
}
|
||||
case []int16:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint(v)
|
||||
}
|
||||
case []int32:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint(v)
|
||||
}
|
||||
case []int64:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint(v)
|
||||
}
|
||||
case []uint8:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint(v)
|
||||
}
|
||||
case []uint16:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint(v)
|
||||
}
|
||||
case []uint32:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint(v)
|
||||
}
|
||||
case []uint64:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint(v)
|
||||
}
|
||||
case []bool:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
if v {
|
||||
array[k] = 1
|
||||
} else {
|
||||
array[k] = 0
|
||||
}
|
||||
}
|
||||
case []float32:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint(v)
|
||||
}
|
||||
case []float64:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint(v)
|
||||
}
|
||||
case []interface{}:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint(v)
|
||||
}
|
||||
case [][]byte:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint(v)
|
||||
}
|
||||
default:
|
||||
return []uint{Uint(i)}
|
||||
}
|
||||
return array
|
||||
}
|
||||
}
|
||||
|
||||
// Strings converts <i> to []string.
|
||||
func Strings(i interface{}) []string {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
if r, ok := i.([]string); ok {
|
||||
return r
|
||||
} else {
|
||||
var array []string
|
||||
switch value := i.(type) {
|
||||
case []int:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []int8:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []int16:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []int32:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []int64:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []uint:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []uint8:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []uint16:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []uint32:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []uint64:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []bool:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []float32:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []float64:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []interface{}:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case [][]byte:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
default:
|
||||
return []string{String(i)}
|
||||
}
|
||||
return array
|
||||
}
|
||||
}
|
||||
|
||||
// Strings converts <i> to []float64.
|
||||
func Floats(i interface{}) []float64 {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
if r, ok := i.([]float64); ok {
|
||||
return r
|
||||
} else {
|
||||
var array []float64
|
||||
switch value := i.(type) {
|
||||
case []string:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []int:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []int8:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []int16:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []int32:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []int64:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []uint:
|
||||
for _, v := range value {
|
||||
array = append(array, Float64(v))
|
||||
}
|
||||
case []uint8:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []uint16:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []uint32:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []uint64:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []bool:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []float32:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []interface{}:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
default:
|
||||
return []float64{Float64(i)}
|
||||
}
|
||||
return array
|
||||
}
|
||||
}
|
||||
|
||||
// Type assert api for Interfaces.
|
||||
type apiInterfaces interface {
|
||||
Interfaces() []interface{}
|
||||
}
|
||||
|
||||
// Interfaces converts <i> to []interface{}.
|
||||
func Interfaces(i interface{}) []interface{} {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
if r, ok := i.([]interface{}); ok {
|
||||
return r
|
||||
} else if r, ok := i.(apiInterfaces); ok {
|
||||
return r.Interfaces()
|
||||
} else {
|
||||
var array []interface{}
|
||||
switch value := i.(type) {
|
||||
case []string:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []int:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []int8:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []int16:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []int32:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []int64:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []uint:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []uint8:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []uint16:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []uint32:
|
||||
for _, v := range value {
|
||||
array = append(array, v)
|
||||
}
|
||||
case []uint64:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []bool:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []float32:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []float64:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
default:
|
||||
// Finally we use reflection.
|
||||
rv := reflect.ValueOf(i)
|
||||
kind := rv.Kind()
|
||||
for kind == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
}
|
||||
switch kind {
|
||||
case reflect.Slice, reflect.Array:
|
||||
array = make([]interface{}, rv.Len())
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
array[i] = rv.Index(i).Interface()
|
||||
}
|
||||
case reflect.Struct:
|
||||
rt := rv.Type()
|
||||
array = make([]interface{}, 0)
|
||||
for i := 0; i < rv.NumField(); i++ {
|
||||
// Only public attributes.
|
||||
if !utilstr.IsLetterUpper(rt.Field(i).Name[0]) {
|
||||
continue
|
||||
}
|
||||
array = append(array, rv.Field(i).Interface())
|
||||
}
|
||||
default:
|
||||
return []interface{}{i}
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
}
|
||||
|
||||
// Maps converts <i> to []map[string]interface{}.
|
||||
func Maps(value interface{}, tags ...string) []map[string]interface{} {
|
||||
if value == nil {
|
||||
|
||||
135
util/gconv/gconv_slice_any.go
Normal file
135
util/gconv/gconv_slice_any.go
Normal file
@ -0,0 +1,135 @@
|
||||
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gconv
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/internal/utilstr"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// SliceAny is alias of Interfaces.
|
||||
func SliceAny(i interface{}) []interface{} {
|
||||
return Interfaces(i)
|
||||
}
|
||||
|
||||
// Type assert api for Interfaces.
|
||||
type apiInterfaces interface {
|
||||
Interfaces() []interface{}
|
||||
}
|
||||
|
||||
// Interfaces converts <i> to []interface{}.
|
||||
func Interfaces(i interface{}) []interface{} {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
if r, ok := i.([]interface{}); ok {
|
||||
return r
|
||||
} else if r, ok := i.(apiInterfaces); ok {
|
||||
return r.Interfaces()
|
||||
} else {
|
||||
var array []interface{}
|
||||
switch value := i.(type) {
|
||||
case []string:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []int:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []int8:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []int16:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []int32:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []int64:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []uint:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []uint8:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []uint16:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []uint32:
|
||||
for _, v := range value {
|
||||
array = append(array, v)
|
||||
}
|
||||
case []uint64:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []bool:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []float32:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
case []float64:
|
||||
array = make([]interface{}, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = v
|
||||
}
|
||||
default:
|
||||
// Finally we use reflection.
|
||||
rv := reflect.ValueOf(i)
|
||||
kind := rv.Kind()
|
||||
for kind == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
}
|
||||
switch kind {
|
||||
case reflect.Slice, reflect.Array:
|
||||
array = make([]interface{}, rv.Len())
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
array[i] = rv.Index(i).Interface()
|
||||
}
|
||||
case reflect.Struct:
|
||||
rt := rv.Type()
|
||||
array = make([]interface{}, 0)
|
||||
for i := 0; i < rv.NumField(); i++ {
|
||||
// Only public attributes.
|
||||
if !utilstr.IsLetterUpper(rt.Field(i).Name[0]) {
|
||||
continue
|
||||
}
|
||||
array = append(array, rv.Field(i).Interface())
|
||||
}
|
||||
default:
|
||||
return []interface{}{i}
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
}
|
||||
199
util/gconv/gconv_slice_float.go
Normal file
199
util/gconv/gconv_slice_float.go
Normal file
@ -0,0 +1,199 @@
|
||||
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gconv
|
||||
|
||||
// SliceFloat is alias of Floats.
|
||||
func SliceFloat(i interface{}) []float64 {
|
||||
return Floats(i)
|
||||
}
|
||||
|
||||
// SliceFloat32 is alias of Float32s.
|
||||
func SliceFloat32(i interface{}) []float32 {
|
||||
return Float32s(i)
|
||||
}
|
||||
|
||||
// SliceFloat64 is alias of Float64s.
|
||||
func SliceFloat64(i interface{}) []float64 {
|
||||
return Floats(i)
|
||||
}
|
||||
|
||||
// Floats converts <i> to []float64.
|
||||
func Floats(i interface{}) []float64 {
|
||||
return Float64s(i)
|
||||
}
|
||||
|
||||
// Float32s converts <i> to []float32.
|
||||
func Float32s(i interface{}) []float32 {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
if r, ok := i.([]float32); ok {
|
||||
return r
|
||||
} else {
|
||||
var array []float32
|
||||
switch value := i.(type) {
|
||||
case []string:
|
||||
array = make([]float32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float32(v)
|
||||
}
|
||||
case []int:
|
||||
array = make([]float32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float32(v)
|
||||
}
|
||||
case []int8:
|
||||
array = make([]float32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float32(v)
|
||||
}
|
||||
case []int16:
|
||||
array = make([]float32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float32(v)
|
||||
}
|
||||
case []int32:
|
||||
array = make([]float32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float32(v)
|
||||
}
|
||||
case []int64:
|
||||
array = make([]float32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float32(v)
|
||||
}
|
||||
case []uint:
|
||||
for _, v := range value {
|
||||
array = append(array, Float32(v))
|
||||
}
|
||||
case []uint8:
|
||||
array = make([]float32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float32(v)
|
||||
}
|
||||
case []uint16:
|
||||
array = make([]float32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float32(v)
|
||||
}
|
||||
case []uint32:
|
||||
array = make([]float32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float32(v)
|
||||
}
|
||||
case []uint64:
|
||||
array = make([]float32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float32(v)
|
||||
}
|
||||
case []bool:
|
||||
array = make([]float32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float32(v)
|
||||
}
|
||||
case []float64:
|
||||
array = make([]float32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float32(v)
|
||||
}
|
||||
case []interface{}:
|
||||
array = make([]float32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float32(v)
|
||||
}
|
||||
default:
|
||||
return []float32{Float32(i)}
|
||||
}
|
||||
return array
|
||||
}
|
||||
}
|
||||
|
||||
// Float64s converts <i> to []float64.
|
||||
func Float64s(i interface{}) []float64 {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
if r, ok := i.([]float64); ok {
|
||||
return r
|
||||
} else {
|
||||
var array []float64
|
||||
switch value := i.(type) {
|
||||
case []string:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []int:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []int8:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []int16:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []int32:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []int64:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []uint:
|
||||
for _, v := range value {
|
||||
array = append(array, Float64(v))
|
||||
}
|
||||
case []uint8:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []uint16:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []uint32:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []uint64:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []bool:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []float32:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
case []interface{}:
|
||||
array = make([]float64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Float64(v)
|
||||
}
|
||||
default:
|
||||
return []float64{Float64(i)}
|
||||
}
|
||||
return array
|
||||
}
|
||||
}
|
||||
310
util/gconv/gconv_slice_int.go
Normal file
310
util/gconv/gconv_slice_int.go
Normal file
@ -0,0 +1,310 @@
|
||||
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gconv
|
||||
|
||||
// SliceInt is alias of Ints.
|
||||
func SliceInt(i interface{}) []int {
|
||||
return Ints(i)
|
||||
}
|
||||
|
||||
// SliceInt32 is alias of Int32s.
|
||||
func SliceInt32(i interface{}) []int32 {
|
||||
return Int32s(i)
|
||||
}
|
||||
|
||||
// SliceInt is alias of Int64s.
|
||||
func SliceInt64(i interface{}) []int64 {
|
||||
return Int64s(i)
|
||||
}
|
||||
|
||||
// Ints converts <i> to []int.
|
||||
func Ints(i interface{}) []int {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
if r, ok := i.([]int); ok {
|
||||
return r
|
||||
} else {
|
||||
var array []int
|
||||
switch value := i.(type) {
|
||||
case []string:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int(v)
|
||||
}
|
||||
case []int8:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int(v)
|
||||
}
|
||||
case []int16:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int(v)
|
||||
}
|
||||
case []int32:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int(v)
|
||||
}
|
||||
case []int64:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int(v)
|
||||
}
|
||||
case []uint:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int(v)
|
||||
}
|
||||
case []uint8:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int(v)
|
||||
}
|
||||
case []uint16:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int(v)
|
||||
}
|
||||
case []uint32:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int(v)
|
||||
}
|
||||
case []uint64:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int(v)
|
||||
}
|
||||
case []bool:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
if v {
|
||||
array[k] = 1
|
||||
} else {
|
||||
array[k] = 0
|
||||
}
|
||||
}
|
||||
case []float32:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int(v)
|
||||
}
|
||||
case []float64:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int(v)
|
||||
}
|
||||
case []interface{}:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int(v)
|
||||
}
|
||||
case [][]byte:
|
||||
array = make([]int, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int(v)
|
||||
}
|
||||
default:
|
||||
return []int{Int(i)}
|
||||
}
|
||||
return array
|
||||
}
|
||||
}
|
||||
|
||||
// Int32s converts <i> to []int32.
|
||||
func Int32s(i interface{}) []int32 {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
if r, ok := i.([]int32); ok {
|
||||
return r
|
||||
} else {
|
||||
var array []int32
|
||||
switch value := i.(type) {
|
||||
case []string:
|
||||
array = make([]int32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int32(v)
|
||||
}
|
||||
case []int:
|
||||
array = make([]int32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int32(v)
|
||||
}
|
||||
case []int8:
|
||||
array = make([]int32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int32(v)
|
||||
}
|
||||
case []int16:
|
||||
array = make([]int32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int32(v)
|
||||
}
|
||||
case []int64:
|
||||
array = make([]int32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int32(v)
|
||||
}
|
||||
case []uint:
|
||||
array = make([]int32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int32(v)
|
||||
}
|
||||
case []uint8:
|
||||
array = make([]int32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int32(v)
|
||||
}
|
||||
case []uint16:
|
||||
array = make([]int32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int32(v)
|
||||
}
|
||||
case []uint32:
|
||||
array = make([]int32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int32(v)
|
||||
}
|
||||
case []uint64:
|
||||
array = make([]int32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int32(v)
|
||||
}
|
||||
case []bool:
|
||||
array = make([]int32, len(value))
|
||||
for k, v := range value {
|
||||
if v {
|
||||
array[k] = 1
|
||||
} else {
|
||||
array[k] = 0
|
||||
}
|
||||
}
|
||||
case []float32:
|
||||
array = make([]int32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int32(v)
|
||||
}
|
||||
case []float64:
|
||||
array = make([]int32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int32(v)
|
||||
}
|
||||
case []interface{}:
|
||||
array = make([]int32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int32(v)
|
||||
}
|
||||
case [][]byte:
|
||||
array = make([]int32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int32(v)
|
||||
}
|
||||
default:
|
||||
return []int32{Int32(i)}
|
||||
}
|
||||
return array
|
||||
}
|
||||
}
|
||||
|
||||
// Int64s converts <i> to []int64.
|
||||
func Int64s(i interface{}) []int64 {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
if r, ok := i.([]int64); ok {
|
||||
return r
|
||||
} else {
|
||||
var array []int64
|
||||
switch value := i.(type) {
|
||||
case []string:
|
||||
array = make([]int64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int64(v)
|
||||
}
|
||||
case []int:
|
||||
array = make([]int64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int64(v)
|
||||
}
|
||||
case []int8:
|
||||
array = make([]int64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int64(v)
|
||||
}
|
||||
case []int16:
|
||||
array = make([]int64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int64(v)
|
||||
}
|
||||
case []int32:
|
||||
array = make([]int64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int64(v)
|
||||
}
|
||||
case []uint:
|
||||
array = make([]int64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int64(v)
|
||||
}
|
||||
case []uint8:
|
||||
array = make([]int64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int64(v)
|
||||
}
|
||||
case []uint16:
|
||||
array = make([]int64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int64(v)
|
||||
}
|
||||
case []uint32:
|
||||
array = make([]int64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int64(v)
|
||||
}
|
||||
case []uint64:
|
||||
array = make([]int64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = int64(v)
|
||||
}
|
||||
case []bool:
|
||||
array = make([]int64, len(value))
|
||||
for k, v := range value {
|
||||
if v {
|
||||
array[k] = 1
|
||||
} else {
|
||||
array[k] = 0
|
||||
}
|
||||
}
|
||||
case []float32:
|
||||
array = make([]int64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int64(v)
|
||||
}
|
||||
case []float64:
|
||||
array = make([]int64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int64(v)
|
||||
}
|
||||
case []interface{}:
|
||||
array = make([]int64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int64(v)
|
||||
}
|
||||
case [][]byte:
|
||||
array = make([]int64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Int64(v)
|
||||
}
|
||||
default:
|
||||
return []int64{Int64(i)}
|
||||
}
|
||||
return array
|
||||
}
|
||||
}
|
||||
104
util/gconv/gconv_slice_str.go
Normal file
104
util/gconv/gconv_slice_str.go
Normal file
@ -0,0 +1,104 @@
|
||||
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gconv
|
||||
|
||||
// SliceStr is alias of Strings.
|
||||
func SliceStr(i interface{}) []string {
|
||||
return Strings(i)
|
||||
}
|
||||
|
||||
// Strings converts <i> to []string.
|
||||
func Strings(i interface{}) []string {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
if r, ok := i.([]string); ok {
|
||||
return r
|
||||
} else {
|
||||
var array []string
|
||||
switch value := i.(type) {
|
||||
case []int:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []int8:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []int16:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []int32:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []int64:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []uint:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []uint8:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []uint16:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []uint32:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []uint64:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []bool:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []float32:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []float64:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case []interface{}:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
case [][]byte:
|
||||
array = make([]string, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = String(v)
|
||||
}
|
||||
default:
|
||||
return []string{String(i)}
|
||||
}
|
||||
return array
|
||||
}
|
||||
}
|
||||
295
util/gconv/gconv_slice_uint.go
Normal file
295
util/gconv/gconv_slice_uint.go
Normal file
@ -0,0 +1,295 @@
|
||||
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gconv
|
||||
|
||||
// SliceUint is alias of Uints.
|
||||
func SliceUint(i interface{}) []uint {
|
||||
return Uints(i)
|
||||
}
|
||||
|
||||
// SliceUint32 is alias of Uint32s.
|
||||
func SliceUint32(i interface{}) []uint32 {
|
||||
return Uint32s(i)
|
||||
}
|
||||
|
||||
// SliceUint64 is alias of Uint64s.
|
||||
func SliceUint64(i interface{}) []uint64 {
|
||||
return Uint64s(i)
|
||||
}
|
||||
|
||||
// Uints converts <i> to []uint.
|
||||
func Uints(i interface{}) []uint {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
if r, ok := i.([]uint); ok {
|
||||
return r
|
||||
} else {
|
||||
var array []uint
|
||||
switch value := i.(type) {
|
||||
case []string:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint(v)
|
||||
}
|
||||
case []int8:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint(v)
|
||||
}
|
||||
case []int16:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint(v)
|
||||
}
|
||||
case []int32:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint(v)
|
||||
}
|
||||
case []int64:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint(v)
|
||||
}
|
||||
case []uint8:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint(v)
|
||||
}
|
||||
case []uint16:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint(v)
|
||||
}
|
||||
case []uint32:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint(v)
|
||||
}
|
||||
case []uint64:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint(v)
|
||||
}
|
||||
case []bool:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
if v {
|
||||
array[k] = 1
|
||||
} else {
|
||||
array[k] = 0
|
||||
}
|
||||
}
|
||||
case []float32:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint(v)
|
||||
}
|
||||
case []float64:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint(v)
|
||||
}
|
||||
case []interface{}:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint(v)
|
||||
}
|
||||
case [][]byte:
|
||||
array = make([]uint, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint(v)
|
||||
}
|
||||
default:
|
||||
return []uint{Uint(i)}
|
||||
}
|
||||
return array
|
||||
}
|
||||
}
|
||||
|
||||
// Uint32s converts <i> to []uint32.
|
||||
func Uint32s(i interface{}) []uint32 {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
if r, ok := i.([]uint32); ok {
|
||||
return r
|
||||
} else {
|
||||
var array []uint32
|
||||
switch value := i.(type) {
|
||||
case []string:
|
||||
array = make([]uint32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint32(v)
|
||||
}
|
||||
case []int8:
|
||||
array = make([]uint32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint32(v)
|
||||
}
|
||||
case []int16:
|
||||
array = make([]uint32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint32(v)
|
||||
}
|
||||
case []int32:
|
||||
array = make([]uint32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint32(v)
|
||||
}
|
||||
case []int64:
|
||||
array = make([]uint32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint32(v)
|
||||
}
|
||||
case []uint:
|
||||
array = make([]uint32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint32(v)
|
||||
}
|
||||
case []uint8:
|
||||
array = make([]uint32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint32(v)
|
||||
}
|
||||
case []uint16:
|
||||
array = make([]uint32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint32(v)
|
||||
}
|
||||
case []uint64:
|
||||
array = make([]uint32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint32(v)
|
||||
}
|
||||
case []bool:
|
||||
array = make([]uint32, len(value))
|
||||
for k, v := range value {
|
||||
if v {
|
||||
array[k] = 1
|
||||
} else {
|
||||
array[k] = 0
|
||||
}
|
||||
}
|
||||
case []float32:
|
||||
array = make([]uint32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint32(v)
|
||||
}
|
||||
case []float64:
|
||||
array = make([]uint32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint32(v)
|
||||
}
|
||||
case []interface{}:
|
||||
array = make([]uint32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint32(v)
|
||||
}
|
||||
case [][]byte:
|
||||
array = make([]uint32, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint32(v)
|
||||
}
|
||||
default:
|
||||
return []uint32{Uint32(i)}
|
||||
}
|
||||
return array
|
||||
}
|
||||
}
|
||||
|
||||
// Uint64s converts <i> to []uint64.
|
||||
func Uint64s(i interface{}) []uint64 {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
if r, ok := i.([]uint64); ok {
|
||||
return r
|
||||
} else {
|
||||
var array []uint64
|
||||
switch value := i.(type) {
|
||||
case []string:
|
||||
array = make([]uint64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint64(v)
|
||||
}
|
||||
case []int8:
|
||||
array = make([]uint64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint64(v)
|
||||
}
|
||||
case []int16:
|
||||
array = make([]uint64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint64(v)
|
||||
}
|
||||
case []int32:
|
||||
array = make([]uint64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint64(v)
|
||||
}
|
||||
case []int64:
|
||||
array = make([]uint64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint64(v)
|
||||
}
|
||||
case []uint:
|
||||
array = make([]uint64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint64(v)
|
||||
}
|
||||
case []uint8:
|
||||
array = make([]uint64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint64(v)
|
||||
}
|
||||
case []uint16:
|
||||
array = make([]uint64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint64(v)
|
||||
}
|
||||
case []uint32:
|
||||
array = make([]uint64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = uint64(v)
|
||||
}
|
||||
case []bool:
|
||||
array = make([]uint64, len(value))
|
||||
for k, v := range value {
|
||||
if v {
|
||||
array[k] = 1
|
||||
} else {
|
||||
array[k] = 0
|
||||
}
|
||||
}
|
||||
case []float32:
|
||||
array = make([]uint64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint64(v)
|
||||
}
|
||||
case []float64:
|
||||
array = make([]uint64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint64(v)
|
||||
}
|
||||
case []interface{}:
|
||||
array = make([]uint64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint64(v)
|
||||
}
|
||||
case [][]byte:
|
||||
array = make([]uint64, len(value))
|
||||
for k, v := range value {
|
||||
array[k] = Uint64(v)
|
||||
}
|
||||
default:
|
||||
return []uint64{Uint64(i)}
|
||||
}
|
||||
return array
|
||||
}
|
||||
}
|
||||
98
util/gconv/gconv_z_unit_struct_slice_test.go
Normal file
98
util/gconv/gconv_z_unit_struct_slice_test.go
Normal file
@ -0,0 +1,98 @@
|
||||
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gconv_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
func Test_Struct_Slice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
type User struct {
|
||||
Scores []int
|
||||
}
|
||||
user := new(User)
|
||||
array := g.Slice{1, 2, 3}
|
||||
err := gconv.Struct(g.Map{"scores": array}, user)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(user.Scores, array)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
type User struct {
|
||||
Scores []int32
|
||||
}
|
||||
user := new(User)
|
||||
array := g.Slice{1, 2, 3}
|
||||
err := gconv.Struct(g.Map{"scores": array}, user)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(user.Scores, array)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
type User struct {
|
||||
Scores []int64
|
||||
}
|
||||
user := new(User)
|
||||
array := g.Slice{1, 2, 3}
|
||||
err := gconv.Struct(g.Map{"scores": array}, user)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(user.Scores, array)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
type User struct {
|
||||
Scores []uint
|
||||
}
|
||||
user := new(User)
|
||||
array := g.Slice{1, 2, 3}
|
||||
err := gconv.Struct(g.Map{"scores": array}, user)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(user.Scores, array)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
type User struct {
|
||||
Scores []uint32
|
||||
}
|
||||
user := new(User)
|
||||
array := g.Slice{1, 2, 3}
|
||||
err := gconv.Struct(g.Map{"scores": array}, user)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(user.Scores, array)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
type User struct {
|
||||
Scores []uint64
|
||||
}
|
||||
user := new(User)
|
||||
array := g.Slice{1, 2, 3}
|
||||
err := gconv.Struct(g.Map{"scores": array}, user)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(user.Scores, array)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
type User struct {
|
||||
Scores []float32
|
||||
}
|
||||
user := new(User)
|
||||
array := g.Slice{1, 2, 3}
|
||||
err := gconv.Struct(g.Map{"scores": array}, user)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(user.Scores, array)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
type User struct {
|
||||
Scores []float64
|
||||
}
|
||||
user := new(User)
|
||||
array := g.Slice{1, 2, 3}
|
||||
err := gconv.Struct(g.Map{"scores": array}, user)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(user.Scores, array)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user