package main import ( _ "embed" "encoding/gob" "html/template" "io" "log" "net/http" "os" "os/signal" "runtime/debug" ) // File for persistent storage var DataFilename = "ideas.data" // Version number used for debugging compatibility with the .data file var Version string // layout for how the date should be output in html var DateLayout string = "02/01/2006 on 15:04" // template for listing out the ideas, should be bundled inside the executable // //go:embed ideas.html var ideas_html string var data Store // ToDo's // - [ ] Add a post // - [ ] Remove a post // - [ ] work with funcmaps in templates // - [ ] Put a reaction on a post // - [x] Store ideas to a file (encoder/gob) // - [x] Change the date format printing // Represents an idea // CreatedAt is a formatted date string // out of 5 rating of the idea // formatted time string with DateLayout type Idea struct { Title string Description string Author string CreatedAt string } // Data needed through the programm, this data is written to DataFilename for persistent storage // Is also the format for the Data file type Store struct { Version string Ideas []Idea } func GetVersion() string { buildinfo, ok := debug.ReadBuildInfo() if !ok { log.Fatalln("Could not read buildinfo to know package version.") } return buildinfo.Main.Version } func main() { Version = GetVersion() // Create a .data file in the cache directory and decode eventual ideas from it { p := os.Getenv("XDG_CACHE_HOME") // TODO: remove for testing p = "" if p == "" { p = "." } DataFilename = p + "/" + DataFilename f, err := os.OpenFile(DataFilename, os.O_RDONLY|os.O_CREATE, 0666) if err != nil { log.Fatalln("Error while opening data file:", err) } dec := gob.NewDecoder(f) if err := dec.Decode(&data); err != io.EOF && err != nil { log.Fatalln("Error while decoding ideas:", err) } log.Println(data) if data.Version != Version { log.Fatalf("Version mismatch for datafile@%s != package@%s\n", data.Version, Version) } log.Printf("Imported @%s: %d ideas\n", data.Version, len(data.Ideas)) if err := f.Close(); err != nil { log.Fatalln("Error while closing file:", err) } } // Handle SIGINT // On program exit it should write all its data to the datafile // TODO: Instead of recreating the file the new ideas should be appended, a way to achieve this would be that every time a new idea is added it is appended to the file, this way there is no need to ensure this. go func() { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) <-c f, err := os.Create(DataFilename) if err != nil { log.Fatalln(err) } defer f.Close() enc := gob.NewEncoder(f) if err := enc.Encode(data); err != nil { log.Fatalln(err) } log.Println("data saved.") os.Exit(0) }() tmpl, err := template.New("ideas_html").Parse(ideas_html) if err != nil { log.Fatalln(err) } http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { tmpl.Execute(w, data) }) log.Println("Listening on http://localhost:8080") err = http.ListenAndServe(":8080", nil) if err != nil { log.Fatalln(err) } }