github.com/codingeasygo/util@v0.0.0-20231206062002-1ce2f004b7d9/xio/processor.go (about)

     1  package xio
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"net"
     7  	"strings"
     8  	"sync"
     9  )
    10  
    11  // Processor is interface for process connection
    12  type Processor interface {
    13  	ProcConn(conn io.ReadWriteCloser) (err error)
    14  }
    15  
    16  // ProcessorF is func to implement Processor
    17  type ProcessorF func(conn io.ReadWriteCloser) (err error)
    18  
    19  // ProcConn is process connection by func
    20  func (p ProcessorF) ProcConn(conn io.ReadWriteCloser) (err error) {
    21  	err = p(conn)
    22  	return
    23  }
    24  
    25  // ErrAsyncRunning is error for async running on PipeConn
    26  var ErrAsyncRunning = fmt.Errorf("asynced")
    27  
    28  // Piper is interface for process pipe connection
    29  type Piper interface {
    30  	PipeConn(conn io.ReadWriteCloser, target string) (err error)
    31  	Close() (err error)
    32  }
    33  
    34  // PiperF is func to implement Piper
    35  type PiperF func(conn io.ReadWriteCloser, target string) (err error)
    36  
    37  func (p PiperF) PipeConn(conn io.ReadWriteCloser, target string) (err error) {
    38  	err = p(conn, target)
    39  	return
    40  }
    41  
    42  func (p PiperF) Close() (err error) {
    43  	return
    44  }
    45  
    46  // PiperDialer is interface for implement piper dialer
    47  type PiperDialer interface {
    48  	DialPiper(uri string, bufferSize int) (raw Piper, err error)
    49  }
    50  
    51  // PiperDialerF is func to implement PiperDialer
    52  type PiperDialerF func(uri string, bufferSize int) (raw Piper, err error)
    53  
    54  // DialPiper will dial one piper by uri
    55  func (p PiperDialerF) DialPiper(uri string, bufferSize int) (raw Piper, err error) {
    56  	raw, err = p(uri, bufferSize)
    57  	return
    58  }
    59  
    60  // NetPiper is Piper implement by net.Dial
    61  type NetPiper struct {
    62  	net.Conn
    63  	CopyPiper
    64  }
    65  
    66  // DialNetPiper will return new NetPiper by net.Dial
    67  func DialNetPiper(uri string, bufferSize int) (piper Piper, err error) {
    68  	var network, address string
    69  	parts := strings.SplitN(uri, "://", 2)
    70  	if len(parts) < 2 {
    71  		network = "tcp"
    72  		address = parts[0]
    73  	} else {
    74  		network = parts[0]
    75  		address = parts[1]
    76  	}
    77  	conn, err := net.Dial(network, address)
    78  	if err == nil {
    79  		piper = &NetPiper{
    80  			Conn: conn,
    81  			CopyPiper: CopyPiper{
    82  				ReadWriteCloser: conn,
    83  				BufferSize:      bufferSize,
    84  			},
    85  		}
    86  	}
    87  	return
    88  }
    89  
    90  // CopyPiper is Piper implement by copy
    91  type CopyPiper struct {
    92  	io.ReadWriteCloser
    93  	BufferSize int
    94  	XX         string
    95  }
    96  
    97  // NewCopyPiper will return new CopyPiper
    98  func NewCopyPiper(raw io.ReadWriteCloser, bufferSize int) (piper *CopyPiper) {
    99  	piper = &CopyPiper{ReadWriteCloser: raw, BufferSize: bufferSize}
   100  	return
   101  }
   102  
   103  // PipeConn will pipe connection to raw
   104  func (c *CopyPiper) PipeConn(conn io.ReadWriteCloser, target string) (err error) {
   105  	wc := make(chan int, 1)
   106  	go func() {
   107  		var readErr error
   108  		if to, ok := conn.(io.WriterTo); ok {
   109  			_, readErr = to.WriteTo(c.ReadWriteCloser)
   110  		} else if from, ok := c.ReadWriteCloser.(io.ReaderFrom); ok {
   111  			_, readErr = from.ReadFrom(conn)
   112  		} else {
   113  			_, readErr = io.CopyBuffer(c.ReadWriteCloser, conn, make([]byte, c.BufferSize))
   114  		}
   115  		c.ReadWriteCloser.Close()
   116  		wc <- 1
   117  		if err == nil {
   118  			err = readErr
   119  		}
   120  	}()
   121  	{
   122  		var writeErr error
   123  		if from, ok := conn.(io.ReaderFrom); ok {
   124  			_, writeErr = from.ReadFrom(c.ReadWriteCloser)
   125  		} else if to, ok := c.ReadWriteCloser.(io.WriterTo); ok {
   126  			_, writeErr = to.WriteTo(conn)
   127  		} else {
   128  			_, writeErr = io.CopyBuffer(conn, c.ReadWriteCloser, make([]byte, c.BufferSize))
   129  		}
   130  		conn.Close()
   131  		if err == nil {
   132  			err = writeErr
   133  		}
   134  	}
   135  	<-wc
   136  	close(wc)
   137  	return
   138  }
   139  
   140  // ByteDistributeProcessor is distribute processor by prefix read first byte
   141  type ByteDistributeProcessor struct {
   142  	Next      map[byte]Processor
   143  	conns     map[string]io.ReadWriteCloser
   144  	listeners map[string]net.Listener
   145  	locker    sync.RWMutex
   146  }
   147  
   148  // NewByteDistributeProcessor will return new processor
   149  func NewByteDistributeProcessor() (processor *ByteDistributeProcessor) {
   150  	processor = &ByteDistributeProcessor{
   151  		Next:      map[byte]Processor{},
   152  		conns:     map[string]io.ReadWriteCloser{},
   153  		listeners: map[string]net.Listener{},
   154  		locker:    sync.RWMutex{},
   155  	}
   156  	return
   157  }
   158  
   159  // AddProcessor will add processor by mode
   160  func (b *ByteDistributeProcessor) AddProcessor(m byte, procesor Processor) {
   161  	b.Next[m] = procesor
   162  }
   163  
   164  // RemoveProcessor will remove processor by mode
   165  func (b *ByteDistributeProcessor) RemoveProcessor(m byte) {
   166  	delete(b.Next, m)
   167  }
   168  
   169  // ProcAccept will loop accept net.Conn and async call ProcConn
   170  func (b *ByteDistributeProcessor) ProcAccept(listener net.Listener) (err error) {
   171  	b.locker.Lock()
   172  	b.listeners[fmt.Sprintf("%p", listener)] = listener
   173  	b.locker.Unlock()
   174  	defer func() {
   175  		b.locker.Lock()
   176  		delete(b.listeners, fmt.Sprintf("%p", listener))
   177  		b.locker.Unlock()
   178  	}()
   179  	procConn := func(c net.Conn) {
   180  		xerr := b.ProcConn(c)
   181  		if xerr != ErrAsyncRunning {
   182  			c.Close()
   183  		}
   184  	}
   185  	var conn net.Conn
   186  	for {
   187  		conn, err = listener.Accept()
   188  		if err != nil {
   189  			break
   190  		}
   191  		go procConn(conn)
   192  	}
   193  	return
   194  }
   195  
   196  // ProcConn will process connection by prefix reader and distribute to next processor
   197  func (b *ByteDistributeProcessor) ProcConn(conn io.ReadWriteCloser) (err error) {
   198  	b.locker.Lock()
   199  	b.conns[fmt.Sprintf("%p", conn)] = conn
   200  	b.locker.Unlock()
   201  	defer func() {
   202  		b.locker.Lock()
   203  		delete(b.conns, fmt.Sprintf("%p", conn))
   204  		b.locker.Unlock()
   205  	}()
   206  	preConn := NewPrefixReadWriteCloser(conn)
   207  	pre, err := preConn.PreRead(1)
   208  	if err != nil {
   209  		return
   210  	}
   211  	processor := b.Next[pre[0]]
   212  	if processor == nil {
   213  		processor = b.Next['*']
   214  	}
   215  	if processor == nil {
   216  		err = fmt.Errorf("processor is not exist by %v", pre[0])
   217  		return
   218  	}
   219  	err = processor.ProcConn(preConn)
   220  	return
   221  }
   222  
   223  // Close will close all listener and connection
   224  func (b *ByteDistributeProcessor) Close() (err error) {
   225  	b.locker.Lock()
   226  	for _, conn := range b.conns {
   227  		conn.Close()
   228  	}
   229  	for _, listener := range b.listeners {
   230  		listener.Close()
   231  	}
   232  	b.locker.Unlock()
   233  	return
   234  }