archive/Router.go
2017-08-13 15:47:03 +12:00

170 lines
3.9 KiB
Go

package archive
import (
"bytes"
"errors"
"fmt"
"net/http"
"net/url"
"strconv"
"time"
)
func (this *ArchiveServer) lookupSourceByNumericString(slug string) *LogSource {
intval, err := strconv.Atoi(slug)
if err != nil {
return nil
}
if intval >= 0 && intval < len(this.cfg.Logs) {
return &this.cfg.Logs[intval]
}
return nil
}
func (this *ArchiveServer) lookupSource(slug string) *LogSource {
if src := this.lookupSourceByNumericString(slug); src != nil {
return src
}
for i, ls := range this.cfg.Logs {
for _, s := range ls.Slugs {
if s == slug {
return &this.cfg.Logs[i]
}
}
}
return nil // not found
}
func (this *ArchiveServer) bestSlugFor(ls *LogSource) (string, error) {
for i := 0; i < len(this.cfg.Logs); i += 1 {
if ls != &this.cfg.Logs[i] {
continue
}
if len(this.cfg.Logs[i].Slugs) > 0 {
return this.cfg.Logs[i].Slugs[0], nil // first slug is preferred
} else {
return fmt.Sprintf(`%d`, i), nil // no slugs present? use numeric log index
}
}
return "", errors.New("Unregistered log source")
}
func (this *ArchiveServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Server", SERVER_VERSION)
if r.Method != "GET" {
http.Error(w, "Expected GET", http.StatusMethodNotAllowed)
return
}
if len(r.URL.Path) == 0 {
http.Error(w, "Invalid request", http.StatusBadRequest)
return
}
// Handle static assets
static, err := Asset(r.URL.Path[1:])
if err == nil {
http.ServeContent(w, r, r.URL.Path[1:], this.startup, bytes.NewReader(static))
return
}
// Handle application routes
arc := NewArchiveState(this)
if r.URL.Path == `/` {
ls := &this.cfg.Logs[0]
slug, _ := this.bestSlugFor(ls)
dt := ls.LatestDate()
http.Redirect(w, r, fmt.Sprintf(`/%s/%d/%d`, slug, dt.Year, dt.Month), http.StatusTemporaryRedirect)
} else if len(r.URL.Query().Get("y")) > 0 || len(r.URL.Query().Get("q")) > 0 || len(r.URL.Query().Get("h")) > 0 {
this.legacyRoute(w, r)
} else if r.URL.Path == `/download` {
arc.renderError(w, "Not implemented.") // FIXME
} else if matches := this.rxViewRoot.FindStringSubmatch(r.URL.Path); len(matches) > 0 {
if ls := this.lookupSource(matches[1]); ls != nil {
arc.selectSource(ls, matches[1])
y, _ := strconv.Atoi(matches[2])
m, _ := strconv.Atoi(matches[3])
arc.ym = YearMonth{Year: y, Month: time.Month(m)} // 1-based months
arc.renderView(w)
} else {
arc.renderError(w, fmt.Sprintf("Unknown source '%s'", matches[1]))
}
} else if this.rxViewPage.MatchString(r.URL.Path) {
arc.renderError(w, "Not implemented.") // FIXME
} else if this.rxSearch.MatchString(r.URL.Path) {
arc.renderError(w, "Not implemented.") // FIXME
} else if this.rxSearchRx.MatchString(r.URL.Path) {
arc.renderError(w, "Not implemented.") // FIXME
} else {
arc.renderError(w, "Unknown route.")
}
}
func (this *ArchiveServer) legacyRoute(w http.ResponseWriter, r *http.Request) {
intval := func(sz string) int {
ret, _ := strconv.Atoi(sz)
return ret
}
get := r.URL.Query().Get
hasGet := func(sz string) bool {
return len(get(sz)) > 0
}
redirectf := func(format string, a ...interface{}) {
http.Redirect(w, r, fmt.Sprintf(format, a...), http.StatusTemporaryRedirect)
}
//
hubid := 0
if hasGet("h") {
hubid = intval(get("h"))
}
if hasGet("q") {
if hasGet("rx") {
redirectf(`/%d/rx/%s`, hubid, url.QueryEscape(get("q")))
} else {
redirectf(`/%d/search/%s`, hubid, url.QueryEscape(get("q")))
}
} else if hasGet("y") && hasGet("m") {
year := intval(get("y"))
month := intval(get("m"))
if hasGet("p") {
redirectf(`/%d/%d/%d/page-%d`, hubid, year, month, intval(get("p")))
} else {
redirectf(`/%d/%d/%d`, hubid, year, month)
}
} else {
if hi := this.lookupSourceByNumericString(get("h")); hi != nil {
currentDate := hi.LatestDate()
redirectf(`/%d/%d/%d`, hubid, currentDate.Year, currentDate.Month)
} else {
redirectf(`/`)
}
}
}