refactor: flatten repository structure to root and archive research notes
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type AccountConfig struct {
|
||||
Username string
|
||||
Password string
|
||||
Role string
|
||||
Default string
|
||||
None []string
|
||||
Read []string
|
||||
Write []string
|
||||
Delete []string
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Path []string
|
||||
Port int
|
||||
Allow string
|
||||
Rules []string
|
||||
Log string
|
||||
FileRemove int
|
||||
ImagePreview bool
|
||||
FolderDownload string
|
||||
SessionTimeout int
|
||||
HTMLTitle string
|
||||
HTMLNotice string
|
||||
UserFile string
|
||||
UserHome string
|
||||
SSLCert string
|
||||
SSLKey string
|
||||
Accounts []AccountConfig
|
||||
}
|
||||
|
||||
func Default() Config {
|
||||
return Config{Path: []string{"."}, Port: 80, FileRemove: 1, ImagePreview: true, FolderDownload: "enable", SessionTimeout: 30, UserHome: "users"}
|
||||
}
|
||||
|
||||
func Load(path string) (Config, error) {
|
||||
c := Default()
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
defer f.Close()
|
||||
s := bufio.NewScanner(f)
|
||||
var section *AccountConfig
|
||||
for s.Scan() {
|
||||
line := strings.TrimSpace(s.Text())
|
||||
if line == "" || strings.HasPrefix(line, ";") || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
|
||||
name := strings.TrimSpace(line[1 : len(line)-1])
|
||||
if name != "" {
|
||||
c.Accounts = append(c.Accounts, AccountConfig{Username: name})
|
||||
section = &c.Accounts[len(c.Accounts)-1]
|
||||
} else {
|
||||
section = nil
|
||||
}
|
||||
continue
|
||||
}
|
||||
i := strings.IndexByte(line, '=')
|
||||
if i < 0 {
|
||||
continue
|
||||
}
|
||||
key, val := strings.TrimSpace(line[:i]), strings.TrimSpace(line[i+1:])
|
||||
val = strings.Trim(val, "\\\"")
|
||||
if section != nil {
|
||||
switch strings.ToLower(key) {
|
||||
case "password":
|
||||
section.Password = val
|
||||
case "role":
|
||||
section.Role = strings.ToLower(val)
|
||||
case "rule.default":
|
||||
section.Default = val
|
||||
case "rule.none":
|
||||
section.None = appendNonEmpty(section.None, val)
|
||||
case "rule.r":
|
||||
section.Read = appendNonEmpty(section.Read, val)
|
||||
case "rule.w":
|
||||
section.Write = appendNonEmpty(section.Write, val)
|
||||
case "rule.d":
|
||||
section.Delete = appendNonEmpty(section.Delete, val)
|
||||
}
|
||||
continue
|
||||
}
|
||||
switch strings.ToLower(key) {
|
||||
case "path":
|
||||
c.Path = splitPath(val)
|
||||
case "port":
|
||||
if n, e := strconv.Atoi(val); e == nil && n > 0 && n < 65536 {
|
||||
c.Port = n
|
||||
}
|
||||
case "allow":
|
||||
c.Allow = val
|
||||
case "rule":
|
||||
if val != "" {
|
||||
c.Rules = append(c.Rules, val)
|
||||
}
|
||||
case "log":
|
||||
c.Log = val
|
||||
case "file.remove":
|
||||
if n, e := strconv.Atoi(val); e == nil {
|
||||
c.FileRemove = n
|
||||
}
|
||||
case "image.preview":
|
||||
c.ImagePreview = parseBool(val, c.ImagePreview)
|
||||
case "folder.download":
|
||||
c.FolderDownload = strings.ToLower(val)
|
||||
case "folder.leaf.download":
|
||||
if parseBool(val, false) {
|
||||
c.FolderDownload = "leaf"
|
||||
}
|
||||
case "session.timeout":
|
||||
if n, e := strconv.Atoi(val); e == nil && n > 0 {
|
||||
c.SessionTimeout = n
|
||||
}
|
||||
case "html.title":
|
||||
c.HTMLTitle = val
|
||||
case "html.notice":
|
||||
c.HTMLNotice = val
|
||||
case "user.file":
|
||||
c.UserFile = val
|
||||
case "user.home":
|
||||
c.UserHome = strings.Trim(val, "/")
|
||||
case "ssl.cert":
|
||||
c.SSLCert = val
|
||||
case "ssl.key":
|
||||
c.SSLKey = val
|
||||
}
|
||||
}
|
||||
if err := s.Err(); err != nil {
|
||||
return c, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func splitPath(v string) []string {
|
||||
var out []string
|
||||
for _, p := range strings.Split(v, "|") {
|
||||
p = strings.TrimSpace(strings.Trim(p, "\\\""))
|
||||
if p != "" {
|
||||
out = append(out, p)
|
||||
}
|
||||
}
|
||||
if len(out) == 0 {
|
||||
return []string{"."}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func parseBool(v string, d bool) bool {
|
||||
switch strings.ToLower(strings.TrimSpace(v)) {
|
||||
case "true", "1", "yes", "on":
|
||||
return true
|
||||
case "false", "0", "no", "off":
|
||||
return false
|
||||
}
|
||||
return d
|
||||
}
|
||||
func (c Config) Validate() error {
|
||||
if len(c.Path) == 0 {
|
||||
return fmt.Errorf("path is empty")
|
||||
}
|
||||
if c.Port < 1 || c.Port > 65535 {
|
||||
return fmt.Errorf("invalid port")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func appendNonEmpty(dst []string, value string) []string {
|
||||
for _, item := range strings.Split(value, "|") {
|
||||
item = strings.TrimSpace(item)
|
||||
if item != "" {
|
||||
dst = append(dst, item)
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLoadAccountSections(t *testing.T) {
|
||||
d := t.TempDir()
|
||||
p := filepath.Join(d, "chfs.ini")
|
||||
content := `path=/srv/share
|
||||
port=8080
|
||||
[demo]
|
||||
password=abc
|
||||
rule.default=r
|
||||
rule.none=secret|private
|
||||
rule.r=docs
|
||||
rule.r=public
|
||||
rule.w=upload
|
||||
rule.d=admin
|
||||
[guest]
|
||||
password=
|
||||
rule.default=
|
||||
rule.none=hidden
|
||||
`
|
||||
if err := os.WriteFile(p, []byte(content), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c, err := Load(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(c.Accounts) != 2 {
|
||||
t.Fatalf("accounts=%d", len(c.Accounts))
|
||||
}
|
||||
if c.Accounts[0].Username != "demo" || c.Accounts[0].Default != "r" {
|
||||
t.Fatalf("demo=%#v", c.Accounts[0])
|
||||
}
|
||||
if len(c.Accounts[0].Read) != 2 || c.Accounts[0].Read[0] != "docs" || c.Accounts[0].Read[1] != "public" {
|
||||
t.Fatalf("read=%#v", c.Accounts[0].Read)
|
||||
}
|
||||
if len(c.Accounts[0].Write) != 1 || len(c.Accounts[0].Delete) != 1 || len(c.Accounts[0].None) != 2 {
|
||||
t.Fatalf("rules=%#v", c.Accounts[0])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user