Make SCUM logs live relay only
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
package companion
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (store *SCUMSQLStore) StoreConsoleRecords(ctx context.Context, records []ConsoleRecord) (int, error) {
|
||||
if store == nil || store.db == nil {
|
||||
return 0, fmt.Errorf("SCUM plugin SQL store is not configured")
|
||||
}
|
||||
normalized := make([]ConsoleRecord, 0, len(records))
|
||||
for _, record := range records {
|
||||
value, err := normalizeConsoleRecord(record)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
normalized = append(normalized, value)
|
||||
}
|
||||
if len(normalized) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
tx, err := store.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("begin SCUM console log write: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
stamp := time.Now().UTC()
|
||||
for _, record := range normalized {
|
||||
if _, err := tx.ExecContext(ctx, scumConsoleLogInsertSQL, scumConsoleRecordKey(record), record.ServerID, record.Stream, record.Sequence, record.OccurredAt, record.Text, stamp, stamp); err != nil {
|
||||
return 0, fmt.Errorf("write SCUM console log: %w", err)
|
||||
}
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return 0, fmt.Errorf("commit SCUM console logs: %w", err)
|
||||
}
|
||||
return len(normalized), nil
|
||||
}
|
||||
|
||||
func (store *SCUMSQLStore) StoreSemanticEventBatch(ctx context.Context, batch SemanticEventBatch) (int, error) {
|
||||
if store == nil || store.db == nil {
|
||||
return 0, fmt.Errorf("SCUM plugin SQL store is not configured")
|
||||
}
|
||||
normalized := make([]SemanticEvent, 0, len(batch.Events))
|
||||
for _, event := range batch.Events {
|
||||
value, err := normalizeSemanticEvent(event)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
normalized = append(normalized, value)
|
||||
}
|
||||
if len(normalized) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
tx, err := store.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("begin SCUM semantic event write: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
stamp := time.Now().UTC()
|
||||
for _, event := range normalized {
|
||||
if _, err := tx.ExecContext(ctx, scumSemanticEventInsertSQL, scumSemanticEventRecordKey(event), event.ServerID, event.Sequence, event.Type, event.PlayerID, nullText(event.DisplayName), event.OccurredAt, nullText(event.NetworkCorrelation), stamp, stamp); err != nil {
|
||||
return 0, fmt.Errorf("write SCUM semantic event: %w", err)
|
||||
}
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return 0, fmt.Errorf("commit SCUM semantic events: %w", err)
|
||||
}
|
||||
return len(normalized), nil
|
||||
}
|
||||
|
||||
func normalizeConsoleRecord(record ConsoleRecord) (ConsoleRecord, error) {
|
||||
record.ServerID = strings.TrimSpace(record.ServerID)
|
||||
record.Stream = strings.TrimSpace(record.Stream)
|
||||
record.Text = strings.TrimRight(record.Text, "\r\n")
|
||||
if record.ServerID == "" || (record.Stream != "stdout" && record.Stream != "stderr") || record.Sequence == 0 || record.OccurredAt.IsZero() || strings.TrimSpace(record.Text) == "" || len(record.Text) > 8192 {
|
||||
return ConsoleRecord{}, fmt.Errorf("SCUM console record is invalid")
|
||||
}
|
||||
record.OccurredAt = record.OccurredAt.UTC()
|
||||
return record, nil
|
||||
}
|
||||
|
||||
func normalizeSemanticEvent(event SemanticEvent) (SemanticEvent, error) {
|
||||
event.ServerID = strings.TrimSpace(event.ServerID)
|
||||
event.Type = strings.TrimSpace(event.Type)
|
||||
event.PlayerID = strings.TrimSpace(event.PlayerID)
|
||||
event.DisplayName = strings.TrimSpace(event.DisplayName)
|
||||
event.NetworkCorrelation = strings.TrimSpace(event.NetworkCorrelation)
|
||||
if event.ServerID == "" || event.Sequence == 0 || event.Type == "" || event.PlayerID == "" || event.OccurredAt.IsZero() || len(event.Type) > 80 || len(event.PlayerID) > 80 || len(event.DisplayName) > 120 || len(event.NetworkCorrelation) > 128 {
|
||||
return SemanticEvent{}, fmt.Errorf("SCUM semantic event is invalid")
|
||||
}
|
||||
event.OccurredAt = event.OccurredAt.UTC()
|
||||
return event, nil
|
||||
}
|
||||
|
||||
func scumConsoleRecordKey(record ConsoleRecord) string {
|
||||
digest := sha256.Sum256([]byte(strings.Join([]string{record.ServerID, record.Stream, fmt.Sprintf("%d", record.Sequence)}, "\x00")))
|
||||
return hex.EncodeToString(digest[:])
|
||||
}
|
||||
|
||||
func scumSemanticEventRecordKey(event SemanticEvent) string {
|
||||
digest := sha256.Sum256([]byte(strings.Join([]string{event.ServerID, event.Type, event.PlayerID, fmt.Sprintf("%d", event.Sequence)}, "\x00")))
|
||||
return hex.EncodeToString(digest[:])
|
||||
}
|
||||
|
||||
const scumConsoleLogInsertSQL = `
|
||||
INSERT INTO scum_console_logs (
|
||||
record_key, server_instance_id, stream, sequence, occurred_at, line_text, created_at, updated_at
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
occurred_at = VALUES(occurred_at),
|
||||
line_text = VALUES(line_text),
|
||||
updated_at = VALUES(updated_at)`
|
||||
|
||||
const scumSemanticEventInsertSQL = `
|
||||
INSERT INTO scum_semantic_events (
|
||||
record_key, server_instance_id, sequence, event_type, player_id, display_name, occurred_at, network_correlation, created_at, updated_at
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
display_name = VALUES(display_name),
|
||||
occurred_at = VALUES(occurred_at),
|
||||
network_correlation = VALUES(network_correlation),
|
||||
updated_at = VALUES(updated_at)`
|
||||
Reference in New Issue
Block a user