diff options
author | Raymaekers Luca <raymaekers.luca@gmail.com> | 2024-09-27 14:37:29 +0200 |
---|---|---|
committer | Raymaekers Luca <raymaekers.luca@gmail.com> | 2024-09-27 14:43:02 +0200 |
commit | 5b2097cd2ed016f78ae2c2bcc068dfe3f42e44bd (patch) | |
tree | ab047ebe3f342570978b487e4ea4d96bc0d0070c /main.go | |
parent | f340f74e1d06aa588dd075f3922505878915da01 (diff) |
Added datafile for persistent ideas
The data file uses a version number for debugging and is serialized into
a data file, for now this is good enough but because of encapsulating
the data in a struct there is no convenient way of appending to the
Ideas slice.
- Removed the Rating as it is not really constructive.
- Added handling of SIGINT to keep the data even on exit from air of
Ctrl-c
- Removed example data
- Use log instaed of fmt everywhere
- Removed Makefile
Diffstat (limited to 'main.go')
-rw-r--r-- | main.go | 125 |
1 files changed, 81 insertions, 44 deletions
@@ -2,14 +2,21 @@ package main import ( _ "embed" - "fmt" + "encoding/gob" "html/template" + "io" "log" "net/http" + "os" + "os/signal" + "runtime/debug" ) // File for persistent storage -const DataFilename = "main.data" +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" @@ -19,13 +26,15 @@ var DateLayout string = "02/01/2006 on 15:04" //go:embed ideas.html var ideas_html string +var data Store + // ToDo's // - [ ] Add a post -// - [ ] Serialize data to a file // - [ ] Remove a post -// - [x] Change the date format printing // - [ ] 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 @@ -38,59 +47,87 @@ type Idea struct { CreatedAt string } -func main() { - var ideas []Idea +// 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 +} - // Create a .data file in the cache directory - { - // data := os.Getenv("XDG_CACHE_HOME") - // if data == "" { - // data = "." - // } - // data = data + "" - // - // file, err := os.Create(data + "/" + DataFilename) - // if err != nil { - // panic(err) - // } +func GetVersion() string { + buildinfo, ok := debug.ReadBuildInfo() + if !ok { + log.Fatalln("Could not read buildinfo to know package version.") } - // hardcoded data + return buildinfo.Main.Version +} + +func main() { + Version = GetVersion() + + // Create a .data file in the cache directory and decode eventual ideas from it { - ideas = []Idea{ - { - Title: "Better Keylogger", - Description: "Keylogger which records statistics about your typing.", - Author: "Me", - CreatedAt: "26/09/2024 on 14:51", - }, - { - Title: "music tracker", - Description: "An app that can track music across multiple music apps such as spotify, apple music, deezer, etc.", - Author: "Me", - CreatedAt: "24/09/2024 on 14:32", - }, - { - Title: "automated hosting", - Description: "Service to host a website where people can drag&drop their files and they are hosted, it also provides a subdomain automatically.", - Author: "Him", - }, + 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) } } - // // Example of parsing a string into time with the layout - // CreatedAt: func() string { - // t, _ := time.Parse(DateLayout, "24/09/2024 on 14:40") - // return t.Format(DateLayout) - tmpl, err := template.New("mytemplate").Parse(ideas_html) + // 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, struct{ Ideas []Idea }{ideas}) + tmpl.Execute(w, data) }) - fmt.Println("Listening on http://localhost:8080") + log.Println("Listening on http://localhost:8080") err = http.ListenAndServe(":8080", nil) if err != nil { log.Fatalln(err) |