fmt, implement missing IRC stuff

This commit is contained in:
eyedeekay
2025-02-03 23:33:00 -05:00
parent a47f72acbb
commit 0efe14fb96
5 changed files with 98 additions and 14 deletions

View File

@ -34,6 +34,16 @@ func (c *ConnFilter) Read(b []byte) (n int, err error) {
return buffer.Len(), nil
}
// Write writes the data to the underlying connection after replacing all occurrences of target strings
// with their corresponding replacement strings. The replacements are made sequentially for each
// target-replacement pair.
func (c *ConnFilter) Write(b []byte) (n int, err error) {
for i := range c.targets {
b = bytes.ReplaceAll(b, []byte(c.targets[i]), []byte(c.replacements[i]))
}
return c.Conn.Write(b)
}
// NewConnFilter creates a new ConnFilter that replaces occurrences of target strings with replacement strings in the data read from the connection.
// It returns an error if the lengths of target and replacement slices are not equal.
func NewConnFilter(parentConn net.Conn, targets, replacements []string) (net.Conn, error) {

View File

@ -27,7 +27,7 @@ var ex net.Conn = &FunctionConnFilter{}
func (c *FunctionConnFilter) Write(b []byte) (n int, err error) {
b2, err := c.WriteFilter(b)
if err != nil {
return len(b), err
return 0, err
}
return c.Conn.Write(b2)
}
@ -36,21 +36,27 @@ func (c *FunctionConnFilter) Write(b []byte) (n int, err error) {
func (c *FunctionConnFilter) Read(b []byte) (n int, err error) {
n, err = c.Conn.Read(b)
if err != nil {
return n, err
return 0, err
}
b2, err := c.ReadFilter(b)
b2, err := c.ReadFilter(b[:n])
if err != nil {
return n, err
return 0, err
}
copy(b, b2)
return len(b2), nil
}
// NewFunctionConnFilter creates a new FunctionConnFilter that has the powerful ability to rewrite any byte that comes across the net.Conn with a user-defined function. By default a no-op function.
func NewFunctionConnFilter(parentConn net.Conn, Function string) (net.Conn, error) {
// NewFunctionConnFilter creates a new FunctionConnFilter that has the powerful ability to rewrite any byte that comes across the net.Conn with user-defined functions. By default, the filters are no-op functions.
func NewFunctionConnFilter(parentConn net.Conn, readFilter, writeFilter func(b []byte) ([]byte, error)) (net.Conn, error) {
if readFilter == nil {
readFilter = noopReadFilter
}
if writeFilter == nil {
writeFilter = noopWriteFilter
}
return &FunctionConnFilter{
Conn: parentConn,
ReadFilter: noopReadFilter,
WriteFilter: noopWriteFilter,
ReadFilter: readFilter,
WriteFilter: writeFilter,
}, nil
}

View File

@ -6,18 +6,19 @@ import (
"log"
"net"
"strings"
"sync"
)
type defaultLogger struct{}
// Debug implements Logger.
func (d *defaultLogger) Debug(format string, args ...interface{}) {
log.Printf("DBG:"+format, args)
log.Printf("DBG:"+format, args...)
}
// Error implements Logger.
func (d *defaultLogger) Error(format string, args ...interface{}) {
log.Printf("ERR:"+format, args)
log.Printf("ERR:"+format, args...)
}
// New creates a new IRC inspector wrapping an existing listener
@ -30,6 +31,7 @@ func New(listener net.Listener, config Config) *Inspector {
listener: listener,
config: config,
filters: make([]Filter, 0),
mu: sync.RWMutex{},
}
}
@ -92,13 +94,15 @@ func (c *ircConn) Read(b []byte) (n int, err error) {
func (c *ircConn) Write(b []byte) (n int, err error) {
if c.writer == nil {
c.writer = bufio.NewWriter(c.Conn)
defer c.writer.Flush()
}
msg, err := parseMessage(string(b))
if err != nil {
return c.writer.Write(b)
}
defer c.writer.Flush()
if err := c.inspector.processMessage(msg); err != nil {
c.inspector.config.Logger.Error("process error: %v", err)
}
@ -147,6 +151,20 @@ func (i *Inspector) AddFilter(filter Filter) {
i.filters = append(i.filters, filter)
}
// parseNumeric converts a 3-character IRC command string to its numeric equivalent.
// It returns an error if the command length is not exactly 3 characters.
func parseNumeric(command string) (int, error) {
if len(command) != 3 {
return 0, fmt.Errorf("invalid command length")
}
for _, char := range command {
if char < '0' || char > '9' {
return 0, fmt.Errorf("command contains non-numeric characters")
}
}
return int(command[0]-'0')*100 + int(command[1]-'0')*10 + int(command[2]-'0'), nil
}
func (i *Inspector) processMessage(msg *Message) error {
i.mu.RLock()
defer i.mu.RUnlock()
@ -167,7 +185,7 @@ func (i *Inspector) processMessage(msg *Message) error {
// Process filters
for _, filter := range i.filters {
if matchesFilter(msg, filter) {
if filter.Command == "" || filter.Command == msg.Command {
if err := filter.Callback(msg); err != nil {
return err
}

View File

@ -2,6 +2,7 @@ package ircinspector
import (
"net"
"strings"
"sync"
)
@ -14,6 +15,21 @@ type Message struct {
Trailing string
}
func (m *Message) String() string {
var parts []string
if m.Prefix != "" {
parts = append(parts, ":"+m.Prefix)
}
parts = append(parts, m.Command)
if len(m.Params) > 0 {
parts = append(parts, strings.Join(m.Params, " "))
}
if m.Trailing != "" {
parts = append(parts, ":"+m.Trailing)
}
return strings.Join(parts, " ") + "\r\n"
}
// Filter defines criteria for message filtering
type Filter struct {
Command string

View File

@ -9,7 +9,7 @@ import (
var ErrInvalidRegexFilter = errors.New("invalid regex filter")
type RegexConnFilter struct {
net.Conn
FunctionConnFilter
match string
}
@ -25,10 +25,44 @@ func (c *RegexConnFilter) Read(b []byte) (n int, err error) {
return buffer.Len(), nil
}
// NewRegexConnFilter creates a new RegexConnFilter that replaces occurrences of target regex with empty strings in the data read from the connection.
// target regex is c.match
func (c *RegexConnFilter) ReadFilter(b []byte) ([]byte, error) {
if c.match == "" {
return b, nil
}
// Create a new bytes buffer
var buffer bytes.Buffer
// Write the modified data to the buffer, with regex matches removed
buffer.Write(bytes.ReplaceAll(b, []byte(c.match), []byte("")))
return buffer.Bytes(), nil
}
// WriteFilter creates a new RegexConnFilter that replaces occurrences of target regex with empty strings in the data read from the connection.
// target regex is c.match
func (c *RegexConnFilter) WriteFilter(b []byte) ([]byte, error) {
if c.match == "" {
return b, nil
}
// Create a new bytes buffer
var buffer bytes.Buffer
// Write the modified data to the buffer, with regex matches removed
buffer.Write(bytes.ReplaceAll(b, []byte(c.match), []byte("")))
return buffer.Bytes(), nil
}
// NewRegexConnFilter creates a new RegexConnFilter that replaces occurrences of target regex with empty strings in the data read from the connection.
// It returns an error if the lengths of target and replacement slices are not equal.
func NewRegexConnFilter(parentConn net.Conn, regex string) (net.Conn, error) {
return &RegexConnFilter{
Conn: parentConn,
FunctionConnFilter: FunctionConnFilter{
Conn: parentConn,
},
}, nil
}