mirror of https://github.com/curusarn/resh
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
97 lines
2.5 KiB
97 lines
2.5 KiB
package histfile
|
|
|
|
import (
|
|
"encoding/json"
|
|
"log"
|
|
"os"
|
|
"sync"
|
|
|
|
"github.com/curusarn/resh/pkg/records"
|
|
)
|
|
|
|
type histfile struct {
|
|
mutex sync.Mutex
|
|
sessions map[string]records.Record
|
|
outputPath string
|
|
}
|
|
|
|
// Go creates histfile and runs two gorutines on it
|
|
func Go(input chan records.Record, outputPath string, sessionsToDrop chan string) {
|
|
hf := histfile{sessions: map[string]records.Record{}, outputPath: outputPath}
|
|
go hf.writer(input)
|
|
go hf.sessionGC(sessionsToDrop)
|
|
}
|
|
|
|
// sessionGC reads sessionIDs from channel and deletes them from histfile struct
|
|
func (h *histfile) sessionGC(sessionsToDrop chan string) {
|
|
for {
|
|
func() {
|
|
session := <-sessionsToDrop
|
|
log.Println("histfile: got session to drop", session)
|
|
h.mutex.Lock()
|
|
defer h.mutex.Unlock()
|
|
if part1, found := h.sessions[session]; found == true {
|
|
log.Println("histfile: Dropping session:", session)
|
|
delete(h.sessions, session)
|
|
go writeRecord(part1, h.outputPath)
|
|
} else {
|
|
log.Println("histfile: No hanging parts for session:", session)
|
|
}
|
|
}()
|
|
}
|
|
}
|
|
|
|
// writer reads records from channel, merges them and writes them to file
|
|
func (h *histfile) writer(input chan records.Record) {
|
|
for {
|
|
func() {
|
|
record := <-input
|
|
h.mutex.Lock()
|
|
defer h.mutex.Unlock()
|
|
|
|
if record.PartOne {
|
|
if _, found := h.sessions[record.SessionID]; found {
|
|
log.Println("histfile ERROR: Got another first part of the records before merging the previous one - overwriting!")
|
|
}
|
|
h.sessions[record.SessionID] = record
|
|
} else {
|
|
part1, found := h.sessions[record.SessionID]
|
|
if found == false {
|
|
log.Println("histfile ERROR: Got second part of records and nothing to merge it with - ignoring!")
|
|
} else {
|
|
delete(h.sessions, record.SessionID)
|
|
go mergeAndWriteRecord(part1, record, h.outputPath)
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
}
|
|
|
|
func mergeAndWriteRecord(part1, part2 records.Record, outputPath string) {
|
|
err := part1.Merge(part2)
|
|
if err != nil {
|
|
log.Println("Error while merging", err)
|
|
return
|
|
}
|
|
writeRecord(part1, outputPath)
|
|
}
|
|
|
|
func writeRecord(rec records.Record, outputPath string) {
|
|
recJSON, err := json.Marshal(rec)
|
|
if err != nil {
|
|
log.Println("Marshalling error", err)
|
|
return
|
|
}
|
|
f, err := os.OpenFile(outputPath,
|
|
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
if err != nil {
|
|
log.Println("Could not open file", err)
|
|
return
|
|
}
|
|
defer f.Close()
|
|
_, err = f.Write(append(recJSON, []byte("\n")...))
|
|
if err != nil {
|
|
log.Printf("Error while writing: %v, %s\n", rec, err)
|
|
return
|
|
}
|
|
}
|
|
|