func geocodeBuildings(c *maps.Client) error { buildings, err := models.LoadMapData() if err != nil { return err } for _, b := range buildings { if b.Position != nil || len(b.Address) == 0 { continue } log.Printf("geocoding %s", b.Name) req := &maps.GeocodingRequest{ Address: b.Address, Region: "ca", } result, err := c.Geocode(context.TODO(), req) if err != nil { return err } if len(result) == 0 { continue } loc := result[0].Geometry.Location b.Position = &models.LatLng{ Lat: loc.Lat, Lng: loc.Lng, } time.Sleep(100 * time.Millisecond) if err := models.SaveMapData(buildings); err != nil { return err } } for _, b := range buildings { if len(b.Floors) == 0 { continue } var lat, lng float64 c := float64(len(b.Floors) * 2) for _, f := range b.Floors { lat += f.Coords.North lat += f.Coords.South lng += f.Coords.West lng += f.Coords.East for _, r := range f.Rooms { lat += r.Position.Lat lng += r.Position.Lng c += 1 } } b.Position.Lat = lat / c b.Position.Lng = lng / c } return models.SaveMapData(buildings) }
func NewServer() (*Server, error) { flag.Parse() if len(*adminPassword) == 0 { log.Println("Warning: no admin password; login impossible") } if len(*googleAPIKey) == 0 { log.Println("Warning: no google api key; OCR impossible") } s := &Server{} s.authenticator = auth.NewBasicAuthenticator("localhost", s.secret) s.r = mux.NewRouter() s.r.HandleFunc("/api/tiles/{zoom}_{x}_{y}_{floor}.png", s.tiles) s.r.HandleFunc("/api/view/{json}", s.view) s.r.HandleFunc("/api/schedule/{loc}", s.schedule) s.r.HandleFunc("/api/search/", s.search) s.r.HandleFunc("/api/item/{json}", s.item) s.r.HandleFunc("/api/dump/", s.dump) s.r.HandleFunc("/api/save_building/", s.authenticator.Wrap(s.saveBuilding)) s.r.HandleFunc("/api/ocr/", s.authenticator.Wrap(s.ocrFloor)) s.r.PathPrefix("/").Handler(http.FileServer(http.Dir("./static/"))) http.Handle("/", s.r) log.Println("Loading existing map data...") buildings, err := models.LoadMapData() if err != nil { return nil, err } s.buildings = buildings s.indexBuildings() s.initCache() s.initTileBuilding() return s, nil }
func scrapeBuildings() error { buildings, err := models.LoadMapData() if err != nil { return err } doc, err := goquery.NewDocument("http://www.maps.ubc.ca/PROD/buildingsListAll.php") if err != nil { return err } detailsDup := make(map[string]bool) var details []string doc.Find("a[href]").Each(func(i int, sel *goquery.Selection) { href, exists := sel.Attr("href") if !exists || !strings.HasPrefix(href, "index_detail.php?") || detailsDup[href] { return } detailsDup[href] = true details = append(details, href) }) relChan := make(chan string, 1) defer close(relChan) outChan := make(chan *models.Building, 1) defer close(outChan) for _ = range make([]interface{}, 20) { go fetchDetails(relChan, outChan) } go func() { for _, rel := range details { relChan <- rel } }() var scrapedBuildings []*models.Building for b := range outChan { if len(b.SIS) == 0 { b.SIS = customSIS[b.Name] } scrapedBuildings = append(scrapedBuildings, b) if len(scrapedBuildings) == len(details) { break } } buildingIndex := make(map[string]*models.Building) for _, building := range buildings { buildingIndex[building.SIS] = building } for _, b := range scrapedBuildings { if len(b.SIS) == 0 { continue } if b2, ok := buildingIndex[b.SIS]; ok { b2.Address = b.Address b2.Image = b.Image b2.Description = b.Description continue } buildingIndex[b.SIS] = b buildings = append(buildings, b) } return models.SaveMapData(buildings) }