summaryrefslogblamecommitdiffstats
path: root/main.go
blob: ed988c9f89b90aedfad479e9d79f0ef1f327daf7 (plain) (tree)
1
2
3
4
5
6
7
8
                                                             



                               

               
              



                       

                 
 
                                       
                                        
                                        

 
                               

                                                           
                                         

                  
                        
                                                   

                    
                  
                                                                                 
 
                  

                                                                                 







                                                                    
             
                           
                                            
 
                                

                                                    


                                              
                       
                                                      

 



























                                                             
                                                           
                       
                                                            
                       
                                                  


                      
                  
                                                                        
                       




                                                        










                                                              
                                                         

                     

                                                  


                                   
                       
                                                  

                      




                                                                      

 
                                  




                                                                           
 
// Copyright © 2022 siddharth ravikumar <s@ricketyspace.net>
// SPDX-License-Identifier: ISC

package main

import (
	"embed"
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"regexp"
	"strconv"

	"ricketyspace.net/peach/search"
	"ricketyspace.net/peach/version"
	"ricketyspace.net/peach/weather"
)

// Peach port. Defaults to 8151
var peachPort = flag.Int("p", 8151, "Port to run peach on")

// Peach listen address. Set during init.
var peachAddr = ""

// Holds static content.
//go:embed templates static/*.min.css static/font/*
var peachFS embed.FS

// HTML templates.
var peachTemplates = template.Must(template.ParseFS(peachFS, "templates/*.tmpl"))

// Lat,Long regex.
var latLngRegex = regexp.MustCompile(`/(-?[0-9]+\.?[0-9]+?),(-?[0-9]+\.?[0-9]+)`)

func init() {
	flag.Parse()
	if *peachPort < 80 {
		log.Fatalf("port number is invalid: %v", *peachPort)
	}
	peachAddr = fmt.Sprintf(":%d", *peachPort)
}

func main() {
	// Default handler.
	http.HandleFunc("/", defaultHandler)

	// Static files handler.
	http.HandleFunc("/static/", serveStaticFile)

	// Search handler.
	http.HandleFunc("/search", showSearch)

	// Start server
	log.Fatal(http.ListenAndServe(peachAddr, nil))
}

func defaultHandler(w http.ResponseWriter, r *http.Request) {
	logRequest(r)

	if r.URL.Path == "/" {
		http.Redirect(w, r, "/41.115,-83.177", 302)
		return
	}
	if r.URL.Path == "/version" {
		fmt.Fprintf(w, "v%s\n", version.Version)
		return
	}

	m := latLngRegex.FindStringSubmatch(r.URL.Path)
	if len(m) != 3 || m[0] != r.URL.Path {
		http.NotFound(w, r)
		return
	}
	lat, err := strconv.ParseFloat(m[1], 32)
	if err != nil {
		http.Error(w, err.Error(), 400)
	}
	lng, err := strconv.ParseFloat(m[2], 32)
	if err != nil {
		http.Error(w, err.Error(), 400)
	}
	showWeather(w, float32(lat), float32(lng))
}

func showWeather(w http.ResponseWriter, lat, lng float32) {
	// Make weather
	weather, err, status := weather.NewWeather(lat, lng)
	if err != nil {
		http.Error(w, err.Error(), status)
		return
	}

	// Render.
	err = peachTemplates.ExecuteTemplate(w, "weather.tmpl", weather)
	if err != nil {
		log.Printf("weather: template: %v", err)
		return
	}
}

func serveStaticFile(w http.ResponseWriter, r *http.Request) {
	logRequest(r)

	// Add Cache-Control header
	w.Header().Set("Cache-Control", "max-age=604800")

	// Serve.
	server := http.FileServer(http.FS(peachFS))
	server.ServeHTTP(w, r)
}

func showSearch(w http.ResponseWriter, r *http.Request) {
	logRequest(r)

	search, err, status := search.NewSearch(r)
	if err != nil && status == 404 {
		http.NotFound(w, r)
		return
	}
	if err != nil {
		http.Error(w, err.Error(), status)
		return
	}
	err = peachTemplates.ExecuteTemplate(w, "search.tmpl", search)
	if err != nil {
		log.Printf("search: template: %v", err)
		return
	}
}

func logRequest(r *http.Request) {
	addr := r.RemoteAddr
	if len(r.Header.Get("X-Forwarded-For")) > 0 {
		addr = r.Header.Get("X-Forwarded-For")
	}
	log.Printf("%v - %v - %v", addr, r.URL, r.Header.Get("User-agent"))
}