Skip to content
Snippets Groups Projects
logs.go 3.14 KiB
//
//  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
}