package main import ( "flag" "fmt" "math/rand" "mime" "net/http" "regexp" "strings" "sync" "time" "code.hackerspace.pl/hscloud/go/mirko" "github.com/golang/glog" "code.hackerspace.pl/hscloud/hswaw/site/calendar" "code.hackerspace.pl/hscloud/hswaw/site/static" ) var ( flagSitePublic string ) type service struct { // feeds is a map from atom feed name to atom feed. This is updated by a // background worker. feeds map[string]*atomFeed // feedsMu locks the feeds field. feedsMu sync.RWMutex // events is a list of upcoming events, sorted so the first event is the // one that will happen the soonests. events []*calendar.UpcomingEvent // eventsMu locks the events field. eventsMu sync.RWMutex } func main() { flag.StringVar(&flagSitePublic, "site_public", "0.0.0.0:8080", "Address at which to serve public HTTP requests") flag.Parse() rand.Seed(time.Now().UnixNano()) mi := mirko.New() if err := mi.Listen(); err != nil { glog.Exitf("Listen failed: %v", err) } s := &service{} go s.feedWorker(mi.Context()) go s.eventsWorker(mi.Context()) mux := http.NewServeMux() s.registerHTTP(mux) go func() { glog.Infof("Listening for public HTTP at %v", flagSitePublic) if err := http.ListenAndServe(flagSitePublic, mux); err != nil { glog.Exit(err) } }() if err := mi.Serve(); err != nil { glog.Exitf("Serve failed: %v", err) } <-mi.Done() } var ( // staticRoutes define the resolution of static file paths into assets // built into //hswaw/site/static, whose names correspond to their origin // within the Bazel workspace. // The regexp will be matched against the normalized within the URL. If it // matches, its first group/submatch will be used to format the string // corresponding to this regexp, and that string will be then used to // retrieve a path embedded within //hswaw/site/static:static // (go_embed_data). // // To see paths available within that go_embed_data, you can do: // $ bazel build //hswaw/site/static:static // $ grep -A100 'Data =' bazel-bin/hswaw/site/static/static.go staticRoutes = map[*regexp.Regexp]string{ regexp.MustCompile(`^static/site/(.+)$`): "hswaw/site/static/%s", regexp.MustCompile(`^static/leaflet/(.+)$`): "external/com_npmjs_leaflet/package/dist/%s", } ) // handleHTTPStatic uses staticRoutes to serve static files embedded within // //hswaw/site/static. func (s *service) handleHTTPStatic(w http.ResponseWriter, r *http.Request) { path := strings.TrimPrefix(r.URL.Path, "/") for from, to := range staticRoutes { match := from.FindStringSubmatch(path) if match == nil { continue } to := fmt.Sprintf(to, match[1]) data, ok := static.Data[to] if !ok { continue } parts := strings.Split(path, ".") ext := fmt.Sprintf(".%s", parts[len(parts)-1]) t := mime.TypeByExtension(ext) w.Header().Set("Content-Type", t) w.Write(data) return } http.NotFound(w, r) } func (s *service) registerHTTP(mux *http.ServeMux) { mux.HandleFunc("/static/", s.handleHTTPStatic) mux.HandleFunc("/spaceapi", s.handleSpaceAPI) mux.HandleFunc("/events.json", s.handleJSONEvents) mux.HandleFunc("/event/", s.handleEvent) mux.HandleFunc("/", s.handleIndex) }