194 строки
3,1 КиБ
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
|
|
}
|