diff options
Diffstat (limited to 'sklad/main.go')
-rw-r--r-- | sklad/main.go | 143 |
1 files changed, 5 insertions, 138 deletions
diff --git a/sklad/main.go b/sklad/main.go index 28fb258..c1eaa99 100644 --- a/sklad/main.go +++ b/sklad/main.go @@ -1,155 +1,19 @@ package main import ( - "encoding/json" - "errors" - "fmt" "html/template" - "io" "log" "net/http" "os" ) -type Series struct { - Prefix string // PK: prefix - Description string // what kind of containers this is for -} - -type Container struct { - Series string // PK: what series does this belong to - Number uint // PK: order within the series - Parent ContainerId // the container we're in, if any, otherwise "" - Description string // description and/or contents of this container -} - -type ContainerId string - -func (c *Container) Id() ContainerId { - return ContainerId(fmt.Sprintf("%s%s%d", db.Prefix, c.Series, c.Number)) -} - -type Database struct { - Password string // password for web users - Prefix string // prefix for all container IDs - Series []*Series // all known series - Containers []*Container // all known containers -} - var ( templates *template.Template - // TODO: Some kind of session storage, somewhere. - - dbPath string - db Database - dbLast Database - dbLog io.Writer - indexSeries = map[string]*Series{} - indexContainer = map[ContainerId]*Container{} - indexChildren = map[ContainerId][]*Container{} + // session storage: UUID -> net.SplitHostPort(http.Server.RemoteAddr)[0] + sessions = map[string]string{} ) -// TODO: Some functions to add, remove and change things in the database. -// Indexes must be kept valid, just like any invariants. - -func dbCommit() error { - // Back up the current database contents. - e := json.NewEncoder(dbLog) - e.SetIndent("", " ") - if err := e.Encode(&dbLast); err != nil { - return err - } - - // Atomically replace the current database file. - tempPath := dbPath + ".new" - temp, err := os.OpenFile(tempPath, os.O_WRONLY|os.O_CREATE, 0644) - if err != nil { - return err - } - defer temp.Close() - - e = json.NewEncoder(temp) - e.SetIndent("", " ") - if err := e.Encode(&db); err != nil { - return err - } - - if err := os.Rename(tempPath, dbPath); err != nil { - return err - } - - dbLast = db - return nil -} - -// loadDatabase loads the database from a simple JSON file. We do not use -// any SQL stuff or even external KV storage because there is no real need -// for our trivial use case, with our general amount of data. -func loadDatabase() error { - dbFile, err := os.Open(dbPath) - if err != nil { - return err - } - if err := json.NewDecoder(dbFile).Decode(&db); err != nil { - return err - } - - // Further validate the database. - if db.Prefix == "" { - return errors.New("misconfigured prefix") - } - - // Construct indexes for primary keys, validate against duplicates. - for _, pv := range db.Series { - if _, ok := indexSeries[pv.Prefix]; ok { - return fmt.Errorf("duplicate series: %s", pv.Prefix) - } - indexSeries[pv.Prefix] = pv - } - for _, pv := range db.Containers { - id := pv.Id() - if _, ok := indexContainer[id]; ok { - return fmt.Errorf("duplicate container: %s", id) - } - indexContainer[id] = pv - } - - // Construct an index that goes from parent containers to their children. - for _, pv := range db.Containers { - if pv.Parent == "" { - continue - } - if _, ok := indexContainer[pv.Parent]; !ok { - return fmt.Errorf("container %s has a nonexistent parent %s", - pv.Id(), pv.Parent) - } - indexChildren[pv.Parent] = append(indexChildren[pv.Parent], pv) - } - - // Validate that no container is a parent of itself on any level. - for _, pv := range db.Containers { - parents := map[ContainerId]bool{pv.Id(): true} - for pv.Parent != "" { - if parents[pv.Parent] { - return fmt.Errorf("%s contains itself", pv.Parent) - } - parents[pv.Parent] = true - pv = indexContainer[pv.Parent] - } - } - - // Open database log file for appending. - if dbLog, err = os.OpenFile(dbPath+".log", - os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err != nil { - return err - } - - // Remember the current state of the database. - dbLast = db - return nil -} - func main() { if len(os.Args) != 3 { log.Fatalf("usage: %s ADDRESS DATABASE\n", os.Args[0]) @@ -170,6 +34,9 @@ func main() { log.Fatalln(err) } + // TODO: Eventually we will need to load a font file for label printing. + // - The path might be part of configuration, or implicit by filename. + // TODO: Some routing, don't forget about sessions. // - https://stackoverflow.com/a/33880971/76313 // |