123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- // This file is subject to a 1-clause BSD license.
- // Its contents can be found in the enclosed LICENSE file.
- package main
- import (
- "bufio"
- "bytes"
- "io"
- "net"
- "os"
- "time"
- )
- // PayloadHandler is a function type for handling incoming
- // server messages.
- type PayloadHandler func([]byte)
- // ConnectionTimeout is the deadline for a connection.
- const ConnectionTimeout = time.Minute * 3
- // Client is an IRC client for a single network connection.
- type Client struct {
- handler PayloadHandler
- conn net.Conn
- reader *bufio.Reader
- }
- // NewClient creates a new client for the given handler.
- func NewClient(handler PayloadHandler) *Client {
- return &Client{
- handler: handler,
- }
- }
- // Open creates a new tcp connection to the given address.
- func (c *Client) Open(address string) error {
- var err error
- c.conn, err = net.Dial("tcp", address)
- if err != nil {
- return err
- }
- c.reader = bufio.NewReader(c.conn)
- return nil
- }
- // OpenFd opens a new client using the given file descriptor.
- // This function is used to hand over the tcp connection between
- // parent and its fork.
- func (c *Client) OpenFd(file *os.File) error {
- var err error
- c.conn, err = net.FileConn(file)
- if err != nil {
- return err
- }
- c.reader = bufio.NewReader(c.conn)
- return nil
- }
- // Close closes the connection.
- func (c *Client) Close() error {
- return c.conn.Close()
- }
- // File returns a file descriptor representing the tcp connection.
- // This call is only valid if the connection is open.
- func (c *Client) File() (*os.File, error) {
- return c.conn.(*net.TCPConn).File()
- }
- // Run starts the message processing loop and does not return for as long
- // as there is an open connection.
- func (c *Client) Run() error {
- for {
- line, err := c.Read()
- if err != nil {
- return err
- }
- go c.handler(line)
- }
- }
- // Write writes the given message to the underlying stream.
- func (c *Client) Write(p []byte) (int, error) {
- if c.conn == nil || len(p) == 0 {
- return 0, io.EOF
- }
- n, err := c.conn.Write(p)
- if err == nil {
- c.conn.SetDeadline(time.Now().Add(ConnectionTimeout))
- }
- return n, err
- }
- // Read reads the next message from the connection.
- // This call blocks until enough data is available or an error occurs.
- func (c *Client) Read() ([]byte, error) {
- if c.conn == nil {
- return nil, io.EOF
- }
- data, err := c.reader.ReadBytes('\n')
- if err != nil {
- return nil, err
- }
- c.conn.SetDeadline(time.Now().Add(ConnectionTimeout))
- return bytes.TrimSpace(data), nil
- }
|