-
Notifications
You must be signed in to change notification settings - Fork 2
/
redis.go
141 lines (119 loc) · 3.18 KB
/
redis.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
package main
import (
"crypto/sha1"
"encoding/json"
"errors"
"fmt"
"github.com/catinello/base62"
"github.com/go-redis/redis"
"strings"
"time"
)
const (
// URLIDKEY Redis auto incr key
URLIDKEY = "next.url.id"
// ShortlinkKey The Key for short_link to url
ShortlinkKey = "shortlink:%s:url"
// URLHashKey The Key for url to short_link
URLHashKey = "urlhash:%s:url"
// ShortlinkDetailKey The Key for short_link to short_link detail
ShortlinkDetailKey = "shortlink:%s:detail"
)
type RedisClient struct {
Cli *redis.Client
}
// ShortlinkInfo short_link info
type ShortlinkInfo struct {
URL string `json:"url"`
CreatedAt string `json:"created_at"`
ExpirationInMinutes int64 `json:"expiration_in_minutes"`
}
func NewRedisCli(addr string, pass string, db int) *RedisClient {
c := redis.NewClient(&redis.Options{
Addr: addr,
Password: pass,
DB: db,
})
if _, err := c.Ping().Result(); err != nil {
panic("create redis client failed")
}
return &RedisClient{Cli: c}
}
func (cli *RedisClient) Shorten(url string, exp int64) (string, error) {
if strings.Index(url, "http") != 0 {
url = "https://" + url
}
shaUtil := sha1.New()
shaUtil.Write([]byte(url))
hashUrl := fmt.Sprintf("%x", shaUtil.Sum(nil))
d, err := cli.Cli.Get(fmt.Sprintf(URLHashKey, hashUrl)).Result()
if err == redis.Nil {
// url not exist, nothing to do
} else if err != nil {
return "", err
} else {
if d == "{}" {
// url expired, nothing to do
} else {
return d, nil
}
}
// Incr global counter
if err := cli.Cli.Incr(URLIDKEY).Err(); err != nil {
return "", err
}
// get global counter
urlId, err := cli.Cli.Get(URLIDKEY).Int()
if err != nil {
return "", err
}
// convert int to short link
eid := base62.Encode(urlId)
// set key fot short link to url
err = cli.Cli.Set(fmt.Sprintf(ShortlinkKey, eid), url, time.Minute*time.Duration(exp)).Err()
if err != nil {
return "", err
}
// set key for sha1(url) to short link
err = cli.Cli.Set(fmt.Sprintf(URLHashKey, hashUrl), eid, time.Minute*time.Duration(exp)).Err()
if err != nil {
return "", err
}
// set detail for short link
shortLinkInfo := &ShortlinkInfo{
URL: url,
ExpirationInMinutes: exp,
CreatedAt: time.Now().String(),
}
// serialize short link info
jsonStr, err := json.Marshal(shortLinkInfo)
if err != nil {
return "", err
}
// set key for short link to detail
err = cli.Cli.Set(fmt.Sprintf(ShortlinkDetailKey, eid), jsonStr, time.Minute*time.Duration(exp)).Err()
if err != nil {
return "", err
}
return eid, err
}
func (cli *RedisClient) ShortlinkInfo(eid string) (interface{}, error) {
jsonStr, err := cli.Cli.Get(fmt.Sprintf(ShortlinkDetailKey, eid)).Result()
if err == redis.Nil {
return nil, StatusError{Code: 404, Err: errors.New("unknown short url")}
} else if err != nil {
return nil, err
} else {
return jsonStr, nil
}
}
func (cli *RedisClient) UnShorten(eid string) (string, error) {
jsonStr, err := cli.Cli.Get(fmt.Sprintf(ShortlinkKey, eid)).Result()
if err == redis.Nil {
return "", StatusError{Code: 404, Err: fmt.Errorf("unknown this short link")}
} else if err != nil {
return "", err
} else {
return jsonStr, nil
}
}