diff --git a/cli.go b/cli.go index ca9c1fc..a3366bc 100644 --- a/cli.go +++ b/cli.go @@ -62,13 +62,17 @@ func main() { }, }, Action: func(c *cli.Context) { - server := NewReseeder() - server.NetDBDir = c.String("netdb") - server.RefreshInterval = c.Duration("refresh") - server.Proxy = c.Bool("proxy") - server.Verbose = c.Bool("verbose") - server.RateLimit = c.Int("rateLimit") - server.Start(c.String("addr"), c.String("port"), c.String("cert"), c.String("key")) + Run(&Config{ + NetDBDir: c.String("netdb"), + RefreshInterval: c.Duration("refresh"), + Proxy: c.Bool("proxy"), + Verbose: c.Bool("verbose"), + RateLimit: c.Int("rateLimit"), + Addr: c.String("addr"), + Port: c.String("port"), + Cert: c.String("cert"), + Key: c.String("key"), + }) }, }, { diff --git a/reseeder.go b/reseeder.go index 7002ebf..64590f7 100644 --- a/reseeder.go +++ b/reseeder.go @@ -15,6 +15,7 @@ package main // https://geti2p.net/en/docs/spec/updates import ( + "fmt" "github.com/PuerkitoBio/throttled" "github.com/PuerkitoBio/throttled/store" "github.com/gorilla/handlers" @@ -29,6 +30,10 @@ import ( "time" ) +const ( + LIST_TEMPLATE = `NetDB` +) + func proxiedHandler(h http.Handler) http.Handler { return remoteAddrFixup{h} } @@ -44,98 +49,124 @@ func (h remoteAddrFixup) ServeHTTP(w http.ResponseWriter, r *http.Request) { h.h.ServeHTTP(w, r) } -type Reseeder struct { +type Config struct { NetDBDir string - nextMap chan []string RefreshInterval time.Duration Proxy bool Verbose bool RateLimit int - listTemplate *template.Template + Addr string + Port string + Cert string + Key string } -func (rs *Reseeder) Start(addr, port, cert, key string) { - var err error +func Run(config *Config) { + legacyReseeder := NewLegacyReseeder(config.NetDBDir) + legacyReseeder.Start(config.RefreshInterval) - go rs.runMap() - go rs.refresher() - - // parse the template for routerInfo lists - rs.listTemplate, err = template.New("routerinfos").Parse(`NetDB`) - if err != nil { - log.Fatalln("error parsing routerInfo list template", err) - return - } + su3Reseeder := NewSu3Reseeder(config.NetDBDir) + su3Reseeder.Start() r := mux.NewRouter() s := r.PathPrefix("/netdb").Subrouter() - s.HandleFunc("/", rs.listHandler) - s.HandleFunc("/i2pseeds.su3", rs.su3Handler) - s.HandleFunc(`/routerInfo-{hash:[A-Za-z0-9+/\-=~]+}.dat`, rs.routerInfoHandler) + s.HandleFunc("/", legacyReseeder.ListHandler) + s.HandleFunc("/i2pseeds.su3", su3Reseeder.Su3Handler) + s.HandleFunc(`/routerInfo-{hash:[A-Za-z0-9+/\-=~]+}.dat`, legacyReseeder.RouterInfoHandler) // timeout muxWithMiddlewares := http.TimeoutHandler(r, time.Second*5, "Timeout!") - th := throttled.RateLimit(throttled.PerMin(rs.RateLimit), &throttled.VaryBy{RemoteAddr: true}, store.NewMemStore(1000)) + th := throttled.RateLimit(throttled.PerMin(config.RateLimit), &throttled.VaryBy{RemoteAddr: true}, store.NewMemStore(1000)) muxWithMiddlewares = th.Throttle(muxWithMiddlewares) - if rs.Proxy { + if config.Proxy { muxWithMiddlewares = proxiedHandler(muxWithMiddlewares) } - if rs.Verbose { + if config.Verbose { muxWithMiddlewares = handlers.CombinedLoggingHandler(os.Stdout, muxWithMiddlewares) } + listenAddress := fmt.Sprintf("%s:%s", config.Addr, config.Port) + // try to start tls server - if _, err = os.Stat(cert); err == nil { - if _, err = os.Stat(key); err == nil { - log.Println("Starting TLS reseed server on " + addr + ":" + port) - err := http.ListenAndServeTLS(addr+":"+port, cert, key, muxWithMiddlewares) - if nil != err { - log.Fatalln(err) + if config.Cert != "" && config.Key != "" { + log.Println("Starting TLS reseed server on " + listenAddress) + err := http.ListenAndServeTLS(listenAddress, config.Cert, config.Key, muxWithMiddlewares) + if nil != err { + log.Fatalln(err) + } + } else { + // fall back to regular http server + log.Println("Starting reseed server on " + listenAddress) + err := http.ListenAndServe(listenAddress, muxWithMiddlewares) + if nil != err { + log.Fatalln(err) + } + } +} + +func NewLegacyReseeder(netdbDir string) *LegacyReseeder { + return &LegacyReseeder{netdbDir: netdbDir, nextMap: make(chan []string)} +} + +func NewSu3Reseeder(netdbDir string) *Su3Reseeder { + return &Su3Reseeder{netdbDir: netdbDir, nextMap: make(chan []string)} +} + +type Su3Reseeder struct { + nextMap chan []string + netdbDir string +} + +func (r *Su3Reseeder) Start() { +} + +func (rs *Su3Reseeder) Su3Handler(w http.ResponseWriter, r *http.Request) { + http.NotFound(w, r) +} + +type LegacyReseeder struct { + nextMap chan []string + netdbDir string + listTemplate *template.Template +} + +func (r *LegacyReseeder) Start(refreshInterval time.Duration) { + go func() { + var m []string + for { + select { + case m = <-r.nextMap: + case r.nextMap <- m: } - - return } - } + }() - // fall back to regular http server - log.Println("Starting reseed server on " + addr + ":" + port) - err = http.ListenAndServe(addr+":"+port, muxWithMiddlewares) - if nil != err { - log.Fatalln(err) - } -} - -func NewReseeder() *Reseeder { - return &Reseeder{nextMap: make(chan []string)} -} - -func (r *Reseeder) runMap() { - var m []string - for { - select { - case m = <-r.nextMap: - case r.nextMap <- m: + go func() { + for { + log.Println("Updating routerInfos") + r.Refresh() + time.Sleep(refreshInterval) } + }() + + // parse the template for routerInfo lists + var err error + r.listTemplate, err = template.New("ri").Parse(LIST_TEMPLATE) + if err != nil { + log.Fatalln("error parsing routerInfo list template", err) + return } } -func (r *Reseeder) refresher() { - for { - log.Println("Updating routerInfos") - r.Refresh() - time.Sleep(r.RefreshInterval) - } -} - -func (r *Reseeder) Refresh() { +func (r *LegacyReseeder) Refresh() { var m []string - src, err := ioutil.ReadDir(r.NetDBDir) + src, err := ioutil.ReadDir(r.netdbDir) if nil != err { log.Fatalln("error reading netdb dir", err) return @@ -162,21 +193,17 @@ func (r *Reseeder) Refresh() { r.nextMap <- m } -func (rs *Reseeder) listHandler(w http.ResponseWriter, r *http.Request) { - err := rs.listTemplate.Execute(w, <-rs.nextMap) +func (lr *LegacyReseeder) ListHandler(w http.ResponseWriter, r *http.Request) { + err := lr.listTemplate.Execute(w, <-lr.nextMap) if err != nil { log.Fatalln("error rending list template", err) } } -func (rs *Reseeder) su3Handler(w http.ResponseWriter, r *http.Request) { - http.NotFound(w, r) -} - -func (rs *Reseeder) routerInfoHandler(w http.ResponseWriter, r *http.Request) { +func (rs *LegacyReseeder) RouterInfoHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) fileName := "routerInfo-" + vars["hash"] + ".dat" - f, err := os.Open(rs.NetDBDir + "/" + fileName) + f, err := os.Open(rs.netdbDir + "/" + fileName) if nil != err { http.NotFound(w, r) log.Println("error sending file", err)