tolo/storage/storage.go

178 lines
3 KiB
Go
Raw Permalink Normal View History

package storage
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"sync"
"time"
)
const configDir = ".tolo"
const dbFile = "tolo.db.json"
type Alias struct {
Name string `json:"name"`
Command string `json:"command"`
CreatedAt string `json:"created_at"`
}
type Data struct {
Aliases []Alias `json:"aliases"`
mu sync.RWMutex
}
var data *Data
var dataFile string
func init() {
homeDir, err := os.UserHomeDir()
if err != nil {
panic(err)
}
dataFile = filepath.Join(homeDir, configDir, dbFile)
data = &Data{}
load()
}
func load() error {
data.mu.Lock()
defer data.mu.Unlock()
if err := os.MkdirAll(filepath.Dir(dataFile), 0755); err != nil {
return err
}
content, err := os.ReadFile(dataFile)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
if len(content) == 0 {
return nil
}
return json.Unmarshal(content, data)
}
func saveLocked() error {
content, err := json.MarshalIndent(data, "", " ")
if err != nil {
return err
}
return os.WriteFile(dataFile, content, 0644)
}
func save() error {
data.mu.Lock()
defer data.mu.Unlock()
return saveLocked()
}
func AddAlias(name, command string) error {
data.mu.Lock()
defer data.mu.Unlock()
for _, a := range data.Aliases {
if a.Name == name {
return fmt.Errorf("alias '%s' already exists", name)
}
}
data.Aliases = append(data.Aliases, Alias{
Name: name,
Command: command,
CreatedAt: time.Now().Format(time.RFC3339),
})
return saveLocked()
}
func GetAlias(name string) (Alias, bool) {
data.mu.RLock()
defer data.mu.RUnlock()
for _, a := range data.Aliases {
if a.Name == name {
return a, true
}
}
return Alias{}, false
}
func UpdateAlias(name, command string) error {
data.mu.Lock()
defer data.mu.Unlock()
for i, a := range data.Aliases {
if a.Name == name {
data.Aliases[i].Command = command
return saveLocked()
}
}
return fmt.Errorf("alias '%s' not found", name)
}
func DeleteAlias(name string) error {
data.mu.Lock()
defer data.mu.Unlock()
for i, a := range data.Aliases {
if a.Name == name {
data.Aliases = append(data.Aliases[:i], data.Aliases[i+1:]...)
return saveLocked()
}
}
return fmt.Errorf("alias '%s' not found", name)
}
func ListAliases() []Alias {
data.mu.RLock()
defer data.mu.RUnlock()
return data.Aliases
}
func ShowAlias(name string) (Alias, bool) {
data.mu.RLock()
defer data.mu.RUnlock()
for _, a := range data.Aliases {
if a.Name == name {
return a, true
}
}
return Alias{}, false
}
func SearchAliases(query string) []Alias {
data.mu.RLock()
defer data.mu.RUnlock()
var results []Alias
for _, a := range data.Aliases {
if contains(a.Name, query) || contains(a.Command, query) {
results = append(results, a)
}
}
return results
}
func contains(s, substr string) bool {
return len(s) >= len(substr) && (s == substr || findSubstring(s, substr))
}
func findSubstring(s, substr string) bool {
for i := 0; i <= len(s)-len(substr); i++ {
if s[i:i+len(substr)] == substr {
return true
}
}
return false
}