diff options
-rw-r--r-- | config.go | 11 | ||||
-rw-r--r-- | go.mod | 1 | ||||
-rw-r--r-- | go.sum | 12 | ||||
-rw-r--r-- | log.go | 4 | ||||
-rw-r--r-- | restart.go | 6 | ||||
-rw-r--r-- | restart_windows.go | 9 | ||||
-rw-r--r-- | store/image.go | 74 | ||||
-rw-r--r-- | store/page.go | 233 | ||||
-rw-r--r-- | store/paths.go | 13 | ||||
-rw-r--r-- | store/secret.go | 11 | ||||
-rw-r--r-- | store/store.go | 66 | ||||
-rw-r--r-- | store/tag.go | 34 | ||||
-rw-r--r-- | store/user.go | 34 | ||||
-rw-r--r-- | web.go | 15 |
14 files changed, 223 insertions, 300 deletions
@@ -4,7 +4,6 @@ import ( "github.com/fsnotify/fsnotify" log "github.com/sirupsen/logrus" "github.com/spf13/viper" - "os" "random.chars.jp/git/image-board/store" ) @@ -39,13 +38,11 @@ func configSetup() { if _, ok := err.(viper.ConfigFileNotFoundError); ok { err = viper.WriteConfigAs("server.toml") if err != nil { - log.Fatalf("Error while generating default configuration, %s", err) - os.Exit(1) + log.Fatalf("Error generating default configuration, %s", err) } log.Warn("Generated default server.toml in current directory.") } else { - log.Fatalf("Error while loading configuration, %s", err) - os.Exit(1) + log.Fatalf("Error loading configuration, %s", err) } } @@ -86,8 +83,7 @@ func openStore() { } instance = store.New(path, single) if instance == nil { - log.Fatalf("Unable to initialize store.") - os.Exit(1) + log.Fatalf("Error initializing store.") } log.Infof("Store opened on %s revision %v compat %v.", path, instance.Revision, instance.Compat) info := instance.User(instance.InitialUser) @@ -99,7 +95,6 @@ func openStore() { } else { if single { log.Fatal("Instance has no initial user, single user mode unavailable.") - os.Exit(1) } } if single { @@ -9,4 +9,5 @@ require ( github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 github.com/sirupsen/logrus v1.8.1 github.com/spf13/viper v1.7.1 + github.com/syndtr/goleveldb v1.0.0 ) @@ -77,6 +77,8 @@ github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaW github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -115,6 +117,7 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= @@ -165,6 +168,9 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -210,6 +216,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= @@ -256,6 +264,7 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -280,6 +289,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -353,9 +363,11 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -4,7 +4,6 @@ import ( log "github.com/sirupsen/logrus" "github.com/spf13/viper" "go/types" - "os" ) type logger types.Nil @@ -37,8 +36,7 @@ func setFormatter() { func setLevel() { level, err := log.ParseLevel(viper.GetStringMap("system")["loglevel"].(string)) if err != nil { - log.Fatalf("Error while parsing log level, %s", err) - os.Exit(1) + log.Fatalf("Error parsing log level, %s", err) } log.SetLevel(level) } @@ -12,14 +12,12 @@ func restart() { var err error if _, err = os.Stat(executable); err != nil { - log.Fatalf("Error while stat executable path, %s", err) - os.Exit(1) + log.Fatalf("Error stat executable path, %s", err) } log.Infof("Re-executing %s...", executable) err = syscall.Exec(executable, os.Args, os.Environ()) if err != nil { - log.Fatalf("Error while re-executing, %s", err) - os.Exit(1) + log.Fatalf("Error re-executing, %s", err) } } diff --git a/restart_windows.go b/restart_windows.go index 4e239dd..59239fb 100644 --- a/restart_windows.go +++ b/restart_windows.go @@ -7,14 +7,12 @@ import ( func restart() { if _, err := os.Stat(executable); err != nil { - log.Fatalf("Unable to get executable path, %s", err) - os.Exit(1) + log.Fatalf("Error getting executable path, %s", err) } log.Infof("Program found at %s.", executable) wd, err := os.Getwd() if err != nil { - log.Fatalf("Unable to get working directory, %s", err) - os.Exit(1) + log.Fatalf("Error getting working directory, %s", err) } log.Infof("Current working directory is %s.", wd) _, err = os.StartProcess(executable, []string{}, &os.ProcAttr{ @@ -24,7 +22,6 @@ func restart() { Sys: nil, }) if err != nil { - log.Fatalf("Unable to create new process, %s", err) - os.Exit(1) + log.Fatalf("Error creating new process, %s", err) } } diff --git a/store/image.go b/store/image.go index d1b7549..6ef019d 100644 --- a/store/image.go +++ b/store/image.go @@ -31,15 +31,13 @@ type Image struct { func (s *Store) Images() []string { var images []string if entries, err := os.ReadDir(s.ImagesDir()); err != nil { - log.Fatalf("Error while reading first level image directory, %s", err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error reading first level image directory, %s", err)) } else { for _, entry := range entries { if entry.IsDir() { var subEntries []os.DirEntry if subEntries, err = os.ReadDir(s.ImagesDir() + "/" + entry.Name()); err != nil { - log.Fatalf("Error while reading second level image directory %s, %s", entry.Name(), err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error reading second level image directory %s, %s", entry.Name(), err)) } else { for _, subEntry := range subEntries { images = append(images, entry.Name()+subEntry.Name()) @@ -66,12 +64,10 @@ func (s *Store) Image(hash string) Image { func (s *Store) ImageMetadataRead(path string) Image { var metadata Image if payload, err := os.ReadFile(path); err != nil { - log.Fatalf("Error while reading image metadata %s, %s", path, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error reading image metadata %s, %s", path, err)) } else { if err = json.Unmarshal(payload, &metadata); err != nil { - log.Fatalf("Error while parsing image metadata %s, %s", path, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error parsing image metadata %s, %s", path, err)) } } return metadata @@ -87,12 +83,10 @@ func (s *Store) ImageData(hash string, preview bool) (Image, []byte) { defer s.getLock(hash).RUnlock() var metadata Image if payload, err := os.ReadFile(s.ImageMetadataPath(hash)); err != nil { - log.Fatalf("Error while reading image %s metadata, %s", hash, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error reading image %s metadata, %s", hash, err)) } else { if err = json.Unmarshal(payload, &metadata); err != nil { - log.Fatalf("Error while parsing image %s metadata, %s", hash, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error parsing image %s metadata, %s", hash, err)) } } var path string @@ -102,8 +96,7 @@ func (s *Store) ImageData(hash string, preview bool) (Image, []byte) { path = s.ImagePreviewFilePath(hash) } if data, err := os.ReadFile(path); err != nil { - log.Fatalf("Error while reading image %s file, %s", hash, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error reading image %s file, %s", hash, err)) } else { return metadata, data } @@ -124,8 +117,7 @@ func (s *Store) ImageTags(flake string) []string { func (s *Store) imageTags(flake string) []string { var tags []string if entries, err := os.ReadDir(s.ImageTagsPath(flake)); err != nil { - log.Fatalf("Error while reading tags of image %s, %s", flake, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error reading tags of image %s, %s", flake, err)) } else { for _, entry := range entries { tags = append(tags, entry.Name()) @@ -158,7 +150,7 @@ func (s *Store) ImageAdd(data []byte, flake string) Image { // Decode image and set format var img image.Image if i, format, err := image.Decode(bytes.NewReader(data)); err != nil { - log.Warnf("Error while decoding upload %s, %s", info.Hash, err) + log.Warnf("Error decoding upload %s, %s", info.Hash, err) return Image{} } else { img = resize.Thumbnail(256, 256, i, resize.Bilinear) @@ -167,39 +159,32 @@ func (s *Store) ImageAdd(data []byte, flake string) Image { // Create image directory and tags if err := os.MkdirAll(s.ImageHashTagsPath(info.Hash), s.PermissionDir); err != nil { - log.Fatalf("Error while creating image %s directory, %s", info.Hash, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error creating image %s directory, %s", info.Hash, err)) } // Generate and save image metadata if payload, err := json.Marshal(info); err != nil { - log.Fatalf("Error while encoding metadata of image %s, %s", info.Hash, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error encoding metadata of image %s, %s", info.Hash, err)) } else { if err = os.WriteFile(s.ImageMetadataPath(info.Hash), payload, s.PermissionFile); err != nil { - log.Fatalf("Error while saving metadata of image %s, %s", info.Hash, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error saving metadata of image %s, %s", info.Hash, err)) } } // Save image if err := os.WriteFile(s.ImageFilePath(info.Hash), data, s.PermissionFile); err != nil { - log.Fatalf("Error while saving image %s, %s", info.Hash, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error saving image %s, %s", info.Hash, err)) } // Save preview image if preview, err := os.Create(s.ImagePreviewFilePath(info.Hash)); err != nil { - log.Fatalf("Error while creating image %s preview, %s", info.Hash, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error creating image %s preview, %s", info.Hash, err)) } else { if err = jpeg.Encode(preview, img, &jpeg.Options{Quality: 100}); err != nil { - log.Fatalf("Error while saving image %s preview, %s", info.Hash, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error saving image %s preview, %s", info.Hash, err)) } if err = preview.Close(); err != nil { - log.Fatalf("Error while closing image %s preview, %s", info.Hash, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error closing image %s preview, %s", info.Hash, err)) } } @@ -233,12 +218,10 @@ func (s *Store) ImageSource(hash, source string) { // Set source and save info.Source = source if payload, err := json.Marshal(info); err != nil { - log.Fatalf("Error while encoding metadata of image %s while updating source, %s", hash, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error encoding metadata of image %s while updating source, %s", hash, err)) } else { if err = os.WriteFile(s.ImageMetadataPath(hash), payload, s.PermissionFile); err != nil { - log.Fatalf("Error while saving metadata of image %s while updating source, %s", hash, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error saving metadata of image %s while updating source, %s", hash, err)) } } log.Infof("Image hash %s source set to %s.", hash, source) @@ -248,8 +231,7 @@ func (s *Store) ImageSource(hash, source string) { func (s *Store) ImageSnowflakes() []string { var snowflakes []string if entries, err := os.ReadDir(s.ImagesSnowflakeDir()); err != nil { - log.Fatalf("Error while reading snowflakes, %s", err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error reading snowflakes, %s", err)) } else { for _, entry := range entries { snowflakes = append(snowflakes, entry.Name()) @@ -264,8 +246,7 @@ func (s *Store) ImageSnowflakeHash(flake string) string { return s.ImageMetadataRead(s.ImageSnowflakePath(flake) + "/" + infoJson).Hash } else { if path, err := os.ReadFile(s.ImageSnowflakePath(flake)); err != nil { - log.Fatalf("Error while reading snowflake %s association file, %s", flake, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error reading snowflake %s association file, %s", flake, err)) } else { return s.ImageMetadataRead(string(path) + "/" + infoJson).Hash } @@ -297,20 +278,17 @@ func (s *Store) ImageDestroy(hash string) { // Remove snowflake if err := os.Remove(s.ImageSnowflakePath(info.Snowflake)); err != nil { - log.Fatalf("Error while destroying snowflake %s of image %s, %s", info.Snowflake, hash, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error destroying snowflake %s of image %s, %s", info.Snowflake, hash, err)) } // Disassociate user if err := os.Remove(s.UserImagesPath(info.User) + "/" + info.Snowflake); err != nil { - log.Fatalf("Error while destroying association %s with user %s, %s.", info.Snowflake, info.User, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error destroying association %s with user %s, %s.", info.Snowflake, info.User, err)) } // Remove data directory if err := os.RemoveAll(s.ImagePath(hash)); err != nil { - log.Fatalf("Error while destroying image %s, %s", hash, err) - log.Exit(1) + s.fatalClose(fmt.Sprintf("Error destroying image %s, %s", hash, err)) } // Register remove counter @@ -349,14 +327,12 @@ func (s *Store) ImageTagRemove(flake, tag string) { func (s *Store) imageTagRemove(flake, tag string) { if s.file(s.ImageTagsPath(flake) + "/" + tag) { if err := os.Remove(s.ImageTagsPath(flake) + "/" + tag); err != nil { - log.Fatalf("Error while unreferencing image %s from tag %s, %s", flake, tag, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error unreferencing image %s from tag %s, %s", flake, tag, err)) } } if s.file(s.TagPath(tag) + "/" + flake) { if err := os.Remove(s.TagPath(tag) + "/" + flake); err != nil { - log.Fatalf("Error while unreferencing tag %s from image %s, %s", tag, flake, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error unreferencing tag %s from image %s, %s", tag, flake, err)) } } s.PageRegisterRemove("tag_"+tag, flake) diff --git a/store/page.go b/store/page.go index f8f8263..f654174 100644 --- a/store/page.go +++ b/store/page.go @@ -1,83 +1,125 @@ package store +import "C" import ( - "encoding/json" + "encoding/binary" + "fmt" log "github.com/sirupsen/logrus" + "github.com/syndtr/goleveldb/leveldb" "os" - "strconv" ) const pageSize = 64 -const balanceThreshold = 16 - -// pageCreateIfNotExist creates a page variant's base directory if it does not exist. -func (s *Store) pageCreateIfNotExist(variant string) { - if !s.dir(s.PagesDir(variant)) { - if err := os.MkdirAll(s.PagesDir(variant), s.PermissionDir); err != nil { - log.Fatalf("Error while crating page variant %s base directory, %s", variant, err) - os.Exit(1) + +// pageDB returns leveldb of page variant and creates it as required. +func (s *Store) pageDB(variant string) *leveldb.DB { + if s.pageldb[variant] != nil { + return s.pageldb[variant] + } else { + if db, err := leveldb.OpenFile(s.PageVariantPath(variant), nil); err != nil { + s.fatalClose(fmt.Sprintf("Error opening leveldb for page variant %s, %s", variant, err)) + } else { + s.pageldb[variant] = db + if _, err = db.Get([]byte("\000"), nil); err != nil { + log.Infof("Page variant %s created.", variant) + s.pageSetTotalCount(variant, 0) + } + return db } } + return nil } -// pageWrite writes payload of a page. -func (s *Store) pageWrite(variant string, entry int, content []string) { - if payload, err := json.Marshal(content); err != nil { - log.Fatalf("Error while generating page %v of variant %s, %s", entry, variant, err) - os.Exit(1) +// pageDBDestroy destroys leveldb of page variant. +func (s *Store) pageDBDestroy(variant string) { + if err := s.pageDB(variant).Close(); err != nil { + s.fatalClose(fmt.Sprintf("Error closing leveldb for page variant %s, %s", variant, err)) } else { - s.pageCreateIfNotExist(variant) - if err = os.WriteFile(s.PagePath(variant, entry), payload, s.PermissionFile); err != nil { - log.Fatalf("Error while saving page %v, %s", entry, err) - os.Exit(1) - } + delete(s.pageldb, variant) + } + + if err := os.RemoveAll(s.PageVariantPath(variant)); err != nil { + s.fatalClose(fmt.Sprintf("Error destroying page variant %s, %s", variant, err)) } -} -// pageLockString returns lock identifier of a page. -func (s *Store) pageLockString(variant string, entry int) string { - return "page_" + variant + "_" + strconv.Itoa(entry) + log.Infof("Page variant %s destroyed.", variant) } -// PageTotal returns total amount of pages. -func (s *Store) PageTotal(variant string) int { - s.pageCreateIfNotExist(variant) - if entries, err := os.ReadDir(s.PagesDir(variant)); err != nil { - log.Fatalf("Error while reading pages of variant %s, %s", variant, err) - os.Exit(1) +// pageGetTotalCount gets total count of a page variant. +func (s *Store) pageGetTotalCount(variant string) uint64 { + db := s.pageDB(variant) + + if payload, err := db.Get([]byte("\000"), nil); err != nil { + s.fatalClose(fmt.Sprintf("Error getting page variant %s total count, %s", variant, err)) } else { - return len(entries) + return binary.LittleEndian.Uint64(payload) } + return 0 } -// Page returns all entries in a page. -func (s *Store) Page(variant string, entry int) []string { - return s.page(variant, entry, true) +// pageSetTotalCount sets total count of a page variant. +func (s *Store) pageSetTotalCount(variant string, value uint64) { + db := s.pageDB(variant) + + payload := make([]byte, 8) + binary.LittleEndian.PutUint64(payload, value) + + if err := db.Put([]byte("\000"), payload, nil); err != nil { + s.fatalClose(fmt.Sprintf("Error setting page variant %s total count, %s", variant, err)) + } +} + +// pageAdvanceTotalCount advances total count of a page variant. +func (s *Store) pageAdvanceTotalCount(variant string) { + s.pageSetTotalCount(variant, s.pageGetTotalCount(variant)+1) +} + +// pageReduceTotalCount reduces total count of a page variant. +func (s *Store) pageReduceTotalCount(variant string) { + s.pageSetTotalCount(variant, s.pageGetTotalCount(variant)-1) } -// page returns all entries in a page with optional locking. -func (s *Store) page(variant string, entry int, lock bool) []string { - if !s.file(s.PagePath(variant, entry)) { +// PageTotal returns total amount of pages. +func (s *Store) PageTotal(variant string) int { + return (int(s.pageGetTotalCount(variant)) / pageSize) + 1 +} + +// Page returns all entries in a page. +func (s *Store) Page(variant string, entry int) []string { + if entry >= s.PageTotal(variant) { return nil } - if lock { - s.getLock(s.pageLockString(variant, entry)).RLock() - defer s.getLock(s.pageLockString(variant, entry)).RUnlock() - } + var page []string + start := entry*pageSize + 1 + end := start + pageSize + begin := false - var flakes []string - if payload, err := os.ReadFile(s.PagePath(variant, entry)); err != nil { - log.Fatalf("Error while reading page %v of variant %s, %s", entry, variant, err) - os.Exit(1) - } else { - if err = json.Unmarshal(payload, &flakes); err != nil { - log.Fatalf("Error while parsing page %v of variant %s, %s", entry, variant, err) - os.Exit(1) + db := s.pageDB(variant) + + iter := db.NewIterator(nil, nil) + i := 0 + for iter.Next() { + if i == end { + break + } + if begin { + page = append(page, string(iter.Key())) + } else { + if i >= start { + begin = true + } } + i++ } - return flakes + iter.Release() + if err := iter.Error(); err != nil { + log.Warnf("Error iterating page variant %s entry %v, %s", variant, entry, err) + return nil + } + + return page } // PageImages returns all images in a page. @@ -103,89 +145,24 @@ func (s *Store) PageInsert(variant, flake string) { return } - entry := s.PageTotal(variant) - 1 - s.getLock(s.pageLockString(variant, entry)).Lock() - defer s.getLock(s.pageLockString(variant, entry)).Unlock() - var page []string - if entry == -1 || len(s.page(variant, entry, false)) == pageSize { - entry++ - page = []string{} - } else { - page = s.page(variant, entry, false) + s.getLock("page_" + variant).Lock() + defer s.getLock("page_" + variant).Unlock() + + db := s.pageDB(variant) + if err := db.Put([]byte(flake), []byte{}, nil); err != nil { + s.fatalClose(fmt.Sprintf("Error inserting image %s into page variant %s, %s", flake, variant, err)) } - page = append(page, flake) - s.pageWrite(variant, entry, page) + s.pageAdvanceTotalCount(variant) } // PageRegisterRemove registers an image remove. func (s *Store) PageRegisterRemove(variant, flake string) { - go func() { - var target int - var targetPayload []string - for i := 0; i < s.PageTotal(variant); i++ { - page := s.page(variant, i, true) - ok := false - for j, f := range page { - if f == flake { - ok = true - page = append(page[:(j)], page[(j+1):]...) - break - } - } - if ok { - s.getLock(s.pageLockString(variant, i)).Lock() - s.pageWrite(variant, i, page) - s.getLock(s.pageLockString(variant, i)).Unlock() - target = i - targetPayload = page - log.Infof("Removed page %v variant %s item %s.", target, variant, flake) - break - } - } - if len(targetPayload) < pageSize-balanceThreshold && (target+1) < s.PageTotal(variant) { - log.Infof("Page %v reached balancing threshold, initiating balance.", target) - s.PageBalance(variant, target, targetPayload) - } - }() -} + s.getLock("page_" + variant).Lock() + defer s.getLock("page_" + variant).Unlock() -// PageBalance balances a page. -func (s *Store) PageBalance(variant string, target int, payload []string) { - if !s.file(s.PagePath(variant, target)) { - return + db := s.pageDB(variant) + if err := db.Delete([]byte(flake), nil); err != nil { + s.fatalClose(fmt.Sprintf("Error removing image %s from page variant %s, %s", flake, variant, err)) } - go func() { - if (target + 1) >= s.PageTotal(variant) { - return - } - s.getLock(s.pageLockString(variant, target)).Lock() - defer s.getLock(s.pageLockString(variant, target)).Unlock() - s.getLock(s.pageLockString(variant, target+1)).Lock() - defer s.getLock(s.pageLockString(variant, target+1)).Unlock() - if payload == nil { - payload = s.page(variant, target, false) - } - comp := pageSize - len(payload) - next := s.page(variant, target+1, false) - empty := false - if len(next) <= comp { - if err := os.Remove(s.PagePath(variant, target+1)); err != nil { - log.Fatalf("Error removing empty page %v, %s", target+1, err) - os.Exit(1) - } - payload = append(payload, next...) - empty = true - } else { - payload = append(payload, next[:comp]...) - next = next[comp+1:] - } - - s.pageWrite(variant, target, payload) - if !empty { - s.pageWrite(variant, target+1, next) - s.PageBalance(variant, target+1, next) - } else { - log.Infof("Removed empty page %v.", target+1) - } - }() + s.pageReduceTotalCount(variant) } diff --git a/store/paths.go b/store/paths.go index bd567cb..b31f3d8 100644 --- a/store/paths.go +++ b/store/paths.go @@ -1,9 +1,5 @@ package store -import ( - "strconv" -) - const infoJson = "info.json" // LockPath returns path to lock file. @@ -126,12 +122,7 @@ func (s *Store) PageBaseDir() string { return s.Path + "/pages" } -// PagesDir returns path to pages of a variant. -func (s *Store) PagesDir(variant string) string { +// PageVariantPath returns path to pages of a variant. +func (s *Store) PageVariantPath(variant string) string { return s.PageBaseDir() + "/" + variant } - -// PagePath returns path to a specific page. -func (s *Store) PagePath(variant string, entry int) string { - return s.PagesDir(variant) + "/" + strconv.Itoa(entry) -} diff --git a/store/secret.go b/store/secret.go index c17443a..5941c2f 100644 --- a/store/secret.go +++ b/store/secret.go @@ -2,7 +2,7 @@ package store import ( "crypto/rand" - log "github.com/sirupsen/logrus" + "fmt" "math/big" "os" ) @@ -12,8 +12,7 @@ func (s *Store) SecretNew() string { secret := make([]byte, 64) for i := 0; i < 64; i++ { if n, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters)))); err != nil { - log.Fatalf("Error while generating secret, %s", err) - log.Exit(1) + s.fatalClose(fmt.Sprintf("Error generating secret, %s", err)) } else { secret[i] = letters[n.Int64()] } @@ -30,8 +29,7 @@ func (s *Store) SecretLookup(secret string) User { return s.user(s.SecretPath(secret) + "/" + infoJson) } else { if path, err := os.ReadFile(s.SecretPath(secret)); err != nil { - log.Fatalf("Error reading association file of secret %s, %s", secret, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error reading association file of secret %s, %s", secret, err)) } else { return s.user(string(path) + "/" + infoJson) } @@ -53,7 +51,6 @@ func (s *Store) SecretDisassociate(secret string) { return } if err := os.Remove(s.SecretPath(secret)); err != nil { - log.Fatalf("Error disassociating secret %s, %s", secret, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error disassociating secret %s, %s", secret, err)) } } diff --git a/store/store.go b/store/store.go index f7420aa..619eff4 100644 --- a/store/store.go +++ b/store/store.go @@ -2,15 +2,17 @@ package store import ( "encoding/json" + "fmt" "github.com/bwmarrin/snowflake" log "github.com/sirupsen/logrus" + "github.com/syndtr/goleveldb/leveldb" "os" "runtime" "strconv" "sync" ) -const revision = -6 +const revision = -7 var ( imageNode *snowflake.Node @@ -37,6 +39,7 @@ type Store struct { InitialUser string PermissionDir os.FileMode PermissionFile os.FileMode + pageldb map[string]*leveldb.DB mutex map[string]*sync.RWMutex sync.RWMutex } @@ -50,8 +53,7 @@ func init() { imageNode, err = snowflake.NewNode(9) userNode, err = snowflake.NewNode(7) if err != nil { - log.Fatalf("Error while creating snowflake generation node, %s", err) - os.Exit(1) + log.Fatalf("Error creating snowflake generation node, %s", err) } } @@ -69,17 +71,16 @@ func New(path string, single bool) *Store { Register: false, PermissionDir: 0700, PermissionFile: 0600, + pageldb: make(map[string]*leveldb.DB), mutex: make(map[string]*sync.RWMutex), } if err = store.create(); err != nil { log.Fatalf("Error creating store, %s", err) - os.Exit(1) } } else { // Exit if store is not a directory. if !stat.IsDir() { log.Fatal("Store is not a directory.") - os.Exit(1) } // Load and parse store info. @@ -87,16 +88,13 @@ func New(path string, single bool) *Store { var payload []byte if payload, err = os.ReadFile(path + "/" + infoJson); err != nil { log.Fatalf("Error reading store information, %s", err) - os.Exit(1) } else { if err = json.Unmarshal(payload, &info); err != nil { log.Fatalf("Error parsing store information, %s", err) - os.Exit(1) } } if info.Revision != revision { log.Fatalf("Store format revision %v, expecting revision %v.", info.Revision, revision) - os.Exit(1) } // Create store instance. @@ -109,34 +107,50 @@ func New(path string, single bool) *Store { InitialUser: info.InitialUser, PermissionDir: info.PermissionDir, PermissionFile: info.PermissionFile, + pageldb: make(map[string]*leveldb.DB), mutex: make(map[string]*sync.RWMutex), } } + + // Handle store locking if store.file(store.LockPath()) { if pid, err := os.ReadFile(store.LockPath()); err != nil { log.Fatalf("Store locked, lock file unreadable, %s", err) - log.Exit(1) } else { log.Fatalf("Store locked by process %s.", string(pid)) - log.Exit(1) } } if err := os.WriteFile(store.LockPath(), []byte(strconv.Itoa(os.Getpid())), store.PermissionFile); err != nil { log.Fatalf("Error locking store, %s", err) - log.Exit(1) } + return store } // Close closes the store. func (s *Store) Close() { + // Close all leveldb + for variant, ldb := range s.pageldb { + if err := ldb.Close(); err != nil { + log.Errorf("Error closing leveldb variant %s, %s", variant, err) + } + log.Infof("Page variant %s closed.", variant) + } + + // Unlock store if err := os.Remove(s.LockPath()); err != nil { - log.Fatalf("Error unlocking store, %s", err) - log.Exit(1) + log.Errorf("Error unlocking store, %s", err) } + log.Info("Store closed.") } +// fatalClose closes the store and as cleanly as possible and exits with a fatal message. +func (s *Store) fatalClose(message string) { + s.Close() + log.Fatal(message) +} + // create sets up the store directory if it does not exist. func (s *Store) create() error { // Check if exists @@ -163,18 +177,17 @@ func (s *Store) create() error { if err := os.Mkdir(s.SecretsDir(), s.PermissionDir); err != nil { return err } - if err := os.Mkdir(s.PageBaseDir(), s.PermissionDir); err != nil { + if err := os.Mkdir(s.UsernamesDir(), s.PermissionDir); err != nil { return err } - if err := os.Mkdir(s.UsernamesDir(), s.PermissionDir); err != nil { + if err := os.Mkdir(s.PageBaseDir(), s.PermissionDir); err != nil { return err } // Create initial user info := s.UserAdd("root", true, "initial") if info.Snowflake == "" { - log.Fatalf("Error creating initial user.") - os.Exit(1) + log.Fatal("Error creating initial user.") } else { log.Infof("Created initial user with username root and password initial.") } @@ -219,8 +232,7 @@ func (s *Store) file(path string) bool { if os.IsNotExist(err) { return false } else { - log.Fatalf("Error while stat %s, %s", path, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error stat %s, %s", path, err)) } } return true @@ -232,13 +244,11 @@ func (s *Store) dir(path string) bool { if os.IsNotExist(err) { return false } else { - log.Fatalf("Error while stat %s, %s", path, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error stat %s, %s", path, err)) } } else { if !stat.IsDir() { - log.Fatalf("Path %s is not a directory.", path) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Path %s is not a directory.", path)) } } return true @@ -257,13 +267,11 @@ func (s *Store) flake(flake string) bool { func (s *Store) link(old, new string) { if !s.Compat { if err := os.Symlink(old, new); err != nil { - log.Fatalf("Error while linking %s to %s, %s", old, new, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error linking %s to %s, %s", old, new, err)) } } else { if err := os.WriteFile(new, []byte(old), s.PermissionFile); err != nil { - log.Fatalf("Error while writing associate file for %s to %s, %s", old, new, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error writing associate file for %s to %s, %s", old, new, err)) } } } @@ -276,7 +284,6 @@ func (s *Store) readlink(path string) string { // return "" // } else { // log.Fatalf("Error reading symlink %s, %s.", path, err) - // os.Exit(1) // } //} else { // return final @@ -287,8 +294,7 @@ func (s *Store) readlink(path string) string { if os.IsNotExist(err) { return "" } else { - log.Fatalf("Error reading association file %s, %s.", path, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error reading association file %s, %s.", path, err)) } } else { return string(final) diff --git a/store/tag.go b/store/tag.go index 5f717bd..2c11880 100644 --- a/store/tag.go +++ b/store/tag.go @@ -2,6 +2,7 @@ package store import ( "encoding/json" + "fmt" log "github.com/sirupsen/logrus" "os" "time" @@ -17,8 +18,7 @@ type Tag struct { func (s *Store) Tags() []string { var tags []string if entries, err := os.ReadDir(s.TagsDir()); err != nil { - log.Fatalf("Error while reading tags, %s", err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error reading tags, %s", err)) } else { for _, entry := range entries { if entry.IsDir() { @@ -36,8 +36,7 @@ func (s *Store) Tag(tag string) []string { } var images []string if entries, err := os.ReadDir(s.TagPath(tag)); err != nil { - log.Fatalf("Error while reading tag %s, %s", tag, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error reading tag %s, %s", tag, err)) } else { for _, entry := range entries { if entry.Name() == infoJson { @@ -58,16 +57,13 @@ func (s *Store) TagCreate(tag string) bool { return false } if err := os.Mkdir(s.TagPath(tag), s.PermissionDir); err != nil { - log.Fatalf("Error while creating tag %s, %s", tag, err) - log.Exit(1) + s.fatalClose(fmt.Sprintf("Error creating tag %s, %s", tag, err)) } if payload, err := json.Marshal(Tag{Type: Generic, CreationTime: time.Now().UTC()}); err != nil { - log.Fatalf("Error while generating tag %s metadata, %s", tag, err) - log.Exit(1) + s.fatalClose(fmt.Sprintf("Error generating tag %s metadata, %s", tag, err)) } else { if err = os.WriteFile(s.TagMetadataPath(tag), payload, s.PermissionFile); err != nil { - log.Fatalf("Error while writing tag %s metadata, %s", tag, err) - log.Exit(1) + s.fatalClose(fmt.Sprintf("Error writing tag %s metadata, %s", tag, err)) } } log.Infof("Tag %s created.", tag) @@ -87,12 +83,10 @@ func (s *Store) TagDestroy(tag string) { s.ImageTagRemove(flake, tag) } if err := os.Remove(s.TagMetadataPath(tag)); err != nil { - log.Fatalf("Error removing tag %s metadata, %s", tag, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error removing tag %s metadata, %s", tag, err)) } if err := os.Remove(s.TagPath(tag)); err != nil { - log.Fatalf("Error removing tag %s, %s", tag, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error removing tag %s, %s", tag, err)) } log.Infof("Tag %s destroyed.", tag) } @@ -106,13 +100,11 @@ func (s *Store) TagInfo(tag string) Tag { s.getLock("tag_" + tag).RLock() defer s.getLock("tag_" + tag).RUnlock() if payload, err := os.ReadFile(s.TagMetadataPath(tag)); err != nil { - log.Fatalf("Error while reading tag %s metadata, %s", tag, err) - log.Exit(1) + s.fatalClose(fmt.Sprintf("Error reading tag %s metadata, %s", tag, err)) } else { var info Tag if err = json.Unmarshal(payload, &info); err != nil { - log.Fatalf("Error while parsing tag %s metadata, %s", tag, err) - log.Exit(1) + s.fatalClose(fmt.Sprintf("Error parsing tag %s metadata, %s", tag, err)) } else { return info } @@ -141,12 +133,10 @@ func (s *Store) TagType(tag, t string) { info := s.TagInfo(tag) info.Type = t if payload, err := json.Marshal(info); err != nil { - log.Fatalf("Error while updating tag %s metadata, %s", tag, err) - log.Exit(1) + s.fatalClose(fmt.Sprintf("Error updating tag %s metadata, %s", tag, err)) } else { if err = os.WriteFile(s.TagMetadataPath(tag), payload, s.PermissionFile); err != nil { - log.Fatalf("Error while writing tag %s metadata, %s", tag, err) - log.Exit(1) + s.fatalClose(fmt.Sprintf("Error writing tag %s metadata, %s", tag, err)) } } log.Infof("Tag %s type set to %s.", tag, t) diff --git a/store/user.go b/store/user.go index d6772c3..7f9eabd 100644 --- a/store/user.go +++ b/store/user.go @@ -2,6 +2,7 @@ package store import ( "encoding/json" + "fmt" log "github.com/sirupsen/logrus" "os" ) @@ -17,13 +18,11 @@ type User struct { // user parses user metadata file. func (s *Store) user(path string) User { if payload, err := os.ReadFile(path); err != nil { - log.Fatalf("Error while reading user metadata %s, %s", path, err) - log.Exit(1) + s.fatalClose(fmt.Sprintf("Error reading user metadata %s, %s", path, err)) } else { var info User if err = json.Unmarshal(payload, &info); err != nil { - log.Fatalf("Error while parsing user metadata %s, %s", path, err) - log.Exit(1) + s.fatalClose(fmt.Sprintf("Error parsing user metadata %s, %s", path, err)) } else { return info } @@ -46,8 +45,7 @@ func (s *Store) User(flake string) User { func (s *Store) Users() []string { var users []string if entries, err := os.ReadDir(s.UsersDir()); err != nil { - log.Fatalf("Error while reading users, %s", err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error reading users, %s", err)) } else { for _, entry := range entries { if entry.IsDir() { @@ -61,12 +59,10 @@ func (s *Store) Users() []string { // UserMetadata sets user metadata. func (s *Store) UserMetadata(info User) { if payload, err := json.Marshal(info); err != nil { - log.Fatalf("Error while updating user %s metadata, %s", info.Snowflake, err) - log.Exit(1) + s.fatalClose(fmt.Sprintf("Error updating user %s metadata, %s", info.Snowflake, err)) } else { if err = os.WriteFile(s.UserMetadataPath(info.Snowflake), payload, s.PermissionFile); err != nil { - log.Fatalf("Error while writing user %s metadata, %s", info.Snowflake, err) - log.Exit(1) + s.fatalClose(fmt.Sprintf("Error writing user %s metadata, %s", info.Snowflake, err)) } } } @@ -85,8 +81,7 @@ func (s *Store) UserAdd(username string, privileged bool, password string) User } // Create user directory and images if err := os.MkdirAll(s.UserImagesPath(info.Snowflake), s.PermissionDir); err != nil { - log.Fatalf("Error while creating user %s directory, %s", info.Snowflake, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error creating user %s directory, %s", info.Snowflake, err)) } s.getLock(info.Snowflake).Lock() defer s.getLock(info.Snowflake).Unlock() @@ -196,8 +191,7 @@ func (s *Store) userUsernameAssociate(flake, username string) { // userUsernameDisassociate disassociates specific username. func (s *Store) userUsernameDisassociate(username string) { if err := os.Remove(s.UsernamePath(username)); err != nil { - log.Fatalf("Error disassociating username %s, %s", username, err) - log.Exit(1) + s.fatalClose(fmt.Sprintf("Error disassociating username %s, %s", username, err)) } } @@ -207,8 +201,7 @@ func (s *Store) userPassword(path string) string { if os.IsNotExist(err) { return "" } - log.Fatalf("Error reading password from user directory %s, %s", path, err) - log.Exit(1) + s.fatalClose(fmt.Sprintf("Error reading password from user directory %s, %s", path, err)) } else { return string(payload) } @@ -221,8 +214,7 @@ func (s *Store) userPasswordUpdate(path, password string) bool { return false } if err := os.WriteFile(path+"/passwd", []byte(password), s.PermissionFile); err != nil { - log.Fatalf("Error setting password for user directory %s, %s", path, err) - log.Exit(1) + s.fatalClose(fmt.Sprintf("Error setting password for user directory %s, %s", path, err)) } else { return true } @@ -295,8 +287,7 @@ func (s *Store) UserDestroy(flake string) { s.SecretDisassociate(info.Snowflake) // Remove user data directory if err := os.RemoveAll(s.UserPath(flake)); err != nil { - log.Fatalf("Error destroying user %s data directory, %s", flake, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error destroying user %s data directory, %s", flake, err)) } log.Infof("User %s username %s destroyed.", info.Snowflake, info.Username) } @@ -312,8 +303,7 @@ func (s *Store) UserImages(flake string) []string { var images []string if entries, err := os.ReadDir(s.UserImagesPath(flake)); err != nil { - log.Fatalf("Error while reading user %s images, %s", flake, err) - os.Exit(1) + s.fatalClose(fmt.Sprintf("Error reading user %s images, %s", flake, err)) } else { for _, entry := range entries { images = append(images, entry.Name()) @@ -57,22 +57,19 @@ func listenerSetup() { strconv.Itoa(int(serverConfig["port"].(int64)))) listener, err = net.Listen("tcp", address) if err != nil { - log.Errorf("Unable to listen on %s, %s", address, err) - os.Exit(1) + log.Errorf("Error binding %s, %s", address, err) } log.Infof("Web server listening on %s.", address) case true: path := serverConfig["host"].(string) listener, err = net.Listen("unix", path) if err != nil { - log.Errorf("Unable to listen on %s, %s", path, err) - os.Exit(1) + log.Errorf("Error binding %s, %s", path, err) } err = syscall.Chmod(path, 0777) if err != nil { - log.Errorf("Unable to change permission of web server socket, %s", err) - os.Exit(1) + log.Errorf("Error changing permission of web server socket, %s", err) } log.Infof("Web server listening on unix socket %s.", path) @@ -87,8 +84,7 @@ func runWebServer() { if err == http.ErrServerClosed { log.Info("Web server closed.") } else { - log.Errorf("Error while serving, %s", err) - os.Exit(1) + log.Errorf("Error starting server, %s", err) } } @@ -105,8 +101,7 @@ func registerWebpage() { var public fs.FS public, err = fs.Sub(assets, "assets") if err != nil { - log.Fatalf("Error while getting subdirectory, %s", err) - os.Exit(1) + log.Fatalf("Error getting subdirectory, %s", err) } router.StaticFS("/web", http.FS(public)) } |