aboutsummaryrefslogtreecommitdiff
path: root/irclog.go
blob: f40dea14eb454645836298e33646b8969062f8b8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121

package main

import (
	"context"
	"fmt"
	"log/slog"
	"os"
	"strconv"
	"strings"
	"unicode"
	"unicode/utf8"
)

type IRCLogHandler struct {
	level slog.Level
}

func NewIRCLogHandler(level slog.Level) *IRCLogHandler {
	return &IRCLogHandler{
		level: level,
	}
}

func (h *IRCLogHandler) Enabled(_ context.Context, level slog.Level) bool {
	return level >= h.level
}

func (h *IRCLogHandler) Handle(_ context.Context, r slog.Record) error {
	var sb strings.Builder

	sb.WriteString("PRIVMSG #logs :")

	sb.WriteString(r.Message)

	r.Attrs(func(a slog.Attr) bool {
		sb.WriteString(" ")

		key := a.Key
		if needsQuoting(key) {
			key = strconv.Quote(key)
		}
		sb.WriteString(key)
		sb.WriteString("=")

		val := attrValueToString(a.Value)
		if needsQuoting(val) {
			val = strconv.Quote(val)
		}
		sb.WriteString(val)

		return true
	})

	str := sb.String()

	select {
	case ircSendBuffered <- str:
	default:
		fmt.Fprintln(os.Stderr, "DROP")
	}

	fmt.Fprintln(os.Stderr, str)

	return nil
}

func (h *IRCLogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
	return h
}

func (h *IRCLogHandler) WithGroup(_ string) slog.Handler {
	return h
}

func attrValueToString(v slog.Value) string {
	return v.String()
}

func init() {
}

// copied from slog
func needsQuoting(s string) bool {
	if len(s) == 0 {
		return true
	}
	for i := 0; i < len(s); {
		b := s[i]
		if b < utf8.RuneSelf {
			if b != '\\' && (b == ' ' || b == '=' || !safeSet[b]) {
				return true
			}
			i++
			continue
		}
		r, size := utf8.DecodeRuneInString(s[i:])
		if r == utf8.RuneError || unicode.IsSpace(r) || !unicode.IsPrint(r) {
			return true
		}
		i += size
	}
	return false
}

var safeSet = [256]bool{
	'!': true, '#': true, '$': true, '%': true, '&': true, '\'': true,
	'*': true, '+': true, ',': true, '-': true, '.': true, '/': true,
	'0': true, '1': true, '2': true, '3': true, '4': true,
	'5': true, '6': true, '7': true, '8': true, '9': true,
	':': true, ';': true, '<': true, '>': true, '?': true, '@': true,
	'A': true, 'B': true, 'C': true, 'D': true, 'E': true, 'F': true,
	'G': true, 'H': true, 'I': true, 'J': true, 'K': true, 'L': true,
	'M': true, 'N': true, 'O': true, 'P': true, 'Q': true, 'R': true,
	'S': true, 'T': true, 'U': true, 'V': true, 'W': true, 'X': true,
	'Y': true, 'Z': true, '[': true, ']': true, '^': true, '_': true,
	'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true,
	'g': true, 'h': true, 'i': true, 'j': true, 'k': true, 'l': true,
	'm': true, 'n': true, 'o': true, 'p': true, 'q': true, 'r': true,
	's': true, 't': true, 'u': true, 'v': true, 'w': true, 'x': true,
	'y': true, 'z': true, '{': true, '|': true, '}': true, '~': true,
}