package main import ( "bytes" "context" "encoding/json" "fmt" "html/template" "io" "log" "net/http" "os" "os/signal" "strings" "time" "gopkg.in/ini.v1" ) type EmailsResonse struct { Emails []string `json:"emails"` } func main() { // Read the config file and get the HMC api settings config, err := ini.Load("app.ini") if err != nil { panic(err) } HMC_CFG := config.Section("hmc") HMC_API_SECRET := HMC_CFG.Key("SHARED_SECRET").String() HMC_API_URL := HMC_CFG.Key("API_URL").String() HMC_CITY := HMC_CFG.Key("CITY").String() // Prepare the go html templates and static file server templates := template.Must(template.ParseGlob("templates/*.html")) static_files := http.FileServer(http.Dir("static/")) mux := http.NewServeMux() mux.Handle("/static/", http.StripPrefix("/static/", static_files)) mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { log.Printf("Hello '%v %v' handler", r.Method, r.URL) templates.ExecuteTemplate(w, "index", nil) }) mux.HandleFunc("/mail-content", func(w http.ResponseWriter, r *http.Request) { log.Printf("Hello '%v %v' handler", r.Method, r.URL) body, err := io.ReadAll(r.Body) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer r.Body.Close() textarea_content := string(body) email_content, _ := strings.CutPrefix(textarea_content, "email_input=") // Return a response to HTMX response := fmt.Sprintf("
Received content: %s
", email_content) w.Write([]byte(response)) }) mux.HandleFunc("/mailing_list", func(w http.ResponseWriter, r *http.Request) { body := []byte(fmt.Sprintf("{\"city\": \"%s\"}", HMC_CITY)) req, err := http.NewRequest("POST", HMC_API_URL, bytes.NewBuffer(body)) if err != nil { panic(err) } req.Header.Add("Content-Type", "application/json") req.Header.Add("Authorization", HMC_API_SECRET) client := &http.Client{} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() response := &EmailsResonse{} decode_error := json.NewDecoder(res.Body).Decode(response) if decode_error != nil { panic(decode_error) } templates.ExecuteTemplate(w, "mailing_list", response) }) srv := &http.Server{ Addr: "0.0.0.0:80", // Good practice to set timeouts to avoid Slowloris attacks. WriteTimeout: time.Second * 15, ReadTimeout: time.Second * 15, IdleTimeout: time.Second * 60, Handler: mux, } go func() { if err := srv.ListenAndServe(); err != nil { log.Println(err) } }() ////////////////////////////// Cleanup ////////////////////////////// c := make(chan os.Signal, 1) // We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C) // SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught. signal.Notify(c, os.Interrupt) log.Println("Waiting for interrupt") // Block until we receive our signal. <-c // Create a deadline to wait for. ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) // Defer calling the canclefunction returned from context.WithTimeout defer cancel() // Doesn't block if no connections, but will otherwise wait // until the timeout deadline. srv.Shutdown(ctx) // Optionally, you could run srv.Shutdown in a goroutine and block on // <-ctx.Done() if your application should wait for other services // to finalize based on context cancellation. log.Println("shutting down") os.Exit(0) }