Skip to content

Commit 6433d09

Browse files
committed
short: auto create vcs alias if available
For #4
1 parent 5b8274f commit 6433d09

File tree

2 files changed

+67
-21
lines changed

2 files changed

+67
-21
lines changed

db.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ const (
1919
prefixip = "redir:ip:"
2020
)
2121

22+
var (
23+
errExistedAlias = errors.New("alias is existed")
24+
)
25+
2226
// arecord indicates an alias record that stores an short alias
2327
// in data store with statistics regarding its UVs and PVs.
2428
type arecord struct {
@@ -81,7 +85,7 @@ func (s *store) StoreAlias(ctx context.Context, a, l string) (err error) {
8185
return
8286
}
8387
if !ok {
84-
err = errors.New("alias already exists in data store")
88+
err = errExistedAlias
8589
return
8690
}
8791
return

short.go

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ func shortCmd(ctx context.Context, operate op, alias, link string) (err error) {
116116
return
117117
}
118118

119-
// sHandler redirects ...
119+
// sHandler redirects the current request to a known link if the alias
120+
// is found in the redir store.
120121
func (s *server) sHandler(w http.ResponseWriter, r *http.Request) {
121122
ctx := r.Context()
122123

@@ -131,35 +132,24 @@ func (s *server) sHandler(w http.ResponseWriter, r *http.Request) {
131132
}
132133
}()
133134

135+
// statistic page
134136
alias := strings.TrimSuffix(strings.TrimPrefix(r.URL.Path, conf.S.Prefix), "/")
135137
if alias == "" {
136138
err = s.stats(ctx, w)
137139
return
138140
}
139141

140-
checkdb := func(url string) (string, error) {
141-
raw, err := s.db.FetchAlias(ctx, alias)
142-
if err != nil {
143-
return "", err
144-
}
145-
c := arecord{}
146-
err = json.Unmarshal(StringToBytes(raw), &c)
147-
if err != nil {
148-
return "", err
149-
}
150-
if url != c.URL {
151-
s.cache.Put(alias, c.URL)
152-
url = c.URL
153-
}
154-
return url, nil
155-
}
156-
142+
// figure out redirect location
157143
url, ok := s.cache.Get(alias)
158144
if !ok {
159-
url, err = checkdb(url)
145+
url, err = s.checkdb(ctx, alias)
160146
if err != nil {
161-
return
147+
url, err = s.checkvcs(ctx, alias)
148+
if err != nil {
149+
return
150+
}
162151
}
152+
s.cache.Put(alias, url)
163153
}
164154

165155
// redirect the user immediate, but run pv/uv count in background
@@ -169,6 +159,58 @@ func (s *server) sHandler(w http.ResponseWriter, r *http.Request) {
169159
go func() { s.visitCh <- visit{s.readIP(r), alias} }()
170160
}
171161

162+
// checkdb checks whether the given alias is exsited in the redir database,
163+
// and updates the in-memory cache if
164+
func (s *server) checkdb(ctx context.Context, alias string) (string, error) {
165+
raw, err := s.db.FetchAlias(ctx, alias)
166+
if err != nil {
167+
return "", err
168+
}
169+
c := arecord{}
170+
err = json.Unmarshal(StringToBytes(raw), &c)
171+
if err != nil {
172+
return "", err
173+
}
174+
return c.URL, nil
175+
}
176+
177+
// checkvcs checks whether the given alias is an repository on VCS, if so,
178+
// then creates a new alias and returns url of the vcs repository.
179+
func (s *server) checkvcs(ctx context.Context, alias string) (string, error) {
180+
181+
// construct the try path and make the request to vcs
182+
repoPath := conf.X.RepoPath
183+
if strings.HasSuffix(repoPath, "/*") {
184+
repoPath = strings.TrimSuffix(repoPath, "/*")
185+
}
186+
tryPath := fmt.Sprintf("%s/%s", repoPath, alias)
187+
resp, err := http.Get(tryPath)
188+
if err != nil {
189+
return "", err
190+
}
191+
defer resp.Body.Close()
192+
if resp.StatusCode != http.StatusOK &&
193+
resp.StatusCode != http.StatusMovedPermanently {
194+
return "", fmt.Errorf("%s is not a repository", tryPath)
195+
}
196+
197+
// figure out the new location
198+
if resp.StatusCode == http.StatusMovedPermanently {
199+
tryPath = resp.Header.Get("Location")
200+
}
201+
202+
// store such a try path
203+
err = s.db.StoreAlias(ctx, alias, tryPath)
204+
if err != nil {
205+
if errors.Is(err, errExistedAlias) {
206+
return s.checkdb(ctx, alias)
207+
}
208+
return "", err
209+
}
210+
211+
return tryPath, nil
212+
}
213+
172214
// readIP implements a best effort approach to return the real client IP,
173215
// it parses X-Real-IP and X-Forwarded-For in order to work properly with
174216
// reverse-proxies such us: nginx or haproxy. Use X-Forwarded-For before

0 commit comments

Comments
 (0)