// // tank // // Import and Playlist Daemon for autoradio project // // // Copyright (C) 2017-2019 Christian Pointner <equinox@helsinki.at> // // This file is part of tank. // // tank is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // any later version. // // tank is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with tank. If not, see <http://www.gnu.org/licenses/>. // package store import ( "bytes" "compress/gzip" "encoding/json" "io" "time" ) func (l *Log) Append(stream, line string) { l.m.Lock() defer l.m.Unlock() l.lines = append(l.lines, LogLine{stream, time.Now(), line}) } func (l *Log) MarshalJSON() ([]byte, error) { l.m.RLock() defer l.m.RUnlock() return json.Marshal(l.lines) } func (l *Log) encode() ([]byte, error) { l.m.RLock() defer l.m.RUnlock() var buf bytes.Buffer comp := gzip.NewWriter(&buf) enc := json.NewEncoder(comp) if err := enc.Encode(l.lines); err != nil { return nil, err } if err := comp.Close(); err != nil { return nil, err } return buf.Bytes(), nil } func (l *Log) decode(data []byte) error { l.m.RLock() defer l.m.RUnlock() l.lines = nil buf := bytes.NewBuffer(data) decomp, err := gzip.NewReader(buf) if err != nil { return err } dec := json.NewDecoder(decomp) return dec.Decode(&l.lines) } func (l *Log) NewReader(stream string) *LogReader { return &LogReader{l, -1, stream} } // LogReader is not a perfect io.Reader: // - lines longer than len(p) will be truncated !!! // - it will only return one line on each invocation even if len(p) would allow us to // return more than one line type LogReader struct { log *Log pos int stream string } func (r *LogReader) Read(p []byte) (n int, err error) { r.log.m.RLock() defer r.log.m.RUnlock() for { r.pos++ if r.pos >= len(r.log.lines) { return 0, io.EOF } if r.stream == "" || r.log.lines[r.pos].Stream == r.stream { return copy(p, []byte(r.log.lines[r.pos].Line)), nil } } } func (st *Store) AddImportLog(show string, id uint64, importStep string, log *Log) (err error) { encodedLog, err := log.encode() if err != nil { return err } return st.db.Create(&ImportLog{File: File{ID: id, ShowName: show}, ImportStep: importStep, Encoded: encodedLog}).Error } func (st *Store) GetImportLogs(show string, id uint64) (logs ImportLogs, err error) { cnt := 0 if err = st.db.Model(&File{ID: id}).Where("show_name = ?", show).Count(&cnt).Error; err != nil { return } if cnt == 0 { return nil, ErrNotFound } var results []ImportLog if err = st.db.Where("file_id = ?", id).Find(&results).Error; err != nil { return } logs = make(map[string]*Log) for _, result := range results { l := &Log{} if err = l.decode(result.Encoded); err != nil { return } logs[result.ImportStep] = l } return }