mirror of
https://github.com/go-i2p/go-connfilter.git
synced 2025-07-12 19:04:51 -04:00
fmt, implement missing IRC stuff
This commit is contained in:
10
filter.go
10
filter.go
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
16
irc/types.go
16
irc/types.go
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user