package storage import ( "context" "encoding/gob" "fmt" "io" "os" "github.com/rs/zerolog" "go.neonxp.dev/djson/internal/model" jsonModel "go.neonxp.dev/json/model" ) func init() { gob.Register(new(jsonModel.ArrayNode)) gob.Register(new(jsonModel.ObjectNode)) gob.Register(new(jsonModel.StringNode)) gob.Register(new(jsonModel.BooleanNode)) gob.Register(new(jsonModel.NullNode)) gob.Register(new(jsonModel.NumberNode)) } type fsStorage struct { logger zerolog.Logger enc *gob.Encoder dec *gob.Decoder fh *os.File fileName string mutationsLog []model.Mutation } func New(fileName string, logger zerolog.Logger) (Storage, error) { logger.Info().Str("path", fileName).Msg("loading db") fh, err := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0o666) if err != nil { return nil, err } return &fsStorage{ logger: logger, fileName: fileName, fh: fh, enc: gob.NewEncoder(fh), dec: gob.NewDecoder(fh), mutationsLog: []model.Mutation{}, }, nil } func (fs *fsStorage) Commit(ctx context.Context, mut model.Mutation) error { if fs.enc == nil { return fmt.Errorf("file storage not initiated") } return fs.enc.Encode(mut) } func (fs *fsStorage) Load() chan model.Mutation { ch := make(chan model.Mutation) go func() { for { m := model.Mutation{} if err := fs.dec.Decode(&m); err != nil { if err != io.EOF { fs.logger.Err(err) } close(ch) return } fs.logger.Debug().RawJSON("json", []byte(m.String())).Msg("loaded mutation") fs.mutationsLog = append(fs.mutationsLog, m) ch <- m } }() return ch } func (fs *fsStorage) Close() error { return fs.fh.Close() }