add shorturl
This commit is contained in:
120
src/routes/shorturl.go
Normal file
120
src/routes/shorturl.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/patrickmn/go-cache"
|
||||
"sour.is/x/toolbox/httpsrv"
|
||||
"sour.is/x/toolbox/uuid"
|
||||
)
|
||||
|
||||
func init() {
|
||||
s := NewShortManager(365 * 24 * time.Hour)
|
||||
|
||||
httpsrv.HttpRegister("short", httpsrv.HttpRoutes{
|
||||
{Name: "getShort", Method: "GET", Pattern: "/s/{id}", HandlerFunc: s.getShort},
|
||||
{Name: "putShort", Method: "PUT", Pattern: "/s/{id}", HandlerFunc: s.putShort},
|
||||
})
|
||||
}
|
||||
|
||||
type shortManager struct {
|
||||
defaultExpire time.Duration
|
||||
db *cache.Cache
|
||||
}
|
||||
|
||||
type shortURL struct {
|
||||
ID string
|
||||
URL string
|
||||
Secret string
|
||||
}
|
||||
|
||||
func NewShortManager(defaultExpire time.Duration) *shortManager {
|
||||
return &shortManager{
|
||||
defaultExpire: defaultExpire,
|
||||
db: cache.New(defaultExpire, defaultExpire/10),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *shortManager) GetURL(id string) *shortURL {
|
||||
if u, ok := s.db.Get(id); ok {
|
||||
if url, ok := u.(*shortURL); ok {
|
||||
return url
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (s *shortManager) PutURL(id string, url *shortURL) {
|
||||
s.db.SetDefault(id, url)
|
||||
}
|
||||
|
||||
func (s *shortManager) getShort(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
id := vars["id"]
|
||||
url := s.GetURL(id)
|
||||
|
||||
if url == nil {
|
||||
httpsrv.WriteError(w, 404, "not found")
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Location", url.URL)
|
||||
w.WriteHeader(http.StatusFound)
|
||||
}
|
||||
|
||||
func (s *shortManager) putShort(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
|
||||
id := vars["id"]
|
||||
secret := r.FormValue("secret")
|
||||
u, err := url.Parse(r.FormValue("url"))
|
||||
if err != nil {
|
||||
httpsrv.WriteError(w, 400, "bad url")
|
||||
return
|
||||
}
|
||||
|
||||
short := s.GetURL(id)
|
||||
|
||||
if short == nil {
|
||||
short = newshort(id, secret, u.String())
|
||||
|
||||
s.PutURL(short.ID, short)
|
||||
httpsrv.WriteObject(w, 200, short)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if secret == "" {
|
||||
httpsrv.WriteError(w, 401, "no auth")
|
||||
return
|
||||
}
|
||||
|
||||
if secret != short.Secret {
|
||||
httpsrv.WriteError(w, 403, "forbidden")
|
||||
return
|
||||
}
|
||||
|
||||
short.URL = u.String()
|
||||
|
||||
s.PutURL(short.ID, short)
|
||||
httpsrv.WriteObject(w, 200, short)
|
||||
}
|
||||
|
||||
func newshort(id, secret, u string) *shortURL {
|
||||
m, err := regexp.MatchString("[a-z-]{1,64}", id)
|
||||
if id == "" || !m || err != nil {
|
||||
id = uuid.V4()
|
||||
}
|
||||
m, err = regexp.MatchString("[a-z-]{1,64}", secret)
|
||||
if secret == "" || !m || err != nil {
|
||||
secret = uuid.V4()
|
||||
}
|
||||
return &shortURL{ID: id, Secret: secret, URL: u}
|
||||
}
|
||||
Reference in New Issue
Block a user