Add map section with geocoded family pins

This commit is contained in:
Ian Gulliver
2026-08-15 23:21:03 -07:00
parent c56310d219
commit fd52c948db
11 changed files with 350 additions and 13 deletions
+50 -5
View File
@@ -6,18 +6,20 @@ import (
"time"
"heliosian/internal/data"
"heliosian/internal/geocode"
)
const refreshInterval = 5 * time.Minute
type Cache struct {
source data.Source
mu sync.RWMutex
model *Model
source data.Source
geocoder *geocode.Client
mu sync.RWMutex
model *Model
}
func NewCache(source data.Source) (*Cache, error) {
c := &Cache{source: source}
func NewCache(source data.Source, geocoder *geocode.Client) (*Cache, error) {
c := &Cache{source: source, geocoder: geocoder}
if err := c.refresh(); err != nil {
return nil, err
}
@@ -45,6 +47,7 @@ func (c *Cache) refresh() error {
if err != nil {
return err
}
c.geocodeFamilies(model)
c.mu.Lock()
c.model = model
c.mu.Unlock()
@@ -53,3 +56,45 @@ func (c *Cache) refresh() error {
time.Since(start).Round(time.Millisecond))
return nil
}
func (c *Cache) geocodeFamilies(model *Model) {
start := time.Now()
type job struct {
key string
address string
}
jobs := make(chan job)
var wg sync.WaitGroup
var mu sync.Mutex
located := 0
for range 8 {
wg.Add(1)
go func() {
defer wg.Done()
for j := range jobs {
point, err := c.geocoder.Lookup(j.address)
if err != nil {
log.Printf("[ERROR] %v", err)
continue
}
mu.Lock()
family := model.Families[j.key]
family.Lat = point.Lat
family.Lng = point.Lng
model.Families[j.key] = family
located++
mu.Unlock()
}
}()
}
total := 0
for key, family := range model.Families {
if family.Address != "" {
total++
jobs <- job{key: key, address: family.Address}
}
}
close(jobs)
wg.Wait()
log.Printf("geocoded %d of %d family addresses in %s", located, total, time.Since(start).Round(time.Millisecond))
}
+5 -3
View File
@@ -23,11 +23,12 @@ var legacy = map[string]string{
}
type app struct {
cache *Cache
cache *Cache
mapsKey string
}
func Register(mux *http.ServeMux, cache *Cache) {
a := app{cache: cache}
func Register(mux *http.ServeMux, cache *Cache, mapsKey string) {
a := app{cache: cache, mapsKey: mapsKey}
for _, section := range sections {
mux.HandleFunc("GET /"+section, a.page)
}
@@ -60,6 +61,7 @@ func (a app) page(w http.ResponseWriter, r *http.Request) {
"UserName": name,
"UserInitial": strings.ToUpper(name[:1]),
"UserEmail": auth.Email(r),
"MapsKey": a.mapsKey,
}
if err := t.Execute(w, data); err != nil {
log.Printf("[ERROR] render directory page: %v", err)
+2
View File
@@ -28,6 +28,8 @@ type Family struct {
Key string `json:"key"`
Name string `json:"name,omitempty"`
Address string `json:"address,omitempty"`
Lat float64 `json:"lat,omitempty"`
Lng float64 `json:"lng,omitempty"`
PhotoURL string `json:"photoUrl,omitempty"`
PhotoCaption string `json:"photoCaption,omitempty"`
PronunciationURL string `json:"pronunciationUrl,omitempty"`