├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── cmd └── cmd.go ├── config └── config.go ├── delay-queue.conf ├── delayqueue ├── bucket.go ├── delay_queue.go ├── job.go ├── ready_queue.go └── redis.go ├── main.go ├── routers └── routers.go └── vendor ├── github.com ├── garyburd │ └── redigo │ │ ├── LICENSE │ │ ├── internal │ │ └── commandinfo.go │ │ └── redis │ │ ├── conn.go │ │ ├── doc.go │ │ ├── go17.go │ │ ├── log.go │ │ ├── pool.go │ │ ├── pre_go17.go │ │ ├── pubsub.go │ │ ├── redis.go │ │ ├── reply.go │ │ ├── scan.go │ │ └── script.go └── vmihailenco │ └── msgpack │ ├── CHANGELOG.md │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── appengine.go │ ├── codes │ └── codes.go │ ├── decode.go │ ├── decode_map.go │ ├── decode_number.go │ ├── decode_query.go │ ├── decode_slice.go │ ├── decode_string.go │ ├── decode_value.go │ ├── encode.go │ ├── encode_map.go │ ├── encode_number.go │ ├── encode_slice.go │ ├── encode_value.go │ ├── ext.go │ ├── msgpack.go │ ├── tags.go │ ├── time.go │ └── types.go ├── gopkg.in └── ini.v1 │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── README_ZH.md │ ├── error.go │ ├── ini.go │ ├── key.go │ ├── parser.go │ ├── section.go │ └── struct.go └── vendor.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 14 | .glide/ 15 | 16 | 17 | # PHPStorm 18 | .idea 19 | 20 | # project 21 | delay-queue 22 | main 23 | node_modules 24 | package.json -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.7.x 4 | 5 | notifications: 6 | on_success: never 7 | on_failure: always -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 qiang.ou 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # delay-queue 2 | [![Go Report Card](https://goreportcard.com/badge/github.com/ouqiang/delay-queue)](https://goreportcard.com/report/github.com/ouqiang/delay-queue) 3 | [![Downloads](https://img.shields.io/github/downloads/ouqiang/delay-queue/total.svg)](https://github.com/ouqiang/delay-queue/releases) 4 | [![license](https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000)](https://github.com/ouqiang/delay-queue/blob/master/LICENSE) 5 | [![Release](https://img.shields.io/github/release/ouqiang/delay-queue.svg?label=Release)](https://github.com/ouqiang/delay-queue/releases) 6 | 7 | 基于Redis实现的延迟队列, 参考[有赞延迟队列设计](http://tech.youzan.com/queuing_delay)实现 8 | 9 | ## 应用场景 10 | * 订单超过30分钟未支付,自动关闭 11 | * 订单完成后, 如果用户一直未评价, 5天后自动好评 12 | * 会员到期前15天, 到期前3天分别发送短信提醒 13 | 14 | ## 支付宝异步通知实现 15 | 支付宝异步通知时间间隔是如何实现的(通知的间隔频率一般是:2m,10m,10m,1h,2h,6h,15h)   16 | 17 | 订单支付成功后, 生成通知任务, 放入消息队列中. 18 | 任务内容包含Array{0,0,2m,10m,10m,1h,2h,6h,15h}和通知到第几次N(这里N=1, 即第1次). 19 | 消费者从队列中取出任务, 根据N取得对应的时间间隔为0, 立即发送通知. 20 | 21 | 第1次通知失败, N += 1 => 2 22 | 从Array中取得间隔时间为2m, 添加一个延迟时间为2m的任务到延迟队列, 任务内容仍包含Array和N 23 | 24 | 第2次通知失败, N += 1 => 3, 取出对应的间隔时间10m, 添加一个任务到延迟队列, 同上 25 | ...... 26 | 第7次通知失败, N += 1 => 8, 取出对应的间隔时间15h, 添加一个任务到延迟队列, 同上 27 | 第8次通知失败, N += 1 => 9, 取不到间隔时间, 结束通知 28 | 29 | 30 | ## 实现原理 31 | > 利用Redis的有序集合,member为JobId, score为任务执行的时间戳, 32 | 每秒扫描一次集合,取出执行时间小于等于当前时间的任务. 33 | 34 | ## 依赖 35 | * Redis 36 | 37 | ## 下载 38 | [releases](https://github.com/ouqiang/delay-queue/releases) 39 | 40 | 41 | ## 源码安装 42 | * `go`语言版本1.7+ 43 | * `go get -d github.com/ouqiang/delay-queue` 44 | * `go build` 45 | 46 | 47 | ## 运行 48 | `./delay-queue -c delay-queue.conf` 49 | > HTTP Server监听`0.0.0.0:9277`, Redis连接地址`127.0.0.1:6379`, 数据库编号`1` 50 | 51 | ## 客户端 52 | [PHP](https://github.com/ouqiang/delayqueue-php) 53 | 54 | ## HTTP接口 55 | 56 | * 请求方法 `POST` 57 | * 请求Body及返回值均为`json` 58 | 59 | ### 返回值 60 | ```json 61 | { 62 | "code": 0, 63 | "message": "添加成功", 64 | "data": null 65 | } 66 | ``` 67 | 68 | | 参数名 | 类型 | 含义 | 备注 | 69 | |:-------:|:-----------:|:------------:|:-----------------:| 70 | | code | int | 状态码 | 0: 成功 非0: 失败 | 71 | | message | string | 状态描述信息 | | 72 | | data | object, null | 附加信息 | | 73 | 74 | ### 添加任务 75 | URL地址 `/push` 76 | ```json 77 | { 78 | "topic": "order", 79 | "id": "15702398321", 80 | "delay": 3600, 81 | "ttr": 120, 82 | "body": "{\"uid\": 10829378,\"created\": 1498657365 }" 83 | } 84 | ``` 85 | | 参数名 | 类型 | 含义 | 备注 | 86 | |:-------:|:-----------:|:------------:|:-----------------:| 87 | | topic | string | Job类型 | | 88 | | id | string | Job唯一标识 | 需确保JobID唯一 | 89 | | delay | int | Job需要延迟的时间, 单位:秒 | | 90 | | ttr | int | Job执行超时时间, 单位:秒 | | 91 | | body | string | Job的内容,供消费者做具体的业务处理,如果是json格式需转义 | | 92 | 93 | ### 轮询队列获取任务 94 | 服务端会Hold住连接, 直到队列中有任务或180秒后超时返回, 95 | 任务执行完成后需调用`finish`接口删除任务, 否则任务会重复投递, 消费端需能处理同一任务的多次投递 96 | 97 | 98 | URL地址 `/pop` 99 | ```json 100 | { 101 | "topic": "order" 102 | } 103 | ``` 104 | | 参数名 | 类型 | 含义 | 备注 | 105 | |:-------:|:-----------:|:------------:|:-----------------:| 106 | | topic | string | Job类型 | | 107 | 108 | 109 | 队列中有任务返回值 110 | ```json 111 | { 112 | "code": 0, 113 | "message": "操作成功", 114 | "data": { 115 | "id": "15702398321", 116 | "body": "{\"uid\": 10829378,\"created\": 1498657365 }" 117 | } 118 | } 119 | ``` 120 | 队列为空返回值 121 | ```json 122 | { 123 | "code": 0, 124 | "message": "操作成功", 125 | "data": null 126 | } 127 | ``` 128 | 129 | 130 | ### 删除任务 131 | URL地址 `/delete` 132 | 133 | ```json 134 | { 135 | "id": "15702398321" 136 | } 137 | ``` 138 | 139 | | 参数名 | 类型 | 含义 | 备注 | 140 | |:-------:|:-----------:|:------------:|:-----------------:| 141 | | id | string | Job唯一标识 | | 142 | 143 | 144 | ### 完成任务 145 | URL地址 `/finish` 146 | 147 | ```json 148 | { 149 | "id": "15702398321" 150 | } 151 | ``` 152 | 153 | | 参数名 | 类型 | 含义 | 备注 | 154 | |:-------:|:-----------:|:------------:|:-----------------:| 155 | | id | string | Job唯一标识 | | 156 | 157 | 158 | ### 查询任务 159 | URL地址 `/get` 160 | 161 | ```json 162 | { 163 | "id": "15702398321" 164 | } 165 | ``` 166 | 167 | | 参数名 | 类型 | 含义 | 备注 | 168 | |:-------:|:-----------:|:------------:|:-----------------:| 169 | | id | string | Job唯一标识 | | 170 | 171 | 172 | 返回值 173 | ```json 174 | { 175 | "code": 0, 176 | "message": "操作成功", 177 | "data": { 178 | "topic": "order", 179 | "id": "15702398321", 180 | "delay": 1506787453, 181 | "ttr": 60, 182 | "body": "{\"uid\": 10829378,\"created\": 1498657365 }" 183 | 184 | } 185 | } 186 | ``` 187 | 188 | | 参数名 | 类型 | 含义 | 备注 | 189 | |:-------:|:-----------:|:------------:|:-----------------:| 190 | | topic | string | Job类型 | | 191 | | id | string | Job唯一标识 | | 192 | | delay | int | Job延迟执行的时间戳 | | 193 | | ttr | int | Job执行超时时间, 单位:秒 | | 194 | | body | string | Job内容,供消费者做具体的业务处理 | 195 | 196 | 197 | Job不存在返回值 198 | ```json 199 | { 200 | "code": 0, 201 | "message": "操作成功", 202 | "data": null 203 | } 204 | ``` 205 | -------------------------------------------------------------------------------- /cmd/cmd.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | "os" 9 | 10 | "github.com/ouqiang/delay-queue/config" 11 | "github.com/ouqiang/delay-queue/delayqueue" 12 | "github.com/ouqiang/delay-queue/routers" 13 | ) 14 | 15 | // Cmd 应用入口Command 16 | type Cmd struct{} 17 | 18 | var ( 19 | version bool 20 | configFile string 21 | ) 22 | 23 | const ( 24 | // AppVersion 应用版本号 25 | AppVersion = "0.4" 26 | ) 27 | 28 | // Run 运行应用 29 | func (cmd *Cmd) Run() { 30 | 31 | // 解析命令行参数 32 | cmd.parseCommandArgs() 33 | if version { 34 | fmt.Println(AppVersion) 35 | os.Exit(0) 36 | } 37 | // 初始化配置 38 | config.Init(configFile) 39 | // 初始化队列 40 | delayqueue.Init() 41 | 42 | // 运行web server 43 | cmd.runWeb() 44 | } 45 | 46 | // 解析命令行参数 47 | func (cmd *Cmd) parseCommandArgs() { 48 | // 配置文件 49 | flag.StringVar(&configFile, "c", "", "./delay-queue -c /path/to/delay-queue.conf") 50 | // 版本 51 | flag.BoolVar(&version, "v", false, "./delay-queue -v") 52 | flag.Parse() 53 | } 54 | 55 | // 运行Web Server 56 | func (cmd *Cmd) runWeb() { 57 | http.HandleFunc("/push", routers.Push) 58 | http.HandleFunc("/pop", routers.Pop) 59 | http.HandleFunc("/finish", routers.Delete) 60 | http.HandleFunc("/delete", routers.Delete) 61 | http.HandleFunc("/get", routers.Get) 62 | 63 | log.Printf("listen %s\n", config.Setting.BindAddress) 64 | err := http.ListenAndServe(config.Setting.BindAddress, nil) 65 | log.Fatalln(err) 66 | } 67 | -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "log" 5 | 6 | "gopkg.in/ini.v1" 7 | ) 8 | 9 | // 解析配置文件 10 | 11 | var ( 12 | // Setting 配置实例 13 | Setting *Config 14 | ) 15 | 16 | const ( 17 | // DefaultBindAddress 监听地址 18 | DefaultBindAddress = "0.0.0.0:9277" 19 | // DefaultBucketSize bucket数量 20 | DefaultBucketSize = 3 21 | // DefaultBucketName bucket名称 22 | DefaultBucketName = "dq_bucket_%d" 23 | // DefaultQueueName 队列名称 24 | DefaultQueueName = "dq_queue_%s" 25 | // DefaultQueueBlockTimeout 轮询队列超时时间 26 | DefaultQueueBlockTimeout = 178 27 | // DefaultRedisHost Redis连接地址 28 | DefaultRedisHost = "127.0.0.1:6379" 29 | // DefaultRedisDb Redis数据库编号 30 | DefaultRedisDb = 1 31 | // DefaultRedisPassword Redis密码 32 | DefaultRedisPassword = "" 33 | // DefaultRedisMaxIdle Redis连接池闲置连接数 34 | DefaultRedisMaxIdle = 10 35 | // DefaultRedisMaxActive Redis连接池最大激活连接数, 0为不限制 36 | DefaultRedisMaxActive = 0 37 | // DefaultRedisConnectTimeout Redis连接超时时间,单位毫秒 38 | DefaultRedisConnectTimeout = 5000 39 | // DefaultRedisReadTimeout Redis读取超时时间, 单位毫秒 40 | DefaultRedisReadTimeout = 180000 41 | // DefaultRedisWriteTimeout Redis写入超时时间, 单位毫秒 42 | DefaultRedisWriteTimeout = 3000 43 | ) 44 | 45 | // Config 应用配置 46 | type Config struct { 47 | BindAddress string // http server 监听地址 48 | BucketSize int // bucket数量 49 | BucketName string // bucket在redis中的键名, 50 | QueueName string // ready queue在redis中的键名 51 | QueueBlockTimeout int // 调用blpop阻塞超时时间, 单位秒, 修改此项, redis.read_timeout必须做相应调整 52 | Redis RedisConfig // redis配置 53 | } 54 | 55 | // RedisConfig Redis配置 56 | type RedisConfig struct { 57 | Host string 58 | Db int 59 | Password string 60 | MaxIdle int // 连接池最大空闲连接数 61 | MaxActive int // 连接池最大激活连接数 62 | ConnectTimeout int // 连接超时, 单位毫秒 63 | ReadTimeout int // 读取超时, 单位毫秒 64 | WriteTimeout int // 写入超时, 单位毫秒 65 | } 66 | 67 | // Init 初始化配置 68 | func Init(path string) { 69 | Setting = &Config{} 70 | if path == "" { 71 | Setting.initDefaultConfig() 72 | return 73 | } 74 | 75 | Setting.parse(path) 76 | } 77 | 78 | // 解析配置文件 79 | func (config *Config) parse(path string) { 80 | file, err := ini.Load(path) 81 | if err != nil { 82 | log.Fatalf("无法解析配置文件#%s", err.Error()) 83 | } 84 | 85 | section := file.Section("") 86 | config.BindAddress = section.Key("bind_address").MustString(DefaultBindAddress) 87 | config.BucketSize = section.Key("bucket_size").MustInt(DefaultBucketSize) 88 | config.BucketName = section.Key("bucket_name").MustString(DefaultBucketName) 89 | config.QueueName = section.Key("queue_name").MustString(DefaultQueueName) 90 | config.QueueBlockTimeout = section.Key("queue_block_timeout").MustInt(DefaultQueueBlockTimeout) 91 | 92 | config.Redis.Host = section.Key("redis.host").MustString(DefaultRedisHost) 93 | config.Redis.Db = section.Key("redis.db").MustInt(DefaultRedisDb) 94 | config.Redis.Password = section.Key("redis.password").MustString(DefaultRedisPassword) 95 | config.Redis.MaxIdle = section.Key("redis.max_idle").MustInt(DefaultRedisMaxIdle) 96 | config.Redis.MaxActive = section.Key("redis.max_active").MustInt(DefaultRedisMaxActive) 97 | config.Redis.ConnectTimeout = section.Key("redis.connect_timeout").MustInt(DefaultRedisConnectTimeout) 98 | config.Redis.ReadTimeout = section.Key("redis.read_timeout").MustInt(DefaultRedisReadTimeout) 99 | config.Redis.WriteTimeout = section.Key("redis.write_timeout").MustInt(DefaultRedisWriteTimeout) 100 | } 101 | 102 | // 初始化默认配置 103 | func (config *Config) initDefaultConfig() { 104 | config.BindAddress = DefaultBindAddress 105 | config.BucketSize = DefaultBucketSize 106 | config.BucketName = DefaultBucketName 107 | config.QueueName = DefaultQueueName 108 | config.QueueBlockTimeout = DefaultQueueBlockTimeout 109 | 110 | config.Redis.Host = DefaultRedisHost 111 | config.Redis.Db = DefaultRedisDb 112 | config.Redis.Password = DefaultRedisPassword 113 | config.Redis.MaxIdle = DefaultRedisMaxIdle 114 | config.Redis.MaxActive = DefaultRedisMaxActive 115 | config.Redis.ConnectTimeout = DefaultRedisConnectTimeout 116 | config.Redis.ReadTimeout = DefaultRedisReadTimeout 117 | config.Redis.WriteTimeout = DefaultRedisWriteTimeout 118 | } 119 | -------------------------------------------------------------------------------- /delay-queue.conf: -------------------------------------------------------------------------------- 1 | ;bind_address = 0.0.0.0:9278 ; http server监听地址 2 | ;bucket_size = 3 ; bucket数量 3 | ;bucket_name = dq_bucket_%d ; bucket在redis中的键名, %d必须保留 4 | ;queue_name = dq_queue_%s ; ready queue在redis中的键名, %s必须保留 5 | ;queue_block_timeout = 178 ; 调用blpop阻塞超时时间, 单位秒, 必须小于redis.read_timeout, 修改此项, redis.read_timeout需做相应调整 6 | ;redis.host = 127.0.0.1:6379 ; redis连接地址 7 | ;redis.db = 1 ; 建议选择未被使用的数据库或新建redis实例,防止key冲突 8 | ;redis.password = ; redis密码, 无需密码留空 9 | ;redis.max_idle = 10 ; redis连接池最大空闲连接数 10 | ;redis.max_active = 0 ; redis连接池最大激活连接数, 0为不限制 11 | ;redis.connect_timeout = 5000 ; redis连接超时时间, 单位毫秒 12 | ;redis.read_timeout = 180000 ; redis读取超时时间, 单位毫秒 13 | ;redis.write_timeout = 3000 ; redis写入超时时间, 单位毫秒 14 | -------------------------------------------------------------------------------- /delayqueue/bucket.go: -------------------------------------------------------------------------------- 1 | package delayqueue 2 | 3 | import ( 4 | "strconv" 5 | ) 6 | 7 | // BucketItem bucket中的元素 8 | type BucketItem struct { 9 | timestamp int64 10 | jobId string 11 | } 12 | 13 | // 添加JobId到bucket中 14 | func pushToBucket(key string, timestamp int64, jobId string) error { 15 | _, err := execRedisCommand("ZADD", key, timestamp, jobId) 16 | 17 | return err 18 | } 19 | 20 | // 从bucket中获取延迟时间最小的JobId 21 | func getFromBucket(key string) (*BucketItem, error) { 22 | value, err := execRedisCommand("ZRANGE", key, 0, 0, "WITHSCORES") 23 | if err != nil { 24 | return nil, err 25 | } 26 | if value == nil { 27 | return nil, nil 28 | } 29 | 30 | var valueBytes []interface{} 31 | valueBytes = value.([]interface{}) 32 | if len(valueBytes) == 0 { 33 | return nil, nil 34 | } 35 | timestampStr := string(valueBytes[1].([]byte)) 36 | item := &BucketItem{} 37 | item.timestamp, _ = strconv.ParseInt(timestampStr, 10, 64) 38 | item.jobId = string(valueBytes[0].([]byte)) 39 | 40 | return item, nil 41 | } 42 | 43 | // 从bucket中删除JobId 44 | func removeFromBucket(bucket string, jobId string) error { 45 | _, err := execRedisCommand("ZREM", bucket, jobId) 46 | 47 | return err 48 | } 49 | -------------------------------------------------------------------------------- /delayqueue/delay_queue.go: -------------------------------------------------------------------------------- 1 | package delayqueue 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "log" 7 | "time" 8 | 9 | "github.com/ouqiang/delay-queue/config" 10 | ) 11 | 12 | var ( 13 | // 每个定时器对应一个bucket 14 | timers []*time.Ticker 15 | // bucket名称chan 16 | bucketNameChan <-chan string 17 | ) 18 | 19 | // Init 初始化延时队列 20 | func Init() { 21 | RedisPool = initRedisPool() 22 | initTimers() 23 | bucketNameChan = generateBucketName() 24 | } 25 | 26 | // Push 添加一个Job到队列中 27 | func Push(job Job) error { 28 | if job.Id == "" || job.Topic == "" || job.Delay < 0 || job.TTR <= 0 { 29 | return errors.New("invalid job") 30 | } 31 | 32 | err := putJob(job.Id, job) 33 | if err != nil { 34 | log.Printf("添加job到job pool失败#job-%+v#%s", job, err.Error()) 35 | return err 36 | } 37 | err = pushToBucket(<-bucketNameChan, job.Delay, job.Id) 38 | if err != nil { 39 | log.Printf("添加job到bucket失败#job-%+v#%s", job, err.Error()) 40 | return err 41 | } 42 | 43 | return nil 44 | } 45 | 46 | // Pop 轮询获取Job 47 | func Pop(topics []string) (*Job, error) { 48 | jobId, err := blockPopFromReadyQueue(topics, config.Setting.QueueBlockTimeout) 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | // 队列为空 54 | if jobId == "" { 55 | return nil, nil 56 | } 57 | 58 | // 获取job元信息 59 | job, err := getJob(jobId) 60 | if err != nil { 61 | return job, err 62 | } 63 | 64 | // 消息不存在, 可能已被删除 65 | if job == nil { 66 | return nil, nil 67 | } 68 | 69 | timestamp := time.Now().Unix() + job.TTR 70 | err = pushToBucket(<-bucketNameChan, timestamp, job.Id) 71 | 72 | return job, err 73 | } 74 | 75 | // Remove 删除Job 76 | func Remove(jobId string) error { 77 | return removeJob(jobId) 78 | } 79 | 80 | // Get 查询Job 81 | func Get(jobId string) (*Job, error) { 82 | job, err := getJob(jobId) 83 | if err != nil { 84 | return job, err 85 | } 86 | 87 | // 消息不存在, 可能已被删除 88 | if job == nil { 89 | return nil, nil 90 | } 91 | return job, err 92 | } 93 | 94 | // 轮询获取bucket名称, 使job分布到不同bucket中, 提高扫描速度 95 | func generateBucketName() <-chan string { 96 | c := make(chan string) 97 | go func() { 98 | i := 1 99 | for { 100 | c <- fmt.Sprintf(config.Setting.BucketName, i) 101 | if i >= config.Setting.BucketSize { 102 | i = 1 103 | } else { 104 | i++ 105 | } 106 | } 107 | }() 108 | 109 | return c 110 | } 111 | 112 | // 初始化定时器 113 | func initTimers() { 114 | timers = make([]*time.Ticker, config.Setting.BucketSize) 115 | var bucketName string 116 | for i := 0; i < config.Setting.BucketSize; i++ { 117 | timers[i] = time.NewTicker(1 * time.Second) 118 | bucketName = fmt.Sprintf(config.Setting.BucketName, i+1) 119 | go waitTicker(timers[i], bucketName) 120 | } 121 | } 122 | 123 | func waitTicker(timer *time.Ticker, bucketName string) { 124 | for { 125 | select { 126 | case t := <-timer.C: 127 | tickHandler(t, bucketName) 128 | } 129 | } 130 | } 131 | 132 | // 扫描bucket, 取出延迟时间小于当前时间的Job 133 | func tickHandler(t time.Time, bucketName string) { 134 | for { 135 | bucketItem, err := getFromBucket(bucketName) 136 | if err != nil { 137 | log.Printf("扫描bucket错误#bucket-%s#%s", bucketName, err.Error()) 138 | return 139 | } 140 | 141 | // 集合为空 142 | if bucketItem == nil { 143 | return 144 | } 145 | 146 | // 延迟时间未到 147 | if bucketItem.timestamp > t.Unix() { 148 | return 149 | } 150 | 151 | // 延迟时间小于等于当前时间, 取出Job元信息并放入ready queue 152 | job, err := getJob(bucketItem.jobId) 153 | if err != nil { 154 | log.Printf("获取Job元信息失败#bucket-%s#%s", bucketName, err.Error()) 155 | continue 156 | } 157 | 158 | // job元信息不存在, 从bucket中删除 159 | if job == nil { 160 | removeFromBucket(bucketName, bucketItem.jobId) 161 | continue 162 | } 163 | 164 | // 再次确认元信息中delay是否小于等于当前时间 165 | if job.Delay > t.Unix() { 166 | // 从bucket中删除旧的jobId 167 | removeFromBucket(bucketName, bucketItem.jobId) 168 | // 重新计算delay时间并放入bucket中 169 | pushToBucket(<-bucketNameChan, job.Delay, bucketItem.jobId) 170 | continue 171 | } 172 | 173 | err = pushToReadyQueue(job.Topic, bucketItem.jobId) 174 | if err != nil { 175 | log.Printf("JobId放入ready queue失败#bucket-%s#job-%+v#%s", 176 | bucketName, job, err.Error()) 177 | continue 178 | } 179 | 180 | // 从bucket中删除 181 | removeFromBucket(bucketName, bucketItem.jobId) 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /delayqueue/job.go: -------------------------------------------------------------------------------- 1 | package delayqueue 2 | 3 | import ( 4 | "github.com/vmihailenco/msgpack" 5 | ) 6 | 7 | // Job 使用msgpack序列化后保存到Redis,减少内存占用 8 | type Job struct { 9 | Topic string `json:"topic" msgpack:"1"` 10 | Id string `json:"id" msgpack:"2"` // job唯一标识ID 11 | Delay int64 `json:"delay" msgpack:"3"` // 延迟时间, unix时间戳 12 | TTR int64 `json:"ttr" msgpack:"4"` 13 | Body string `json:"body" msgpack:"5"` 14 | } 15 | 16 | // 获取Job 17 | func getJob(key string) (*Job, error) { 18 | value, err := execRedisCommand("GET", key) 19 | if err != nil { 20 | return nil, err 21 | } 22 | if value == nil { 23 | return nil, nil 24 | } 25 | 26 | byteValue := value.([]byte) 27 | job := &Job{} 28 | err = msgpack.Unmarshal(byteValue, job) 29 | if err != nil { 30 | return nil, err 31 | } 32 | 33 | return job, nil 34 | } 35 | 36 | // 添加Job 37 | func putJob(key string, job Job) error { 38 | value, err := msgpack.Marshal(job) 39 | if err != nil { 40 | return err 41 | } 42 | _, err = execRedisCommand("SET", key, value) 43 | 44 | return err 45 | } 46 | 47 | // 删除Job 48 | func removeJob(key string) error { 49 | _, err := execRedisCommand("DEL", key) 50 | 51 | return err 52 | } 53 | -------------------------------------------------------------------------------- /delayqueue/ready_queue.go: -------------------------------------------------------------------------------- 1 | package delayqueue 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/ouqiang/delay-queue/config" 7 | ) 8 | 9 | // 添加JobId到队列中 10 | func pushToReadyQueue(queueName string, jobId string) error { 11 | queueName = fmt.Sprintf(config.Setting.QueueName, queueName) 12 | _, err := execRedisCommand("RPUSH", queueName, jobId) 13 | 14 | return err 15 | } 16 | 17 | // 从队列中阻塞获取JobId 18 | func blockPopFromReadyQueue(queues []string, timeout int) (string, error) { 19 | var args []interface{} 20 | for _, queue := range queues { 21 | queue = fmt.Sprintf(config.Setting.QueueName, queue) 22 | args = append(args, queue) 23 | } 24 | args = append(args, timeout) 25 | value, err := execRedisCommand("BLPOP", args...) 26 | if err != nil { 27 | return "", err 28 | } 29 | if value == nil { 30 | return "", nil 31 | } 32 | var valueBytes []interface{} 33 | valueBytes = value.([]interface{}) 34 | if len(valueBytes) == 0 { 35 | return "", nil 36 | } 37 | element := string(valueBytes[1].([]byte)) 38 | 39 | return element, nil 40 | } 41 | -------------------------------------------------------------------------------- /delayqueue/redis.go: -------------------------------------------------------------------------------- 1 | package delayqueue 2 | 3 | import ( 4 | "log" 5 | "time" 6 | 7 | "github.com/garyburd/redigo/redis" 8 | "github.com/ouqiang/delay-queue/config" 9 | ) 10 | 11 | var ( 12 | // RedisPool RedisPool连接池实例 13 | RedisPool *redis.Pool 14 | ) 15 | 16 | // 初始化连接池 17 | func initRedisPool() *redis.Pool { 18 | pool := &redis.Pool{ 19 | MaxIdle: config.Setting.Redis.MaxIdle, 20 | MaxActive: config.Setting.Redis.MaxActive, 21 | IdleTimeout: 300 * time.Second, 22 | Dial: redisDial, 23 | TestOnBorrow: redisTestOnBorrow, 24 | Wait: true, 25 | } 26 | 27 | return pool 28 | } 29 | 30 | // 连接redis 31 | func redisDial() (redis.Conn, error) { 32 | conn, err := redis.Dial( 33 | "tcp", 34 | config.Setting.Redis.Host, 35 | redis.DialConnectTimeout(time.Duration(config.Setting.Redis.ConnectTimeout)*time.Millisecond), 36 | redis.DialReadTimeout(time.Duration(config.Setting.Redis.ReadTimeout)*time.Millisecond), 37 | redis.DialWriteTimeout(time.Duration(config.Setting.Redis.WriteTimeout)*time.Millisecond), 38 | ) 39 | if err != nil { 40 | log.Printf("连接redis失败#%s", err.Error()) 41 | return nil, err 42 | } 43 | 44 | if config.Setting.Redis.Password != "" { 45 | if _, err := conn.Do("AUTH", config.Setting.Redis.Password); err != nil { 46 | conn.Close() 47 | log.Printf("redis认证失败#%s", err.Error()) 48 | return nil, err 49 | } 50 | } 51 | 52 | _, err = conn.Do("SELECT", config.Setting.Redis.Db) 53 | if err != nil { 54 | conn.Close() 55 | log.Printf("redis选择数据库失败#%s", err.Error()) 56 | return nil, err 57 | } 58 | 59 | return conn, nil 60 | } 61 | 62 | // 从池中取出连接后,判断连接是否有效 63 | func redisTestOnBorrow(conn redis.Conn, t time.Time) error { 64 | _, err := conn.Do("PING") 65 | if err != nil { 66 | log.Printf("从redis连接池取出的连接无效#%s", err.Error()) 67 | } 68 | 69 | return err 70 | } 71 | 72 | // 执行redis命令, 执行完成后连接自动放回连接池 73 | func execRedisCommand(command string, args ...interface{}) (interface{}, error) { 74 | redis := RedisPool.Get() 75 | defer redis.Close() 76 | 77 | return redis.Do(command, args...) 78 | } 79 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/ouqiang/delay-queue/cmd" 4 | 5 | func main() { 6 | cmd := new(cmd.Cmd) 7 | cmd.Run() 8 | } 9 | -------------------------------------------------------------------------------- /routers/routers.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | "log" 7 | "net/http" 8 | "strings" 9 | "time" 10 | 11 | "github.com/ouqiang/delay-queue/delayqueue" 12 | ) 13 | 14 | // TopicRequest Job类型请求json 15 | type TopicRequest struct { 16 | Topic string `json:"topic"` 17 | } 18 | 19 | // IdRequest JobId请求json 20 | type IdRequest struct { 21 | Id string `json:"id"` 22 | } 23 | 24 | // Push 添加job 25 | func Push(resp http.ResponseWriter, req *http.Request) { 26 | var job delayqueue.Job 27 | err := readBody(resp, req, &job) 28 | if err != nil { 29 | return 30 | } 31 | 32 | job.Id = strings.TrimSpace(job.Id) 33 | job.Topic = strings.TrimSpace(job.Topic) 34 | job.Body = strings.TrimSpace(job.Body) 35 | if job.Id == "" { 36 | resp.Write(generateFailureBody("job id不能为空")) 37 | return 38 | } 39 | if job.Topic == "" { 40 | resp.Write(generateFailureBody("topic 不能为空")) 41 | return 42 | } 43 | 44 | if job.Delay <= 0 || job.Delay > (1<<31) { 45 | resp.Write(generateFailureBody("delay 取值范围1 - (2^31 - 1)")) 46 | return 47 | } 48 | 49 | if job.TTR <= 0 || job.TTR > 86400 { 50 | resp.Write(generateFailureBody("ttr 取值范围1 - 86400")) 51 | return 52 | } 53 | 54 | log.Printf("add job#%+v\n", job) 55 | job.Delay = time.Now().Unix() + job.Delay 56 | err = delayqueue.Push(job) 57 | 58 | if err != nil { 59 | log.Printf("添加job失败#%s", err.Error()) 60 | resp.Write(generateFailureBody(err.Error())) 61 | } else { 62 | resp.Write(generateSuccessBody("添加成功", nil)) 63 | } 64 | } 65 | 66 | // Pop 获取job 67 | func Pop(resp http.ResponseWriter, req *http.Request) { 68 | var topicRequest TopicRequest 69 | err := readBody(resp, req, &topicRequest) 70 | if err != nil { 71 | return 72 | } 73 | topic := strings.TrimSpace(topicRequest.Topic) 74 | if topic == "" { 75 | resp.Write(generateFailureBody("topic不能为空")) 76 | return 77 | } 78 | // 多个topic逗号分隔 79 | topics := strings.Split(topic, ",") 80 | job, err := delayqueue.Pop(topics) 81 | if err != nil { 82 | log.Printf("获取job失败#%s", err.Error()) 83 | resp.Write(generateFailureBody(err.Error())) 84 | return 85 | } 86 | 87 | if job == nil { 88 | resp.Write(generateSuccessBody("操作成功", nil)) 89 | return 90 | } 91 | 92 | type Data struct { 93 | Id string `json:"id"` 94 | Body string `json:"body"` 95 | } 96 | 97 | data := Data{ 98 | Id: job.Id, 99 | Body: job.Body, 100 | } 101 | 102 | log.Printf("get job#%+v", data) 103 | 104 | resp.Write(generateSuccessBody("操作成功", data)) 105 | } 106 | 107 | // Delete 删除job 108 | func Delete(resp http.ResponseWriter, req *http.Request) { 109 | var idRequest IdRequest 110 | err := readBody(resp, req, &idRequest) 111 | if err != nil { 112 | return 113 | } 114 | id := strings.TrimSpace(idRequest.Id) 115 | if id == "" { 116 | resp.Write(generateFailureBody("job id不能为空")) 117 | return 118 | } 119 | 120 | log.Printf("delete job#jobId-%s\n", id) 121 | err = delayqueue.Remove(id) 122 | if err != nil { 123 | log.Printf("删除job失败#%s", err.Error()) 124 | resp.Write(generateFailureBody(err.Error())) 125 | return 126 | } 127 | 128 | resp.Write(generateSuccessBody("操作成功", nil)) 129 | } 130 | 131 | // Get 查询job 132 | func Get(resp http.ResponseWriter, req *http.Request) { 133 | var idRequest IdRequest 134 | err := readBody(resp, req, &idRequest) 135 | if err != nil { 136 | return 137 | } 138 | id := strings.TrimSpace(idRequest.Id) 139 | if id == "" { 140 | resp.Write(generateFailureBody("job id不能为空")) 141 | return 142 | } 143 | job, err := delayqueue.Get(id) 144 | if err != nil { 145 | log.Printf("查询job失败#%s", err.Error()) 146 | resp.Write(generateFailureBody(err.Error())) 147 | return 148 | } 149 | 150 | if job == nil { 151 | resp.Write(generateSuccessBody("操作成功", nil)) 152 | return 153 | } 154 | 155 | resp.Write(generateSuccessBody("操作成功", job)) 156 | } 157 | 158 | // ResponseBody 响应Body格式 159 | type ResponseBody struct { 160 | Code int `json:"code"` 161 | Message string `json:"message"` 162 | Data interface{} `json:"data"` 163 | } 164 | 165 | func readBody(resp http.ResponseWriter, req *http.Request, v interface{}) error { 166 | body, err := ioutil.ReadAll(req.Body) 167 | if err != nil { 168 | log.Printf("读取body错误#%s", err.Error()) 169 | resp.Write(generateFailureBody("读取request body失败")) 170 | return err 171 | } 172 | err = json.Unmarshal(body, v) 173 | if err != nil { 174 | log.Printf("解析json失败#%s", err.Error()) 175 | resp.Write(generateFailureBody("解析json失败")) 176 | return err 177 | } 178 | 179 | return nil 180 | } 181 | 182 | func generateSuccessBody(msg string, data interface{}) []byte { 183 | return generateResponseBody(0, msg, data) 184 | } 185 | 186 | func generateFailureBody(msg string) []byte { 187 | return generateResponseBody(1, msg, nil) 188 | } 189 | 190 | func generateResponseBody(code int, msg string, data interface{}) []byte { 191 | body := &ResponseBody{} 192 | body.Code = code 193 | body.Message = msg 194 | body.Data = data 195 | 196 | bytes, err := json.Marshal(body) 197 | if err != nil { 198 | log.Printf("生成response body,转换json失败#%s", err.Error()) 199 | return []byte(`{"code":"1", "message": "生成响应body异常", "data":[]}`) 200 | } 201 | 202 | return bytes 203 | } 204 | -------------------------------------------------------------------------------- /vendor/github.com/garyburd/redigo/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | -------------------------------------------------------------------------------- /vendor/github.com/garyburd/redigo/internal/commandinfo.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Gary Burd 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | // License for the specific language governing permissions and limitations 13 | // under the License. 14 | 15 | package internal // import "github.com/garyburd/redigo/internal" 16 | 17 | import ( 18 | "strings" 19 | ) 20 | 21 | const ( 22 | WatchState = 1 << iota 23 | MultiState 24 | SubscribeState 25 | MonitorState 26 | ) 27 | 28 | type CommandInfo struct { 29 | Set, Clear int 30 | } 31 | 32 | var commandInfos = map[string]CommandInfo{ 33 | "WATCH": {Set: WatchState}, 34 | "UNWATCH": {Clear: WatchState}, 35 | "MULTI": {Set: MultiState}, 36 | "EXEC": {Clear: WatchState | MultiState}, 37 | "DISCARD": {Clear: WatchState | MultiState}, 38 | "PSUBSCRIBE": {Set: SubscribeState}, 39 | "SUBSCRIBE": {Set: SubscribeState}, 40 | "MONITOR": {Set: MonitorState}, 41 | } 42 | 43 | func init() { 44 | for n, ci := range commandInfos { 45 | commandInfos[strings.ToLower(n)] = ci 46 | } 47 | } 48 | 49 | func LookupCommandInfo(commandName string) CommandInfo { 50 | if ci, ok := commandInfos[commandName]; ok { 51 | return ci 52 | } 53 | return commandInfos[strings.ToUpper(commandName)] 54 | } 55 | -------------------------------------------------------------------------------- /vendor/github.com/garyburd/redigo/redis/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Gary Burd 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | // License for the specific language governing permissions and limitations 13 | // under the License. 14 | 15 | // Package redis is a client for the Redis database. 16 | // 17 | // The Redigo FAQ (https://github.com/garyburd/redigo/wiki/FAQ) contains more 18 | // documentation about this package. 19 | // 20 | // Connections 21 | // 22 | // The Conn interface is the primary interface for working with Redis. 23 | // Applications create connections by calling the Dial, DialWithTimeout or 24 | // NewConn functions. In the future, functions will be added for creating 25 | // sharded and other types of connections. 26 | // 27 | // The application must call the connection Close method when the application 28 | // is done with the connection. 29 | // 30 | // Executing Commands 31 | // 32 | // The Conn interface has a generic method for executing Redis commands: 33 | // 34 | // Do(commandName string, args ...interface{}) (reply interface{}, err error) 35 | // 36 | // The Redis command reference (http://redis.io/commands) lists the available 37 | // commands. An example of using the Redis APPEND command is: 38 | // 39 | // n, err := conn.Do("APPEND", "key", "value") 40 | // 41 | // The Do method converts command arguments to binary strings for transmission 42 | // to the server as follows: 43 | // 44 | // Go Type Conversion 45 | // []byte Sent as is 46 | // string Sent as is 47 | // int, int64 strconv.FormatInt(v) 48 | // float64 strconv.FormatFloat(v, 'g', -1, 64) 49 | // bool true -> "1", false -> "0" 50 | // nil "" 51 | // all other types fmt.Print(v) 52 | // 53 | // Redis command reply types are represented using the following Go types: 54 | // 55 | // Redis type Go type 56 | // error redis.Error 57 | // integer int64 58 | // simple string string 59 | // bulk string []byte or nil if value not present. 60 | // array []interface{} or nil if value not present. 61 | // 62 | // Use type assertions or the reply helper functions to convert from 63 | // interface{} to the specific Go type for the command result. 64 | // 65 | // Pipelining 66 | // 67 | // Connections support pipelining using the Send, Flush and Receive methods. 68 | // 69 | // Send(commandName string, args ...interface{}) error 70 | // Flush() error 71 | // Receive() (reply interface{}, err error) 72 | // 73 | // Send writes the command to the connection's output buffer. Flush flushes the 74 | // connection's output buffer to the server. Receive reads a single reply from 75 | // the server. The following example shows a simple pipeline. 76 | // 77 | // c.Send("SET", "foo", "bar") 78 | // c.Send("GET", "foo") 79 | // c.Flush() 80 | // c.Receive() // reply from SET 81 | // v, err = c.Receive() // reply from GET 82 | // 83 | // The Do method combines the functionality of the Send, Flush and Receive 84 | // methods. The Do method starts by writing the command and flushing the output 85 | // buffer. Next, the Do method receives all pending replies including the reply 86 | // for the command just sent by Do. If any of the received replies is an error, 87 | // then Do returns the error. If there are no errors, then Do returns the last 88 | // reply. If the command argument to the Do method is "", then the Do method 89 | // will flush the output buffer and receive pending replies without sending a 90 | // command. 91 | // 92 | // Use the Send and Do methods to implement pipelined transactions. 93 | // 94 | // c.Send("MULTI") 95 | // c.Send("INCR", "foo") 96 | // c.Send("INCR", "bar") 97 | // r, err := c.Do("EXEC") 98 | // fmt.Println(r) // prints [1, 1] 99 | // 100 | // Concurrency 101 | // 102 | // Connections support one concurrent caller to the Receive method and one 103 | // concurrent caller to the Send and Flush methods. No other concurrency is 104 | // supported including concurrent calls to the Do method. 105 | // 106 | // For full concurrent access to Redis, use the thread-safe Pool to get, use 107 | // and release a connection from within a goroutine. Connections returned from 108 | // a Pool have the concurrency restrictions described in the previous 109 | // paragraph. 110 | // 111 | // Publish and Subscribe 112 | // 113 | // Use the Send, Flush and Receive methods to implement Pub/Sub subscribers. 114 | // 115 | // c.Send("SUBSCRIBE", "example") 116 | // c.Flush() 117 | // for { 118 | // reply, err := c.Receive() 119 | // if err != nil { 120 | // return err 121 | // } 122 | // // process pushed message 123 | // } 124 | // 125 | // The PubSubConn type wraps a Conn with convenience methods for implementing 126 | // subscribers. The Subscribe, PSubscribe, Unsubscribe and PUnsubscribe methods 127 | // send and flush a subscription management command. The receive method 128 | // converts a pushed message to convenient types for use in a type switch. 129 | // 130 | // psc := redis.PubSubConn{Conn: c} 131 | // psc.Subscribe("example") 132 | // for { 133 | // switch v := psc.Receive().(type) { 134 | // case redis.Message: 135 | // fmt.Printf("%s: message: %s\n", v.Channel, v.Data) 136 | // case redis.Subscription: 137 | // fmt.Printf("%s: %s %d\n", v.Channel, v.Kind, v.Count) 138 | // case error: 139 | // return v 140 | // } 141 | // } 142 | // 143 | // Reply Helpers 144 | // 145 | // The Bool, Int, Bytes, String, Strings and Values functions convert a reply 146 | // to a value of a specific type. To allow convenient wrapping of calls to the 147 | // connection Do and Receive methods, the functions take a second argument of 148 | // type error. If the error is non-nil, then the helper function returns the 149 | // error. If the error is nil, the function converts the reply to the specified 150 | // type: 151 | // 152 | // exists, err := redis.Bool(c.Do("EXISTS", "foo")) 153 | // if err != nil { 154 | // // handle error return from c.Do or type conversion error. 155 | // } 156 | // 157 | // The Scan function converts elements of a array reply to Go types: 158 | // 159 | // var value1 int 160 | // var value2 string 161 | // reply, err := redis.Values(c.Do("MGET", "key1", "key2")) 162 | // if err != nil { 163 | // // handle error 164 | // } 165 | // if _, err := redis.Scan(reply, &value1, &value2); err != nil { 166 | // // handle error 167 | // } 168 | // 169 | // Errors 170 | // 171 | // Connection methods return error replies from the server as type redis.Error. 172 | // 173 | // Call the connection Err() method to determine if the connection encountered 174 | // non-recoverable error such as a network error or protocol parsing error. If 175 | // Err() returns a non-nil value, then the connection is not usable and should 176 | // be closed. 177 | package redis // import "github.com/garyburd/redigo/redis" 178 | -------------------------------------------------------------------------------- /vendor/github.com/garyburd/redigo/redis/go17.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package redis 4 | 5 | import "crypto/tls" 6 | 7 | // similar cloneTLSClientConfig in the stdlib, but also honor skipVerify for the nil case 8 | func cloneTLSClientConfig(cfg *tls.Config, skipVerify bool) *tls.Config { 9 | if cfg == nil { 10 | return &tls.Config{InsecureSkipVerify: skipVerify} 11 | } 12 | return &tls.Config{ 13 | Rand: cfg.Rand, 14 | Time: cfg.Time, 15 | Certificates: cfg.Certificates, 16 | NameToCertificate: cfg.NameToCertificate, 17 | GetCertificate: cfg.GetCertificate, 18 | RootCAs: cfg.RootCAs, 19 | NextProtos: cfg.NextProtos, 20 | ServerName: cfg.ServerName, 21 | ClientAuth: cfg.ClientAuth, 22 | ClientCAs: cfg.ClientCAs, 23 | InsecureSkipVerify: cfg.InsecureSkipVerify, 24 | CipherSuites: cfg.CipherSuites, 25 | PreferServerCipherSuites: cfg.PreferServerCipherSuites, 26 | ClientSessionCache: cfg.ClientSessionCache, 27 | MinVersion: cfg.MinVersion, 28 | MaxVersion: cfg.MaxVersion, 29 | CurvePreferences: cfg.CurvePreferences, 30 | DynamicRecordSizingDisabled: cfg.DynamicRecordSizingDisabled, 31 | Renegotiation: cfg.Renegotiation, 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /vendor/github.com/garyburd/redigo/redis/log.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Gary Burd 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | // License for the specific language governing permissions and limitations 13 | // under the License. 14 | 15 | package redis 16 | 17 | import ( 18 | "bytes" 19 | "fmt" 20 | "log" 21 | ) 22 | 23 | // NewLoggingConn returns a logging wrapper around a connection. 24 | func NewLoggingConn(conn Conn, logger *log.Logger, prefix string) Conn { 25 | if prefix != "" { 26 | prefix = prefix + "." 27 | } 28 | return &loggingConn{conn, logger, prefix} 29 | } 30 | 31 | type loggingConn struct { 32 | Conn 33 | logger *log.Logger 34 | prefix string 35 | } 36 | 37 | func (c *loggingConn) Close() error { 38 | err := c.Conn.Close() 39 | var buf bytes.Buffer 40 | fmt.Fprintf(&buf, "%sClose() -> (%v)", c.prefix, err) 41 | c.logger.Output(2, buf.String()) 42 | return err 43 | } 44 | 45 | func (c *loggingConn) printValue(buf *bytes.Buffer, v interface{}) { 46 | const chop = 32 47 | switch v := v.(type) { 48 | case []byte: 49 | if len(v) > chop { 50 | fmt.Fprintf(buf, "%q...", v[:chop]) 51 | } else { 52 | fmt.Fprintf(buf, "%q", v) 53 | } 54 | case string: 55 | if len(v) > chop { 56 | fmt.Fprintf(buf, "%q...", v[:chop]) 57 | } else { 58 | fmt.Fprintf(buf, "%q", v) 59 | } 60 | case []interface{}: 61 | if len(v) == 0 { 62 | buf.WriteString("[]") 63 | } else { 64 | sep := "[" 65 | fin := "]" 66 | if len(v) > chop { 67 | v = v[:chop] 68 | fin = "...]" 69 | } 70 | for _, vv := range v { 71 | buf.WriteString(sep) 72 | c.printValue(buf, vv) 73 | sep = ", " 74 | } 75 | buf.WriteString(fin) 76 | } 77 | default: 78 | fmt.Fprint(buf, v) 79 | } 80 | } 81 | 82 | func (c *loggingConn) print(method, commandName string, args []interface{}, reply interface{}, err error) { 83 | var buf bytes.Buffer 84 | fmt.Fprintf(&buf, "%s%s(", c.prefix, method) 85 | if method != "Receive" { 86 | buf.WriteString(commandName) 87 | for _, arg := range args { 88 | buf.WriteString(", ") 89 | c.printValue(&buf, arg) 90 | } 91 | } 92 | buf.WriteString(") -> (") 93 | if method != "Send" { 94 | c.printValue(&buf, reply) 95 | buf.WriteString(", ") 96 | } 97 | fmt.Fprintf(&buf, "%v)", err) 98 | c.logger.Output(3, buf.String()) 99 | } 100 | 101 | func (c *loggingConn) Do(commandName string, args ...interface{}) (interface{}, error) { 102 | reply, err := c.Conn.Do(commandName, args...) 103 | c.print("Do", commandName, args, reply, err) 104 | return reply, err 105 | } 106 | 107 | func (c *loggingConn) Send(commandName string, args ...interface{}) error { 108 | err := c.Conn.Send(commandName, args...) 109 | c.print("Send", commandName, args, nil, err) 110 | return err 111 | } 112 | 113 | func (c *loggingConn) Receive() (interface{}, error) { 114 | reply, err := c.Conn.Receive() 115 | c.print("Receive", "", nil, reply, err) 116 | return reply, err 117 | } 118 | -------------------------------------------------------------------------------- /vendor/github.com/garyburd/redigo/redis/pool.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Gary Burd 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | // License for the specific language governing permissions and limitations 13 | // under the License. 14 | 15 | package redis 16 | 17 | import ( 18 | "bytes" 19 | "container/list" 20 | "crypto/rand" 21 | "crypto/sha1" 22 | "errors" 23 | "io" 24 | "strconv" 25 | "sync" 26 | "time" 27 | 28 | "github.com/garyburd/redigo/internal" 29 | ) 30 | 31 | var nowFunc = time.Now // for testing 32 | 33 | // ErrPoolExhausted is returned from a pool connection method (Do, Send, 34 | // Receive, Flush, Err) when the maximum number of database connections in the 35 | // pool has been reached. 36 | var ErrPoolExhausted = errors.New("redigo: connection pool exhausted") 37 | 38 | var ( 39 | errPoolClosed = errors.New("redigo: connection pool closed") 40 | errConnClosed = errors.New("redigo: connection closed") 41 | ) 42 | 43 | // Pool maintains a pool of connections. The application calls the Get method 44 | // to get a connection from the pool and the connection's Close method to 45 | // return the connection's resources to the pool. 46 | // 47 | // The following example shows how to use a pool in a web application. The 48 | // application creates a pool at application startup and makes it available to 49 | // request handlers using a package level variable. The pool configuration used 50 | // here is an example, not a recommendation. 51 | // 52 | // func newPool(addr string) *redis.Pool { 53 | // return &redis.Pool{ 54 | // MaxIdle: 3, 55 | // IdleTimeout: 240 * time.Second, 56 | // Dial: func () (redis.Conn, error) { return redis.Dial("tcp", addr) }, 57 | // } 58 | // } 59 | // 60 | // var ( 61 | // pool *redis.Pool 62 | // redisServer = flag.String("redisServer", ":6379", "") 63 | // ) 64 | // 65 | // func main() { 66 | // flag.Parse() 67 | // pool = newPool(*redisServer) 68 | // ... 69 | // } 70 | // 71 | // A request handler gets a connection from the pool and closes the connection 72 | // when the handler is done: 73 | // 74 | // func serveHome(w http.ResponseWriter, r *http.Request) { 75 | // conn := pool.Get() 76 | // defer conn.Close() 77 | // ... 78 | // } 79 | // 80 | // Use the Dial function to authenticate connections with the AUTH command or 81 | // select a database with the SELECT command: 82 | // 83 | // pool := &redis.Pool{ 84 | // // Other pool configuration not shown in this example. 85 | // Dial: func () (redis.Conn, error) { 86 | // c, err := redis.Dial("tcp", server) 87 | // if err != nil { 88 | // return nil, err 89 | // } 90 | // if _, err := c.Do("AUTH", password); err != nil { 91 | // c.Close() 92 | // return nil, err 93 | // } 94 | // if _, err := c.Do("SELECT", db); err != nil { 95 | // c.Close() 96 | // return nil, err 97 | // } 98 | // return c, nil 99 | // } 100 | // } 101 | // 102 | // Use the TestOnBorrow function to check the health of an idle connection 103 | // before the connection is returned to the application. This example PINGs 104 | // connections that have been idle more than a minute: 105 | // 106 | // pool := &redis.Pool{ 107 | // // Other pool configuration not shown in this example. 108 | // TestOnBorrow: func(c redis.Conn, t time.Time) error { 109 | // if time.Since(t) < time.Minute { 110 | // return nil 111 | // } 112 | // _, err := c.Do("PING") 113 | // return err 114 | // }, 115 | // } 116 | // 117 | type Pool struct { 118 | 119 | // Dial is an application supplied function for creating and configuring a 120 | // connection. 121 | // 122 | // The connection returned from Dial must not be in a special state 123 | // (subscribed to pubsub channel, transaction started, ...). 124 | Dial func() (Conn, error) 125 | 126 | // TestOnBorrow is an optional application supplied function for checking 127 | // the health of an idle connection before the connection is used again by 128 | // the application. Argument t is the time that the connection was returned 129 | // to the pool. If the function returns an error, then the connection is 130 | // closed. 131 | TestOnBorrow func(c Conn, t time.Time) error 132 | 133 | // Maximum number of idle connections in the pool. 134 | MaxIdle int 135 | 136 | // Maximum number of connections allocated by the pool at a given time. 137 | // When zero, there is no limit on the number of connections in the pool. 138 | MaxActive int 139 | 140 | // Close connections after remaining idle for this duration. If the value 141 | // is zero, then idle connections are not closed. Applications should set 142 | // the timeout to a value less than the server's timeout. 143 | IdleTimeout time.Duration 144 | 145 | // If Wait is true and the pool is at the MaxActive limit, then Get() waits 146 | // for a connection to be returned to the pool before returning. 147 | Wait bool 148 | 149 | // mu protects fields defined below. 150 | mu sync.Mutex 151 | cond *sync.Cond 152 | closed bool 153 | active int 154 | 155 | // Stack of idleConn with most recently used at the front. 156 | idle list.List 157 | } 158 | 159 | type idleConn struct { 160 | c Conn 161 | t time.Time 162 | } 163 | 164 | // NewPool creates a new pool. 165 | // 166 | // Deprecated: Initialize the Pool directory as shown in the example. 167 | func NewPool(newFn func() (Conn, error), maxIdle int) *Pool { 168 | return &Pool{Dial: newFn, MaxIdle: maxIdle} 169 | } 170 | 171 | // Get gets a connection. The application must close the returned connection. 172 | // This method always returns a valid connection so that applications can defer 173 | // error handling to the first use of the connection. If there is an error 174 | // getting an underlying connection, then the connection Err, Do, Send, Flush 175 | // and Receive methods return that error. 176 | func (p *Pool) Get() Conn { 177 | c, err := p.get() 178 | if err != nil { 179 | return errorConnection{err} 180 | } 181 | return &pooledConnection{p: p, c: c} 182 | } 183 | 184 | // ActiveCount returns the number of connections in the pool. The count includes idle connections and connections in use. 185 | func (p *Pool) ActiveCount() int { 186 | p.mu.Lock() 187 | active := p.active 188 | p.mu.Unlock() 189 | return active 190 | } 191 | 192 | // IdleCount returns the number of idle connections in the pool. 193 | func (p *Pool) IdleCount() int { 194 | p.mu.Lock() 195 | idle := p.idle.Len() 196 | p.mu.Unlock() 197 | return idle 198 | } 199 | 200 | // Close releases the resources used by the pool. 201 | func (p *Pool) Close() error { 202 | p.mu.Lock() 203 | idle := p.idle 204 | p.idle.Init() 205 | p.closed = true 206 | p.active -= idle.Len() 207 | if p.cond != nil { 208 | p.cond.Broadcast() 209 | } 210 | p.mu.Unlock() 211 | for e := idle.Front(); e != nil; e = e.Next() { 212 | e.Value.(idleConn).c.Close() 213 | } 214 | return nil 215 | } 216 | 217 | // release decrements the active count and signals waiters. The caller must 218 | // hold p.mu during the call. 219 | func (p *Pool) release() { 220 | p.active -= 1 221 | if p.cond != nil { 222 | p.cond.Signal() 223 | } 224 | } 225 | 226 | // get prunes stale connections and returns a connection from the idle list or 227 | // creates a new connection. 228 | func (p *Pool) get() (Conn, error) { 229 | p.mu.Lock() 230 | 231 | // Prune stale connections. 232 | 233 | if timeout := p.IdleTimeout; timeout > 0 { 234 | for i, n := 0, p.idle.Len(); i < n; i++ { 235 | e := p.idle.Back() 236 | if e == nil { 237 | break 238 | } 239 | ic := e.Value.(idleConn) 240 | if ic.t.Add(timeout).After(nowFunc()) { 241 | break 242 | } 243 | p.idle.Remove(e) 244 | p.release() 245 | p.mu.Unlock() 246 | ic.c.Close() 247 | p.mu.Lock() 248 | } 249 | } 250 | 251 | for { 252 | 253 | // Get idle connection. 254 | 255 | for i, n := 0, p.idle.Len(); i < n; i++ { 256 | e := p.idle.Front() 257 | if e == nil { 258 | break 259 | } 260 | ic := e.Value.(idleConn) 261 | p.idle.Remove(e) 262 | test := p.TestOnBorrow 263 | p.mu.Unlock() 264 | if test == nil || test(ic.c, ic.t) == nil { 265 | return ic.c, nil 266 | } 267 | ic.c.Close() 268 | p.mu.Lock() 269 | p.release() 270 | } 271 | 272 | // Check for pool closed before dialing a new connection. 273 | 274 | if p.closed { 275 | p.mu.Unlock() 276 | return nil, errors.New("redigo: get on closed pool") 277 | } 278 | 279 | // Dial new connection if under limit. 280 | 281 | if p.MaxActive == 0 || p.active < p.MaxActive { 282 | dial := p.Dial 283 | p.active += 1 284 | p.mu.Unlock() 285 | c, err := dial() 286 | if err != nil { 287 | p.mu.Lock() 288 | p.release() 289 | p.mu.Unlock() 290 | c = nil 291 | } 292 | return c, err 293 | } 294 | 295 | if !p.Wait { 296 | p.mu.Unlock() 297 | return nil, ErrPoolExhausted 298 | } 299 | 300 | if p.cond == nil { 301 | p.cond = sync.NewCond(&p.mu) 302 | } 303 | p.cond.Wait() 304 | } 305 | } 306 | 307 | func (p *Pool) put(c Conn, forceClose bool) error { 308 | err := c.Err() 309 | p.mu.Lock() 310 | if !p.closed && err == nil && !forceClose { 311 | p.idle.PushFront(idleConn{t: nowFunc(), c: c}) 312 | if p.idle.Len() > p.MaxIdle { 313 | c = p.idle.Remove(p.idle.Back()).(idleConn).c 314 | } else { 315 | c = nil 316 | } 317 | } 318 | 319 | if c == nil { 320 | if p.cond != nil { 321 | p.cond.Signal() 322 | } 323 | p.mu.Unlock() 324 | return nil 325 | } 326 | 327 | p.release() 328 | p.mu.Unlock() 329 | return c.Close() 330 | } 331 | 332 | type pooledConnection struct { 333 | p *Pool 334 | c Conn 335 | state int 336 | } 337 | 338 | var ( 339 | sentinel []byte 340 | sentinelOnce sync.Once 341 | ) 342 | 343 | func initSentinel() { 344 | p := make([]byte, 64) 345 | if _, err := rand.Read(p); err == nil { 346 | sentinel = p 347 | } else { 348 | h := sha1.New() 349 | io.WriteString(h, "Oops, rand failed. Use time instead.") 350 | io.WriteString(h, strconv.FormatInt(time.Now().UnixNano(), 10)) 351 | sentinel = h.Sum(nil) 352 | } 353 | } 354 | 355 | func (pc *pooledConnection) Close() error { 356 | c := pc.c 357 | if _, ok := c.(errorConnection); ok { 358 | return nil 359 | } 360 | pc.c = errorConnection{errConnClosed} 361 | 362 | if pc.state&internal.MultiState != 0 { 363 | c.Send("DISCARD") 364 | pc.state &^= (internal.MultiState | internal.WatchState) 365 | } else if pc.state&internal.WatchState != 0 { 366 | c.Send("UNWATCH") 367 | pc.state &^= internal.WatchState 368 | } 369 | if pc.state&internal.SubscribeState != 0 { 370 | c.Send("UNSUBSCRIBE") 371 | c.Send("PUNSUBSCRIBE") 372 | // To detect the end of the message stream, ask the server to echo 373 | // a sentinel value and read until we see that value. 374 | sentinelOnce.Do(initSentinel) 375 | c.Send("ECHO", sentinel) 376 | c.Flush() 377 | for { 378 | p, err := c.Receive() 379 | if err != nil { 380 | break 381 | } 382 | if p, ok := p.([]byte); ok && bytes.Equal(p, sentinel) { 383 | pc.state &^= internal.SubscribeState 384 | break 385 | } 386 | } 387 | } 388 | c.Do("") 389 | pc.p.put(c, pc.state != 0) 390 | return nil 391 | } 392 | 393 | func (pc *pooledConnection) Err() error { 394 | return pc.c.Err() 395 | } 396 | 397 | func (pc *pooledConnection) Do(commandName string, args ...interface{}) (reply interface{}, err error) { 398 | ci := internal.LookupCommandInfo(commandName) 399 | pc.state = (pc.state | ci.Set) &^ ci.Clear 400 | return pc.c.Do(commandName, args...) 401 | } 402 | 403 | func (pc *pooledConnection) Send(commandName string, args ...interface{}) error { 404 | ci := internal.LookupCommandInfo(commandName) 405 | pc.state = (pc.state | ci.Set) &^ ci.Clear 406 | return pc.c.Send(commandName, args...) 407 | } 408 | 409 | func (pc *pooledConnection) Flush() error { 410 | return pc.c.Flush() 411 | } 412 | 413 | func (pc *pooledConnection) Receive() (reply interface{}, err error) { 414 | return pc.c.Receive() 415 | } 416 | 417 | type errorConnection struct{ err error } 418 | 419 | func (ec errorConnection) Do(string, ...interface{}) (interface{}, error) { return nil, ec.err } 420 | func (ec errorConnection) Send(string, ...interface{}) error { return ec.err } 421 | func (ec errorConnection) Err() error { return ec.err } 422 | func (ec errorConnection) Close() error { return ec.err } 423 | func (ec errorConnection) Flush() error { return ec.err } 424 | func (ec errorConnection) Receive() (interface{}, error) { return nil, ec.err } 425 | -------------------------------------------------------------------------------- /vendor/github.com/garyburd/redigo/redis/pre_go17.go: -------------------------------------------------------------------------------- 1 | // +build !go1.7 2 | 3 | package redis 4 | 5 | import "crypto/tls" 6 | 7 | // similar cloneTLSClientConfig in the stdlib, but also honor skipVerify for the nil case 8 | func cloneTLSClientConfig(cfg *tls.Config, skipVerify bool) *tls.Config { 9 | if cfg == nil { 10 | return &tls.Config{InsecureSkipVerify: skipVerify} 11 | } 12 | return &tls.Config{ 13 | Rand: cfg.Rand, 14 | Time: cfg.Time, 15 | Certificates: cfg.Certificates, 16 | NameToCertificate: cfg.NameToCertificate, 17 | GetCertificate: cfg.GetCertificate, 18 | RootCAs: cfg.RootCAs, 19 | NextProtos: cfg.NextProtos, 20 | ServerName: cfg.ServerName, 21 | ClientAuth: cfg.ClientAuth, 22 | ClientCAs: cfg.ClientCAs, 23 | InsecureSkipVerify: cfg.InsecureSkipVerify, 24 | CipherSuites: cfg.CipherSuites, 25 | PreferServerCipherSuites: cfg.PreferServerCipherSuites, 26 | ClientSessionCache: cfg.ClientSessionCache, 27 | MinVersion: cfg.MinVersion, 28 | MaxVersion: cfg.MaxVersion, 29 | CurvePreferences: cfg.CurvePreferences, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /vendor/github.com/garyburd/redigo/redis/pubsub.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Gary Burd 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | // License for the specific language governing permissions and limitations 13 | // under the License. 14 | 15 | package redis 16 | 17 | import "errors" 18 | 19 | // Subscription represents a subscribe or unsubscribe notification. 20 | type Subscription struct { 21 | 22 | // Kind is "subscribe", "unsubscribe", "psubscribe" or "punsubscribe" 23 | Kind string 24 | 25 | // The channel that was changed. 26 | Channel string 27 | 28 | // The current number of subscriptions for connection. 29 | Count int 30 | } 31 | 32 | // Message represents a message notification. 33 | type Message struct { 34 | 35 | // The originating channel. 36 | Channel string 37 | 38 | // The message data. 39 | Data []byte 40 | } 41 | 42 | // PMessage represents a pmessage notification. 43 | type PMessage struct { 44 | 45 | // The matched pattern. 46 | Pattern string 47 | 48 | // The originating channel. 49 | Channel string 50 | 51 | // The message data. 52 | Data []byte 53 | } 54 | 55 | // Pong represents a pubsub pong notification. 56 | type Pong struct { 57 | Data string 58 | } 59 | 60 | // PubSubConn wraps a Conn with convenience methods for subscribers. 61 | type PubSubConn struct { 62 | Conn Conn 63 | } 64 | 65 | // Close closes the connection. 66 | func (c PubSubConn) Close() error { 67 | return c.Conn.Close() 68 | } 69 | 70 | // Subscribe subscribes the connection to the specified channels. 71 | func (c PubSubConn) Subscribe(channel ...interface{}) error { 72 | c.Conn.Send("SUBSCRIBE", channel...) 73 | return c.Conn.Flush() 74 | } 75 | 76 | // PSubscribe subscribes the connection to the given patterns. 77 | func (c PubSubConn) PSubscribe(channel ...interface{}) error { 78 | c.Conn.Send("PSUBSCRIBE", channel...) 79 | return c.Conn.Flush() 80 | } 81 | 82 | // Unsubscribe unsubscribes the connection from the given channels, or from all 83 | // of them if none is given. 84 | func (c PubSubConn) Unsubscribe(channel ...interface{}) error { 85 | c.Conn.Send("UNSUBSCRIBE", channel...) 86 | return c.Conn.Flush() 87 | } 88 | 89 | // PUnsubscribe unsubscribes the connection from the given patterns, or from all 90 | // of them if none is given. 91 | func (c PubSubConn) PUnsubscribe(channel ...interface{}) error { 92 | c.Conn.Send("PUNSUBSCRIBE", channel...) 93 | return c.Conn.Flush() 94 | } 95 | 96 | // Ping sends a PING to the server with the specified data. 97 | func (c PubSubConn) Ping(data string) error { 98 | c.Conn.Send("PING", data) 99 | return c.Conn.Flush() 100 | } 101 | 102 | // Receive returns a pushed message as a Subscription, Message, PMessage, Pong 103 | // or error. The return value is intended to be used directly in a type switch 104 | // as illustrated in the PubSubConn example. 105 | func (c PubSubConn) Receive() interface{} { 106 | reply, err := Values(c.Conn.Receive()) 107 | if err != nil { 108 | return err 109 | } 110 | 111 | var kind string 112 | reply, err = Scan(reply, &kind) 113 | if err != nil { 114 | return err 115 | } 116 | 117 | switch kind { 118 | case "message": 119 | var m Message 120 | if _, err := Scan(reply, &m.Channel, &m.Data); err != nil { 121 | return err 122 | } 123 | return m 124 | case "pmessage": 125 | var pm PMessage 126 | if _, err := Scan(reply, &pm.Pattern, &pm.Channel, &pm.Data); err != nil { 127 | return err 128 | } 129 | return pm 130 | case "subscribe", "psubscribe", "unsubscribe", "punsubscribe": 131 | s := Subscription{Kind: kind} 132 | if _, err := Scan(reply, &s.Channel, &s.Count); err != nil { 133 | return err 134 | } 135 | return s 136 | case "pong": 137 | var p Pong 138 | if _, err := Scan(reply, &p.Data); err != nil { 139 | return err 140 | } 141 | return p 142 | } 143 | return errors.New("redigo: unknown pubsub notification") 144 | } 145 | -------------------------------------------------------------------------------- /vendor/github.com/garyburd/redigo/redis/redis.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Gary Burd 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | // License for the specific language governing permissions and limitations 13 | // under the License. 14 | 15 | package redis 16 | 17 | // Error represents an error returned in a command reply. 18 | type Error string 19 | 20 | func (err Error) Error() string { return string(err) } 21 | 22 | // Conn represents a connection to a Redis server. 23 | type Conn interface { 24 | // Close closes the connection. 25 | Close() error 26 | 27 | // Err returns a non-nil value when the connection is not usable. 28 | Err() error 29 | 30 | // Do sends a command to the server and returns the received reply. 31 | Do(commandName string, args ...interface{}) (reply interface{}, err error) 32 | 33 | // Send writes the command to the client's output buffer. 34 | Send(commandName string, args ...interface{}) error 35 | 36 | // Flush flushes the output buffer to the Redis server. 37 | Flush() error 38 | 39 | // Receive receives a single reply from the Redis server 40 | Receive() (reply interface{}, err error) 41 | } 42 | 43 | // Argument is implemented by types which want to control how their value is 44 | // interpreted when used as an argument to a redis command. 45 | type Argument interface { 46 | // RedisArg returns the interface that represents the value to be used 47 | // in redis commands. 48 | RedisArg() interface{} 49 | } 50 | 51 | // Scanner is implemented by types which want to control how their value is 52 | // interpreted when read from redis. 53 | type Scanner interface { 54 | // RedisScan assigns a value from a redis value. 55 | // 56 | // An error should be returned if the value cannot be stored without 57 | // loss of information. 58 | RedisScan(src interface{}) error 59 | } 60 | -------------------------------------------------------------------------------- /vendor/github.com/garyburd/redigo/redis/reply.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Gary Burd 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | // License for the specific language governing permissions and limitations 13 | // under the License. 14 | 15 | package redis 16 | 17 | import ( 18 | "errors" 19 | "fmt" 20 | "strconv" 21 | ) 22 | 23 | // ErrNil indicates that a reply value is nil. 24 | var ErrNil = errors.New("redigo: nil returned") 25 | 26 | // Int is a helper that converts a command reply to an integer. If err is not 27 | // equal to nil, then Int returns 0, err. Otherwise, Int converts the 28 | // reply to an int as follows: 29 | // 30 | // Reply type Result 31 | // integer int(reply), nil 32 | // bulk string parsed reply, nil 33 | // nil 0, ErrNil 34 | // other 0, error 35 | func Int(reply interface{}, err error) (int, error) { 36 | if err != nil { 37 | return 0, err 38 | } 39 | switch reply := reply.(type) { 40 | case int64: 41 | x := int(reply) 42 | if int64(x) != reply { 43 | return 0, strconv.ErrRange 44 | } 45 | return x, nil 46 | case []byte: 47 | n, err := strconv.ParseInt(string(reply), 10, 0) 48 | return int(n), err 49 | case nil: 50 | return 0, ErrNil 51 | case Error: 52 | return 0, reply 53 | } 54 | return 0, fmt.Errorf("redigo: unexpected type for Int, got type %T", reply) 55 | } 56 | 57 | // Int64 is a helper that converts a command reply to 64 bit integer. If err is 58 | // not equal to nil, then Int returns 0, err. Otherwise, Int64 converts the 59 | // reply to an int64 as follows: 60 | // 61 | // Reply type Result 62 | // integer reply, nil 63 | // bulk string parsed reply, nil 64 | // nil 0, ErrNil 65 | // other 0, error 66 | func Int64(reply interface{}, err error) (int64, error) { 67 | if err != nil { 68 | return 0, err 69 | } 70 | switch reply := reply.(type) { 71 | case int64: 72 | return reply, nil 73 | case []byte: 74 | n, err := strconv.ParseInt(string(reply), 10, 64) 75 | return n, err 76 | case nil: 77 | return 0, ErrNil 78 | case Error: 79 | return 0, reply 80 | } 81 | return 0, fmt.Errorf("redigo: unexpected type for Int64, got type %T", reply) 82 | } 83 | 84 | var errNegativeInt = errors.New("redigo: unexpected value for Uint64") 85 | 86 | // Uint64 is a helper that converts a command reply to 64 bit integer. If err is 87 | // not equal to nil, then Int returns 0, err. Otherwise, Int64 converts the 88 | // reply to an int64 as follows: 89 | // 90 | // Reply type Result 91 | // integer reply, nil 92 | // bulk string parsed reply, nil 93 | // nil 0, ErrNil 94 | // other 0, error 95 | func Uint64(reply interface{}, err error) (uint64, error) { 96 | if err != nil { 97 | return 0, err 98 | } 99 | switch reply := reply.(type) { 100 | case int64: 101 | if reply < 0 { 102 | return 0, errNegativeInt 103 | } 104 | return uint64(reply), nil 105 | case []byte: 106 | n, err := strconv.ParseUint(string(reply), 10, 64) 107 | return n, err 108 | case nil: 109 | return 0, ErrNil 110 | case Error: 111 | return 0, reply 112 | } 113 | return 0, fmt.Errorf("redigo: unexpected type for Uint64, got type %T", reply) 114 | } 115 | 116 | // Float64 is a helper that converts a command reply to 64 bit float. If err is 117 | // not equal to nil, then Float64 returns 0, err. Otherwise, Float64 converts 118 | // the reply to an int as follows: 119 | // 120 | // Reply type Result 121 | // bulk string parsed reply, nil 122 | // nil 0, ErrNil 123 | // other 0, error 124 | func Float64(reply interface{}, err error) (float64, error) { 125 | if err != nil { 126 | return 0, err 127 | } 128 | switch reply := reply.(type) { 129 | case []byte: 130 | n, err := strconv.ParseFloat(string(reply), 64) 131 | return n, err 132 | case nil: 133 | return 0, ErrNil 134 | case Error: 135 | return 0, reply 136 | } 137 | return 0, fmt.Errorf("redigo: unexpected type for Float64, got type %T", reply) 138 | } 139 | 140 | // String is a helper that converts a command reply to a string. If err is not 141 | // equal to nil, then String returns "", err. Otherwise String converts the 142 | // reply to a string as follows: 143 | // 144 | // Reply type Result 145 | // bulk string string(reply), nil 146 | // simple string reply, nil 147 | // nil "", ErrNil 148 | // other "", error 149 | func String(reply interface{}, err error) (string, error) { 150 | if err != nil { 151 | return "", err 152 | } 153 | switch reply := reply.(type) { 154 | case []byte: 155 | return string(reply), nil 156 | case string: 157 | return reply, nil 158 | case nil: 159 | return "", ErrNil 160 | case Error: 161 | return "", reply 162 | } 163 | return "", fmt.Errorf("redigo: unexpected type for String, got type %T", reply) 164 | } 165 | 166 | // Bytes is a helper that converts a command reply to a slice of bytes. If err 167 | // is not equal to nil, then Bytes returns nil, err. Otherwise Bytes converts 168 | // the reply to a slice of bytes as follows: 169 | // 170 | // Reply type Result 171 | // bulk string reply, nil 172 | // simple string []byte(reply), nil 173 | // nil nil, ErrNil 174 | // other nil, error 175 | func Bytes(reply interface{}, err error) ([]byte, error) { 176 | if err != nil { 177 | return nil, err 178 | } 179 | switch reply := reply.(type) { 180 | case []byte: 181 | return reply, nil 182 | case string: 183 | return []byte(reply), nil 184 | case nil: 185 | return nil, ErrNil 186 | case Error: 187 | return nil, reply 188 | } 189 | return nil, fmt.Errorf("redigo: unexpected type for Bytes, got type %T", reply) 190 | } 191 | 192 | // Bool is a helper that converts a command reply to a boolean. If err is not 193 | // equal to nil, then Bool returns false, err. Otherwise Bool converts the 194 | // reply to boolean as follows: 195 | // 196 | // Reply type Result 197 | // integer value != 0, nil 198 | // bulk string strconv.ParseBool(reply) 199 | // nil false, ErrNil 200 | // other false, error 201 | func Bool(reply interface{}, err error) (bool, error) { 202 | if err != nil { 203 | return false, err 204 | } 205 | switch reply := reply.(type) { 206 | case int64: 207 | return reply != 0, nil 208 | case []byte: 209 | return strconv.ParseBool(string(reply)) 210 | case nil: 211 | return false, ErrNil 212 | case Error: 213 | return false, reply 214 | } 215 | return false, fmt.Errorf("redigo: unexpected type for Bool, got type %T", reply) 216 | } 217 | 218 | // MultiBulk is a helper that converts an array command reply to a []interface{}. 219 | // 220 | // Deprecated: Use Values instead. 221 | func MultiBulk(reply interface{}, err error) ([]interface{}, error) { return Values(reply, err) } 222 | 223 | // Values is a helper that converts an array command reply to a []interface{}. 224 | // If err is not equal to nil, then Values returns nil, err. Otherwise, Values 225 | // converts the reply as follows: 226 | // 227 | // Reply type Result 228 | // array reply, nil 229 | // nil nil, ErrNil 230 | // other nil, error 231 | func Values(reply interface{}, err error) ([]interface{}, error) { 232 | if err != nil { 233 | return nil, err 234 | } 235 | switch reply := reply.(type) { 236 | case []interface{}: 237 | return reply, nil 238 | case nil: 239 | return nil, ErrNil 240 | case Error: 241 | return nil, reply 242 | } 243 | return nil, fmt.Errorf("redigo: unexpected type for Values, got type %T", reply) 244 | } 245 | 246 | // Strings is a helper that converts an array command reply to a []string. If 247 | // err is not equal to nil, then Strings returns nil, err. Nil array items are 248 | // converted to "" in the output slice. Strings returns an error if an array 249 | // item is not a bulk string or nil. 250 | func Strings(reply interface{}, err error) ([]string, error) { 251 | if err != nil { 252 | return nil, err 253 | } 254 | switch reply := reply.(type) { 255 | case []interface{}: 256 | result := make([]string, len(reply)) 257 | for i := range reply { 258 | if reply[i] == nil { 259 | continue 260 | } 261 | p, ok := reply[i].([]byte) 262 | if !ok { 263 | return nil, fmt.Errorf("redigo: unexpected element type for Strings, got type %T", reply[i]) 264 | } 265 | result[i] = string(p) 266 | } 267 | return result, nil 268 | case nil: 269 | return nil, ErrNil 270 | case Error: 271 | return nil, reply 272 | } 273 | return nil, fmt.Errorf("redigo: unexpected type for Strings, got type %T", reply) 274 | } 275 | 276 | // ByteSlices is a helper that converts an array command reply to a [][]byte. 277 | // If err is not equal to nil, then ByteSlices returns nil, err. Nil array 278 | // items are stay nil. ByteSlices returns an error if an array item is not a 279 | // bulk string or nil. 280 | func ByteSlices(reply interface{}, err error) ([][]byte, error) { 281 | if err != nil { 282 | return nil, err 283 | } 284 | switch reply := reply.(type) { 285 | case []interface{}: 286 | result := make([][]byte, len(reply)) 287 | for i := range reply { 288 | if reply[i] == nil { 289 | continue 290 | } 291 | p, ok := reply[i].([]byte) 292 | if !ok { 293 | return nil, fmt.Errorf("redigo: unexpected element type for ByteSlices, got type %T", reply[i]) 294 | } 295 | result[i] = p 296 | } 297 | return result, nil 298 | case nil: 299 | return nil, ErrNil 300 | case Error: 301 | return nil, reply 302 | } 303 | return nil, fmt.Errorf("redigo: unexpected type for ByteSlices, got type %T", reply) 304 | } 305 | 306 | // Ints is a helper that converts an array command reply to a []int. If 307 | // err is not equal to nil, then Ints returns nil, err. 308 | func Ints(reply interface{}, err error) ([]int, error) { 309 | var ints []int 310 | values, err := Values(reply, err) 311 | if err != nil { 312 | return ints, err 313 | } 314 | if err := ScanSlice(values, &ints); err != nil { 315 | return ints, err 316 | } 317 | return ints, nil 318 | } 319 | 320 | // StringMap is a helper that converts an array of strings (alternating key, value) 321 | // into a map[string]string. The HGETALL and CONFIG GET commands return replies in this format. 322 | // Requires an even number of values in result. 323 | func StringMap(result interface{}, err error) (map[string]string, error) { 324 | values, err := Values(result, err) 325 | if err != nil { 326 | return nil, err 327 | } 328 | if len(values)%2 != 0 { 329 | return nil, errors.New("redigo: StringMap expects even number of values result") 330 | } 331 | m := make(map[string]string, len(values)/2) 332 | for i := 0; i < len(values); i += 2 { 333 | key, okKey := values[i].([]byte) 334 | value, okValue := values[i+1].([]byte) 335 | if !okKey || !okValue { 336 | return nil, errors.New("redigo: ScanMap key not a bulk string value") 337 | } 338 | m[string(key)] = string(value) 339 | } 340 | return m, nil 341 | } 342 | 343 | // IntMap is a helper that converts an array of strings (alternating key, value) 344 | // into a map[string]int. The HGETALL commands return replies in this format. 345 | // Requires an even number of values in result. 346 | func IntMap(result interface{}, err error) (map[string]int, error) { 347 | values, err := Values(result, err) 348 | if err != nil { 349 | return nil, err 350 | } 351 | if len(values)%2 != 0 { 352 | return nil, errors.New("redigo: IntMap expects even number of values result") 353 | } 354 | m := make(map[string]int, len(values)/2) 355 | for i := 0; i < len(values); i += 2 { 356 | key, ok := values[i].([]byte) 357 | if !ok { 358 | return nil, errors.New("redigo: ScanMap key not a bulk string value") 359 | } 360 | value, err := Int(values[i+1], nil) 361 | if err != nil { 362 | return nil, err 363 | } 364 | m[string(key)] = value 365 | } 366 | return m, nil 367 | } 368 | 369 | // Int64Map is a helper that converts an array of strings (alternating key, value) 370 | // into a map[string]int64. The HGETALL commands return replies in this format. 371 | // Requires an even number of values in result. 372 | func Int64Map(result interface{}, err error) (map[string]int64, error) { 373 | values, err := Values(result, err) 374 | if err != nil { 375 | return nil, err 376 | } 377 | if len(values)%2 != 0 { 378 | return nil, errors.New("redigo: Int64Map expects even number of values result") 379 | } 380 | m := make(map[string]int64, len(values)/2) 381 | for i := 0; i < len(values); i += 2 { 382 | key, ok := values[i].([]byte) 383 | if !ok { 384 | return nil, errors.New("redigo: ScanMap key not a bulk string value") 385 | } 386 | value, err := Int64(values[i+1], nil) 387 | if err != nil { 388 | return nil, err 389 | } 390 | m[string(key)] = value 391 | } 392 | return m, nil 393 | } 394 | 395 | // Positions is a helper that converts an array of positions (lat, long) 396 | // into a [][2]float64. The GEOPOS command returns replies in this format. 397 | func Positions(result interface{}, err error) ([]*[2]float64, error) { 398 | values, err := Values(result, err) 399 | if err != nil { 400 | return nil, err 401 | } 402 | positions := make([]*[2]float64, len(values)) 403 | for i := range values { 404 | if values[i] == nil { 405 | continue 406 | } 407 | p, ok := values[i].([]interface{}) 408 | if !ok { 409 | return nil, fmt.Errorf("redigo: unexpected element type for interface slice, got type %T", values[i]) 410 | } 411 | if len(p) != 2 { 412 | return nil, fmt.Errorf("redigo: unexpected number of values for a member position, got %d", len(p)) 413 | } 414 | lat, err := Float64(p[0], nil) 415 | if err != nil { 416 | return nil, err 417 | } 418 | long, err := Float64(p[1], nil) 419 | if err != nil { 420 | return nil, err 421 | } 422 | positions[i] = &[2]float64{lat, long} 423 | } 424 | return positions, nil 425 | } 426 | -------------------------------------------------------------------------------- /vendor/github.com/garyburd/redigo/redis/script.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Gary Burd 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | // License for the specific language governing permissions and limitations 13 | // under the License. 14 | 15 | package redis 16 | 17 | import ( 18 | "crypto/sha1" 19 | "encoding/hex" 20 | "io" 21 | "strings" 22 | ) 23 | 24 | // Script encapsulates the source, hash and key count for a Lua script. See 25 | // http://redis.io/commands/eval for information on scripts in Redis. 26 | type Script struct { 27 | keyCount int 28 | src string 29 | hash string 30 | } 31 | 32 | // NewScript returns a new script object. If keyCount is greater than or equal 33 | // to zero, then the count is automatically inserted in the EVAL command 34 | // argument list. If keyCount is less than zero, then the application supplies 35 | // the count as the first value in the keysAndArgs argument to the Do, Send and 36 | // SendHash methods. 37 | func NewScript(keyCount int, src string) *Script { 38 | h := sha1.New() 39 | io.WriteString(h, src) 40 | return &Script{keyCount, src, hex.EncodeToString(h.Sum(nil))} 41 | } 42 | 43 | func (s *Script) args(spec string, keysAndArgs []interface{}) []interface{} { 44 | var args []interface{} 45 | if s.keyCount < 0 { 46 | args = make([]interface{}, 1+len(keysAndArgs)) 47 | args[0] = spec 48 | copy(args[1:], keysAndArgs) 49 | } else { 50 | args = make([]interface{}, 2+len(keysAndArgs)) 51 | args[0] = spec 52 | args[1] = s.keyCount 53 | copy(args[2:], keysAndArgs) 54 | } 55 | return args 56 | } 57 | 58 | // Hash returns the script hash. 59 | func (s *Script) Hash() string { 60 | return s.hash 61 | } 62 | 63 | // Do evaluates the script. Under the covers, Do optimistically evaluates the 64 | // script using the EVALSHA command. If the command fails because the script is 65 | // not loaded, then Do evaluates the script using the EVAL command (thus 66 | // causing the script to load). 67 | func (s *Script) Do(c Conn, keysAndArgs ...interface{}) (interface{}, error) { 68 | v, err := c.Do("EVALSHA", s.args(s.hash, keysAndArgs)...) 69 | if e, ok := err.(Error); ok && strings.HasPrefix(string(e), "NOSCRIPT ") { 70 | v, err = c.Do("EVAL", s.args(s.src, keysAndArgs)...) 71 | } 72 | return v, err 73 | } 74 | 75 | // SendHash evaluates the script without waiting for the reply. The script is 76 | // evaluated with the EVALSHA command. The application must ensure that the 77 | // script is loaded by a previous call to Send, Do or Load methods. 78 | func (s *Script) SendHash(c Conn, keysAndArgs ...interface{}) error { 79 | return c.Send("EVALSHA", s.args(s.hash, keysAndArgs)...) 80 | } 81 | 82 | // Send evaluates the script without waiting for the reply. 83 | func (s *Script) Send(c Conn, keysAndArgs ...interface{}) error { 84 | return c.Send("EVAL", s.args(s.src, keysAndArgs)...) 85 | } 86 | 87 | // Load loads the script without evaluating it. 88 | func (s *Script) Load(c Conn) error { 89 | _, err := c.Do("SCRIPT", "LOAD", s.src) 90 | return err 91 | } 92 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## v3 2 | 3 | - gopkg.in is not supported any more. Update import path to github.com/vmihailenco/msgpack. 4 | - Msgpack maps are decoded into map[string]interface{} by default. 5 | - EncodeSliceLen is removed in favor of EncodeArrayLen. DecodeSliceLen is removed in favor of DecodeArrayLen. 6 | - Embedded structs are automatically inlined where possible. 7 | - Time is encoded using extension as described in https://github.com/msgpack/msgpack/pull/209. Old format is supported as well. 8 | - EncodeInt8/16/32/64 is replaced with EncodeInt. EncodeUint8/16/32/64 is replaced with EncodeUint. There should be no performance differences. 9 | - DecodeInterface can now return int8/16/32 and uint8/16/32. 10 | - PeekCode returns codes.Code instead of byte. 11 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 The github.com/vmihailenco/msgpack Authors. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | go test ./... 3 | env GOOS=linux GOARCH=386 go test ./... 4 | go test ./... -short -race 5 | go vet 6 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/README.md: -------------------------------------------------------------------------------- 1 | # MessagePack encoding for Golang 2 | 3 | [![Build Status](https://travis-ci.org/vmihailenco/msgpack.svg?branch=v2)](https://travis-ci.org/vmihailenco/msgpack) 4 | [![GoDoc](https://godoc.org/github.com/vmihailenco/msgpack?status.svg)](https://godoc.org/github.com/vmihailenco/msgpack) 5 | 6 | Supports: 7 | - Primitives, arrays, maps, structs, time.Time and interface{}. 8 | - Appengine *datastore.Key and datastore.Cursor. 9 | - [CustomEncoder](https://godoc.org/github.com/vmihailenco/msgpack#example-CustomEncoder)/CustomDecoder interfaces for custom encoding. 10 | - [Extensions](https://godoc.org/github.com/vmihailenco/msgpack#example-RegisterExt) to encode type information. 11 | - Renaming fields via `msgpack:"my_field_name"`. 12 | - Omitting empty fields via `msgpack:",omitempty"`. 13 | - [Map keys sorting](https://godoc.org/github.com/vmihailenco/msgpack#Encoder.SortMapKeys). 14 | - Encoding/decoding all [structs as arrays](https://godoc.org/github.com/vmihailenco/msgpack#Encoder.StructAsArray) or [individual structs](https://godoc.org/github.com/vmihailenco/msgpack#example-Marshal--AsArray). 15 | - Simple but very fast and efficient [queries](https://godoc.org/github.com/vmihailenco/msgpack#example-Decoder-Query). 16 | 17 | API docs: https://godoc.org/github.com/vmihailenco/msgpack. 18 | Examples: https://godoc.org/github.com/vmihailenco/msgpack#pkg-examples. 19 | 20 | ## Installation 21 | 22 | Install: 23 | 24 | ```shell 25 | go get -u github.com/vmihailenco/msgpack 26 | ``` 27 | 28 | ## Quickstart 29 | 30 | ```go 31 | func ExampleMarshal() { 32 | type Item struct { 33 | Foo string 34 | } 35 | 36 | b, err := msgpack.Marshal(&Item{Foo: "bar"}) 37 | if err != nil { 38 | panic(err) 39 | } 40 | 41 | var item Item 42 | err = msgpack.Unmarshal(b, &item) 43 | if err != nil { 44 | panic(err) 45 | } 46 | fmt.Println(item.Foo) 47 | // Output: bar 48 | } 49 | ``` 50 | 51 | ## Benchmark 52 | 53 | ``` 54 | BenchmarkStructVmihailencoMsgpack-4 200000 12814 ns/op 2128 B/op 26 allocs/op 55 | BenchmarkStructUgorjiGoMsgpack-4 100000 17678 ns/op 3616 B/op 70 allocs/op 56 | BenchmarkStructUgorjiGoCodec-4 100000 19053 ns/op 7346 B/op 23 allocs/op 57 | BenchmarkStructJSON-4 20000 69438 ns/op 7864 B/op 26 allocs/op 58 | BenchmarkStructGOB-4 10000 104331 ns/op 14664 B/op 278 allocs/op 59 | ``` 60 | 61 | ## Howto 62 | 63 | Please go through [examples](https://godoc.org/github.com/vmihailenco/msgpack#pkg-examples) to get an idea how to use this package. 64 | 65 | ## See also 66 | 67 | - [Golang PostgreSQL ORM](https://github.com/go-pg/pg) 68 | - [Golang message task queue](https://github.com/go-msgqueue/msgqueue) 69 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/appengine.go: -------------------------------------------------------------------------------- 1 | // +build appengine 2 | 3 | package msgpack 4 | 5 | import ( 6 | "reflect" 7 | 8 | ds "google.golang.org/appengine/datastore" 9 | ) 10 | 11 | func init() { 12 | Register((*ds.Key)(nil), encodeDatastoreKeyValue, decodeDatastoreKeyValue) 13 | Register((*ds.Cursor)(nil), encodeDatastoreCursorValue, decodeDatastoreCursorValue) 14 | } 15 | 16 | func EncodeDatastoreKey(e *Encoder, key *ds.Key) error { 17 | if key == nil { 18 | return e.EncodeNil() 19 | } 20 | return e.EncodeString(key.Encode()) 21 | } 22 | 23 | func encodeDatastoreKeyValue(e *Encoder, v reflect.Value) error { 24 | key := v.Interface().(*ds.Key) 25 | return EncodeDatastoreKey(e, key) 26 | } 27 | 28 | func DecodeDatastoreKey(d *Decoder) (*ds.Key, error) { 29 | v, err := d.DecodeString() 30 | if err != nil { 31 | return nil, err 32 | } 33 | if v == "" { 34 | return nil, nil 35 | } 36 | return ds.DecodeKey(v) 37 | } 38 | 39 | func decodeDatastoreKeyValue(d *Decoder, v reflect.Value) error { 40 | key, err := DecodeDatastoreKey(d) 41 | if err != nil { 42 | return err 43 | } 44 | v.Set(reflect.ValueOf(key)) 45 | return nil 46 | } 47 | 48 | func encodeDatastoreCursorValue(e *Encoder, v reflect.Value) error { 49 | cursor := v.Interface().(ds.Cursor) 50 | return e.Encode(cursor.String()) 51 | } 52 | 53 | func decodeDatastoreCursorValue(d *Decoder, v reflect.Value) error { 54 | s, err := d.DecodeString() 55 | if err != nil { 56 | return err 57 | } 58 | cursor, err := ds.DecodeCursor(s) 59 | if err != nil { 60 | return err 61 | } 62 | v.Set(reflect.ValueOf(cursor)) 63 | return nil 64 | } 65 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/codes/codes.go: -------------------------------------------------------------------------------- 1 | package codes 2 | 3 | type Code byte 4 | 5 | var ( 6 | PosFixedNumHigh Code = 0x7f 7 | NegFixedNumLow Code = 0xe0 8 | 9 | Nil Code = 0xc0 10 | 11 | False Code = 0xc2 12 | True Code = 0xc3 13 | 14 | Float Code = 0xca 15 | Double Code = 0xcb 16 | 17 | Uint8 Code = 0xcc 18 | Uint16 Code = 0xcd 19 | Uint32 Code = 0xce 20 | Uint64 Code = 0xcf 21 | 22 | Int8 Code = 0xd0 23 | Int16 Code = 0xd1 24 | Int32 Code = 0xd2 25 | Int64 Code = 0xd3 26 | 27 | FixedStrLow Code = 0xa0 28 | FixedStrHigh Code = 0xbf 29 | FixedStrMask Code = 0x1f 30 | Str8 Code = 0xd9 31 | Str16 Code = 0xda 32 | Str32 Code = 0xdb 33 | 34 | Bin8 Code = 0xc4 35 | Bin16 Code = 0xc5 36 | Bin32 Code = 0xc6 37 | 38 | FixedArrayLow Code = 0x90 39 | FixedArrayHigh Code = 0x9f 40 | FixedArrayMask Code = 0xf 41 | Array16 Code = 0xdc 42 | Array32 Code = 0xdd 43 | 44 | FixedMapLow Code = 0x80 45 | FixedMapHigh Code = 0x8f 46 | FixedMapMask Code = 0xf 47 | Map16 Code = 0xde 48 | Map32 Code = 0xdf 49 | 50 | FixExt1 Code = 0xd4 51 | FixExt2 Code = 0xd5 52 | FixExt4 Code = 0xd6 53 | FixExt8 Code = 0xd7 54 | FixExt16 Code = 0xd8 55 | Ext8 Code = 0xc7 56 | Ext16 Code = 0xc8 57 | Ext32 Code = 0xc9 58 | ) 59 | 60 | func IsFixedNum(c Code) bool { 61 | return c <= PosFixedNumHigh || c >= NegFixedNumLow 62 | } 63 | 64 | func IsFixedMap(c Code) bool { 65 | return c >= FixedMapLow && c <= FixedMapHigh 66 | } 67 | 68 | func IsFixedArray(c Code) bool { 69 | return c >= FixedArrayLow && c <= FixedArrayHigh 70 | } 71 | 72 | func IsFixedString(c Code) bool { 73 | return c >= FixedStrLow && c <= FixedStrHigh 74 | } 75 | 76 | func IsExt(c Code) bool { 77 | return (c >= FixExt1 && c <= FixExt16) || (c >= Ext8 && c <= Ext32) 78 | } 79 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/decode.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "errors" 7 | "fmt" 8 | "io" 9 | "reflect" 10 | "time" 11 | 12 | "github.com/vmihailenco/msgpack/codes" 13 | ) 14 | 15 | const bytesAllocLimit = 1024 * 1024 // 1mb 16 | 17 | type bufReader interface { 18 | Read([]byte) (int, error) 19 | ReadByte() (byte, error) 20 | UnreadByte() error 21 | } 22 | 23 | func newBufReader(r io.Reader) bufReader { 24 | if br, ok := r.(bufReader); ok { 25 | return br 26 | } 27 | return bufio.NewReader(r) 28 | } 29 | 30 | func makeBuffer() []byte { 31 | return make([]byte, 0, 64) 32 | } 33 | 34 | // Unmarshal decodes the MessagePack-encoded data and stores the result 35 | // in the value pointed to by v. 36 | func Unmarshal(data []byte, v ...interface{}) error { 37 | return NewDecoder(bytes.NewReader(data)).Decode(v...) 38 | } 39 | 40 | type Decoder struct { 41 | r bufReader 42 | buf []byte 43 | 44 | extLen int 45 | rec []byte // accumulates read data if not nil 46 | 47 | decodeMapFunc func(*Decoder) (interface{}, error) 48 | } 49 | 50 | func NewDecoder(r io.Reader) *Decoder { 51 | return &Decoder{ 52 | decodeMapFunc: decodeMap, 53 | 54 | r: newBufReader(r), 55 | buf: makeBuffer(), 56 | } 57 | } 58 | 59 | func (d *Decoder) SetDecodeMapFunc(fn func(*Decoder) (interface{}, error)) { 60 | d.decodeMapFunc = fn 61 | } 62 | 63 | func (d *Decoder) Reset(r io.Reader) error { 64 | d.r = newBufReader(r) 65 | return nil 66 | } 67 | 68 | func (d *Decoder) Decode(v ...interface{}) error { 69 | for _, vv := range v { 70 | if err := d.decode(vv); err != nil { 71 | return err 72 | } 73 | } 74 | return nil 75 | } 76 | 77 | func (d *Decoder) decode(dst interface{}) error { 78 | var err error 79 | switch v := dst.(type) { 80 | case *string: 81 | if v != nil { 82 | *v, err = d.DecodeString() 83 | return err 84 | } 85 | case *[]byte: 86 | if v != nil { 87 | return d.decodeBytesPtr(v) 88 | } 89 | case *int: 90 | if v != nil { 91 | *v, err = d.DecodeInt() 92 | return err 93 | } 94 | case *int8: 95 | if v != nil { 96 | *v, err = d.DecodeInt8() 97 | return err 98 | } 99 | case *int16: 100 | if v != nil { 101 | *v, err = d.DecodeInt16() 102 | return err 103 | } 104 | case *int32: 105 | if v != nil { 106 | *v, err = d.DecodeInt32() 107 | return err 108 | } 109 | case *int64: 110 | if v != nil { 111 | *v, err = d.DecodeInt64() 112 | return err 113 | } 114 | case *uint: 115 | if v != nil { 116 | *v, err = d.DecodeUint() 117 | return err 118 | } 119 | case *uint8: 120 | if v != nil { 121 | *v, err = d.DecodeUint8() 122 | return err 123 | } 124 | case *uint16: 125 | if v != nil { 126 | *v, err = d.DecodeUint16() 127 | return err 128 | } 129 | case *uint32: 130 | if v != nil { 131 | *v, err = d.DecodeUint32() 132 | return err 133 | } 134 | case *uint64: 135 | if v != nil { 136 | *v, err = d.DecodeUint64() 137 | return err 138 | } 139 | case *bool: 140 | if v != nil { 141 | *v, err = d.DecodeBool() 142 | return err 143 | } 144 | case *float32: 145 | if v != nil { 146 | *v, err = d.DecodeFloat32() 147 | return err 148 | } 149 | case *float64: 150 | if v != nil { 151 | *v, err = d.DecodeFloat64() 152 | return err 153 | } 154 | case *[]string: 155 | return d.decodeStringSlicePtr(v) 156 | case *map[string]string: 157 | return d.decodeMapStringStringPtr(v) 158 | case *map[string]interface{}: 159 | return d.decodeMapStringInterfacePtr(v) 160 | case *time.Duration: 161 | if v != nil { 162 | vv, err := d.DecodeInt64() 163 | *v = time.Duration(vv) 164 | return err 165 | } 166 | case *time.Time: 167 | if v != nil { 168 | *v, err = d.DecodeTime() 169 | return err 170 | } 171 | } 172 | 173 | v := reflect.ValueOf(dst) 174 | if !v.IsValid() { 175 | return errors.New("msgpack: Decode(nil)") 176 | } 177 | if v.Kind() != reflect.Ptr { 178 | return fmt.Errorf("msgpack: Decode(nonsettable %T)", dst) 179 | } 180 | v = v.Elem() 181 | if !v.IsValid() { 182 | return fmt.Errorf("msgpack: Decode(nonsettable %T)", dst) 183 | } 184 | return d.DecodeValue(v) 185 | } 186 | 187 | func (d *Decoder) DecodeValue(v reflect.Value) error { 188 | decode := getDecoder(v.Type()) 189 | return decode(d, v) 190 | } 191 | 192 | func (d *Decoder) DecodeNil() error { 193 | c, err := d.readCode() 194 | if err != nil { 195 | return err 196 | } 197 | if c != codes.Nil { 198 | return fmt.Errorf("msgpack: invalid code=%x decoding nil", c) 199 | } 200 | return nil 201 | } 202 | 203 | func (d *Decoder) decodeNilValue(v reflect.Value) error { 204 | err := d.DecodeNil() 205 | if v.IsNil() { 206 | return err 207 | } 208 | if v.Kind() == reflect.Ptr { 209 | v = v.Elem() 210 | } 211 | v.Set(reflect.Zero(v.Type())) 212 | return err 213 | } 214 | 215 | func (d *Decoder) DecodeBool() (bool, error) { 216 | c, err := d.readCode() 217 | if err != nil { 218 | return false, err 219 | } 220 | return d.bool(c) 221 | } 222 | 223 | func (d *Decoder) bool(c codes.Code) (bool, error) { 224 | if c == codes.False { 225 | return false, nil 226 | } 227 | if c == codes.True { 228 | return true, nil 229 | } 230 | return false, fmt.Errorf("msgpack: invalid code=%x decoding bool", c) 231 | } 232 | 233 | func (d *Decoder) interfaceValue(v reflect.Value) error { 234 | vv, err := d.DecodeInterface() 235 | if err != nil { 236 | return err 237 | } 238 | if vv != nil { 239 | if v.Type() == errorType { 240 | if vv, ok := vv.(string); ok { 241 | v.Set(reflect.ValueOf(errors.New(vv))) 242 | return nil 243 | } 244 | } 245 | 246 | v.Set(reflect.ValueOf(vv)) 247 | } 248 | return nil 249 | } 250 | 251 | // DecodeInterface decodes value into interface. Possible value types are: 252 | // - nil, 253 | // - bool, 254 | // - int8, int16, int32, int64, 255 | // - uint8, uint16, uint32, uint64, 256 | // - float32 and float64, 257 | // - string, 258 | // - slices of any of the above, 259 | // - maps of any of the above. 260 | func (d *Decoder) DecodeInterface() (interface{}, error) { 261 | c, err := d.readCode() 262 | if err != nil { 263 | return nil, err 264 | } 265 | 266 | if codes.IsFixedNum(c) { 267 | return int8(c), nil 268 | } 269 | if codes.IsFixedMap(c) { 270 | d.r.UnreadByte() 271 | return d.DecodeMap() 272 | } 273 | if codes.IsFixedArray(c) { 274 | return d.decodeSlice(c) 275 | } 276 | if codes.IsFixedString(c) { 277 | return d.string(c) 278 | } 279 | 280 | switch c { 281 | case codes.Nil: 282 | return nil, nil 283 | case codes.False, codes.True: 284 | return d.bool(c) 285 | case codes.Float: 286 | return d.float32(c) 287 | case codes.Double: 288 | return d.float64(c) 289 | case codes.Uint8: 290 | return d.uint8() 291 | case codes.Uint16: 292 | return d.uint16() 293 | case codes.Uint32: 294 | return d.uint32() 295 | case codes.Uint64: 296 | return d.uint64() 297 | case codes.Int8: 298 | return d.int8() 299 | case codes.Int16: 300 | return d.int16() 301 | case codes.Int32: 302 | return d.int32() 303 | case codes.Int64: 304 | return d.int64() 305 | case codes.Bin8, codes.Bin16, codes.Bin32: 306 | return d.bytes(c, nil) 307 | case codes.Str8, codes.Str16, codes.Str32: 308 | return d.string(c) 309 | case codes.Array16, codes.Array32: 310 | return d.decodeSlice(c) 311 | case codes.Map16, codes.Map32: 312 | d.r.UnreadByte() 313 | return d.DecodeMap() 314 | case codes.FixExt1, codes.FixExt2, codes.FixExt4, codes.FixExt8, codes.FixExt16, 315 | codes.Ext8, codes.Ext16, codes.Ext32: 316 | return d.ext(c) 317 | } 318 | 319 | return 0, fmt.Errorf("msgpack: unknown code %x decoding interface{}", c) 320 | } 321 | 322 | // Skip skips next value. 323 | func (d *Decoder) Skip() error { 324 | c, err := d.readCode() 325 | if err != nil { 326 | return err 327 | } 328 | 329 | if codes.IsFixedNum(c) { 330 | return nil 331 | } else if codes.IsFixedMap(c) { 332 | return d.skipMap(c) 333 | } else if codes.IsFixedArray(c) { 334 | return d.skipSlice(c) 335 | } else if codes.IsFixedString(c) { 336 | return d.skipBytes(c) 337 | } 338 | 339 | switch c { 340 | case codes.Nil, codes.False, codes.True: 341 | return nil 342 | case codes.Uint8, codes.Int8: 343 | return d.skipN(1) 344 | case codes.Uint16, codes.Int16: 345 | return d.skipN(2) 346 | case codes.Uint32, codes.Int32, codes.Float: 347 | return d.skipN(4) 348 | case codes.Uint64, codes.Int64, codes.Double: 349 | return d.skipN(8) 350 | case codes.Bin8, codes.Bin16, codes.Bin32: 351 | return d.skipBytes(c) 352 | case codes.Str8, codes.Str16, codes.Str32: 353 | return d.skipBytes(c) 354 | case codes.Array16, codes.Array32: 355 | return d.skipSlice(c) 356 | case codes.Map16, codes.Map32: 357 | return d.skipMap(c) 358 | case codes.FixExt1, codes.FixExt2, codes.FixExt4, codes.FixExt8, codes.FixExt16, codes.Ext8, codes.Ext16, codes.Ext32: 359 | return d.skipExt(c) 360 | } 361 | 362 | return fmt.Errorf("msgpack: unknown code %x", c) 363 | } 364 | 365 | // PeekCode returns the next MessagePack code without advancing the reader. 366 | // Subpackage msgpack/codes contains list of available codes. 367 | func (d *Decoder) PeekCode() (codes.Code, error) { 368 | c, err := d.r.ReadByte() 369 | if err != nil { 370 | return 0, err 371 | } 372 | return codes.Code(c), d.r.UnreadByte() 373 | } 374 | 375 | func (d *Decoder) hasNilCode() bool { 376 | code, err := d.PeekCode() 377 | return err == nil && code == codes.Nil 378 | } 379 | 380 | func (d *Decoder) readCode() (codes.Code, error) { 381 | c, err := d.r.ReadByte() 382 | if err != nil { 383 | return 0, err 384 | } 385 | if d.rec != nil { 386 | d.rec = append(d.rec, c) 387 | } 388 | return codes.Code(c), nil 389 | } 390 | 391 | func (d *Decoder) readFull(b []byte) error { 392 | _, err := io.ReadFull(d.r, b) 393 | if err != nil { 394 | return err 395 | } 396 | if d.rec != nil { 397 | d.rec = append(d.rec, b...) 398 | } 399 | return nil 400 | } 401 | 402 | func (d *Decoder) readN(n int) ([]byte, error) { 403 | buf, err := readN(d.r, d.buf, n) 404 | if err != nil { 405 | return nil, err 406 | } 407 | d.buf = buf 408 | if d.rec != nil { 409 | d.rec = append(d.rec, buf...) 410 | } 411 | return buf, nil 412 | } 413 | 414 | func readN(r io.Reader, b []byte, n int) ([]byte, error) { 415 | if n == 0 && b == nil { 416 | return make([]byte, 0), nil 417 | } 418 | 419 | if cap(b) >= n { 420 | b = b[:n] 421 | _, err := io.ReadFull(r, b) 422 | return b, err 423 | } 424 | b = b[:cap(b)] 425 | 426 | var pos int 427 | for len(b) < n { 428 | diff := n - len(b) 429 | if diff > bytesAllocLimit { 430 | diff = bytesAllocLimit 431 | } 432 | b = append(b, make([]byte, diff)...) 433 | 434 | _, err := io.ReadFull(r, b[pos:]) 435 | if err != nil { 436 | return nil, err 437 | } 438 | 439 | pos = len(b) 440 | } 441 | 442 | return b, nil 443 | } 444 | 445 | func min(a, b int) int { 446 | if a <= b { 447 | return a 448 | } 449 | return b 450 | } 451 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/decode_map.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | 7 | "github.com/vmihailenco/msgpack/codes" 8 | ) 9 | 10 | const mapElemsAllocLimit = 1e4 11 | 12 | var mapStringStringPtrType = reflect.TypeOf((*map[string]string)(nil)) 13 | var mapStringStringType = mapStringStringPtrType.Elem() 14 | 15 | var mapStringInterfacePtrType = reflect.TypeOf((*map[string]interface{})(nil)) 16 | var mapStringInterfaceType = mapStringInterfacePtrType.Elem() 17 | 18 | func decodeMapValue(d *Decoder, v reflect.Value) error { 19 | n, err := d.DecodeMapLen() 20 | if err != nil { 21 | return err 22 | } 23 | 24 | typ := v.Type() 25 | if n == -1 { 26 | v.Set(reflect.Zero(typ)) 27 | return nil 28 | } 29 | 30 | if v.IsNil() { 31 | v.Set(reflect.MakeMap(typ)) 32 | } 33 | keyType := typ.Key() 34 | valueType := typ.Elem() 35 | 36 | for i := 0; i < n; i++ { 37 | mk := reflect.New(keyType).Elem() 38 | if err := d.DecodeValue(mk); err != nil { 39 | return err 40 | } 41 | 42 | mv := reflect.New(valueType).Elem() 43 | if err := d.DecodeValue(mv); err != nil { 44 | return err 45 | } 46 | 47 | v.SetMapIndex(mk, mv) 48 | } 49 | 50 | return nil 51 | } 52 | 53 | func decodeMap(d *Decoder) (interface{}, error) { 54 | n, err := d.DecodeMapLen() 55 | if err != nil { 56 | return nil, err 57 | } 58 | if n == -1 { 59 | return nil, nil 60 | } 61 | 62 | m := make(map[string]interface{}, min(n, mapElemsAllocLimit)) 63 | for i := 0; i < n; i++ { 64 | mk, err := d.DecodeString() 65 | if err != nil { 66 | return nil, err 67 | } 68 | mv, err := d.DecodeInterface() 69 | if err != nil { 70 | return nil, err 71 | } 72 | m[mk] = mv 73 | } 74 | return m, nil 75 | } 76 | 77 | func (d *Decoder) DecodeMapLen() (int, error) { 78 | c, err := d.readCode() 79 | if err != nil { 80 | return 0, err 81 | } 82 | 83 | if codes.IsExt(c) { 84 | if err = d.skipExtHeader(c); err != nil { 85 | return 0, err 86 | } 87 | 88 | c, err = d.readCode() 89 | if err != nil { 90 | return 0, err 91 | } 92 | } 93 | 94 | return d.mapLen(c) 95 | } 96 | 97 | func (d *Decoder) mapLen(c codes.Code) (int, error) { 98 | if c == codes.Nil { 99 | return -1, nil 100 | } 101 | if c >= codes.FixedMapLow && c <= codes.FixedMapHigh { 102 | return int(c & codes.FixedMapMask), nil 103 | } 104 | if c == codes.Map16 { 105 | n, err := d.uint16() 106 | return int(n), err 107 | } 108 | if c == codes.Map32 { 109 | n, err := d.uint32() 110 | return int(n), err 111 | } 112 | return 0, fmt.Errorf("msgpack: invalid code=%x decoding map length", c) 113 | } 114 | 115 | func decodeMapStringStringValue(d *Decoder, v reflect.Value) error { 116 | mptr := v.Addr().Convert(mapStringStringPtrType).Interface().(*map[string]string) 117 | return d.decodeMapStringStringPtr(mptr) 118 | } 119 | 120 | func (d *Decoder) decodeMapStringStringPtr(ptr *map[string]string) error { 121 | n, err := d.DecodeMapLen() 122 | if err != nil { 123 | return err 124 | } 125 | if n == -1 { 126 | *ptr = nil 127 | return nil 128 | } 129 | 130 | m := *ptr 131 | if m == nil { 132 | *ptr = make(map[string]string, min(n, mapElemsAllocLimit)) 133 | m = *ptr 134 | } 135 | 136 | for i := 0; i < n; i++ { 137 | mk, err := d.DecodeString() 138 | if err != nil { 139 | return err 140 | } 141 | mv, err := d.DecodeString() 142 | if err != nil { 143 | return err 144 | } 145 | m[mk] = mv 146 | } 147 | 148 | return nil 149 | } 150 | 151 | func decodeMapStringInterfaceValue(d *Decoder, v reflect.Value) error { 152 | ptr := v.Addr().Convert(mapStringInterfacePtrType).Interface().(*map[string]interface{}) 153 | return d.decodeMapStringInterfacePtr(ptr) 154 | } 155 | 156 | func (d *Decoder) decodeMapStringInterfacePtr(ptr *map[string]interface{}) error { 157 | n, err := d.DecodeMapLen() 158 | if err != nil { 159 | return err 160 | } 161 | if n == -1 { 162 | *ptr = nil 163 | return nil 164 | } 165 | 166 | m := *ptr 167 | if m == nil { 168 | *ptr = make(map[string]interface{}, min(n, mapElemsAllocLimit)) 169 | m = *ptr 170 | } 171 | 172 | for i := 0; i < n; i++ { 173 | mk, err := d.DecodeString() 174 | if err != nil { 175 | return err 176 | } 177 | mv, err := d.DecodeInterface() 178 | if err != nil { 179 | return err 180 | } 181 | m[mk] = mv 182 | } 183 | 184 | return nil 185 | } 186 | 187 | func (d *Decoder) DecodeMap() (interface{}, error) { 188 | return d.decodeMapFunc(d) 189 | } 190 | 191 | func (d *Decoder) skipMap(c codes.Code) error { 192 | n, err := d.mapLen(c) 193 | if err != nil { 194 | return err 195 | } 196 | for i := 0; i < n; i++ { 197 | if err := d.Skip(); err != nil { 198 | return err 199 | } 200 | if err := d.Skip(); err != nil { 201 | return err 202 | } 203 | } 204 | return nil 205 | } 206 | 207 | func decodeStructValue(d *Decoder, strct reflect.Value) error { 208 | c, err := d.readCode() 209 | if err != nil { 210 | return err 211 | } 212 | 213 | var isArray bool 214 | 215 | n, err := d.mapLen(c) 216 | if err != nil { 217 | var err2 error 218 | n, err2 = d.arrayLen(c) 219 | if err2 != nil { 220 | return err 221 | } 222 | isArray = true 223 | } 224 | if n == -1 { 225 | strct.Set(reflect.Zero(strct.Type())) 226 | return nil 227 | } 228 | 229 | fields := structs.Fields(strct.Type()) 230 | 231 | if isArray { 232 | for i, f := range fields.List { 233 | if i >= n { 234 | break 235 | } 236 | if err := f.DecodeValue(d, strct); err != nil { 237 | return err 238 | } 239 | } 240 | // Skip extra values. 241 | for i := len(fields.List); i < n; i++ { 242 | if err := d.Skip(); err != nil { 243 | return err 244 | } 245 | } 246 | return nil 247 | } 248 | 249 | for i := 0; i < n; i++ { 250 | name, err := d.DecodeString() 251 | if err != nil { 252 | return err 253 | } 254 | if f := fields.Table[name]; f != nil { 255 | if err := f.DecodeValue(d, strct); err != nil { 256 | return err 257 | } 258 | } else { 259 | if err := d.Skip(); err != nil { 260 | return err 261 | } 262 | } 263 | } 264 | 265 | return nil 266 | } 267 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/decode_number.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "reflect" 7 | 8 | "github.com/vmihailenco/msgpack/codes" 9 | ) 10 | 11 | func (d *Decoder) skipN(n int) error { 12 | _, err := d.readN(n) 13 | return err 14 | } 15 | 16 | func (d *Decoder) uint8() (uint8, error) { 17 | c, err := d.readCode() 18 | if err != nil { 19 | return 0, err 20 | } 21 | return uint8(c), nil 22 | } 23 | 24 | func (d *Decoder) int8() (int8, error) { 25 | n, err := d.uint8() 26 | return int8(n), err 27 | } 28 | 29 | func (d *Decoder) uint16() (uint16, error) { 30 | b, err := d.readN(2) 31 | if err != nil { 32 | return 0, err 33 | } 34 | return (uint16(b[0]) << 8) | uint16(b[1]), nil 35 | } 36 | 37 | func (d *Decoder) int16() (int16, error) { 38 | n, err := d.uint16() 39 | return int16(n), err 40 | } 41 | 42 | func (d *Decoder) uint32() (uint32, error) { 43 | b, err := d.readN(4) 44 | if err != nil { 45 | return 0, err 46 | } 47 | n := (uint32(b[0]) << 24) | 48 | (uint32(b[1]) << 16) | 49 | (uint32(b[2]) << 8) | 50 | uint32(b[3]) 51 | return n, nil 52 | } 53 | 54 | func (d *Decoder) int32() (int32, error) { 55 | n, err := d.uint32() 56 | return int32(n), err 57 | } 58 | 59 | func (d *Decoder) uint64() (uint64, error) { 60 | b, err := d.readN(8) 61 | if err != nil { 62 | return 0, err 63 | } 64 | n := (uint64(b[0]) << 56) | 65 | (uint64(b[1]) << 48) | 66 | (uint64(b[2]) << 40) | 67 | (uint64(b[3]) << 32) | 68 | (uint64(b[4]) << 24) | 69 | (uint64(b[5]) << 16) | 70 | (uint64(b[6]) << 8) | 71 | uint64(b[7]) 72 | return n, nil 73 | } 74 | 75 | func (d *Decoder) int64() (int64, error) { 76 | n, err := d.uint64() 77 | return int64(n), err 78 | } 79 | 80 | func (d *Decoder) DecodeUint64() (uint64, error) { 81 | c, err := d.readCode() 82 | if err != nil { 83 | return 0, err 84 | } 85 | return d.uint(c) 86 | } 87 | 88 | func (d *Decoder) uint(c codes.Code) (uint64, error) { 89 | if c == codes.Nil { 90 | return 0, nil 91 | } 92 | if codes.IsFixedNum(c) { 93 | return uint64(int8(c)), nil 94 | } 95 | switch c { 96 | case codes.Uint8: 97 | n, err := d.uint8() 98 | return uint64(n), err 99 | case codes.Int8: 100 | n, err := d.int8() 101 | return uint64(n), err 102 | case codes.Uint16: 103 | n, err := d.uint16() 104 | return uint64(n), err 105 | case codes.Int16: 106 | n, err := d.int16() 107 | return uint64(n), err 108 | case codes.Uint32: 109 | n, err := d.uint32() 110 | return uint64(n), err 111 | case codes.Int32: 112 | n, err := d.int32() 113 | return uint64(n), err 114 | case codes.Uint64, codes.Int64: 115 | return d.uint64() 116 | } 117 | return 0, fmt.Errorf("msgpack: invalid code=%x decoding uint64", c) 118 | } 119 | 120 | func (d *Decoder) DecodeInt64() (int64, error) { 121 | c, err := d.readCode() 122 | if err != nil { 123 | return 0, err 124 | } 125 | return d.int(c) 126 | } 127 | 128 | func (d *Decoder) int(c codes.Code) (int64, error) { 129 | if c == codes.Nil { 130 | return 0, nil 131 | } 132 | if codes.IsFixedNum(c) { 133 | return int64(int8(c)), nil 134 | } 135 | switch c { 136 | case codes.Uint8: 137 | n, err := d.uint8() 138 | return int64(n), err 139 | case codes.Int8: 140 | n, err := d.uint8() 141 | return int64(int8(n)), err 142 | case codes.Uint16: 143 | n, err := d.uint16() 144 | return int64(n), err 145 | case codes.Int16: 146 | n, err := d.uint16() 147 | return int64(int16(n)), err 148 | case codes.Uint32: 149 | n, err := d.uint32() 150 | return int64(n), err 151 | case codes.Int32: 152 | n, err := d.uint32() 153 | return int64(int32(n)), err 154 | case codes.Uint64, codes.Int64: 155 | n, err := d.uint64() 156 | return int64(n), err 157 | } 158 | return 0, fmt.Errorf("msgpack: invalid code=%x decoding int64", c) 159 | } 160 | 161 | func (d *Decoder) DecodeFloat32() (float32, error) { 162 | c, err := d.readCode() 163 | if err != nil { 164 | return 0, err 165 | } 166 | return d.float32(c) 167 | } 168 | 169 | func (d *Decoder) float32(c codes.Code) (float32, error) { 170 | if c == codes.Float { 171 | n, err := d.uint32() 172 | if err != nil { 173 | return 0, err 174 | } 175 | return math.Float32frombits(n), nil 176 | } 177 | 178 | n, err := d.int(c) 179 | if err != nil { 180 | return 0, fmt.Errorf("msgpack: invalid code=%x decoding float32", c) 181 | } 182 | return float32(n), nil 183 | } 184 | 185 | func (d *Decoder) DecodeFloat64() (float64, error) { 186 | c, err := d.readCode() 187 | if err != nil { 188 | return 0, err 189 | } 190 | return d.float64(c) 191 | } 192 | 193 | func (d *Decoder) float64(c codes.Code) (float64, error) { 194 | switch c { 195 | case codes.Float: 196 | n, err := d.float32(c) 197 | if err != nil { 198 | return 0, err 199 | } 200 | return float64(n), nil 201 | case codes.Double: 202 | n, err := d.uint64() 203 | if err != nil { 204 | return 0, err 205 | } 206 | return math.Float64frombits(n), nil 207 | } 208 | 209 | n, err := d.int(c) 210 | if err != nil { 211 | return 0, fmt.Errorf("msgpack: invalid code=%x decoding float32", c) 212 | } 213 | return float64(n), nil 214 | } 215 | 216 | func (d *Decoder) DecodeUint() (uint, error) { 217 | n, err := d.DecodeUint64() 218 | return uint(n), err 219 | } 220 | 221 | func (d *Decoder) DecodeUint8() (uint8, error) { 222 | n, err := d.DecodeUint64() 223 | return uint8(n), err 224 | } 225 | 226 | func (d *Decoder) DecodeUint16() (uint16, error) { 227 | n, err := d.DecodeUint64() 228 | return uint16(n), err 229 | } 230 | 231 | func (d *Decoder) DecodeUint32() (uint32, error) { 232 | n, err := d.DecodeUint64() 233 | return uint32(n), err 234 | } 235 | 236 | func (d *Decoder) DecodeInt() (int, error) { 237 | n, err := d.DecodeInt64() 238 | return int(n), err 239 | } 240 | 241 | func (d *Decoder) DecodeInt8() (int8, error) { 242 | n, err := d.DecodeInt64() 243 | return int8(n), err 244 | } 245 | 246 | func (d *Decoder) DecodeInt16() (int16, error) { 247 | n, err := d.DecodeInt64() 248 | return int16(n), err 249 | } 250 | 251 | func (d *Decoder) DecodeInt32() (int32, error) { 252 | n, err := d.DecodeInt64() 253 | return int32(n), err 254 | } 255 | 256 | func decodeFloat32Value(d *Decoder, v reflect.Value) error { 257 | f, err := d.DecodeFloat32() 258 | if err != nil { 259 | return err 260 | } 261 | v.SetFloat(float64(f)) 262 | return nil 263 | } 264 | 265 | func decodeFloat64Value(d *Decoder, v reflect.Value) error { 266 | f, err := d.DecodeFloat64() 267 | if err != nil { 268 | return err 269 | } 270 | v.SetFloat(f) 271 | return nil 272 | } 273 | 274 | func decodeInt64Value(d *Decoder, v reflect.Value) error { 275 | n, err := d.DecodeInt64() 276 | if err != nil { 277 | return err 278 | } 279 | v.SetInt(n) 280 | return nil 281 | } 282 | 283 | func decodeUint64Value(d *Decoder, v reflect.Value) error { 284 | n, err := d.DecodeUint64() 285 | if err != nil { 286 | return err 287 | } 288 | v.SetUint(n) 289 | return nil 290 | } 291 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/decode_query.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | 8 | "github.com/vmihailenco/msgpack/codes" 9 | ) 10 | 11 | type queryResult struct { 12 | query string 13 | key string 14 | hasAsterisk bool 15 | 16 | values []interface{} 17 | } 18 | 19 | func (q *queryResult) nextKey() { 20 | ind := strings.IndexByte(q.query, '.') 21 | if ind == -1 { 22 | q.key = q.query 23 | q.query = "" 24 | return 25 | } 26 | q.key = q.query[:ind] 27 | q.query = q.query[ind+1:] 28 | } 29 | 30 | // Query extracts data specified by the query from the msgpack stream skipping 31 | // any other data. Query consists of map keys and array indexes separated with dot, 32 | // e.g. key1.0.key2. 33 | func (d *Decoder) Query(query string) ([]interface{}, error) { 34 | res := queryResult{ 35 | query: query, 36 | } 37 | if err := d.query(&res); err != nil { 38 | return nil, err 39 | } 40 | return res.values, nil 41 | } 42 | 43 | func (d *Decoder) query(q *queryResult) error { 44 | q.nextKey() 45 | if q.key == "" { 46 | v, err := d.DecodeInterface() 47 | if err != nil { 48 | return err 49 | } 50 | q.values = append(q.values, v) 51 | return nil 52 | } 53 | 54 | code, err := d.PeekCode() 55 | if err != nil { 56 | return err 57 | } 58 | 59 | switch { 60 | case code == codes.Map16 || code == codes.Map32 || codes.IsFixedMap(code): 61 | err = d.queryMapKey(q) 62 | case code == codes.Array16 || code == codes.Array32 || codes.IsFixedArray(code): 63 | err = d.queryArrayIndex(q) 64 | default: 65 | err = fmt.Errorf("msgpack: unsupported code=%x decoding key=%q", code, q.key) 66 | } 67 | return err 68 | } 69 | 70 | func (d *Decoder) queryMapKey(q *queryResult) error { 71 | n, err := d.DecodeMapLen() 72 | if err != nil { 73 | return err 74 | } 75 | if n == -1 { 76 | return nil 77 | } 78 | 79 | for i := 0; i < n; i++ { 80 | k, err := d.bytesNoCopy() 81 | if err != nil { 82 | return err 83 | } 84 | 85 | if string(k) == q.key { 86 | if err := d.query(q); err != nil { 87 | return err 88 | } 89 | if q.hasAsterisk { 90 | return d.skipNext((n - i - 1) * 2) 91 | } 92 | return nil 93 | } 94 | 95 | if err := d.Skip(); err != nil { 96 | return err 97 | } 98 | } 99 | 100 | return nil 101 | } 102 | 103 | func (d *Decoder) queryArrayIndex(q *queryResult) error { 104 | n, err := d.DecodeArrayLen() 105 | if err != nil { 106 | return err 107 | } 108 | if n == -1 { 109 | return nil 110 | } 111 | 112 | if q.key == "*" { 113 | q.hasAsterisk = true 114 | 115 | query := q.query 116 | for i := 0; i < n; i++ { 117 | q.query = query 118 | if err := d.query(q); err != nil { 119 | return err 120 | } 121 | } 122 | 123 | q.hasAsterisk = false 124 | return nil 125 | } 126 | 127 | ind, err := strconv.Atoi(q.key) 128 | if err != nil { 129 | return err 130 | } 131 | 132 | for i := 0; i < n; i++ { 133 | if i == ind { 134 | if err := d.query(q); err != nil { 135 | return err 136 | } 137 | if q.hasAsterisk { 138 | return d.skipNext(n - i - 1) 139 | } 140 | return nil 141 | } 142 | 143 | if err := d.Skip(); err != nil { 144 | return err 145 | } 146 | } 147 | 148 | return nil 149 | } 150 | 151 | func (d *Decoder) skipNext(n int) error { 152 | for i := 0; i < n; i++ { 153 | if err := d.Skip(); err != nil { 154 | return err 155 | } 156 | } 157 | return nil 158 | } 159 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/decode_slice.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | 7 | "github.com/vmihailenco/msgpack/codes" 8 | ) 9 | 10 | const sliceElemsAllocLimit = 1e4 11 | 12 | var sliceStringPtrType = reflect.TypeOf((*[]string)(nil)) 13 | 14 | func (d *Decoder) DecodeArrayLen() (int, error) { 15 | c, err := d.readCode() 16 | if err != nil { 17 | return 0, err 18 | } 19 | return d.arrayLen(c) 20 | } 21 | 22 | func (d *Decoder) arrayLen(c codes.Code) (int, error) { 23 | if c == codes.Nil { 24 | return -1, nil 25 | } else if c >= codes.FixedArrayLow && c <= codes.FixedArrayHigh { 26 | return int(c & codes.FixedArrayMask), nil 27 | } 28 | switch c { 29 | case codes.Array16: 30 | n, err := d.uint16() 31 | return int(n), err 32 | case codes.Array32: 33 | n, err := d.uint32() 34 | return int(n), err 35 | } 36 | return 0, fmt.Errorf("msgpack: invalid code=%x decoding array length", c) 37 | } 38 | 39 | func decodeStringSliceValue(d *Decoder, v reflect.Value) error { 40 | ptr := v.Addr().Convert(sliceStringPtrType).Interface().(*[]string) 41 | return d.decodeStringSlicePtr(ptr) 42 | } 43 | 44 | func (d *Decoder) decodeStringSlicePtr(ptr *[]string) error { 45 | n, err := d.DecodeArrayLen() 46 | if err != nil { 47 | return err 48 | } 49 | if n == -1 { 50 | return nil 51 | } 52 | 53 | ss := setStringsCap(*ptr, n) 54 | for i := 0; i < n; i++ { 55 | s, err := d.DecodeString() 56 | if err != nil { 57 | return err 58 | } 59 | ss = append(ss, s) 60 | } 61 | *ptr = ss 62 | 63 | return nil 64 | } 65 | 66 | func setStringsCap(s []string, n int) []string { 67 | if n > sliceElemsAllocLimit { 68 | n = sliceElemsAllocLimit 69 | } 70 | 71 | if s == nil { 72 | return make([]string, 0, n) 73 | } 74 | 75 | if cap(s) >= n { 76 | return s[:0] 77 | } 78 | 79 | s = s[:cap(s)] 80 | s = append(s, make([]string, n-len(s))...) 81 | return s[:0] 82 | } 83 | 84 | func decodeSliceValue(d *Decoder, v reflect.Value) error { 85 | n, err := d.DecodeArrayLen() 86 | if err != nil { 87 | return err 88 | } 89 | 90 | if n == -1 { 91 | v.Set(reflect.Zero(v.Type())) 92 | return nil 93 | } 94 | if n == 0 && v.IsNil() { 95 | v.Set(reflect.MakeSlice(v.Type(), 0, 0)) 96 | return nil 97 | } 98 | 99 | if v.Cap() >= n { 100 | v.Set(v.Slice(0, n)) 101 | } else if v.Len() < v.Cap() { 102 | v.Set(v.Slice(0, v.Cap())) 103 | } 104 | 105 | for i := 0; i < n; i++ { 106 | if i >= v.Len() { 107 | v.Set(growSliceValue(v, n)) 108 | } 109 | sv := v.Index(i) 110 | if err := d.DecodeValue(sv); err != nil { 111 | return err 112 | } 113 | } 114 | 115 | return nil 116 | } 117 | 118 | func growSliceValue(v reflect.Value, n int) reflect.Value { 119 | diff := n - v.Len() 120 | if diff > sliceElemsAllocLimit { 121 | diff = sliceElemsAllocLimit 122 | } 123 | v = reflect.AppendSlice(v, reflect.MakeSlice(v.Type(), diff, diff)) 124 | return v 125 | } 126 | 127 | func decodeArrayValue(d *Decoder, v reflect.Value) error { 128 | n, err := d.DecodeArrayLen() 129 | if err != nil { 130 | return err 131 | } 132 | 133 | if n == -1 { 134 | return nil 135 | } 136 | 137 | if n > v.Len() { 138 | return fmt.Errorf("%s len is %d, but msgpack has %d elements", v.Type(), v.Len(), n) 139 | } 140 | for i := 0; i < n; i++ { 141 | sv := v.Index(i) 142 | if err := d.DecodeValue(sv); err != nil { 143 | return err 144 | } 145 | } 146 | 147 | return nil 148 | } 149 | 150 | func (d *Decoder) DecodeSlice() ([]interface{}, error) { 151 | c, err := d.readCode() 152 | if err != nil { 153 | return nil, err 154 | } 155 | return d.decodeSlice(c) 156 | } 157 | 158 | func (d *Decoder) decodeSlice(c codes.Code) ([]interface{}, error) { 159 | n, err := d.arrayLen(c) 160 | if err != nil { 161 | return nil, err 162 | } 163 | if n == -1 { 164 | return nil, nil 165 | } 166 | 167 | s := make([]interface{}, 0, min(n, sliceElemsAllocLimit)) 168 | for i := 0; i < n; i++ { 169 | v, err := d.DecodeInterface() 170 | if err != nil { 171 | return nil, err 172 | } 173 | s = append(s, v) 174 | } 175 | 176 | return s, nil 177 | } 178 | 179 | func (d *Decoder) skipSlice(c codes.Code) error { 180 | n, err := d.arrayLen(c) 181 | if err != nil { 182 | return err 183 | } 184 | 185 | for i := 0; i < n; i++ { 186 | if err := d.Skip(); err != nil { 187 | return err 188 | } 189 | } 190 | 191 | return nil 192 | } 193 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/decode_string.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | 7 | "github.com/vmihailenco/msgpack/codes" 8 | ) 9 | 10 | func (d *Decoder) bytesLen(c codes.Code) (int, error) { 11 | if c == codes.Nil { 12 | return -1, nil 13 | } else if codes.IsFixedString(c) { 14 | return int(c & codes.FixedStrMask), nil 15 | } 16 | switch c { 17 | case codes.Str8, codes.Bin8: 18 | n, err := d.uint8() 19 | return int(n), err 20 | case codes.Str16, codes.Bin16: 21 | n, err := d.uint16() 22 | return int(n), err 23 | case codes.Str32, codes.Bin32: 24 | n, err := d.uint32() 25 | return int(n), err 26 | } 27 | return 0, fmt.Errorf("msgpack: invalid code=%x decoding bytes length", c) 28 | } 29 | 30 | func (d *Decoder) DecodeString() (string, error) { 31 | c, err := d.readCode() 32 | if err != nil { 33 | return "", err 34 | } 35 | return d.string(c) 36 | } 37 | 38 | func (d *Decoder) string(c codes.Code) (string, error) { 39 | n, err := d.bytesLen(c) 40 | if err != nil { 41 | return "", err 42 | } 43 | if n == -1 { 44 | return "", nil 45 | } 46 | b, err := d.readN(n) 47 | return string(b), err 48 | } 49 | 50 | func decodeStringValue(d *Decoder, v reflect.Value) error { 51 | s, err := d.DecodeString() 52 | if err != nil { 53 | return err 54 | } 55 | v.SetString(s) 56 | return nil 57 | } 58 | 59 | func (d *Decoder) DecodeBytesLen() (int, error) { 60 | c, err := d.readCode() 61 | if err != nil { 62 | return 0, err 63 | } 64 | return d.bytesLen(c) 65 | } 66 | 67 | func (d *Decoder) DecodeBytes() ([]byte, error) { 68 | c, err := d.readCode() 69 | if err != nil { 70 | return nil, err 71 | } 72 | return d.bytes(c, nil) 73 | } 74 | 75 | func (d *Decoder) bytes(c codes.Code, b []byte) ([]byte, error) { 76 | n, err := d.bytesLen(c) 77 | if err != nil { 78 | return nil, err 79 | } 80 | if n == -1 { 81 | return nil, nil 82 | } 83 | return readN(d.r, b, n) 84 | } 85 | 86 | func (d *Decoder) bytesNoCopy() ([]byte, error) { 87 | c, err := d.readCode() 88 | if err != nil { 89 | return nil, err 90 | } 91 | n, err := d.bytesLen(c) 92 | if err != nil { 93 | return nil, err 94 | } 95 | if n == -1 { 96 | return nil, nil 97 | } 98 | return d.readN(n) 99 | } 100 | 101 | func (d *Decoder) decodeBytesPtr(ptr *[]byte) error { 102 | c, err := d.readCode() 103 | if err != nil { 104 | return err 105 | } 106 | return d.bytesPtr(c, ptr) 107 | } 108 | 109 | func (d *Decoder) bytesPtr(c codes.Code, ptr *[]byte) error { 110 | n, err := d.bytesLen(c) 111 | if err != nil { 112 | return err 113 | } 114 | if n == -1 { 115 | *ptr = nil 116 | return nil 117 | } 118 | 119 | *ptr, err = readN(d.r, *ptr, n) 120 | return err 121 | } 122 | 123 | func (d *Decoder) skipBytes(c codes.Code) error { 124 | n, err := d.bytesLen(c) 125 | if err != nil { 126 | return err 127 | } 128 | if n == -1 { 129 | return nil 130 | } 131 | return d.skipN(n) 132 | } 133 | 134 | func decodeBytesValue(d *Decoder, v reflect.Value) error { 135 | c, err := d.readCode() 136 | if err != nil { 137 | return err 138 | } 139 | 140 | b, err := d.bytes(c, v.Bytes()) 141 | if err != nil { 142 | return err 143 | } 144 | v.SetBytes(b) 145 | 146 | return nil 147 | } 148 | 149 | func decodeByteArrayValue(d *Decoder, v reflect.Value) error { 150 | c, err := d.readCode() 151 | if err != nil { 152 | return err 153 | } 154 | 155 | n, err := d.bytesLen(c) 156 | if err != nil { 157 | return err 158 | } 159 | if n == -1 { 160 | return nil 161 | } 162 | if n > v.Len() { 163 | return fmt.Errorf("%s len is %d, but msgpack has %d elements", v.Type(), v.Len(), n) 164 | } 165 | 166 | b := v.Slice(0, n).Bytes() 167 | return d.readFull(b) 168 | } 169 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/decode_value.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | 7 | "github.com/vmihailenco/msgpack/codes" 8 | ) 9 | 10 | var interfaceType = reflect.TypeOf((*interface{})(nil)).Elem() 11 | var stringType = reflect.TypeOf((*string)(nil)).Elem() 12 | 13 | var valueDecoders []decoderFunc 14 | 15 | func init() { 16 | valueDecoders = []decoderFunc{ 17 | reflect.Bool: decodeBoolValue, 18 | reflect.Int: decodeInt64Value, 19 | reflect.Int8: decodeInt64Value, 20 | reflect.Int16: decodeInt64Value, 21 | reflect.Int32: decodeInt64Value, 22 | reflect.Int64: decodeInt64Value, 23 | reflect.Uint: decodeUint64Value, 24 | reflect.Uint8: decodeUint64Value, 25 | reflect.Uint16: decodeUint64Value, 26 | reflect.Uint32: decodeUint64Value, 27 | reflect.Uint64: decodeUint64Value, 28 | reflect.Float32: decodeFloat32Value, 29 | reflect.Float64: decodeFloat64Value, 30 | reflect.Complex64: decodeUnsupportedValue, 31 | reflect.Complex128: decodeUnsupportedValue, 32 | reflect.Array: decodeArrayValue, 33 | reflect.Chan: decodeUnsupportedValue, 34 | reflect.Func: decodeUnsupportedValue, 35 | reflect.Interface: decodeInterfaceValue, 36 | reflect.Map: decodeMapValue, 37 | reflect.Ptr: decodeUnsupportedValue, 38 | reflect.Slice: decodeSliceValue, 39 | reflect.String: decodeStringValue, 40 | reflect.Struct: decodeStructValue, 41 | reflect.UnsafePointer: decodeUnsupportedValue, 42 | } 43 | } 44 | 45 | func getDecoder(typ reflect.Type) decoderFunc { 46 | kind := typ.Kind() 47 | 48 | if decoder, ok := typDecMap[typ]; ok { 49 | return decoder 50 | } 51 | 52 | if typ.Implements(customDecoderType) { 53 | return decodeCustomValue 54 | } 55 | if typ.Implements(unmarshalerType) { 56 | return unmarshalValue 57 | } 58 | 59 | // Addressable struct field value. 60 | if kind != reflect.Ptr { 61 | ptr := reflect.PtrTo(typ) 62 | if ptr.Implements(customDecoderType) { 63 | return decodeCustomValueAddr 64 | } 65 | if ptr.Implements(unmarshalerType) { 66 | return unmarshalValueAddr 67 | } 68 | } 69 | 70 | switch kind { 71 | case reflect.Ptr: 72 | return ptrDecoderFunc(typ) 73 | case reflect.Slice: 74 | elem := typ.Elem() 75 | switch elem.Kind() { 76 | case reflect.Uint8: 77 | return decodeBytesValue 78 | } 79 | switch elem { 80 | case stringType: 81 | return decodeStringSliceValue 82 | } 83 | case reflect.Array: 84 | if typ.Elem().Kind() == reflect.Uint8 { 85 | return decodeByteArrayValue 86 | } 87 | case reflect.Map: 88 | if typ.Key() == stringType { 89 | switch typ.Elem() { 90 | case stringType: 91 | return decodeMapStringStringValue 92 | case interfaceType: 93 | return decodeMapStringInterfaceValue 94 | } 95 | } 96 | } 97 | return valueDecoders[kind] 98 | } 99 | 100 | func ptrDecoderFunc(typ reflect.Type) decoderFunc { 101 | decoder := getDecoder(typ.Elem()) 102 | return func(d *Decoder, v reflect.Value) error { 103 | if d.hasNilCode() { 104 | v.Set(reflect.Zero(v.Type())) 105 | return d.DecodeNil() 106 | } 107 | if v.IsNil() { 108 | if !v.CanSet() { 109 | return fmt.Errorf("msgpack: Decode(nonsettable %T)", v.Interface()) 110 | } 111 | v.Set(reflect.New(v.Type().Elem())) 112 | } 113 | return decoder(d, v.Elem()) 114 | } 115 | } 116 | 117 | func decodeCustomValueAddr(d *Decoder, v reflect.Value) error { 118 | if !v.CanAddr() { 119 | return fmt.Errorf("msgpack: Decode(nonsettable %T)", v.Interface()) 120 | } 121 | return decodeCustomValue(d, v.Addr()) 122 | } 123 | 124 | func decodeCustomValue(d *Decoder, v reflect.Value) error { 125 | c, err := d.PeekCode() 126 | if err != nil { 127 | return err 128 | } 129 | 130 | if codes.IsExt(c) { 131 | c, err = d.readCode() 132 | if err != nil { 133 | return err 134 | } 135 | 136 | _, err = d.parseExtLen(c) 137 | if err != nil { 138 | return err 139 | } 140 | 141 | _, err = d.readCode() 142 | if err != nil { 143 | return err 144 | } 145 | 146 | c, err = d.PeekCode() 147 | if err != nil { 148 | return err 149 | } 150 | } 151 | 152 | if c == codes.Nil { 153 | return d.decodeNilValue(v) 154 | } 155 | 156 | if v.IsNil() { 157 | v.Set(reflect.New(v.Type().Elem())) 158 | } 159 | 160 | decoder := v.Interface().(CustomDecoder) 161 | return decoder.DecodeMsgpack(d) 162 | } 163 | 164 | func unmarshalValueAddr(d *Decoder, v reflect.Value) error { 165 | if !v.CanAddr() { 166 | return fmt.Errorf("msgpack: Decode(nonsettable %T)", v.Interface()) 167 | } 168 | return unmarshalValue(d, v.Addr()) 169 | } 170 | 171 | func unmarshalValue(d *Decoder, v reflect.Value) error { 172 | c, err := d.PeekCode() 173 | if err != nil { 174 | return err 175 | } 176 | 177 | if codes.IsExt(c) { 178 | c, err = d.readCode() 179 | if err != nil { 180 | return err 181 | } 182 | 183 | extLen, err := d.parseExtLen(c) 184 | if err != nil { 185 | return err 186 | } 187 | d.extLen = extLen 188 | 189 | _, err = d.readCode() 190 | if err != nil { 191 | return err 192 | } 193 | 194 | c, err = d.PeekCode() 195 | if err != nil { 196 | return err 197 | } 198 | } 199 | 200 | if c == codes.Nil { 201 | return d.decodeNilValue(v) 202 | } 203 | 204 | if v.IsNil() { 205 | v.Set(reflect.New(v.Type().Elem())) 206 | } 207 | 208 | if d.extLen != 0 { 209 | b, err := d.readN(d.extLen) 210 | d.extLen = 0 211 | if err != nil { 212 | return err 213 | } 214 | d.rec = b 215 | } else { 216 | d.rec = makeBuffer() 217 | if err := d.Skip(); err != nil { 218 | return err 219 | } 220 | } 221 | 222 | unmarshaler := v.Interface().(Unmarshaler) 223 | err = unmarshaler.UnmarshalMsgpack(d.rec) 224 | d.rec = nil 225 | return err 226 | } 227 | 228 | func decodeBoolValue(d *Decoder, v reflect.Value) error { 229 | flag, err := d.DecodeBool() 230 | if err != nil { 231 | return err 232 | } 233 | v.SetBool(flag) 234 | return nil 235 | } 236 | 237 | func decodeInterfaceValue(d *Decoder, v reflect.Value) error { 238 | if v.IsNil() { 239 | return d.interfaceValue(v) 240 | } 241 | return d.DecodeValue(v.Elem()) 242 | } 243 | 244 | func decodeUnsupportedValue(d *Decoder, v reflect.Value) error { 245 | return fmt.Errorf("msgpack: Decode(unsupported %s)", v.Type()) 246 | } 247 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/encode.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "reflect" 7 | "time" 8 | 9 | "github.com/vmihailenco/msgpack/codes" 10 | ) 11 | 12 | type writer interface { 13 | io.Writer 14 | WriteByte(byte) error 15 | WriteString(string) (int, error) 16 | } 17 | 18 | type byteWriter struct { 19 | io.Writer 20 | } 21 | 22 | func (w byteWriter) WriteByte(b byte) error { 23 | _, err := w.Write([]byte{b}) 24 | return err 25 | } 26 | 27 | func (w byteWriter) WriteString(s string) (int, error) { 28 | return w.Write([]byte(s)) 29 | } 30 | 31 | // Marshal returns the MessagePack encoding of v. 32 | func Marshal(v ...interface{}) ([]byte, error) { 33 | var buf bytes.Buffer 34 | err := NewEncoder(&buf).Encode(v...) 35 | return buf.Bytes(), err 36 | } 37 | 38 | type Encoder struct { 39 | w writer 40 | buf []byte 41 | 42 | sortMapKeys bool 43 | structAsArray bool 44 | } 45 | 46 | func NewEncoder(w io.Writer) *Encoder { 47 | bw, ok := w.(writer) 48 | if !ok { 49 | bw = byteWriter{Writer: w} 50 | } 51 | return &Encoder{ 52 | w: bw, 53 | buf: make([]byte, 9), 54 | } 55 | } 56 | 57 | // SortMapKeys causes the Encoder to encode map keys in increasing order. 58 | // Supported map types are: 59 | // - map[string]string 60 | // - map[string]interface{} 61 | func (e *Encoder) SortMapKeys(v bool) *Encoder { 62 | e.sortMapKeys = v 63 | return e 64 | } 65 | 66 | // StructAsArray causes the Encoder to encode Go structs as MessagePack arrays. 67 | func (e *Encoder) StructAsArray(v bool) *Encoder { 68 | e.structAsArray = v 69 | return e 70 | } 71 | 72 | func (e *Encoder) Encode(v ...interface{}) error { 73 | for _, vv := range v { 74 | if err := e.encode(vv); err != nil { 75 | return err 76 | } 77 | } 78 | return nil 79 | } 80 | 81 | func (e *Encoder) encode(v interface{}) error { 82 | switch v := v.(type) { 83 | case nil: 84 | return e.EncodeNil() 85 | case string: 86 | return e.EncodeString(v) 87 | case []byte: 88 | return e.EncodeBytes(v) 89 | case int: 90 | return e.EncodeInt(int64(v)) 91 | case int64: 92 | return e.EncodeInt(v) 93 | case uint: 94 | return e.EncodeUint(uint64(v)) 95 | case uint64: 96 | return e.EncodeUint(v) 97 | case bool: 98 | return e.EncodeBool(v) 99 | case float32: 100 | return e.EncodeFloat32(v) 101 | case float64: 102 | return e.EncodeFloat64(v) 103 | case time.Duration: 104 | return e.EncodeInt(int64(v)) 105 | case time.Time: 106 | return e.EncodeTime(v) 107 | } 108 | return e.EncodeValue(reflect.ValueOf(v)) 109 | } 110 | 111 | func (e *Encoder) EncodeValue(v reflect.Value) error { 112 | encode := getEncoder(v.Type()) 113 | return encode(e, v) 114 | } 115 | 116 | func (e *Encoder) EncodeNil() error { 117 | return e.writeCode(codes.Nil) 118 | } 119 | 120 | func (e *Encoder) EncodeBool(value bool) error { 121 | if value { 122 | return e.writeCode(codes.True) 123 | } 124 | return e.writeCode(codes.False) 125 | } 126 | 127 | func (e *Encoder) writeCode(c codes.Code) error { 128 | return e.w.WriteByte(byte(c)) 129 | } 130 | 131 | func (e *Encoder) write(b []byte) error { 132 | _, err := e.w.Write(b) 133 | return err 134 | } 135 | 136 | func (e *Encoder) writeString(s string) error { 137 | _, err := e.w.WriteString(s) 138 | return err 139 | } 140 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/encode_map.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "reflect" 5 | "sort" 6 | 7 | "github.com/vmihailenco/msgpack/codes" 8 | ) 9 | 10 | func encodeMapValue(e *Encoder, v reflect.Value) error { 11 | if v.IsNil() { 12 | return e.EncodeNil() 13 | } 14 | 15 | if err := e.EncodeMapLen(v.Len()); err != nil { 16 | return err 17 | } 18 | 19 | for _, key := range v.MapKeys() { 20 | if err := e.EncodeValue(key); err != nil { 21 | return err 22 | } 23 | if err := e.EncodeValue(v.MapIndex(key)); err != nil { 24 | return err 25 | } 26 | } 27 | 28 | return nil 29 | } 30 | 31 | func encodeMapStringStringValue(e *Encoder, v reflect.Value) error { 32 | if v.IsNil() { 33 | return e.EncodeNil() 34 | } 35 | 36 | if err := e.EncodeMapLen(v.Len()); err != nil { 37 | return err 38 | } 39 | 40 | m := v.Convert(mapStringStringType).Interface().(map[string]string) 41 | if e.sortMapKeys { 42 | return e.encodeSortedMapStringString(m) 43 | } 44 | 45 | for mk, mv := range m { 46 | if err := e.EncodeString(mk); err != nil { 47 | return err 48 | } 49 | if err := e.EncodeString(mv); err != nil { 50 | return err 51 | } 52 | } 53 | 54 | return nil 55 | } 56 | 57 | func encodeMapStringInterfaceValue(e *Encoder, v reflect.Value) error { 58 | if v.IsNil() { 59 | return e.EncodeNil() 60 | } 61 | 62 | if err := e.EncodeMapLen(v.Len()); err != nil { 63 | return err 64 | } 65 | 66 | m := v.Convert(mapStringInterfaceType).Interface().(map[string]interface{}) 67 | if e.sortMapKeys { 68 | return e.encodeSortedMapStringInterface(m) 69 | } 70 | 71 | for mk, mv := range m { 72 | if err := e.EncodeString(mk); err != nil { 73 | return err 74 | } 75 | if err := e.Encode(mv); err != nil { 76 | return err 77 | } 78 | } 79 | 80 | return nil 81 | } 82 | 83 | func (e *Encoder) encodeSortedMapStringString(m map[string]string) error { 84 | keys := make([]string, 0, len(m)) 85 | for k, _ := range m { 86 | keys = append(keys, k) 87 | } 88 | sort.Strings(keys) 89 | 90 | for _, k := range keys { 91 | err := e.EncodeString(k) 92 | if err != nil { 93 | return err 94 | } 95 | if err = e.EncodeString(m[k]); err != nil { 96 | return err 97 | } 98 | } 99 | 100 | return nil 101 | } 102 | 103 | func (e *Encoder) encodeSortedMapStringInterface(m map[string]interface{}) error { 104 | keys := make([]string, 0, len(m)) 105 | for k, _ := range m { 106 | keys = append(keys, k) 107 | } 108 | sort.Strings(keys) 109 | 110 | for _, k := range keys { 111 | err := e.EncodeString(k) 112 | if err != nil { 113 | return err 114 | } 115 | if err = e.Encode(m[k]); err != nil { 116 | return err 117 | } 118 | } 119 | 120 | return nil 121 | } 122 | 123 | func (e *Encoder) EncodeMapLen(l int) error { 124 | if l < 16 { 125 | return e.writeCode(codes.FixedMapLow | codes.Code(l)) 126 | } 127 | if l < 65536 { 128 | return e.write2(codes.Map16, uint64(l)) 129 | } 130 | return e.write4(codes.Map32, uint32(l)) 131 | } 132 | 133 | func encodeStructValue(e *Encoder, strct reflect.Value) error { 134 | structFields := structs.Fields(strct.Type()) 135 | if e.structAsArray || structFields.asArray { 136 | return encodeStructValueAsArray(e, strct, structFields.List) 137 | } 138 | fields := structFields.OmitEmpty(strct) 139 | 140 | if err := e.EncodeMapLen(len(fields)); err != nil { 141 | return err 142 | } 143 | 144 | for _, f := range fields { 145 | if err := e.EncodeString(f.name); err != nil { 146 | return err 147 | } 148 | if err := f.EncodeValue(e, strct); err != nil { 149 | return err 150 | } 151 | } 152 | 153 | return nil 154 | } 155 | 156 | func encodeStructValueAsArray(e *Encoder, strct reflect.Value, fields []*field) error { 157 | if err := e.EncodeArrayLen(len(fields)); err != nil { 158 | return err 159 | } 160 | for _, f := range fields { 161 | if err := f.EncodeValue(e, strct); err != nil { 162 | return err 163 | } 164 | } 165 | return nil 166 | } 167 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/encode_number.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "math" 5 | "reflect" 6 | 7 | "github.com/vmihailenco/msgpack/codes" 8 | ) 9 | 10 | // EncodeUint encodes an uint64 in 1, 2, 3, 5, or 9 bytes. 11 | func (e *Encoder) EncodeUint(v uint64) error { 12 | if v <= math.MaxInt8 { 13 | return e.w.WriteByte(byte(v)) 14 | } 15 | if v <= math.MaxUint8 { 16 | return e.write1(codes.Uint8, v) 17 | } 18 | if v <= math.MaxUint16 { 19 | return e.write2(codes.Uint16, v) 20 | } 21 | if v <= math.MaxUint32 { 22 | return e.write4(codes.Uint32, uint32(v)) 23 | } 24 | return e.write8(codes.Uint64, v) 25 | } 26 | 27 | // EncodeInt encodes an int64 in 1, 2, 3, 5, or 9 bytes. 28 | func (e *Encoder) EncodeInt(v int64) error { 29 | if v >= 0 { 30 | return e.EncodeUint(uint64(v)) 31 | } 32 | if v >= int64(int8(codes.NegFixedNumLow)) { 33 | return e.w.WriteByte(byte(v)) 34 | } 35 | if v >= math.MinInt8 { 36 | return e.write1(codes.Int8, uint64(v)) 37 | } 38 | if v >= math.MinInt16 { 39 | return e.write2(codes.Int16, uint64(v)) 40 | } 41 | if v >= math.MinInt32 { 42 | return e.write4(codes.Int32, uint32(v)) 43 | } 44 | return e.write8(codes.Int64, uint64(v)) 45 | } 46 | 47 | func (e *Encoder) EncodeFloat32(n float32) error { 48 | return e.write4(codes.Float, math.Float32bits(n)) 49 | } 50 | 51 | func (e *Encoder) EncodeFloat64(n float64) error { 52 | return e.write8(codes.Double, math.Float64bits(n)) 53 | } 54 | 55 | func (e *Encoder) write1(code codes.Code, n uint64) error { 56 | e.buf = e.buf[:2] 57 | e.buf[0] = byte(code) 58 | e.buf[1] = byte(n) 59 | return e.write(e.buf) 60 | } 61 | 62 | func (e *Encoder) write2(code codes.Code, n uint64) error { 63 | e.buf = e.buf[:3] 64 | e.buf[0] = byte(code) 65 | e.buf[1] = byte(n >> 8) 66 | e.buf[2] = byte(n) 67 | return e.write(e.buf) 68 | } 69 | 70 | func (e *Encoder) write4(code codes.Code, n uint32) error { 71 | e.buf = e.buf[:5] 72 | e.buf[0] = byte(code) 73 | e.buf[1] = byte(n >> 24) 74 | e.buf[2] = byte(n >> 16) 75 | e.buf[3] = byte(n >> 8) 76 | e.buf[4] = byte(n) 77 | return e.write(e.buf) 78 | } 79 | 80 | func (e *Encoder) write8(code codes.Code, n uint64) error { 81 | e.buf = e.buf[:9] 82 | e.buf[0] = byte(code) 83 | e.buf[1] = byte(n >> 56) 84 | e.buf[2] = byte(n >> 48) 85 | e.buf[3] = byte(n >> 40) 86 | e.buf[4] = byte(n >> 32) 87 | e.buf[5] = byte(n >> 24) 88 | e.buf[6] = byte(n >> 16) 89 | e.buf[7] = byte(n >> 8) 90 | e.buf[8] = byte(n) 91 | return e.write(e.buf) 92 | } 93 | 94 | func encodeInt64Value(e *Encoder, v reflect.Value) error { 95 | return e.EncodeInt(v.Int()) 96 | } 97 | 98 | func encodeUint64Value(e *Encoder, v reflect.Value) error { 99 | return e.EncodeUint(v.Uint()) 100 | } 101 | 102 | func encodeFloat32Value(e *Encoder, v reflect.Value) error { 103 | return e.EncodeFloat32(float32(v.Float())) 104 | } 105 | 106 | func encodeFloat64Value(e *Encoder, v reflect.Value) error { 107 | return e.EncodeFloat64(v.Float()) 108 | } 109 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/encode_slice.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/vmihailenco/msgpack/codes" 7 | ) 8 | 9 | func encodeStringValue(e *Encoder, v reflect.Value) error { 10 | return e.EncodeString(v.String()) 11 | } 12 | 13 | func encodeByteSliceValue(e *Encoder, v reflect.Value) error { 14 | return e.EncodeBytes(v.Bytes()) 15 | } 16 | 17 | func encodeByteArrayValue(e *Encoder, v reflect.Value) error { 18 | if err := e.EncodeBytesLen(v.Len()); err != nil { 19 | return err 20 | } 21 | 22 | if v.CanAddr() { 23 | b := v.Slice(0, v.Len()).Bytes() 24 | return e.write(b) 25 | } 26 | 27 | b := make([]byte, v.Len()) 28 | reflect.Copy(reflect.ValueOf(b), v) 29 | return e.write(b) 30 | } 31 | 32 | func (e *Encoder) EncodeBytesLen(l int) error { 33 | if l < 256 { 34 | return e.write1(codes.Bin8, uint64(l)) 35 | } 36 | if l < 65536 { 37 | return e.write2(codes.Bin16, uint64(l)) 38 | } 39 | return e.write4(codes.Bin32, uint32(l)) 40 | } 41 | 42 | func (e *Encoder) encodeStrLen(l int) error { 43 | if l < 32 { 44 | return e.writeCode(codes.FixedStrLow | codes.Code(l)) 45 | } 46 | if l < 256 { 47 | return e.write1(codes.Str8, uint64(l)) 48 | } 49 | if l < 65536 { 50 | return e.write2(codes.Str16, uint64(l)) 51 | } 52 | return e.write4(codes.Str32, uint32(l)) 53 | } 54 | 55 | func (e *Encoder) EncodeString(v string) error { 56 | if err := e.encodeStrLen(len(v)); err != nil { 57 | return err 58 | } 59 | return e.writeString(v) 60 | } 61 | 62 | func (e *Encoder) EncodeBytes(v []byte) error { 63 | if v == nil { 64 | return e.EncodeNil() 65 | } 66 | if err := e.EncodeBytesLen(len(v)); err != nil { 67 | return err 68 | } 69 | return e.write(v) 70 | } 71 | 72 | func (e *Encoder) EncodeArrayLen(l int) error { 73 | if l < 16 { 74 | return e.writeCode(codes.FixedArrayLow | codes.Code(l)) 75 | } 76 | if l < 65536 { 77 | return e.write2(codes.Array16, uint64(l)) 78 | } 79 | return e.write4(codes.Array32, uint32(l)) 80 | } 81 | 82 | func (e *Encoder) encodeStringSlice(s []string) error { 83 | if s == nil { 84 | return e.EncodeNil() 85 | } 86 | if err := e.EncodeArrayLen(len(s)); err != nil { 87 | return err 88 | } 89 | for _, v := range s { 90 | if err := e.EncodeString(v); err != nil { 91 | return err 92 | } 93 | } 94 | return nil 95 | } 96 | 97 | func encodeSliceValue(e *Encoder, v reflect.Value) error { 98 | if v.IsNil() { 99 | return e.EncodeNil() 100 | } 101 | return encodeArrayValue(e, v) 102 | } 103 | 104 | func encodeArrayValue(e *Encoder, v reflect.Value) error { 105 | l := v.Len() 106 | if err := e.EncodeArrayLen(l); err != nil { 107 | return err 108 | } 109 | for i := 0; i < l; i++ { 110 | if err := e.EncodeValue(v.Index(i)); err != nil { 111 | return err 112 | } 113 | } 114 | return nil 115 | } 116 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/encode_value.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | var valueEncoders []encoderFunc 9 | 10 | func init() { 11 | valueEncoders = []encoderFunc{ 12 | reflect.Bool: encodeBoolValue, 13 | reflect.Int: encodeInt64Value, 14 | reflect.Int8: encodeInt64Value, 15 | reflect.Int16: encodeInt64Value, 16 | reflect.Int32: encodeInt64Value, 17 | reflect.Int64: encodeInt64Value, 18 | reflect.Uint: encodeUint64Value, 19 | reflect.Uint8: encodeUint64Value, 20 | reflect.Uint16: encodeUint64Value, 21 | reflect.Uint32: encodeUint64Value, 22 | reflect.Uint64: encodeUint64Value, 23 | reflect.Float32: encodeFloat32Value, 24 | reflect.Float64: encodeFloat64Value, 25 | reflect.Complex64: encodeUnsupportedValue, 26 | reflect.Complex128: encodeUnsupportedValue, 27 | reflect.Array: encodeArrayValue, 28 | reflect.Chan: encodeUnsupportedValue, 29 | reflect.Func: encodeUnsupportedValue, 30 | reflect.Interface: encodeInterfaceValue, 31 | reflect.Map: encodeMapValue, 32 | reflect.Ptr: encodeUnsupportedValue, 33 | reflect.Slice: encodeSliceValue, 34 | reflect.String: encodeStringValue, 35 | reflect.Struct: encodeStructValue, 36 | reflect.UnsafePointer: encodeUnsupportedValue, 37 | } 38 | } 39 | 40 | func getEncoder(typ reflect.Type) encoderFunc { 41 | if encoder, ok := typEncMap[typ]; ok { 42 | return encoder 43 | } 44 | 45 | if typ.Implements(customEncoderType) { 46 | return encodeCustomValue 47 | } 48 | if typ.Implements(marshalerType) { 49 | return marshalValue 50 | } 51 | 52 | kind := typ.Kind() 53 | 54 | // Addressable struct field value. 55 | if kind != reflect.Ptr { 56 | ptr := reflect.PtrTo(typ) 57 | if ptr.Implements(customEncoderType) { 58 | return encodeCustomValuePtr 59 | } 60 | if ptr.Implements(marshalerType) { 61 | return marshalValuePtr 62 | } 63 | } 64 | 65 | if typ == errorType { 66 | return encodeErrorValue 67 | } 68 | 69 | switch kind { 70 | case reflect.Ptr: 71 | return ptrEncoderFunc(typ) 72 | case reflect.Slice: 73 | if typ.Elem().Kind() == reflect.Uint8 { 74 | return encodeByteSliceValue 75 | } 76 | case reflect.Array: 77 | if typ.Elem().Kind() == reflect.Uint8 { 78 | return encodeByteArrayValue 79 | } 80 | case reflect.Map: 81 | if typ.Key() == stringType { 82 | switch typ.Elem() { 83 | case stringType: 84 | return encodeMapStringStringValue 85 | case interfaceType: 86 | return encodeMapStringInterfaceValue 87 | } 88 | } 89 | } 90 | return valueEncoders[kind] 91 | } 92 | 93 | func ptrEncoderFunc(typ reflect.Type) encoderFunc { 94 | encoder := getEncoder(typ.Elem()) 95 | return func(e *Encoder, v reflect.Value) error { 96 | if v.IsNil() { 97 | return e.EncodeNil() 98 | } 99 | return encoder(e, v.Elem()) 100 | } 101 | } 102 | 103 | func encodeCustomValuePtr(e *Encoder, v reflect.Value) error { 104 | if !v.CanAddr() { 105 | return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface()) 106 | } 107 | encoder := v.Addr().Interface().(CustomEncoder) 108 | return encoder.EncodeMsgpack(e) 109 | } 110 | 111 | func encodeCustomValue(e *Encoder, v reflect.Value) error { 112 | switch v.Kind() { 113 | case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: 114 | if v.IsNil() { 115 | return e.EncodeNil() 116 | } 117 | } 118 | 119 | encoder := v.Interface().(CustomEncoder) 120 | return encoder.EncodeMsgpack(e) 121 | } 122 | 123 | func marshalValuePtr(e *Encoder, v reflect.Value) error { 124 | if !v.CanAddr() { 125 | return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface()) 126 | } 127 | return marshalValue(e, v.Addr()) 128 | } 129 | 130 | func marshalValue(e *Encoder, v reflect.Value) error { 131 | switch v.Kind() { 132 | case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: 133 | if v.IsNil() { 134 | return e.EncodeNil() 135 | } 136 | } 137 | 138 | marshaler := v.Interface().(Marshaler) 139 | b, err := marshaler.MarshalMsgpack() 140 | if err != nil { 141 | return err 142 | } 143 | _, err = e.w.Write(b) 144 | return err 145 | } 146 | 147 | func encodeBoolValue(e *Encoder, v reflect.Value) error { 148 | return e.EncodeBool(v.Bool()) 149 | } 150 | 151 | func encodeInterfaceValue(e *Encoder, v reflect.Value) error { 152 | if v.IsNil() { 153 | return e.EncodeNil() 154 | } 155 | return e.EncodeValue(v.Elem()) 156 | } 157 | 158 | func encodeErrorValue(e *Encoder, v reflect.Value) error { 159 | if v.IsNil() { 160 | return e.EncodeNil() 161 | } 162 | return e.EncodeString(v.Interface().(error).Error()) 163 | } 164 | 165 | func encodeUnsupportedValue(e *Encoder, v reflect.Value) error { 166 | return fmt.Errorf("msgpack: Encode(unsupported %s)", v.Type()) 167 | } 168 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/ext.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "reflect" 7 | "sync" 8 | 9 | "github.com/vmihailenco/msgpack/codes" 10 | ) 11 | 12 | var extTypes = make(map[int8]reflect.Type) 13 | 14 | var bufferPool = &sync.Pool{ 15 | New: func() interface{} { 16 | return new(bytes.Buffer) 17 | }, 18 | } 19 | 20 | // RegisterExt records a type, identified by a value for that type, 21 | // under the provided id. That id will identify the concrete type of a value 22 | // sent or received as an interface variable. Only types that will be 23 | // transferred as implementations of interface values need to be registered. 24 | // Expecting to be used only during initialization, it panics if the mapping 25 | // between types and ids is not a bijection. 26 | func RegisterExt(id int8, value interface{}) { 27 | typ := reflect.TypeOf(value) 28 | if typ.Kind() == reflect.Ptr { 29 | typ = typ.Elem() 30 | } 31 | ptr := reflect.PtrTo(typ) 32 | 33 | if _, ok := extTypes[id]; ok { 34 | panic(fmt.Errorf("msgpack: ext with id=%d is already registered", id)) 35 | } 36 | extTypes[id] = typ 37 | 38 | registerExt(id, ptr, getEncoder(ptr), nil) 39 | registerExt(id, typ, getEncoder(typ), getDecoder(typ)) 40 | } 41 | 42 | func registerExt(id int8, typ reflect.Type, enc encoderFunc, dec decoderFunc) { 43 | if enc != nil { 44 | typEncMap[typ] = makeExtEncoder(id, enc) 45 | } 46 | if dec != nil { 47 | typDecMap[typ] = dec 48 | } 49 | } 50 | 51 | func makeExtEncoder(typeId int8, enc encoderFunc) encoderFunc { 52 | return func(e *Encoder, v reflect.Value) error { 53 | buf := bufferPool.Get().(*bytes.Buffer) 54 | defer bufferPool.Put(buf) 55 | buf.Reset() 56 | 57 | oldw := e.w 58 | e.w = buf 59 | err := enc(e, v) 60 | e.w = oldw 61 | 62 | if err != nil { 63 | return err 64 | } 65 | 66 | if err := e.encodeExtLen(buf.Len()); err != nil { 67 | return err 68 | } 69 | if err := e.w.WriteByte(byte(typeId)); err != nil { 70 | return err 71 | } 72 | return e.write(buf.Bytes()) 73 | } 74 | } 75 | 76 | func (e *Encoder) encodeExtLen(l int) error { 77 | switch l { 78 | case 1: 79 | return e.writeCode(codes.FixExt1) 80 | case 2: 81 | return e.writeCode(codes.FixExt2) 82 | case 4: 83 | return e.writeCode(codes.FixExt4) 84 | case 8: 85 | return e.writeCode(codes.FixExt8) 86 | case 16: 87 | return e.writeCode(codes.FixExt16) 88 | } 89 | if l < 256 { 90 | return e.write1(codes.Ext8, uint64(l)) 91 | } 92 | if l < 65536 { 93 | return e.write2(codes.Ext16, uint64(l)) 94 | } 95 | return e.write4(codes.Ext32, uint32(l)) 96 | } 97 | 98 | func (d *Decoder) decodeExtLen() (int, error) { 99 | c, err := d.readCode() 100 | if err != nil { 101 | return 0, err 102 | } 103 | return d.parseExtLen(c) 104 | } 105 | 106 | func (d *Decoder) parseExtLen(c codes.Code) (int, error) { 107 | switch c { 108 | case codes.FixExt1: 109 | return 1, nil 110 | case codes.FixExt2: 111 | return 2, nil 112 | case codes.FixExt4: 113 | return 4, nil 114 | case codes.FixExt8: 115 | return 8, nil 116 | case codes.FixExt16: 117 | return 16, nil 118 | case codes.Ext8: 119 | n, err := d.uint8() 120 | return int(n), err 121 | case codes.Ext16: 122 | n, err := d.uint16() 123 | return int(n), err 124 | case codes.Ext32: 125 | n, err := d.uint32() 126 | return int(n), err 127 | default: 128 | return 0, fmt.Errorf("msgpack: invalid code=%x decoding ext length", c) 129 | } 130 | } 131 | 132 | func (d *Decoder) decodeExt() (interface{}, error) { 133 | c, err := d.readCode() 134 | if err != nil { 135 | return 0, err 136 | } 137 | return d.ext(c) 138 | } 139 | 140 | func (d *Decoder) ext(c codes.Code) (interface{}, error) { 141 | extLen, err := d.parseExtLen(c) 142 | if err != nil { 143 | return nil, err 144 | } 145 | // Save for later use. 146 | d.extLen = extLen 147 | 148 | extId, err := d.readCode() 149 | if err != nil { 150 | return nil, err 151 | } 152 | 153 | typ, ok := extTypes[int8(extId)] 154 | if !ok { 155 | return nil, fmt.Errorf("msgpack: unregistered ext id=%d", extId) 156 | } 157 | 158 | v := reflect.New(typ).Elem() 159 | if err := d.DecodeValue(v); err != nil { 160 | return nil, err 161 | } 162 | 163 | return v.Interface(), nil 164 | } 165 | 166 | func (d *Decoder) skipExt(c codes.Code) error { 167 | n, err := d.parseExtLen(c) 168 | if err != nil { 169 | return err 170 | } 171 | return d.skipN(n) 172 | } 173 | 174 | func (d *Decoder) skipExtHeader(c codes.Code) error { 175 | // Read ext type. 176 | _, err := d.readCode() 177 | if err != nil { 178 | return err 179 | } 180 | // Read ext body len. 181 | for i := 0; i < extHeaderLen(c); i++ { 182 | _, err := d.readCode() 183 | if err != nil { 184 | return err 185 | } 186 | } 187 | return nil 188 | } 189 | 190 | func extHeaderLen(c codes.Code) int { 191 | switch c { 192 | case codes.Ext8: 193 | return 1 194 | case codes.Ext16: 195 | return 2 196 | case codes.Ext32: 197 | return 4 198 | } 199 | return 0 200 | } 201 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/msgpack.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | type Marshaler interface { 4 | MarshalMsgpack() ([]byte, error) 5 | } 6 | 7 | type Unmarshaler interface { 8 | UnmarshalMsgpack([]byte) error 9 | } 10 | 11 | type CustomEncoder interface { 12 | EncodeMsgpack(*Encoder) error 13 | } 14 | 15 | type CustomDecoder interface { 16 | DecodeMsgpack(*Decoder) error 17 | } 18 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/tags.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package msgpack 6 | 7 | import ( 8 | "strings" 9 | ) 10 | 11 | // tagOptions is the string following a comma in a struct field's "json" 12 | // tag, or the empty string. It does not include the leading comma. 13 | type tagOptions string 14 | 15 | // parseTag splits a struct field's json tag into its name and 16 | // comma-separated options. 17 | func parseTag(tag string) (string, tagOptions) { 18 | if idx := strings.Index(tag, ","); idx != -1 { 19 | return tag[:idx], tagOptions(tag[idx+1:]) 20 | } 21 | return tag, tagOptions("") 22 | } 23 | 24 | // Contains reports whether a comma-separated list of options 25 | // contains a particular substr flag. substr must be surrounded by a 26 | // string boundary or commas. 27 | func (o tagOptions) Contains(optionName string) bool { 28 | if len(o) == 0 { 29 | return false 30 | } 31 | s := string(o) 32 | for s != "" { 33 | var next string 34 | i := strings.IndexRune(s, ',') 35 | if i >= 0 { 36 | s, next = s[:i], s[i+1:] 37 | } 38 | if s == optionName { 39 | return true 40 | } 41 | s = next 42 | } 43 | return false 44 | } 45 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/time.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "reflect" 7 | "time" 8 | 9 | "github.com/vmihailenco/msgpack/codes" 10 | ) 11 | 12 | var timeExtId int8 = -1 13 | 14 | func init() { 15 | timeType := reflect.TypeOf((*time.Time)(nil)).Elem() 16 | registerExt(timeExtId, timeType, encodeTimeValue, decodeTimeValue) 17 | } 18 | 19 | func (e *Encoder) EncodeTime(tm time.Time) error { 20 | b := e.encodeTime(tm) 21 | if err := e.encodeExtLen(len(b)); err != nil { 22 | return err 23 | } 24 | if err := e.w.WriteByte(byte(timeExtId)); err != nil { 25 | return err 26 | } 27 | return e.write(b) 28 | } 29 | 30 | func (e *Encoder) encodeTime(tm time.Time) []byte { 31 | secs := uint64(tm.Unix()) 32 | if secs>>34 == 0 { 33 | data := uint64(tm.Nanosecond())<<34 | secs 34 | if data&0xffffffff00000000 == 0 { 35 | b := make([]byte, 4) 36 | binary.BigEndian.PutUint32(b, uint32(data)) 37 | return b 38 | } else { 39 | b := make([]byte, 8) 40 | binary.BigEndian.PutUint64(b, data) 41 | return b 42 | } 43 | } 44 | 45 | b := make([]byte, 12) 46 | binary.BigEndian.PutUint32(b, uint32(tm.Nanosecond())) 47 | binary.BigEndian.PutUint64(b[4:], uint64(secs)) 48 | return b 49 | } 50 | 51 | func (d *Decoder) DecodeTime() (time.Time, error) { 52 | c, err := d.readCode() 53 | if err != nil { 54 | return time.Time{}, err 55 | } 56 | 57 | // Legacy format. 58 | if c == codes.FixedArrayLow|2 { 59 | sec, err := d.DecodeInt64() 60 | if err != nil { 61 | return time.Time{}, err 62 | } 63 | nsec, err := d.DecodeInt64() 64 | if err != nil { 65 | return time.Time{}, err 66 | } 67 | return time.Unix(sec, nsec), nil 68 | } 69 | 70 | extLen, err := d.parseExtLen(c) 71 | if err != nil { 72 | return time.Time{}, err 73 | } 74 | 75 | _, err = d.r.ReadByte() 76 | if err != nil { 77 | return time.Time{}, nil 78 | } 79 | 80 | b, err := d.readN(extLen) 81 | if err != nil { 82 | return time.Time{}, err 83 | } 84 | 85 | switch len(b) { 86 | case 4: 87 | sec := binary.BigEndian.Uint32(b) 88 | return time.Unix(int64(sec), 0), nil 89 | case 8: 90 | sec := binary.BigEndian.Uint64(b) 91 | nsec := int64(sec >> 34) 92 | sec &= 0x00000003ffffffff 93 | return time.Unix(int64(sec), nsec), nil 94 | case 12: 95 | nsec := binary.BigEndian.Uint32(b) 96 | sec := binary.BigEndian.Uint64(b[4:]) 97 | return time.Unix(int64(sec), int64(nsec)), nil 98 | default: 99 | return time.Time{}, fmt.Errorf("msgpack: invalid ext len=%d decoding time", extLen) 100 | } 101 | } 102 | 103 | func encodeTimeValue(e *Encoder, v reflect.Value) error { 104 | tm := v.Interface().(time.Time) 105 | b := e.encodeTime(tm) 106 | return e.write(b) 107 | } 108 | 109 | func decodeTimeValue(d *Decoder, v reflect.Value) error { 110 | tm, err := d.DecodeTime() 111 | if err != nil { 112 | return err 113 | } 114 | v.Set(reflect.ValueOf(tm)) 115 | return nil 116 | } 117 | -------------------------------------------------------------------------------- /vendor/github.com/vmihailenco/msgpack/types.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "reflect" 5 | "sync" 6 | ) 7 | 8 | var errorType = reflect.TypeOf((*error)(nil)).Elem() 9 | 10 | var customEncoderType = reflect.TypeOf((*CustomEncoder)(nil)).Elem() 11 | var customDecoderType = reflect.TypeOf((*CustomDecoder)(nil)).Elem() 12 | 13 | var marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() 14 | var unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() 15 | 16 | type encoderFunc func(*Encoder, reflect.Value) error 17 | type decoderFunc func(*Decoder, reflect.Value) error 18 | 19 | var typEncMap = make(map[reflect.Type]encoderFunc) 20 | var typDecMap = make(map[reflect.Type]decoderFunc) 21 | 22 | // Register registers encoder and decoder functions for a value. 23 | // This is low level API and in most cases you should prefer implementing 24 | // Marshaler/CustomEncoder and Unmarshaler/CustomDecoder interfaces. 25 | func Register(value interface{}, enc encoderFunc, dec decoderFunc) { 26 | typ := reflect.TypeOf(value) 27 | if enc != nil { 28 | typEncMap[typ] = enc 29 | } 30 | if dec != nil { 31 | typDecMap[typ] = dec 32 | } 33 | } 34 | 35 | //------------------------------------------------------------------------------ 36 | 37 | var structs = newStructCache() 38 | 39 | type structCache struct { 40 | mu sync.RWMutex 41 | m map[reflect.Type]*fields 42 | } 43 | 44 | func newStructCache() *structCache { 45 | return &structCache{ 46 | m: make(map[reflect.Type]*fields), 47 | } 48 | } 49 | 50 | func (m *structCache) Fields(typ reflect.Type) *fields { 51 | m.mu.RLock() 52 | fs, ok := m.m[typ] 53 | m.mu.RUnlock() 54 | if ok { 55 | return fs 56 | } 57 | 58 | m.mu.Lock() 59 | fs, ok = m.m[typ] 60 | if !ok { 61 | fs = getFields(typ) 62 | m.m[typ] = fs 63 | } 64 | m.mu.Unlock() 65 | 66 | return fs 67 | } 68 | 69 | //------------------------------------------------------------------------------ 70 | 71 | type field struct { 72 | name string 73 | index []int 74 | omitEmpty bool 75 | 76 | encoder encoderFunc 77 | decoder decoderFunc 78 | } 79 | 80 | func (f *field) value(strct reflect.Value) reflect.Value { 81 | return strct.FieldByIndex(f.index) 82 | } 83 | 84 | func (f *field) Omit(strct reflect.Value) bool { 85 | return f.omitEmpty && isEmptyValue(f.value(strct)) 86 | } 87 | 88 | func (f *field) EncodeValue(e *Encoder, strct reflect.Value) error { 89 | return f.encoder(e, f.value(strct)) 90 | } 91 | 92 | func (f *field) DecodeValue(d *Decoder, strct reflect.Value) error { 93 | return f.decoder(d, f.value(strct)) 94 | } 95 | 96 | //------------------------------------------------------------------------------ 97 | 98 | type fields struct { 99 | List []*field 100 | Table map[string]*field 101 | 102 | asArray bool 103 | omitEmpty bool 104 | } 105 | 106 | func newFields(numField int) *fields { 107 | return &fields{ 108 | List: make([]*field, 0, numField), 109 | Table: make(map[string]*field, numField), 110 | } 111 | } 112 | 113 | func (fs *fields) Len() int { 114 | return len(fs.List) 115 | } 116 | 117 | func (fs *fields) Add(field *field) { 118 | fs.List = append(fs.List, field) 119 | fs.Table[field.name] = field 120 | if field.omitEmpty { 121 | fs.omitEmpty = field.omitEmpty 122 | } 123 | } 124 | 125 | func (fs *fields) OmitEmpty(strct reflect.Value) []*field { 126 | if !fs.omitEmpty { 127 | return fs.List 128 | } 129 | 130 | fields := make([]*field, 0, fs.Len()) 131 | for _, f := range fs.List { 132 | if !f.Omit(strct) { 133 | fields = append(fields, f) 134 | } 135 | } 136 | return fields 137 | } 138 | 139 | func getFields(typ reflect.Type) *fields { 140 | numField := typ.NumField() 141 | fs := newFields(numField) 142 | 143 | var omitEmpty bool 144 | for i := 0; i < numField; i++ { 145 | f := typ.Field(i) 146 | 147 | name, opt := parseTag(f.Tag.Get("msgpack")) 148 | if name == "-" { 149 | continue 150 | } 151 | 152 | if f.Name == "_msgpack" { 153 | if opt.Contains("asArray") { 154 | fs.asArray = true 155 | } 156 | if opt.Contains("omitempty") { 157 | omitEmpty = true 158 | } 159 | } 160 | 161 | if f.PkgPath != "" && !f.Anonymous { 162 | continue 163 | } 164 | 165 | if name == "" { 166 | name = f.Name 167 | } 168 | field := &field{ 169 | name: name, 170 | index: f.Index, 171 | omitEmpty: omitEmpty || opt.Contains("omitempty"), 172 | encoder: getEncoder(f.Type), 173 | decoder: getDecoder(f.Type), 174 | } 175 | 176 | if f.Anonymous && inlineFields(fs, f.Type, field) { 177 | continue 178 | } 179 | 180 | fs.Add(field) 181 | } 182 | return fs 183 | } 184 | 185 | var encodeStructValuePtr uintptr 186 | var decodeStructValuePtr uintptr 187 | 188 | func init() { 189 | encodeStructValuePtr = reflect.ValueOf(encodeStructValue).Pointer() 190 | decodeStructValuePtr = reflect.ValueOf(decodeStructValue).Pointer() 191 | } 192 | 193 | func inlineFields(fs *fields, typ reflect.Type, f *field) bool { 194 | if typ.Kind() == reflect.Ptr { 195 | typ = typ.Elem() 196 | } 197 | if typ.Kind() != reflect.Struct { 198 | return false 199 | } 200 | 201 | if reflect.ValueOf(f.encoder).Pointer() != encodeStructValuePtr { 202 | return false 203 | } 204 | if reflect.ValueOf(f.decoder).Pointer() != decodeStructValuePtr { 205 | return false 206 | } 207 | 208 | inlinedFields := getFields(typ).List 209 | for _, field := range inlinedFields { 210 | if _, ok := fs.Table[field.name]; ok { 211 | // Don't overwrite shadowed fields. 212 | continue 213 | } 214 | field.index = append(f.index, field.index...) 215 | fs.Add(field) 216 | } 217 | return true 218 | } 219 | 220 | func isEmptyValue(v reflect.Value) bool { 221 | switch v.Kind() { 222 | case reflect.Array, reflect.Map, reflect.Slice, reflect.String: 223 | return v.Len() == 0 224 | case reflect.Bool: 225 | return !v.Bool() 226 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 227 | return v.Int() == 0 228 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 229 | return v.Uint() == 0 230 | case reflect.Float32, reflect.Float64: 231 | return v.Float() == 0 232 | case reflect.Interface, reflect.Ptr: 233 | return v.IsNil() 234 | } 235 | return false 236 | } 237 | -------------------------------------------------------------------------------- /vendor/gopkg.in/ini.v1/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 13 | owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities 16 | that control, are controlled by, or are under common control with that entity. 17 | For the purposes of this definition, "control" means (i) the power, direct or 18 | indirect, to cause the direction or management of such entity, whether by 19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 20 | outstanding shares, or (iii) beneficial ownership of such entity. 21 | 22 | "You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, including 26 | but not limited to software source code, documentation source, and configuration 27 | files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation or 30 | translation of a Source form, including but not limited to compiled object code, 31 | generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, made 34 | available under the License, as indicated by a copyright notice that is included 35 | in or attached to the work (an example is provided in the Appendix below). 36 | 37 | "Derivative Works" shall mean any work, whether in Source or Object form, that 38 | is based on (or derived from) the Work and for which the editorial revisions, 39 | annotations, elaborations, or other modifications represent, as a whole, an 40 | original work of authorship. For the purposes of this License, Derivative Works 41 | shall not include works that remain separable from, or merely link (or bind by 42 | name) to the interfaces of, the Work and Derivative Works thereof. 43 | 44 | "Contribution" shall mean any work of authorship, including the original version 45 | of the Work and any modifications or additions to that Work or Derivative Works 46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 47 | by the copyright owner or by an individual or Legal Entity authorized to submit 48 | on behalf of the copyright owner. For the purposes of this definition, 49 | "submitted" means any form of electronic, verbal, or written communication sent 50 | to the Licensor or its representatives, including but not limited to 51 | communication on electronic mailing lists, source code control systems, and 52 | issue tracking systems that are managed by, or on behalf of, the Licensor for 53 | the purpose of discussing and improving the Work, but excluding communication 54 | that is conspicuously marked or otherwise designated in writing by the copyright 55 | owner as "Not a Contribution." 56 | 57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 58 | of whom a Contribution has been received by Licensor and subsequently 59 | incorporated within the Work. 60 | 61 | 2. Grant of Copyright License. 62 | 63 | Subject to the terms and conditions of this License, each Contributor hereby 64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 65 | irrevocable copyright license to reproduce, prepare Derivative Works of, 66 | publicly display, publicly perform, sublicense, and distribute the Work and such 67 | Derivative Works in Source or Object form. 68 | 69 | 3. Grant of Patent License. 70 | 71 | Subject to the terms and conditions of this License, each Contributor hereby 72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 73 | irrevocable (except as stated in this section) patent license to make, have 74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 75 | such license applies only to those patent claims licensable by such Contributor 76 | that are necessarily infringed by their Contribution(s) alone or by combination 77 | of their Contribution(s) with the Work to which such Contribution(s) was 78 | submitted. If You institute patent litigation against any entity (including a 79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 80 | Contribution incorporated within the Work constitutes direct or contributory 81 | patent infringement, then any patent licenses granted to You under this License 82 | for that Work shall terminate as of the date such litigation is filed. 83 | 84 | 4. Redistribution. 85 | 86 | You may reproduce and distribute copies of the Work or Derivative Works thereof 87 | in any medium, with or without modifications, and in Source or Object form, 88 | provided that You meet the following conditions: 89 | 90 | You must give any other recipients of the Work or Derivative Works a copy of 91 | this License; and 92 | You must cause any modified files to carry prominent notices stating that You 93 | changed the files; and 94 | You must retain, in the Source form of any Derivative Works that You distribute, 95 | all copyright, patent, trademark, and attribution notices from the Source form 96 | of the Work, excluding those notices that do not pertain to any part of the 97 | Derivative Works; and 98 | If the Work includes a "NOTICE" text file as part of its distribution, then any 99 | Derivative Works that You distribute must include a readable copy of the 100 | attribution notices contained within such NOTICE file, excluding those notices 101 | that do not pertain to any part of the Derivative Works, in at least one of the 102 | following places: within a NOTICE text file distributed as part of the 103 | Derivative Works; within the Source form or documentation, if provided along 104 | with the Derivative Works; or, within a display generated by the Derivative 105 | Works, if and wherever such third-party notices normally appear. The contents of 106 | the NOTICE file are for informational purposes only and do not modify the 107 | License. You may add Your own attribution notices within Derivative Works that 108 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 109 | provided that such additional attribution notices cannot be construed as 110 | modifying the License. 111 | You may add Your own copyright statement to Your modifications and may provide 112 | additional or different license terms and conditions for use, reproduction, or 113 | distribution of Your modifications, or for any such Derivative Works as a whole, 114 | provided Your use, reproduction, and distribution of the Work otherwise complies 115 | with the conditions stated in this License. 116 | 117 | 5. Submission of Contributions. 118 | 119 | Unless You explicitly state otherwise, any Contribution intentionally submitted 120 | for inclusion in the Work by You to the Licensor shall be under the terms and 121 | conditions of this License, without any additional terms or conditions. 122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 123 | any separate license agreement you may have executed with Licensor regarding 124 | such Contributions. 125 | 126 | 6. Trademarks. 127 | 128 | This License does not grant permission to use the trade names, trademarks, 129 | service marks, or product names of the Licensor, except as required for 130 | reasonable and customary use in describing the origin of the Work and 131 | reproducing the content of the NOTICE file. 132 | 133 | 7. Disclaimer of Warranty. 134 | 135 | Unless required by applicable law or agreed to in writing, Licensor provides the 136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 138 | including, without limitation, any warranties or conditions of TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 140 | solely responsible for determining the appropriateness of using or 141 | redistributing the Work and assume any risks associated with Your exercise of 142 | permissions under this License. 143 | 144 | 8. Limitation of Liability. 145 | 146 | In no event and under no legal theory, whether in tort (including negligence), 147 | contract, or otherwise, unless required by applicable law (such as deliberate 148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 149 | liable to You for damages, including any direct, indirect, special, incidental, 150 | or consequential damages of any character arising as a result of this License or 151 | out of the use or inability to use the Work (including but not limited to 152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 153 | any and all other commercial damages or losses), even if such Contributor has 154 | been advised of the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. 157 | 158 | While redistributing the Work or Derivative Works thereof, You may choose to 159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 160 | other liability obligations and/or rights consistent with this License. However, 161 | in accepting such obligations, You may act only on Your own behalf and on Your 162 | sole responsibility, not on behalf of any other Contributor, and only if You 163 | agree to indemnify, defend, and hold each Contributor harmless for any liability 164 | incurred by, or claims asserted against, such Contributor by reason of your 165 | accepting any such warranty or additional liability. 166 | 167 | END OF TERMS AND CONDITIONS 168 | 169 | APPENDIX: How to apply the Apache License to your work 170 | 171 | To apply the Apache License to your work, attach the following boilerplate 172 | notice, with the fields enclosed by brackets "[]" replaced with your own 173 | identifying information. (Don't include the brackets!) The text should be 174 | enclosed in the appropriate comment syntax for the file format. We also 175 | recommend that a file or class name and description of purpose be included on 176 | the same "printed page" as the copyright notice for easier identification within 177 | third-party archives. 178 | 179 | Copyright [yyyy] [name of copyright owner] 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. 192 | -------------------------------------------------------------------------------- /vendor/gopkg.in/ini.v1/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build test bench vet 2 | 3 | build: vet bench 4 | 5 | test: 6 | go test -v -cover -race 7 | 8 | bench: 9 | go test -v -cover -race -test.bench=. -test.benchmem 10 | 11 | vet: 12 | go vet 13 | -------------------------------------------------------------------------------- /vendor/gopkg.in/ini.v1/error.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Unknwon 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | // License for the specific language governing permissions and limitations 13 | // under the License. 14 | 15 | package ini 16 | 17 | import ( 18 | "fmt" 19 | ) 20 | 21 | type ErrDelimiterNotFound struct { 22 | Line string 23 | } 24 | 25 | func IsErrDelimiterNotFound(err error) bool { 26 | _, ok := err.(ErrDelimiterNotFound) 27 | return ok 28 | } 29 | 30 | func (err ErrDelimiterNotFound) Error() string { 31 | return fmt.Sprintf("key-value delimiter not found: %s", err.Line) 32 | } 33 | -------------------------------------------------------------------------------- /vendor/gopkg.in/ini.v1/parser.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Unknwon 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | // License for the specific language governing permissions and limitations 13 | // under the License. 14 | 15 | package ini 16 | 17 | import ( 18 | "bufio" 19 | "bytes" 20 | "fmt" 21 | "io" 22 | "strconv" 23 | "strings" 24 | "unicode" 25 | ) 26 | 27 | type tokenType int 28 | 29 | const ( 30 | _TOKEN_INVALID tokenType = iota 31 | _TOKEN_COMMENT 32 | _TOKEN_SECTION 33 | _TOKEN_KEY 34 | ) 35 | 36 | type parser struct { 37 | buf *bufio.Reader 38 | isEOF bool 39 | count int 40 | comment *bytes.Buffer 41 | } 42 | 43 | func newParser(r io.Reader) *parser { 44 | return &parser{ 45 | buf: bufio.NewReader(r), 46 | count: 1, 47 | comment: &bytes.Buffer{}, 48 | } 49 | } 50 | 51 | // BOM handles header of UTF-8, UTF-16 LE and UTF-16 BE's BOM format. 52 | // http://en.wikipedia.org/wiki/Byte_order_mark#Representations_of_byte_order_marks_by_encoding 53 | func (p *parser) BOM() error { 54 | mask, err := p.buf.Peek(2) 55 | if err != nil && err != io.EOF { 56 | return err 57 | } else if len(mask) < 2 { 58 | return nil 59 | } 60 | 61 | switch { 62 | case mask[0] == 254 && mask[1] == 255: 63 | fallthrough 64 | case mask[0] == 255 && mask[1] == 254: 65 | p.buf.Read(mask) 66 | case mask[0] == 239 && mask[1] == 187: 67 | mask, err := p.buf.Peek(3) 68 | if err != nil && err != io.EOF { 69 | return err 70 | } else if len(mask) < 3 { 71 | return nil 72 | } 73 | if mask[2] == 191 { 74 | p.buf.Read(mask) 75 | } 76 | } 77 | return nil 78 | } 79 | 80 | func (p *parser) readUntil(delim byte) ([]byte, error) { 81 | data, err := p.buf.ReadBytes(delim) 82 | if err != nil { 83 | if err == io.EOF { 84 | p.isEOF = true 85 | } else { 86 | return nil, err 87 | } 88 | } 89 | return data, nil 90 | } 91 | 92 | func cleanComment(in []byte) ([]byte, bool) { 93 | i := bytes.IndexAny(in, "#;") 94 | if i == -1 { 95 | return nil, false 96 | } 97 | return in[i:], true 98 | } 99 | 100 | func readKeyName(in []byte) (string, int, error) { 101 | line := string(in) 102 | 103 | // Check if key name surrounded by quotes. 104 | var keyQuote string 105 | if line[0] == '"' { 106 | if len(line) > 6 && string(line[0:3]) == `"""` { 107 | keyQuote = `"""` 108 | } else { 109 | keyQuote = `"` 110 | } 111 | } else if line[0] == '`' { 112 | keyQuote = "`" 113 | } 114 | 115 | // Get out key name 116 | endIdx := -1 117 | if len(keyQuote) > 0 { 118 | startIdx := len(keyQuote) 119 | // FIXME: fail case -> """"""name"""=value 120 | pos := strings.Index(line[startIdx:], keyQuote) 121 | if pos == -1 { 122 | return "", -1, fmt.Errorf("missing closing key quote: %s", line) 123 | } 124 | pos += startIdx 125 | 126 | // Find key-value delimiter 127 | i := strings.IndexAny(line[pos+startIdx:], "=:") 128 | if i < 0 { 129 | return "", -1, ErrDelimiterNotFound{line} 130 | } 131 | endIdx = pos + i 132 | return strings.TrimSpace(line[startIdx:pos]), endIdx + startIdx + 1, nil 133 | } 134 | 135 | endIdx = strings.IndexAny(line, "=:") 136 | if endIdx < 0 { 137 | return "", -1, ErrDelimiterNotFound{line} 138 | } 139 | return strings.TrimSpace(line[0:endIdx]), endIdx + 1, nil 140 | } 141 | 142 | func (p *parser) readMultilines(line, val, valQuote string) (string, error) { 143 | for { 144 | data, err := p.readUntil('\n') 145 | if err != nil { 146 | return "", err 147 | } 148 | next := string(data) 149 | 150 | pos := strings.LastIndex(next, valQuote) 151 | if pos > -1 { 152 | val += next[:pos] 153 | 154 | comment, has := cleanComment([]byte(next[pos:])) 155 | if has { 156 | p.comment.Write(bytes.TrimSpace(comment)) 157 | } 158 | break 159 | } 160 | val += next 161 | if p.isEOF { 162 | return "", fmt.Errorf("missing closing key quote from '%s' to '%s'", line, next) 163 | } 164 | } 165 | return val, nil 166 | } 167 | 168 | func (p *parser) readContinuationLines(val string) (string, error) { 169 | for { 170 | data, err := p.readUntil('\n') 171 | if err != nil { 172 | return "", err 173 | } 174 | next := strings.TrimSpace(string(data)) 175 | 176 | if len(next) == 0 { 177 | break 178 | } 179 | val += next 180 | if val[len(val)-1] != '\\' { 181 | break 182 | } 183 | val = val[:len(val)-1] 184 | } 185 | return val, nil 186 | } 187 | 188 | // hasSurroundedQuote check if and only if the first and last characters 189 | // are quotes \" or \'. 190 | // It returns false if any other parts also contain same kind of quotes. 191 | func hasSurroundedQuote(in string, quote byte) bool { 192 | return len(in) >= 2 && in[0] == quote && in[len(in)-1] == quote && 193 | strings.IndexByte(in[1:], quote) == len(in)-2 194 | } 195 | 196 | func (p *parser) readValue(in []byte, ignoreContinuation, ignoreInlineComment bool) (string, error) { 197 | line := strings.TrimLeftFunc(string(in), unicode.IsSpace) 198 | if len(line) == 0 { 199 | return "", nil 200 | } 201 | 202 | var valQuote string 203 | if len(line) > 3 && string(line[0:3]) == `"""` { 204 | valQuote = `"""` 205 | } else if line[0] == '`' { 206 | valQuote = "`" 207 | } 208 | 209 | if len(valQuote) > 0 { 210 | startIdx := len(valQuote) 211 | pos := strings.LastIndex(line[startIdx:], valQuote) 212 | // Check for multi-line value 213 | if pos == -1 { 214 | return p.readMultilines(line, line[startIdx:], valQuote) 215 | } 216 | 217 | return line[startIdx : pos+startIdx], nil 218 | } 219 | 220 | // Won't be able to reach here if value only contains whitespace 221 | line = strings.TrimSpace(line) 222 | 223 | // Check continuation lines when desired 224 | if !ignoreContinuation && line[len(line)-1] == '\\' { 225 | return p.readContinuationLines(line[:len(line)-1]) 226 | } 227 | 228 | // Check if ignore inline comment 229 | if !ignoreInlineComment { 230 | i := strings.IndexAny(line, "#;") 231 | if i > -1 { 232 | p.comment.WriteString(line[i:]) 233 | line = strings.TrimSpace(line[:i]) 234 | } 235 | } 236 | 237 | // Trim single quotes 238 | if hasSurroundedQuote(line, '\'') || 239 | hasSurroundedQuote(line, '"') { 240 | line = line[1 : len(line)-1] 241 | } 242 | return line, nil 243 | } 244 | 245 | // parse parses data through an io.Reader. 246 | func (f *File) parse(reader io.Reader) (err error) { 247 | p := newParser(reader) 248 | if err = p.BOM(); err != nil { 249 | return fmt.Errorf("BOM: %v", err) 250 | } 251 | 252 | // Ignore error because default section name is never empty string. 253 | section, _ := f.NewSection(DEFAULT_SECTION) 254 | 255 | var line []byte 256 | var inUnparseableSection bool 257 | for !p.isEOF { 258 | line, err = p.readUntil('\n') 259 | if err != nil { 260 | return err 261 | } 262 | 263 | line = bytes.TrimLeftFunc(line, unicode.IsSpace) 264 | if len(line) == 0 { 265 | continue 266 | } 267 | 268 | // Comments 269 | if line[0] == '#' || line[0] == ';' { 270 | // Note: we do not care ending line break, 271 | // it is needed for adding second line, 272 | // so just clean it once at the end when set to value. 273 | p.comment.Write(line) 274 | continue 275 | } 276 | 277 | // Section 278 | if line[0] == '[' { 279 | // Read to the next ']' (TODO: support quoted strings) 280 | // TODO(unknwon): use LastIndexByte when stop supporting Go1.4 281 | closeIdx := bytes.LastIndex(line, []byte("]")) 282 | if closeIdx == -1 { 283 | return fmt.Errorf("unclosed section: %s", line) 284 | } 285 | 286 | name := string(line[1:closeIdx]) 287 | section, err = f.NewSection(name) 288 | if err != nil { 289 | return err 290 | } 291 | 292 | comment, has := cleanComment(line[closeIdx+1:]) 293 | if has { 294 | p.comment.Write(comment) 295 | } 296 | 297 | section.Comment = strings.TrimSpace(p.comment.String()) 298 | 299 | // Reset aotu-counter and comments 300 | p.comment.Reset() 301 | p.count = 1 302 | 303 | inUnparseableSection = false 304 | for i := range f.options.UnparseableSections { 305 | if f.options.UnparseableSections[i] == name || 306 | (f.options.Insensitive && strings.ToLower(f.options.UnparseableSections[i]) == strings.ToLower(name)) { 307 | inUnparseableSection = true 308 | continue 309 | } 310 | } 311 | continue 312 | } 313 | 314 | if inUnparseableSection { 315 | section.isRawSection = true 316 | section.rawBody += string(line) 317 | continue 318 | } 319 | 320 | kname, offset, err := readKeyName(line) 321 | if err != nil { 322 | // Treat as boolean key when desired, and whole line is key name. 323 | if IsErrDelimiterNotFound(err) && f.options.AllowBooleanKeys { 324 | kname, err := p.readValue(line, f.options.IgnoreContinuation, f.options.IgnoreInlineComment) 325 | if err != nil { 326 | return err 327 | } 328 | key, err := section.NewBooleanKey(kname) 329 | if err != nil { 330 | return err 331 | } 332 | key.Comment = strings.TrimSpace(p.comment.String()) 333 | p.comment.Reset() 334 | continue 335 | } 336 | return err 337 | } 338 | 339 | // Auto increment. 340 | isAutoIncr := false 341 | if kname == "-" { 342 | isAutoIncr = true 343 | kname = "#" + strconv.Itoa(p.count) 344 | p.count++ 345 | } 346 | 347 | value, err := p.readValue(line[offset:], f.options.IgnoreContinuation, f.options.IgnoreInlineComment) 348 | if err != nil { 349 | return err 350 | } 351 | 352 | key, err := section.NewKey(kname, value) 353 | if err != nil { 354 | return err 355 | } 356 | key.isAutoIncrement = isAutoIncr 357 | key.Comment = strings.TrimSpace(p.comment.String()) 358 | p.comment.Reset() 359 | } 360 | return nil 361 | } 362 | -------------------------------------------------------------------------------- /vendor/gopkg.in/ini.v1/section.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Unknwon 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | // License for the specific language governing permissions and limitations 13 | // under the License. 14 | 15 | package ini 16 | 17 | import ( 18 | "errors" 19 | "fmt" 20 | "strings" 21 | ) 22 | 23 | // Section represents a config section. 24 | type Section struct { 25 | f *File 26 | Comment string 27 | name string 28 | keys map[string]*Key 29 | keyList []string 30 | keysHash map[string]string 31 | 32 | isRawSection bool 33 | rawBody string 34 | } 35 | 36 | func newSection(f *File, name string) *Section { 37 | return &Section{ 38 | f: f, 39 | name: name, 40 | keys: make(map[string]*Key), 41 | keyList: make([]string, 0, 10), 42 | keysHash: make(map[string]string), 43 | } 44 | } 45 | 46 | // Name returns name of Section. 47 | func (s *Section) Name() string { 48 | return s.name 49 | } 50 | 51 | // Body returns rawBody of Section if the section was marked as unparseable. 52 | // It still follows the other rules of the INI format surrounding leading/trailing whitespace. 53 | func (s *Section) Body() string { 54 | return strings.TrimSpace(s.rawBody) 55 | } 56 | 57 | // NewKey creates a new key to given section. 58 | func (s *Section) NewKey(name, val string) (*Key, error) { 59 | if len(name) == 0 { 60 | return nil, errors.New("error creating new key: empty key name") 61 | } else if s.f.options.Insensitive { 62 | name = strings.ToLower(name) 63 | } 64 | 65 | if s.f.BlockMode { 66 | s.f.lock.Lock() 67 | defer s.f.lock.Unlock() 68 | } 69 | 70 | if inSlice(name, s.keyList) { 71 | if s.f.options.AllowShadows { 72 | if err := s.keys[name].addShadow(val); err != nil { 73 | return nil, err 74 | } 75 | } else { 76 | s.keys[name].value = val 77 | } 78 | return s.keys[name], nil 79 | } 80 | 81 | s.keyList = append(s.keyList, name) 82 | s.keys[name] = newKey(s, name, val) 83 | s.keysHash[name] = val 84 | return s.keys[name], nil 85 | } 86 | 87 | // NewBooleanKey creates a new boolean type key to given section. 88 | func (s *Section) NewBooleanKey(name string) (*Key, error) { 89 | key, err := s.NewKey(name, "true") 90 | if err != nil { 91 | return nil, err 92 | } 93 | 94 | key.isBooleanType = true 95 | return key, nil 96 | } 97 | 98 | // GetKey returns key in section by given name. 99 | func (s *Section) GetKey(name string) (*Key, error) { 100 | // FIXME: change to section level lock? 101 | if s.f.BlockMode { 102 | s.f.lock.RLock() 103 | } 104 | if s.f.options.Insensitive { 105 | name = strings.ToLower(name) 106 | } 107 | key := s.keys[name] 108 | if s.f.BlockMode { 109 | s.f.lock.RUnlock() 110 | } 111 | 112 | if key == nil { 113 | // Check if it is a child-section. 114 | sname := s.name 115 | for { 116 | if i := strings.LastIndex(sname, "."); i > -1 { 117 | sname = sname[:i] 118 | sec, err := s.f.GetSection(sname) 119 | if err != nil { 120 | continue 121 | } 122 | return sec.GetKey(name) 123 | } else { 124 | break 125 | } 126 | } 127 | return nil, fmt.Errorf("error when getting key of section '%s': key '%s' not exists", s.name, name) 128 | } 129 | return key, nil 130 | } 131 | 132 | // HasKey returns true if section contains a key with given name. 133 | func (s *Section) HasKey(name string) bool { 134 | key, _ := s.GetKey(name) 135 | return key != nil 136 | } 137 | 138 | // Haskey is a backwards-compatible name for HasKey. 139 | func (s *Section) Haskey(name string) bool { 140 | return s.HasKey(name) 141 | } 142 | 143 | // HasValue returns true if section contains given raw value. 144 | func (s *Section) HasValue(value string) bool { 145 | if s.f.BlockMode { 146 | s.f.lock.RLock() 147 | defer s.f.lock.RUnlock() 148 | } 149 | 150 | for _, k := range s.keys { 151 | if value == k.value { 152 | return true 153 | } 154 | } 155 | return false 156 | } 157 | 158 | // Key assumes named Key exists in section and returns a zero-value when not. 159 | func (s *Section) Key(name string) *Key { 160 | key, err := s.GetKey(name) 161 | if err != nil { 162 | // It's OK here because the only possible error is empty key name, 163 | // but if it's empty, this piece of code won't be executed. 164 | key, _ = s.NewKey(name, "") 165 | return key 166 | } 167 | return key 168 | } 169 | 170 | // Keys returns list of keys of section. 171 | func (s *Section) Keys() []*Key { 172 | keys := make([]*Key, len(s.keyList)) 173 | for i := range s.keyList { 174 | keys[i] = s.Key(s.keyList[i]) 175 | } 176 | return keys 177 | } 178 | 179 | // ParentKeys returns list of keys of parent section. 180 | func (s *Section) ParentKeys() []*Key { 181 | var parentKeys []*Key 182 | sname := s.name 183 | for { 184 | if i := strings.LastIndex(sname, "."); i > -1 { 185 | sname = sname[:i] 186 | sec, err := s.f.GetSection(sname) 187 | if err != nil { 188 | continue 189 | } 190 | parentKeys = append(parentKeys, sec.Keys()...) 191 | } else { 192 | break 193 | } 194 | 195 | } 196 | return parentKeys 197 | } 198 | 199 | // KeyStrings returns list of key names of section. 200 | func (s *Section) KeyStrings() []string { 201 | list := make([]string, len(s.keyList)) 202 | copy(list, s.keyList) 203 | return list 204 | } 205 | 206 | // KeysHash returns keys hash consisting of names and values. 207 | func (s *Section) KeysHash() map[string]string { 208 | if s.f.BlockMode { 209 | s.f.lock.RLock() 210 | defer s.f.lock.RUnlock() 211 | } 212 | 213 | hash := map[string]string{} 214 | for key, value := range s.keysHash { 215 | hash[key] = value 216 | } 217 | return hash 218 | } 219 | 220 | // DeleteKey deletes a key from section. 221 | func (s *Section) DeleteKey(name string) { 222 | if s.f.BlockMode { 223 | s.f.lock.Lock() 224 | defer s.f.lock.Unlock() 225 | } 226 | 227 | for i, k := range s.keyList { 228 | if k == name { 229 | s.keyList = append(s.keyList[:i], s.keyList[i+1:]...) 230 | delete(s.keys, name) 231 | return 232 | } 233 | } 234 | } 235 | 236 | // ChildSections returns a list of child sections of current section. 237 | // For example, "[parent.child1]" and "[parent.child12]" are child sections 238 | // of section "[parent]". 239 | func (s *Section) ChildSections() []*Section { 240 | prefix := s.name + "." 241 | children := make([]*Section, 0, 3) 242 | for _, name := range s.f.sectionList { 243 | if strings.HasPrefix(name, prefix) { 244 | children = append(children, s.f.sections[name]) 245 | } 246 | } 247 | return children 248 | } 249 | -------------------------------------------------------------------------------- /vendor/gopkg.in/ini.v1/struct.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Unknwon 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | // License for the specific language governing permissions and limitations 13 | // under the License. 14 | 15 | package ini 16 | 17 | import ( 18 | "bytes" 19 | "errors" 20 | "fmt" 21 | "reflect" 22 | "strings" 23 | "time" 24 | "unicode" 25 | ) 26 | 27 | // NameMapper represents a ini tag name mapper. 28 | type NameMapper func(string) string 29 | 30 | // Built-in name getters. 31 | var ( 32 | // AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE. 33 | AllCapsUnderscore NameMapper = func(raw string) string { 34 | newstr := make([]rune, 0, len(raw)) 35 | for i, chr := range raw { 36 | if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { 37 | if i > 0 { 38 | newstr = append(newstr, '_') 39 | } 40 | } 41 | newstr = append(newstr, unicode.ToUpper(chr)) 42 | } 43 | return string(newstr) 44 | } 45 | // TitleUnderscore converts to format title_underscore. 46 | TitleUnderscore NameMapper = func(raw string) string { 47 | newstr := make([]rune, 0, len(raw)) 48 | for i, chr := range raw { 49 | if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { 50 | if i > 0 { 51 | newstr = append(newstr, '_') 52 | } 53 | chr -= ('A' - 'a') 54 | } 55 | newstr = append(newstr, chr) 56 | } 57 | return string(newstr) 58 | } 59 | ) 60 | 61 | func (s *Section) parseFieldName(raw, actual string) string { 62 | if len(actual) > 0 { 63 | return actual 64 | } 65 | if s.f.NameMapper != nil { 66 | return s.f.NameMapper(raw) 67 | } 68 | return raw 69 | } 70 | 71 | func parseDelim(actual string) string { 72 | if len(actual) > 0 { 73 | return actual 74 | } 75 | return "," 76 | } 77 | 78 | var reflectTime = reflect.TypeOf(time.Now()).Kind() 79 | 80 | // setSliceWithProperType sets proper values to slice based on its type. 81 | func setSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error { 82 | var strs []string 83 | if allowShadow { 84 | strs = key.StringsWithShadows(delim) 85 | } else { 86 | strs = key.Strings(delim) 87 | } 88 | 89 | numVals := len(strs) 90 | if numVals == 0 { 91 | return nil 92 | } 93 | 94 | var vals interface{} 95 | var err error 96 | 97 | sliceOf := field.Type().Elem().Kind() 98 | switch sliceOf { 99 | case reflect.String: 100 | vals = strs 101 | case reflect.Int: 102 | vals, err = key.parseInts(strs, true, false) 103 | case reflect.Int64: 104 | vals, err = key.parseInt64s(strs, true, false) 105 | case reflect.Uint: 106 | vals, err = key.parseUints(strs, true, false) 107 | case reflect.Uint64: 108 | vals, err = key.parseUint64s(strs, true, false) 109 | case reflect.Float64: 110 | vals, err = key.parseFloat64s(strs, true, false) 111 | case reflectTime: 112 | vals, err = key.parseTimesFormat(time.RFC3339, strs, true, false) 113 | default: 114 | return fmt.Errorf("unsupported type '[]%s'", sliceOf) 115 | } 116 | if isStrict { 117 | return err 118 | } 119 | 120 | slice := reflect.MakeSlice(field.Type(), numVals, numVals) 121 | for i := 0; i < numVals; i++ { 122 | switch sliceOf { 123 | case reflect.String: 124 | slice.Index(i).Set(reflect.ValueOf(vals.([]string)[i])) 125 | case reflect.Int: 126 | slice.Index(i).Set(reflect.ValueOf(vals.([]int)[i])) 127 | case reflect.Int64: 128 | slice.Index(i).Set(reflect.ValueOf(vals.([]int64)[i])) 129 | case reflect.Uint: 130 | slice.Index(i).Set(reflect.ValueOf(vals.([]uint)[i])) 131 | case reflect.Uint64: 132 | slice.Index(i).Set(reflect.ValueOf(vals.([]uint64)[i])) 133 | case reflect.Float64: 134 | slice.Index(i).Set(reflect.ValueOf(vals.([]float64)[i])) 135 | case reflectTime: 136 | slice.Index(i).Set(reflect.ValueOf(vals.([]time.Time)[i])) 137 | } 138 | } 139 | field.Set(slice) 140 | return nil 141 | } 142 | 143 | func wrapStrictError(err error, isStrict bool) error { 144 | if isStrict { 145 | return err 146 | } 147 | return nil 148 | } 149 | 150 | // setWithProperType sets proper value to field based on its type, 151 | // but it does not return error for failing parsing, 152 | // because we want to use default value that is already assigned to strcut. 153 | func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error { 154 | switch t.Kind() { 155 | case reflect.String: 156 | if len(key.String()) == 0 { 157 | return nil 158 | } 159 | field.SetString(key.String()) 160 | case reflect.Bool: 161 | boolVal, err := key.Bool() 162 | if err != nil { 163 | return wrapStrictError(err, isStrict) 164 | } 165 | field.SetBool(boolVal) 166 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 167 | durationVal, err := key.Duration() 168 | // Skip zero value 169 | if err == nil && int(durationVal) > 0 { 170 | field.Set(reflect.ValueOf(durationVal)) 171 | return nil 172 | } 173 | 174 | intVal, err := key.Int64() 175 | if err != nil { 176 | return wrapStrictError(err, isStrict) 177 | } 178 | field.SetInt(intVal) 179 | // byte is an alias for uint8, so supporting uint8 breaks support for byte 180 | case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64: 181 | durationVal, err := key.Duration() 182 | // Skip zero value 183 | if err == nil && int(durationVal) > 0 { 184 | field.Set(reflect.ValueOf(durationVal)) 185 | return nil 186 | } 187 | 188 | uintVal, err := key.Uint64() 189 | if err != nil { 190 | return wrapStrictError(err, isStrict) 191 | } 192 | field.SetUint(uintVal) 193 | 194 | case reflect.Float32, reflect.Float64: 195 | floatVal, err := key.Float64() 196 | if err != nil { 197 | return wrapStrictError(err, isStrict) 198 | } 199 | field.SetFloat(floatVal) 200 | case reflectTime: 201 | timeVal, err := key.Time() 202 | if err != nil { 203 | return wrapStrictError(err, isStrict) 204 | } 205 | field.Set(reflect.ValueOf(timeVal)) 206 | case reflect.Slice: 207 | return setSliceWithProperType(key, field, delim, allowShadow, isStrict) 208 | default: 209 | return fmt.Errorf("unsupported type '%s'", t) 210 | } 211 | return nil 212 | } 213 | 214 | func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bool) { 215 | opts := strings.SplitN(tag, ",", 3) 216 | rawName = opts[0] 217 | if len(opts) > 1 { 218 | omitEmpty = opts[1] == "omitempty" 219 | } 220 | if len(opts) > 2 { 221 | allowShadow = opts[2] == "allowshadow" 222 | } 223 | return rawName, omitEmpty, allowShadow 224 | } 225 | 226 | func (s *Section) mapTo(val reflect.Value, isStrict bool) error { 227 | if val.Kind() == reflect.Ptr { 228 | val = val.Elem() 229 | } 230 | typ := val.Type() 231 | 232 | for i := 0; i < typ.NumField(); i++ { 233 | field := val.Field(i) 234 | tpField := typ.Field(i) 235 | 236 | tag := tpField.Tag.Get("ini") 237 | if tag == "-" { 238 | continue 239 | } 240 | 241 | rawName, _, allowShadow := parseTagOptions(tag) 242 | fieldName := s.parseFieldName(tpField.Name, rawName) 243 | if len(fieldName) == 0 || !field.CanSet() { 244 | continue 245 | } 246 | 247 | isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous 248 | isStruct := tpField.Type.Kind() == reflect.Struct 249 | if isAnonymous { 250 | field.Set(reflect.New(tpField.Type.Elem())) 251 | } 252 | 253 | if isAnonymous || isStruct { 254 | if sec, err := s.f.GetSection(fieldName); err == nil { 255 | if err = sec.mapTo(field, isStrict); err != nil { 256 | return fmt.Errorf("error mapping field(%s): %v", fieldName, err) 257 | } 258 | continue 259 | } 260 | } 261 | 262 | if key, err := s.GetKey(fieldName); err == nil { 263 | delim := parseDelim(tpField.Tag.Get("delim")) 264 | if err = setWithProperType(tpField.Type, key, field, delim, allowShadow, isStrict); err != nil { 265 | return fmt.Errorf("error mapping field(%s): %v", fieldName, err) 266 | } 267 | } 268 | } 269 | return nil 270 | } 271 | 272 | // MapTo maps section to given struct. 273 | func (s *Section) MapTo(v interface{}) error { 274 | typ := reflect.TypeOf(v) 275 | val := reflect.ValueOf(v) 276 | if typ.Kind() == reflect.Ptr { 277 | typ = typ.Elem() 278 | val = val.Elem() 279 | } else { 280 | return errors.New("cannot map to non-pointer struct") 281 | } 282 | 283 | return s.mapTo(val, false) 284 | } 285 | 286 | // MapTo maps section to given struct in strict mode, 287 | // which returns all possible error including value parsing error. 288 | func (s *Section) StrictMapTo(v interface{}) error { 289 | typ := reflect.TypeOf(v) 290 | val := reflect.ValueOf(v) 291 | if typ.Kind() == reflect.Ptr { 292 | typ = typ.Elem() 293 | val = val.Elem() 294 | } else { 295 | return errors.New("cannot map to non-pointer struct") 296 | } 297 | 298 | return s.mapTo(val, true) 299 | } 300 | 301 | // MapTo maps file to given struct. 302 | func (f *File) MapTo(v interface{}) error { 303 | return f.Section("").MapTo(v) 304 | } 305 | 306 | // MapTo maps file to given struct in strict mode, 307 | // which returns all possible error including value parsing error. 308 | func (f *File) StrictMapTo(v interface{}) error { 309 | return f.Section("").StrictMapTo(v) 310 | } 311 | 312 | // MapTo maps data sources to given struct with name mapper. 313 | func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error { 314 | cfg, err := Load(source, others...) 315 | if err != nil { 316 | return err 317 | } 318 | cfg.NameMapper = mapper 319 | return cfg.MapTo(v) 320 | } 321 | 322 | // StrictMapToWithMapper maps data sources to given struct with name mapper in strict mode, 323 | // which returns all possible error including value parsing error. 324 | func StrictMapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error { 325 | cfg, err := Load(source, others...) 326 | if err != nil { 327 | return err 328 | } 329 | cfg.NameMapper = mapper 330 | return cfg.StrictMapTo(v) 331 | } 332 | 333 | // MapTo maps data sources to given struct. 334 | func MapTo(v, source interface{}, others ...interface{}) error { 335 | return MapToWithMapper(v, nil, source, others...) 336 | } 337 | 338 | // StrictMapTo maps data sources to given struct in strict mode, 339 | // which returns all possible error including value parsing error. 340 | func StrictMapTo(v, source interface{}, others ...interface{}) error { 341 | return StrictMapToWithMapper(v, nil, source, others...) 342 | } 343 | 344 | // reflectSliceWithProperType does the opposite thing as setSliceWithProperType. 345 | func reflectSliceWithProperType(key *Key, field reflect.Value, delim string) error { 346 | slice := field.Slice(0, field.Len()) 347 | if field.Len() == 0 { 348 | return nil 349 | } 350 | 351 | var buf bytes.Buffer 352 | sliceOf := field.Type().Elem().Kind() 353 | for i := 0; i < field.Len(); i++ { 354 | switch sliceOf { 355 | case reflect.String: 356 | buf.WriteString(slice.Index(i).String()) 357 | case reflect.Int, reflect.Int64: 358 | buf.WriteString(fmt.Sprint(slice.Index(i).Int())) 359 | case reflect.Uint, reflect.Uint64: 360 | buf.WriteString(fmt.Sprint(slice.Index(i).Uint())) 361 | case reflect.Float64: 362 | buf.WriteString(fmt.Sprint(slice.Index(i).Float())) 363 | case reflectTime: 364 | buf.WriteString(slice.Index(i).Interface().(time.Time).Format(time.RFC3339)) 365 | default: 366 | return fmt.Errorf("unsupported type '[]%s'", sliceOf) 367 | } 368 | buf.WriteString(delim) 369 | } 370 | key.SetValue(buf.String()[:buf.Len()-1]) 371 | return nil 372 | } 373 | 374 | // reflectWithProperType does the opposite thing as setWithProperType. 375 | func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error { 376 | switch t.Kind() { 377 | case reflect.String: 378 | key.SetValue(field.String()) 379 | case reflect.Bool: 380 | key.SetValue(fmt.Sprint(field.Bool())) 381 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 382 | key.SetValue(fmt.Sprint(field.Int())) 383 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 384 | key.SetValue(fmt.Sprint(field.Uint())) 385 | case reflect.Float32, reflect.Float64: 386 | key.SetValue(fmt.Sprint(field.Float())) 387 | case reflectTime: 388 | key.SetValue(fmt.Sprint(field.Interface().(time.Time).Format(time.RFC3339))) 389 | case reflect.Slice: 390 | return reflectSliceWithProperType(key, field, delim) 391 | default: 392 | return fmt.Errorf("unsupported type '%s'", t) 393 | } 394 | return nil 395 | } 396 | 397 | // CR: copied from encoding/json/encode.go with modifications of time.Time support. 398 | // TODO: add more test coverage. 399 | func isEmptyValue(v reflect.Value) bool { 400 | switch v.Kind() { 401 | case reflect.Array, reflect.Map, reflect.Slice, reflect.String: 402 | return v.Len() == 0 403 | case reflect.Bool: 404 | return !v.Bool() 405 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 406 | return v.Int() == 0 407 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 408 | return v.Uint() == 0 409 | case reflect.Float32, reflect.Float64: 410 | return v.Float() == 0 411 | case reflectTime: 412 | return v.Interface().(time.Time).IsZero() 413 | case reflect.Interface, reflect.Ptr: 414 | return v.IsNil() 415 | } 416 | return false 417 | } 418 | 419 | func (s *Section) reflectFrom(val reflect.Value) error { 420 | if val.Kind() == reflect.Ptr { 421 | val = val.Elem() 422 | } 423 | typ := val.Type() 424 | 425 | for i := 0; i < typ.NumField(); i++ { 426 | field := val.Field(i) 427 | tpField := typ.Field(i) 428 | 429 | tag := tpField.Tag.Get("ini") 430 | if tag == "-" { 431 | continue 432 | } 433 | 434 | opts := strings.SplitN(tag, ",", 2) 435 | if len(opts) == 2 && opts[1] == "omitempty" && isEmptyValue(field) { 436 | continue 437 | } 438 | 439 | fieldName := s.parseFieldName(tpField.Name, opts[0]) 440 | if len(fieldName) == 0 || !field.CanSet() { 441 | continue 442 | } 443 | 444 | if (tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous) || 445 | (tpField.Type.Kind() == reflect.Struct && tpField.Type.Name() != "Time") { 446 | // Note: The only error here is section doesn't exist. 447 | sec, err := s.f.GetSection(fieldName) 448 | if err != nil { 449 | // Note: fieldName can never be empty here, ignore error. 450 | sec, _ = s.f.NewSection(fieldName) 451 | } 452 | if err = sec.reflectFrom(field); err != nil { 453 | return fmt.Errorf("error reflecting field (%s): %v", fieldName, err) 454 | } 455 | continue 456 | } 457 | 458 | // Note: Same reason as secion. 459 | key, err := s.GetKey(fieldName) 460 | if err != nil { 461 | key, _ = s.NewKey(fieldName, "") 462 | } 463 | if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil { 464 | return fmt.Errorf("error reflecting field (%s): %v", fieldName, err) 465 | } 466 | 467 | } 468 | return nil 469 | } 470 | 471 | // ReflectFrom reflects secion from given struct. 472 | func (s *Section) ReflectFrom(v interface{}) error { 473 | typ := reflect.TypeOf(v) 474 | val := reflect.ValueOf(v) 475 | if typ.Kind() == reflect.Ptr { 476 | typ = typ.Elem() 477 | val = val.Elem() 478 | } else { 479 | return errors.New("cannot reflect from non-pointer struct") 480 | } 481 | 482 | return s.reflectFrom(val) 483 | } 484 | 485 | // ReflectFrom reflects file from given struct. 486 | func (f *File) ReflectFrom(v interface{}) error { 487 | return f.Section("").ReflectFrom(v) 488 | } 489 | 490 | // ReflectFrom reflects data sources from given struct with name mapper. 491 | func ReflectFromWithMapper(cfg *File, v interface{}, mapper NameMapper) error { 492 | cfg.NameMapper = mapper 493 | return cfg.ReflectFrom(v) 494 | } 495 | 496 | // ReflectFrom reflects data sources from given struct. 497 | func ReflectFrom(cfg *File, v interface{}) error { 498 | return ReflectFromWithMapper(cfg, v, nil) 499 | } 500 | -------------------------------------------------------------------------------- /vendor/vendor.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment": "", 3 | "ignore": "test", 4 | "package": [ 5 | { 6 | "checksumSHA1": "2UmMbNHc8FBr98mJFN1k8ISOIHk=", 7 | "path": "github.com/garyburd/redigo/internal", 8 | "revision": "57f1cd7de6175c96b423e7ac2534ff2b39e2ef79", 9 | "revisionTime": "2017-06-15T18:53:09Z" 10 | }, 11 | { 12 | "checksumSHA1": "dGCqjUjHaREgF/BM+u0UdebD4fk=", 13 | "path": "github.com/garyburd/redigo/redis", 14 | "revision": "57f1cd7de6175c96b423e7ac2534ff2b39e2ef79", 15 | "revisionTime": "2017-06-15T18:53:09Z" 16 | }, 17 | { 18 | "checksumSHA1": "ddHQ3AbnzgLL4tpi6FEEWArLCIk=", 19 | "path": "github.com/vmihailenco/msgpack", 20 | "revision": "d91c9f43689d8565046de42f51a19bb80ebb8360", 21 | "revisionTime": "2017-06-22T07:12:44Z" 22 | }, 23 | { 24 | "checksumSHA1": "tOMrkwvdZiNeJDeT/Cjuo7fCpg0=", 25 | "path": "github.com/vmihailenco/msgpack/codes", 26 | "revision": "d91c9f43689d8565046de42f51a19bb80ebb8360", 27 | "revisionTime": "2017-06-22T07:12:44Z" 28 | }, 29 | { 30 | "path": "google.golang.org/appengine/datastore", 31 | "revision": "" 32 | }, 33 | { 34 | "checksumSHA1": "WNjUTH01NMhPWjpwnsaL3SW52Gw=", 35 | "path": "gopkg.in/ini.v1", 36 | "revision": "d3de07a94d22b4a0972deb4b96d790c2c0ce8333", 37 | "revisionTime": "2017-06-02T20:46:24Z" 38 | } 39 | ], 40 | "rootPath": "github.com/ouqiang/delay-queue" 41 | } 42 | --------------------------------------------------------------------------------