update file
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
bin/tinyurl
|
bin/tinyurl
|
||||||
|
test/
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
FROM golang:alpine as builder
|
FROM golang:alpine as builder
|
||||||
|
LABEL anther="github.com/Sakurasan"
|
||||||
# RUN apt install -y git make
|
# RUN apt install -y git make
|
||||||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && apk update && apk --no-cache add make git
|
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && apk update && apk --no-cache add make git
|
||||||
LABEL anther="cjun"
|
|
||||||
WORKDIR /tinyurl
|
WORKDIR /tinyurl
|
||||||
COPY . /tinyurl
|
COPY . /tinyurl
|
||||||
ENV GO111MODULE=on
|
ENV GO111MODULE=on
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ server:
|
|||||||
data:
|
data:
|
||||||
database:
|
database:
|
||||||
driver: mysql
|
driver: mysql
|
||||||
source: root:root@tcp(127.0.0.1:3306)/test
|
source: tinyurl:tinyurl@tcp(127.0.0.1:3306)/tinyurl?charset=utf8mb4&parseTime=True&loc=Local
|
||||||
redis:
|
redis:
|
||||||
addr: 127.0.0.1:6379
|
addr: 127.0.0.1:6379
|
||||||
read_timeout: 0.2s
|
read_timeout: 0.2s
|
||||||
@@ -16,8 +16,8 @@ log:
|
|||||||
development: true
|
development: true
|
||||||
rotate:
|
rotate:
|
||||||
filename: ./app.log
|
filename: ./app.log
|
||||||
maxsize: 10
|
maxsize: 10 #Mb
|
||||||
maxage: 7
|
maxage: 7 #day
|
||||||
maxbackups:
|
# maxbackups:
|
||||||
localtime:
|
# localtime:
|
||||||
compress:
|
# compress:
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
2
dist/index.html
vendored
2
dist/index.html
vendored
@@ -5,7 +5,7 @@
|
|||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>TinyUrl</title>
|
<title>TinyUrl</title>
|
||||||
<script type="module" crossorigin src="/assets/index.b2aedd95.js"></script>
|
<script type="module" crossorigin src="/assets/index.a180db26.js"></script>
|
||||||
<link rel="stylesheet" href="/assets/index.cf87a41a.css">
|
<link rel="stylesheet" href="/assets/index.cf87a41a.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
42
docker-compose.yml
Normal file
42
docker-compose.yml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
tinyurl:
|
||||||
|
# The official v2 Traefik docker image
|
||||||
|
image: mirrors2/tinyurl
|
||||||
|
container_name: tinyurl
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "2830:2830"
|
||||||
|
# volumes: #default log term
|
||||||
|
# - $PWD/log:/app/tinyurl/log
|
||||||
|
# - config.yml:/app/tinyurl/configs/config.yml
|
||||||
|
entrypoint:
|
||||||
|
- DSN=tinyurl:tinyurl@tcp(db:3306)/tinyurl?charset=utf8mb4
|
||||||
|
logging:
|
||||||
|
driver: "json-file"
|
||||||
|
options:
|
||||||
|
max-size: "10m"
|
||||||
|
|
||||||
|
tinyurl_db:
|
||||||
|
image: mariadb
|
||||||
|
container_name: tinyurl_db
|
||||||
|
restart: always
|
||||||
|
networks:
|
||||||
|
- gitea
|
||||||
|
expose:
|
||||||
|
- 3306
|
||||||
|
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||||
|
environment:
|
||||||
|
- MYSQL_ROOT_PASSWORD=supermen
|
||||||
|
- MYSQL_DATABASE=tinyurl
|
||||||
|
- MYSQL_USER=tinyurl
|
||||||
|
- MYSQL_PASSWORD=tinyurl
|
||||||
|
- TZ=Asia/Shanghai
|
||||||
|
volumes:
|
||||||
|
- ./db:/var/lib/mysql
|
||||||
|
# 标准 Linux 系统下使用
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
# healthcheck:
|
||||||
|
# test: ["CMD-SHELL", "/etc/init.d/mysql status"]
|
||||||
|
# interval: 30s
|
||||||
13
pkg/db/db.go
13
pkg/db/db.go
@@ -1,6 +1,7 @@
|
|||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gorm.io/driver/mysql"
|
"gorm.io/driver/mysql"
|
||||||
@@ -13,10 +14,11 @@ var (
|
|||||||
|
|
||||||
type TinyUrl struct {
|
type TinyUrl struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
LongUrl string `gorm:"size:200"`
|
LongUrl string `gorm:"size:7713"`
|
||||||
ShortUrl string `gorm:"size:50"`
|
ShortUrl string `gorm:"size:20"`
|
||||||
ExpireTime time.Time
|
ExpireTime time.Time
|
||||||
Counter float64
|
Counter float64
|
||||||
|
AddIP string
|
||||||
}
|
}
|
||||||
|
|
||||||
type URLDetail struct {
|
type URLDetail struct {
|
||||||
@@ -27,7 +29,12 @@ type URLDetail struct {
|
|||||||
|
|
||||||
func InitDb() {
|
func InitDb() {
|
||||||
// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
|
// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
|
||||||
dsn := "tinyurl:tinyurl@tcp(42.192.36.14:3306)/tinyurl?charset=utf8mb4&parseTime=True&loc=Local"
|
var dsn string
|
||||||
|
if len(os.Getenv("DSN")) > 1 {
|
||||||
|
dsn = os.Getenv("DSN")
|
||||||
|
} else {
|
||||||
|
dsn = "tinyurl:tinyurl@tcp(42.192.36.14:3306)/tinyurl?charset=utf8mb4&parseTime=True&loc=Local"
|
||||||
|
}
|
||||||
var err error
|
var err error
|
||||||
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -85,11 +85,11 @@ func getConsoleEncoder() zapcore.Encoder {
|
|||||||
func getFileWriter(c config.Rotate) zapcore.WriteSyncer {
|
func getFileWriter(c config.Rotate) zapcore.WriteSyncer {
|
||||||
logger := &lumberjack.Logger{
|
logger := &lumberjack.Logger{
|
||||||
Filename: c.Filename,
|
Filename: c.Filename,
|
||||||
MaxSize: c.MaxSize,
|
MaxSize: c.MaxSize, //Mb
|
||||||
MaxAge: c.MaxAge,
|
MaxAge: c.MaxAge, //days
|
||||||
MaxBackups: c.MaxBackups,
|
MaxBackups: c.MaxBackups, //int backup maximum number of old log files
|
||||||
LocalTime: c.LocalTime,
|
LocalTime: c.LocalTime, //bool backup files is the computer's local time
|
||||||
Compress: c.Compress,
|
Compress: c.Compress, //bool
|
||||||
}
|
}
|
||||||
return zapcore.AddSync(logger)
|
return zapcore.AddSync(logger)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import (
|
|||||||
func Route(f *flamego.Flame) {
|
func Route(f *flamego.Flame) {
|
||||||
f.Get("/version", auth.Basic("admin", "admin"), func() string { return "1.1.1" })
|
f.Get("/version", auth.Basic("admin", "admin"), func() string { return "1.1.1" })
|
||||||
// f.Get("/{url: **, capture: 10}", tinyurl.TinyurlHandler)
|
// f.Get("/{url: **, capture: 10}", tinyurl.TinyurlHandler)
|
||||||
f.Get("/{url: **, capture: 10}", tinyurl.TinyUtlTo)
|
f.Get("/{url: **, capture: 10}", tinyurl.TinyUrlTo)
|
||||||
f.Router.Any("/api/v1/tiny", binding.JSON(tinyurl.Param{}), tinyurl.TinyUrl)
|
f.Post("/api/v1/tiny", binding.JSON(tinyurl.Param{}), tinyurl.TinyUrl)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"tinyurl/pkg/base62"
|
"tinyurl/pkg/base62"
|
||||||
"tinyurl/pkg/config"
|
"tinyurl/pkg/config"
|
||||||
@@ -53,18 +54,15 @@ func TinyUrl(c flamego.Context, w http.ResponseWriter, form Param, errs binding.
|
|||||||
_, _ = c.ResponseWriter().Write([]byte(fmt.Sprintf("Oops! Error occurred: %v", err)))
|
_, _ = c.ResponseWriter().Write([]byte(fmt.Sprintf("Oops! Error occurred: %v", err)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !strings.HasPrefix(form.LongUrl, "http://") || !strings.HasPrefix(form.LongUrl, "https://") {
|
||||||
|
form.LongUrl = "http://" + form.LongUrl
|
||||||
|
}
|
||||||
logger.Info(c.Request().Context(), form.LongUrl)
|
logger.Info(c.Request().Context(), form.LongUrl)
|
||||||
var tm = data.TinyUrl{}
|
var tm = data.TinyUrl{}
|
||||||
tm.LongUrl = form.LongUrl
|
tm.LongUrl = form.LongUrl
|
||||||
tm.ShortUrl = base62.TinyUrl(form.LongUrl + time.Now().String())
|
tm.ShortUrl = base62.TinyUrl(form.LongUrl + "?" + time.Now().String())
|
||||||
if err := db.Create(&tm).Error; err != nil {
|
if err := db.Create(&tm).Error; err != nil {
|
||||||
logger.Info(c.Request().Context(), err.Error())
|
logger.Info(c.Request().Context(), err.Error())
|
||||||
// bytejson, _ := json.Marshal(map[string]interface{}{
|
|
||||||
// "code": http.StatusBadGateway,
|
|
||||||
// "msg": "please try again",
|
|
||||||
// })
|
|
||||||
// io.WriteString(c.ResponseWriter(), string(bytejson))
|
|
||||||
// return
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
"code": http.StatusBadGateway,
|
"code": http.StatusBadGateway,
|
||||||
@@ -78,19 +76,10 @@ func TinyUrl(c flamego.Context, w http.ResponseWriter, form Param, errs binding.
|
|||||||
"msg": "success",
|
"msg": "success",
|
||||||
"shortUrl": cfg.Server.Domain + tm.ShortUrl,
|
"shortUrl": cfg.Server.Domain + tm.ShortUrl,
|
||||||
})
|
})
|
||||||
// bytejson, err := json.Marshal(map[string]interface{}{
|
|
||||||
// "code": http.StatusOK,
|
|
||||||
// "msg": "success",
|
|
||||||
// "shortUrl": tm.ShortUrl,
|
|
||||||
// })
|
|
||||||
// if err != nil {
|
|
||||||
// logger.Error(c.Request().Context(), err.Error())
|
|
||||||
// }
|
|
||||||
// io.WriteString(c.ResponseWriter(), string(bytejson))
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TinyUtlTo(c flamego.Context, logger *log.Logger, db *gorm.DB, l *lru.Cache, cfg *config.Config) {
|
func TinyUrlTo(c flamego.Context, logger *log.Logger, db *gorm.DB, l *lru.Cache, cfg *config.Config) {
|
||||||
tiny := c.Param("url")
|
tiny := c.Param("url")
|
||||||
if v, ok := l.Get(tiny); ok {
|
if v, ok := l.Get(tiny); ok {
|
||||||
c.Redirect(v.(string), http.StatusFound)
|
c.Redirect(v.(string), http.StatusFound)
|
||||||
|
|||||||
24
tests/dl.go
24
tests/dl.go
@@ -1,24 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
dlpath := "http://pan.oneisall.xyz/Outline.apk"
|
|
||||||
req, _ := http.NewRequest(http.MethodHead, dlpath, nil)
|
|
||||||
rsp, _ := http.DefaultClient.Do(req)
|
|
||||||
defer rsp.Body.Close()
|
|
||||||
fmt.Println(rsp.Status)
|
|
||||||
// dump, _ := httputil.DumpResponse(rsp, false)
|
|
||||||
// fmt.Println(string(dump))
|
|
||||||
// if rsp.Header != nil {
|
|
||||||
// fmt.Printf("%v", rsp.Header)
|
|
||||||
for k, v := range rsp.Header {
|
|
||||||
fmt.Println(k, v)
|
|
||||||
}
|
|
||||||
fmt.Println(rsp.Header.Get("Content-Length"))
|
|
||||||
fmt.Println(rsp.Header.Get("Accept-Ranges"))
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httputil"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
mux := http.NewServeMux()
|
|
||||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
bytereq, _ := httputil.DumpRequest(r, true)
|
|
||||||
bytebody, _ := io.ReadAll(r.Body)
|
|
||||||
log.Println(string(bytereq))
|
|
||||||
m := map[string]interface{}{
|
|
||||||
"host": r.Host,
|
|
||||||
"requestUrl": r.RequestURI,
|
|
||||||
"proto": r.Proto,
|
|
||||||
"path": r.URL.String(),
|
|
||||||
"method": r.Method,
|
|
||||||
"body": string(bytebody),
|
|
||||||
"header": r.Header,
|
|
||||||
"form": r.Form,
|
|
||||||
"postform": r.PostForm,
|
|
||||||
"dumpreq": string(bytereq),
|
|
||||||
}
|
|
||||||
bj, _ := json.Marshal(m)
|
|
||||||
fmt.Println(string(bj))
|
|
||||||
// json.NewEncoder(w).Encode(m)
|
|
||||||
|
|
||||||
for k, v := range cors {
|
|
||||||
w.Header().Set(k, v)
|
|
||||||
}
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
io.WriteString(w, string(bj))
|
|
||||||
return
|
|
||||||
})
|
|
||||||
server := http.Server{
|
|
||||||
Addr: ":890",
|
|
||||||
Handler: mux,
|
|
||||||
}
|
|
||||||
server.ListenAndServe()
|
|
||||||
}
|
|
||||||
|
|
||||||
var cors = map[string]string{
|
|
||||||
"Access-Control-Allow-Origin": "*",
|
|
||||||
"Access-Control-Allow-Methods": "POST,OPTIONS,GET",
|
|
||||||
"Access-Control-Max-Age": "3600",
|
|
||||||
"Access-Control-Allow-Headers": "accept,x-requested-with,Content-Type",
|
|
||||||
"Access-Control-Allow-Credentials": "true",
|
|
||||||
}
|
|
||||||
18
tests/lru.go
18
tests/lru.go
@@ -1,18 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
l, _ := lru.New(10)
|
|
||||||
for i := 0; i < 100; i++ {
|
|
||||||
l.Add(i, i)
|
|
||||||
}
|
|
||||||
for l.Len() > 0 {
|
|
||||||
fmt.Println(l.RemoveOldest())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user