forked from zimulala/goqless
/
goqless.go
162 lines (141 loc) · 3.24 KB
/
goqless.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// reference: https://github.com/seomoz/qless-py
package goqless
import (
"bytes"
"crypto/md5"
"crypto/rand"
"encoding/json"
"fmt"
"github.com/garyburd/redigo/redis"
mrand "math/rand"
"os"
"bitbucket.org/kardianos/osext"
"strconv"
"strings"
"time"
"unicode"
"unicode/utf8"
)
// type Opts map[string]interface{}
// func (o Opts) Get(name string, dfault interface{}) interface{} {
// if v, ok := o[name]; ok {
// return v
// }
// return dfault
// }
// represents a string slice with special json unmarshalling
type StringSlice []string
var workerNameStr string
func init() {
hn, err := os.Hostname()
if err != nil {
hn = os.Getenv("HOSTNAME")
}
if hn == "" {
hn = "localhost"
}
workerNameStr = fmt.Sprintf("%s-%d", hn, os.Getpid())
}
func GetCurrentDir() (string, error) {
dir, err := osext.Executable()
if err != nil {
return "", err
}
dir = string(dir[:len(dir)-1])
pos := strings.LastIndex(dir, "/")
dir = string(dir[:pos])
return dir, nil
}
func (s *StringSlice) UnmarshalJSON(data []byte) error {
// because tables and arrays are equal in LUA,
// an empty array would be presented as "{}".
if bytes.Equal(data, []byte("{}")) {
*s = []string{}
return nil
}
var str []string
err := json.Unmarshal(data, &str)
if err != nil {
return err
}
*s = str
return nil
}
// Generates a jid
func generateJID() string {
hasher := md5.New()
uuid := make([]byte, 16)
n, err := rand.Read(uuid)
if err != nil || n != len(uuid) {
src := mrand.NewSource(time.Now().UnixNano())
r := mrand.New(src)
for n, _ := range uuid {
uuid[n] = byte(r.Int())
}
}
hasher.Write([]byte(workerNameStr))
hasher.Write(uuid)
hasher.Write([]byte(time.Now().String()))
return fmt.Sprintf("%x", hasher.Sum(nil))
}
// returns a timestamp used in LUA calls
func timestamp() int64 {
return time.Now().UTC().Unix()
}
// returns a worker name for this machine/process
func workerName() string {
return workerNameStr
}
// makes the first character of a string upper case
func ucfirst(s string) string {
if s == "" {
return ""
}
r, n := utf8.DecodeRuneInString(s)
return string(unicode.ToUpper(r)) + s[n:]
}
// marshals a value. if the value happens to be
// a string or []byte, just return it.
func marshal(i interface{}) []byte {
//switch v := i.(type) {
//case []byte:
// return v
//case string:
// return []byte(v)
//}
byts, err := json.Marshal(i)
if err != nil {
return nil
}
return byts
}
// Bool is a helper that converts a command reply to a boolean. If err is not
// equal to nil, then Bool returns false, err. Otherwise Bool converts the
// reply to boolean as follows:
//
// Reply type Result
// integer value != 0, nil
// bulk strconv.ParseBool(reply) or r != "False", nil
// nil false, ErrNil
// other false, error
func Bool(reply interface{}, err error) (bool, error) {
if err != nil {
return false, err
}
switch reply := reply.(type) {
case int64:
return reply != 0, nil
case []byte:
r := string(reply)
b, err := strconv.ParseBool(r)
if err != nil {
return r != "False", nil
}
return b, err
case nil:
return false, redis.ErrNil
case redis.Error:
return false, reply
}
return false, fmt.Errorf("redigo: unexpected type for Bool, got type %T", reply)
}