Skip to content

Commit c7525c8

Browse files
committed
Add .env & move webserver to a new package
1 parent f19490b commit c7525c8

File tree

9 files changed

+180
-187
lines changed

9 files changed

+180
-187
lines changed

.env.example

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Redis_Addr=""
2+
Redis_Pwd=""

go.mod

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ require (
2020
github.com/go-playground/validator/v10 v10.10.1 // indirect
2121
github.com/golang/protobuf v1.5.2 // indirect
2222
github.com/hashicorp/hcl v1.0.0 // indirect
23+
github.com/joho/godotenv v1.4.0 // indirect
2324
github.com/json-iterator/go v1.1.12 // indirect
2425
github.com/leodido/go-urn v1.2.1 // indirect
2526
github.com/magiconair/properties v1.8.5 // indirect
@@ -42,4 +43,4 @@ require (
4243
gopkg.in/yaml.v2 v2.4.0 // indirect
4344
)
4445

45-
replace "internal" => "../../internal"
46+
replace internal => ../../internal

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
254254
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
255255
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
256256
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
257+
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
258+
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
257259
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
258260
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
259261
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=

internal/cache/cache.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ import (
66
"time"
77

88
"github.com/go-redis/redis/v8"
9-
"github.com/steveyiyo/url-shortener/internal/tools"
9+
"github.com/steveyiyo/url-shortener/package/tools"
1010
)
1111

1212
var Redis *redis.Client
1313

1414
// Init Client
15-
func InitRedis() {
15+
func InitRedis(Redis_Addr, Redis_Pwd string) {
1616
Redis = redis.NewClient(&redis.Options{
17-
Addr: "127.0.0.1:6379",
18-
Password: "",
17+
Addr: Redis_Addr,
18+
Password: Redis_Pwd,
1919
DB: 0,
2020
})
2121
}

internal/cache/cache_test.go

+2-48
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,14 @@
1-
package cache_test
1+
package cache
22

33
import (
4-
"context"
54
"fmt"
6-
"log"
75
"testing"
86
"time"
9-
10-
"github.com/go-redis/redis/v8"
11-
"github.com/steveyiyo/url-shortener/internal/tools"
127
)
138

14-
var Redis *redis.Client
15-
16-
// Init Client
17-
func InitRedis() {
18-
Redis = redis.NewClient(&redis.Options{
19-
Addr: "127.0.0.1:6379",
20-
Password: "",
21-
DB: 0,
22-
})
23-
}
24-
25-
// Add data to Redis
26-
func AddData(key string, value string, second time.Duration) bool {
27-
ctx := context.Background()
28-
29-
err := Redis.Set(ctx, key, value, second*time.Second).Err()
30-
return tools.ErrCheck(err)
31-
}
32-
33-
// Query data from Redis
34-
func QueryData(key string) (bool, string) {
35-
ctx := context.Background()
36-
37-
var return_status bool
38-
var return_value string
39-
40-
value, err := Redis.Get(ctx, key).Result()
41-
tools.ErrCheck(err)
42-
43-
if err == redis.Nil {
44-
return_status = false
45-
return_value = ""
46-
} else if !tools.ErrCheck(err) {
47-
log.Println(err)
48-
} else {
49-
return_status = true
50-
return_value = value
51-
}
52-
return return_status, return_value
53-
}
54-
559
// It's a test function.
5610
func TestMain(t *testing.T) {
57-
InitRedis()
11+
InitRedis("127.0.0.1", "")
5812
AddData("hi", "pong", 5)
5913
status, data := QueryData("hi")
6014
if status {

internal/database/database.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@ import (
55
"time"
66

77
_ "github.com/mattn/go-sqlite3"
8-
"github.com/steveyiyo/url-shortener/internal/tools"
8+
"github.com/steveyiyo/url-shortener/package/tools"
99
)
1010

1111
var db *sql.DB
1212

1313
func Init() {
1414
db, _ = sql.Open("sqlite3", "./data.db")
15+
createTable()
1516
}
1617

1718
// Create file and table
18-
func CreateTable() {
19+
func createTable() {
1920
// Create Table
2021
stmt, err := db.Prepare("CREATE TABLE IF NOT EXISTS urlinfo (ShortID string, Link string, Expireat string);")
2122
tools.ErrCheck(err)

internal/webserver/webserver.go

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package webserver
2+
3+
import (
4+
"github.com/gin-contrib/cors"
5+
"github.com/gin-gonic/gin"
6+
"github.com/steveyiyo/url-shortener/internal/cache"
7+
"github.com/steveyiyo/url-shortener/internal/database"
8+
"github.com/steveyiyo/url-shortener/package/tools"
9+
)
10+
11+
// Predefined variable and struct
12+
type Config struct {
13+
Host string `yaml:"Host"`
14+
Port string `yaml:"Port"`
15+
}
16+
17+
type Result struct {
18+
Status bool
19+
Message string
20+
}
21+
22+
var Listen string
23+
var Host string
24+
var Port string
25+
var URL string
26+
27+
type Data struct {
28+
URL string `json:"url"`
29+
ExpiredAt string `json:"expireAt"`
30+
}
31+
32+
type URLid struct {
33+
ID string `json:"id"`
34+
ShortURL string `json:"shortUrl"`
35+
}
36+
37+
func Init(Init_Listen, Init_Host, Init_Port, Init_URL string) {
38+
39+
Listen = Init_Listen
40+
Host = Init_Host
41+
Port = Init_Port
42+
URL = Init_URL
43+
44+
// Init Web Server
45+
gin.SetMode(gin.ReleaseMode)
46+
route := gin.New()
47+
route.Use(gin.Logger(), gin.Recovery())
48+
49+
config := cors.DefaultConfig()
50+
config.AllowOrigins = []string{"*"}
51+
52+
route.Use(cors.New(config))
53+
route.GET("/:ShortID", RedirectURL)
54+
route.POST("/api/v1/urls", AddURL)
55+
56+
route.Run(Listen + ":" + Port)
57+
}
58+
59+
// AddURL
60+
func AddURL(c *gin.Context) {
61+
// Get JSON Data
62+
var data Data
63+
c.BindJSON(&data)
64+
65+
// Init return result
66+
var return_data URLid
67+
68+
// Check Time and Convert to Unix format
69+
isTimestampOk, timestamp := tools.ConvertTimetoUnix(data.ExpiredAt)
70+
71+
// Check Limit IP
72+
limit_check, _ := cache.QueryData(c.ClientIP())
73+
74+
// Check Limit
75+
if !limit_check {
76+
// Check Link and Time Valid
77+
if tools.CheckLinkValid(data.URL) && (isTimestampOk) {
78+
79+
// Random Short ID
80+
ShortID := tools.RandomString(5)
81+
82+
// Add data to DB
83+
database.AddData(ShortID, data.URL, timestamp)
84+
85+
// Add Limit IP to Redis
86+
cache.AddData(c.ClientIP(), "", 5)
87+
88+
// Return result
89+
return_data = URLid{ID: ShortID, ShortURL: URL + ShortID}
90+
c.JSON(200, return_data)
91+
} else {
92+
// Return result
93+
return_data = URLid{ID: "", ShortURL: ""}
94+
c.JSON(400, return_data)
95+
}
96+
} else {
97+
// Return result
98+
var return_result Result
99+
return_result = Result{Status: false, Message: "Too many requests, please try again later."}
100+
c.JSON(400, return_result)
101+
}
102+
}
103+
104+
// RedirectURL
105+
func RedirectURL(c *gin.Context) {
106+
107+
// Get Short ID from URL
108+
ID := c.Param("ShortID")
109+
110+
// Query Link in Redis
111+
isExist, URL := cache.QueryData(ID)
112+
if !isExist {
113+
// Query Link in DB
114+
Check, Link := database.QueryData(ID)
115+
if Check {
116+
// Add hit to Redis
117+
cache.AddData(ID, Link, 30)
118+
c.Redirect(301, Link)
119+
} else {
120+
// Add miss link to Redis (Not Found or Expire)
121+
cache.AddData(ID, "MISS", 30)
122+
123+
// Return result
124+
var return_result Result
125+
return_result = Result{Status: false, Message: "Not Found."}
126+
c.JSON(404, return_result)
127+
}
128+
} else {
129+
if URL == "MISS" {
130+
// Return result
131+
var return_result Result
132+
return_result = Result{Status: false, Message: "Not Found."}
133+
c.JSON(404, return_result)
134+
} else {
135+
c.Redirect(301, URL)
136+
}
137+
}
138+
}

0 commit comments

Comments
 (0)