package client import ( "crypto/tls" "errors" "io" "net" "time" "go.rctt.net/solec/core" ) type Handler interface { HandleMessage(msg core.Message) HandleListItem(list core.ListItem) HandleError(err error) } type Config struct { Addr string User string Pass string Tls bool TlsInsecure bool } type Client struct { h Handler cfg Config conn net.Conn } func NewClient(handler Handler, cfg Config) *Client { return &Client{ h: handler, cfg: cfg, } } func (c *Client) Connect() error { var err error if c.cfg.Tls { c.conn, err = tls.Dial("tcp", c.cfg.Addr, &tls.Config{ InsecureSkipVerify: c.cfg.TlsInsecure, }) if err != nil { return err } defer c.conn.Close() } else { c.conn, err = net.Dial("tcp", c.cfg.Addr) if err != nil { return err } defer c.conn.Close() } hs := core.Handshake{0, 1, core.ConnTypeUser} if err := core.Send(c.conn, hs); err != nil { return err } auth := core.UserAuth{Addr: c.cfg.User, Pass: c.cfg.Pass} if err := core.Send(c.conn, auth); err != nil { return err } c.read() return nil } func (c *Client) SendMessage(target, content string) error { msg := core.Message{ Source: c.cfg.User, Target: target, Content: content, } return core.Send(c.conn, msg) } func (c *Client) Join(channel string) error { umod := core.Usermode{ UserAddr: c.cfg.User, ChannelAddr: channel, Mode: core.UsermodeInChannel, } return core.Send(c.conn, umod) } func (c *Client) Leave(channel string) error { umod := core.Usermode{ UserAddr: c.cfg.User, ChannelAddr: channel, Mode: core.UsermodeNone, } return core.Send(c.conn, umod) } func (c *Client) GetHistory(channel string, since time.Time, count, offset int) error { hist := core.History{ Channel: channel, Since: since, Count: int64(count), Offset: int64(offset), } return core.Send(c.conn, hist) } func (c *Client) GetList(count, offset int) error { list := core.List{ Count: int64(count), Offset: int64(offset), } return core.Send(c.conn, list) } func (c *Client) read() { for { payload, err := core.Read(c.conn) if err != nil { c.h.HandleError(err) if errors.Is(err, io.EOF) { break } } c.handlePayload(payload) } } func (c *Client) handlePayload(payload any) { switch v := payload.(type) { case core.Message: c.h.HandleMessage(v) case core.ListItem: c.h.HandleListItem(v) } }