|
|
@@ -4,15 +4,16 @@ import (
|
|
|
"encoding/base64"
|
|
|
"flag"
|
|
|
"fmt"
|
|
|
- "github.com/gin-gonic/gin"
|
|
|
- "github.com/gomodule/redigo/redis"
|
|
|
- "github.com/sirupsen/logrus"
|
|
|
"log"
|
|
|
"math/rand"
|
|
|
"net/http"
|
|
|
"os"
|
|
|
"path"
|
|
|
"time"
|
|
|
+
|
|
|
+ "github.com/gin-gonic/gin"
|
|
|
+ "github.com/gomodule/redigo/redis"
|
|
|
+ "github.com/sirupsen/logrus"
|
|
|
)
|
|
|
|
|
|
type Response struct {
|
|
|
@@ -35,7 +36,7 @@ type redisPoolConf struct {
|
|
|
const letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
|
|
const defaultPort int = 8002
|
|
|
-const defaultExpire = 90
|
|
|
+const defaultExpire = 180
|
|
|
const defaultRedisConfig = "127.0.0.1:6379"
|
|
|
|
|
|
const defaultLockPrefix = "myurls:lock:"
|
|
|
@@ -58,7 +59,7 @@ func main() {
|
|
|
|
|
|
port := flag.Int("port", defaultPort, "服务端口")
|
|
|
domain := flag.String("domain", "", "短链接域名,必填项")
|
|
|
- ttl := flag.Int("ttl", defaultExpire, "短链接有效期,单位(天),默认90天。")
|
|
|
+ ttl := flag.Int("ttl", defaultExpire, "短链接有效期,单位(天),默认180天。")
|
|
|
conn := flag.String("conn", defaultRedisConfig, "Redis连接,格式: host:port")
|
|
|
passwd := flag.String("passwd", "", "Redis连接密码")
|
|
|
https := flag.Int("https", 1, "是否返回 https 短链接")
|
|
|
@@ -151,6 +152,90 @@ func main() {
|
|
|
router.Run(fmt.Sprintf(":%d", *port))
|
|
|
}
|
|
|
|
|
|
+// 短链接转长链接
|
|
|
+func shortToLong(shortKey string) string {
|
|
|
+ redisClient = redisPool.Get()
|
|
|
+ defer redisClient.Close()
|
|
|
+
|
|
|
+ longUrl, _ := redis.String(redisClient.Do("get", shortKey))
|
|
|
+
|
|
|
+ // 获取到长链接后,续命1天。每天仅允许续命1次。
|
|
|
+ if longUrl != "" {
|
|
|
+ renew(shortKey)
|
|
|
+ }
|
|
|
+
|
|
|
+ return longUrl
|
|
|
+}
|
|
|
+
|
|
|
+// 长链接转短链接
|
|
|
+func longToShort(longUrl string, ttl int) string {
|
|
|
+ redisClient = redisPool.Get()
|
|
|
+ defer redisClient.Close()
|
|
|
+
|
|
|
+ // 是否生成过该长链接对应短链接
|
|
|
+ _existsKey, _ := redis.String(redisClient.Do("get", longUrl))
|
|
|
+ if _existsKey != "" {
|
|
|
+ _, _ = redisClient.Do("expire", _existsKey, ttl)
|
|
|
+
|
|
|
+ log.Println("Hit cache: " + _existsKey)
|
|
|
+ return _existsKey
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重试三次
|
|
|
+ var shortKey string
|
|
|
+ for i := 0; i < 3; i++ {
|
|
|
+ shortKey = generate(7)
|
|
|
+
|
|
|
+ _existsLongUrl, _ := redis.String(redisClient.Do("get", shortKey))
|
|
|
+ if _existsLongUrl == "" {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if shortKey != "" {
|
|
|
+ _, _ = redisClient.Do("mset", shortKey, longUrl, longUrl, shortKey)
|
|
|
+
|
|
|
+ _, _ = redisClient.Do("expire", shortKey, ttl)
|
|
|
+ _, _ = redisClient.Do("expire", longUrl, secondsPerDay)
|
|
|
+ }
|
|
|
+
|
|
|
+ return shortKey
|
|
|
+}
|
|
|
+
|
|
|
+// 续命
|
|
|
+func renew(shortKey string) {
|
|
|
+ redisClient = redisPool.Get()
|
|
|
+ defer redisClient.Close()
|
|
|
+
|
|
|
+ // 加锁
|
|
|
+ lockKey := defaultLockPrefix + shortKey
|
|
|
+ lock, _ := redis.Int(redisClient.Do("setnx", lockKey, 1))
|
|
|
+ if lock == 1 {
|
|
|
+ // 设置锁过期时间
|
|
|
+ _, _ = redisClient.Do("expire", lockKey, defaultRenewal*secondsPerDay)
|
|
|
+
|
|
|
+ // 续命
|
|
|
+ ttl, _ := redis.Int(redisClient.Do("ttl", shortKey))
|
|
|
+ if ttl != -1 {
|
|
|
+ _, _ = redisClient.Do("expire", shortKey, ttl+defaultRenewal*secondsPerDay)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 产生一个63位随机整数
|
|
|
+func generate(bits int) string {
|
|
|
+ b := make([]byte, bits)
|
|
|
+
|
|
|
+ currentTime := time.Now().UnixNano()
|
|
|
+ rand.Seed(currentTime)
|
|
|
+
|
|
|
+ for i := range b {
|
|
|
+ b[i] = letterBytes[rand.Intn(len(letterBytes))]
|
|
|
+ }
|
|
|
+ return string(b)
|
|
|
+}
|
|
|
+
|
|
|
+// 定义 logger
|
|
|
func Logger() *logrus.Logger {
|
|
|
logFilePath := ""
|
|
|
if dir, err := os.Getwd(); err == nil {
|
|
|
@@ -191,6 +276,7 @@ func Logger() *logrus.Logger {
|
|
|
return logger
|
|
|
}
|
|
|
|
|
|
+// 文件日志
|
|
|
func LoggerToFile() gin.HandlerFunc {
|
|
|
logger := Logger()
|
|
|
return func(c *gin.Context) {
|
|
|
@@ -230,81 +316,19 @@ func LoggerToFile() gin.HandlerFunc {
|
|
|
// logger.Info(string(logJson))
|
|
|
|
|
|
logger.WithFields(logrus.Fields{
|
|
|
- "startTime": logMap["startTime"],
|
|
|
- "endTime": logMap["endTime"],
|
|
|
+ "startTime": logMap["startTime"],
|
|
|
+ "endTime": logMap["endTime"],
|
|
|
"latencyTime": logMap["latencyTime"],
|
|
|
- "reqMethod": logMap["reqMethod"],
|
|
|
- "reqUri": logMap["reqUri"],
|
|
|
- "statusCode": logMap["statusCode"],
|
|
|
- "clientIP": logMap["clientIP"],
|
|
|
- "clientUA": logMap["clientUA"],
|
|
|
+ "reqMethod": logMap["reqMethod"],
|
|
|
+ "reqUri": logMap["reqUri"],
|
|
|
+ "statusCode": logMap["statusCode"],
|
|
|
+ "clientIP": logMap["clientIP"],
|
|
|
+ "clientUA": logMap["clientUA"],
|
|
|
}).Info()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 短链接转长链接
|
|
|
-func shortToLong(shortKey string) string {
|
|
|
- redisClient = redisPool.Get()
|
|
|
- defer redisClient.Close()
|
|
|
-
|
|
|
- longUrl, _ := redis.String(redisClient.Do("get", shortKey))
|
|
|
-
|
|
|
- // 获取到长链接后,续命1天。每天仅允许续命1次。
|
|
|
- if longUrl != "" {
|
|
|
- renew(shortKey)
|
|
|
- }
|
|
|
-
|
|
|
- return longUrl
|
|
|
-}
|
|
|
-
|
|
|
-// 长链接转短链接
|
|
|
-func longToShort(longUrl string, ttl int) string {
|
|
|
- redisClient = redisPool.Get()
|
|
|
- defer redisClient.Close()
|
|
|
-
|
|
|
- // 是否生成过该长链接对应短链接
|
|
|
- _existsKey, _ := redis.String(redisClient.Do("get", longUrl))
|
|
|
- if _existsKey != "" {
|
|
|
- _, _ = redisClient.Do("expire", _existsKey, ttl)
|
|
|
-
|
|
|
- log.Println("Hit cache: " + _existsKey)
|
|
|
- return _existsKey
|
|
|
- }
|
|
|
-
|
|
|
- // 重试三次
|
|
|
- var shortKey string
|
|
|
- for i := 0; i < 3; i++ {
|
|
|
- shortKey = generate(7)
|
|
|
-
|
|
|
- _existsLongUrl, _ := redis.String(redisClient.Do("get", shortKey))
|
|
|
- if _existsLongUrl == "" {
|
|
|
- break
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if shortKey != "" {
|
|
|
- _, _ = redisClient.Do("mset", shortKey, longUrl, longUrl, shortKey)
|
|
|
-
|
|
|
- _, _ = redisClient.Do("expire", shortKey, ttl)
|
|
|
- _, _ = redisClient.Do("expire", longUrl, secondsPerDay)
|
|
|
- }
|
|
|
-
|
|
|
- return shortKey
|
|
|
-}
|
|
|
-
|
|
|
-// 产生一个63位随机整数
|
|
|
-func generate(bits int) string {
|
|
|
- b := make([]byte, bits)
|
|
|
-
|
|
|
- currentTime := time.Now().UnixNano()
|
|
|
- rand.Seed(currentTime)
|
|
|
-
|
|
|
- for i := range b {
|
|
|
- b[i] = letterBytes[rand.Intn(len(letterBytes))]
|
|
|
- }
|
|
|
- return string(b)
|
|
|
-}
|
|
|
-
|
|
|
+// redis 连接池
|
|
|
func initRedisPool() {
|
|
|
// 建立连接池
|
|
|
redisPool = &redis.Pool{
|
|
|
@@ -326,22 +350,3 @@ func initRedisPool() {
|
|
|
},
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-func renew(shortKey string) {
|
|
|
- redisClient = redisPool.Get()
|
|
|
- defer redisClient.Close()
|
|
|
-
|
|
|
- // 加锁
|
|
|
- lockKey := defaultLockPrefix + shortKey
|
|
|
- lock, _ := redis.Int(redisClient.Do("setnx", lockKey, 1))
|
|
|
- if lock == 1 {
|
|
|
- // 设置锁过期时间
|
|
|
- _, _ = redisClient.Do("expire", lockKey, defaultRenewal*secondsPerDay)
|
|
|
-
|
|
|
- // 续命
|
|
|
- ttl, _ := redis.Int(redisClient.Do("ttl", shortKey))
|
|
|
- if ttl != -1 {
|
|
|
- _, _ = redisClient.Do("expire", shortKey, ttl+defaultRenewal*secondsPerDay)
|
|
|
- }
|
|
|
- }
|
|
|
-}
|