irc/pkg/ircv3/message.go

140 lines
2.6 KiB
Go

package ircv3
import (
"errors"
"io"
"strings"
)
type Message struct {
Source *NUH
Command string
Params []string
Tags Tags
}
func NewMessage(command string, params ...string) *Message {
return &Message{
Source: nil,
Command: command,
Params: params,
Tags: make(Tags),
}
}
func (m *Message) SetSource(nuh *NUH) *Message {
m.Source = nuh
return m
}
func (m *Message) Param(i int) string {
if len(m.Params) > i {
return m.Params[i]
}
return ""
}
func (msg *Message) String() string {
sb := new(strings.Builder)
msg.Encode(sb)
return sb.String()
}
func (msg *Message) Encode(w io.Writer) error {
if msg.Command == "" {
return nil
}
if msg.Tags != nil && len(msg.Tags) > 0 {
_, err := msg.Tags.WriteTo(w)
if err != nil {
return err
}
_, err = w.Write([]byte(" "))
if err != nil {
return err
}
}
if msg.Source != nil {
if _, err := w.Write([]byte(":")); err != nil {
return err
}
if _, err := w.Write([]byte(msg.Source.String())); err != nil {
return err
}
if _, err := w.Write([]byte(" ")); err != nil {
return err
}
}
// now write command
if _, err := w.Write([]byte(msg.Command)); err != nil {
return err
}
if len(msg.Params) > 0 {
if _, err := w.Write([]byte(" ")); err != nil {
return err
}
}
for idx, v := range msg.Params {
if idx != 0 {
if _, err := w.Write([]byte(" ")); err != nil {
return err
}
}
// now write any params
if len(msg.Params)-1 == idx && strings.Contains(v, " ") {
if _, err := w.Write([]byte(":")); err != nil {
return err
}
}
if _, err := w.Write([]byte(v)); err != nil {
return err
}
}
return nil
}
type NUH struct {
Name string
User string
Host string
}
var (
MalformedNUH = errors.New("NUH is malformed")
)
// ParseNUH parses a NUH source of an IRC message into its constituent parts;
// name (nickname or server name), username, and hostname.
func ParseNUH(in string) (out NUH, err error) {
if len(in) == 0 {
return out, MalformedNUH
}
hostStart := strings.IndexByte(in, '@')
if hostStart != -1 {
out.Host = in[hostStart+1:]
in = in[:hostStart]
}
userStart := strings.IndexByte(in, '!')
if userStart != -1 {
out.User = in[userStart+1:]
in = in[:userStart]
}
out.Name = in
return
}
// Canonical returns the canonical string representation of the NUH.
func (nuh *NUH) String() (result string) {
var out strings.Builder
out.Grow(len(nuh.Name) + len(nuh.User) + len(nuh.Host) + 2)
out.WriteString(nuh.Name)
if len(nuh.User) != 0 {
out.WriteByte('!')
out.WriteString(nuh.User)
}
if len(nuh.Host) != 0 {
out.WriteByte('@')
out.WriteString(nuh.Host)
}
return out.String()
}