ktgo/pkg/storage/storage.go

194 строки
3,1 КиБ
Go

package storage
import (
"bufio"
"log"
"my/ktgo/pkg/lib"
"os"
"strings"
"sync"
"time"
"github.com/fsnotify/fsnotify"
)
type Storage struct {
filename string
fd *os.File
watcher *fsnotify.Watcher
list, listCase List
lock sync.RWMutex
}
type List []string
func NewStorage(filename string) (*Storage, error) {
s := &Storage{
filename: filename,
}
err := s.reCreateWatcher()
if err != nil {
return nil, err
}
return s, nil
}
func (s *Storage) reReadFile() error {
fd, err := os.OpenFile(s.filename, os.O_RDONLY, 0)
if err != nil {
return err
}
var newlist, newlistCase List
scanner := bufio.NewScanner(fd)
for {
ok := scanner.Scan()
if !ok {
break
}
line := scanner.Text()
if strings.HasSuffix(line, "==") {
newlistCase = append(newlistCase, line[:len(line)-2])
} else {
newlist = append(newlist, line)
}
}
s.lock.Lock()
defer s.lock.Unlock()
s.list = newlist
s.listCase = newlistCase
return nil
}
func (s *Storage) reCreateWatcher() error {
go s.reCreateWatcher_sync()
return nil
}
func (s *Storage) reCreateWatcher_sync() error {
s.closeWatcher()
s.waitForAndReadFile()
watcher, err := s.createNewWatcher()
if err != nil {
return err
}
s.lock.Lock()
defer s.lock.Unlock()
s.watcher = watcher
go s.watcherListener()
return nil
}
func (s *Storage) waitForAndReadFile() {
for {
err := s.reReadFile()
if err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
}
func (s *Storage) createNewWatcher() (*fsnotify.Watcher, error) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
return nil, err
}
err = watcher.Add(s.filename)
if err != nil {
return nil, err
}
return watcher, nil
}
func (s *Storage) watcherListener() {
s.lock.RLock()
if s.watcher == nil {
s.lock.RUnlock()
s.reCreateWatcher()
return
}
defer s.lock.RUnlock()
select {
case event, ok := <-s.watcher.Events:
if !ok {
return
}
s.handleWatcherEvent(event)
case err, ok := <-s.watcher.Errors:
if !ok {
return
}
log.Println("error:", err)
}
}
func (s *Storage) handleWatcherEvent(event fsnotify.Event) {
log.Printf("Storage: %v: %v", s.filename, event.String())
s.onStorageUpdated()
}
func (s *Storage) onStorageUpdated() {
err := s.reCreateWatcher()
if err != nil {
log.Printf("Storage watcher creating: %v", err)
}
}
func (s *Storage) GetList() *List {
s.lock.RLock()
defer s.lock.RUnlock()
return &s.list
}
func (s *Storage) GetListCase() *List {
s.lock.RLock()
defer s.lock.RUnlock()
return &s.listCase
}
func (s *Storage) AddLine(p, v string) error {
return nil
}
func (s *Storage) Save() error {
s.makeBackup()
return s.doSave()
}
func (s *Storage) doSave() error {
buf := strings.Join(s.list, "\n")
buf += strings.Join(s.listCase, "==\n")
return lib.WriteFile(s.filename, buf)
}
func (s *Storage) makeBackup() {
cmd := "cp " + s.filename + " " + s.filename + ".backup"
lib.Bash(cmd)
}
func (s *Storage) Close() {
s.closeWatcher()
}
func (s *Storage) closeWatcher() {
s.lock.RLock()
if s.watcher != nil {
s.watcher.Close()
}
s.lock.RUnlock()
s.lock.Lock()
defer s.lock.Unlock()
s.watcher = nil
}