github.com/ergo-services/ergo@v1.999.224/gen/tcp_handler.go (about)

     1  package gen
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"net"
     7  	"time"
     8  
     9  	"github.com/ergo-services/ergo/etf"
    10  	"github.com/ergo-services/ergo/lib"
    11  )
    12  
    13  type TCPHandlerStatus error
    14  
    15  var (
    16  	TCPHandlerStatusOK    TCPHandlerStatus = nil
    17  	TCPHandlerStatusClose TCPHandlerStatus = fmt.Errorf("close")
    18  
    19  	defaultQueueLength = 10
    20  )
    21  
    22  type TCPHandlerBehavior interface {
    23  	ServerBehavior
    24  
    25  	// Mandatory callback
    26  	HandlePacket(process *TCPHandlerProcess, packet []byte, conn *TCPConnection) (int, int, TCPHandlerStatus)
    27  
    28  	// Optional callbacks
    29  	HandleConnect(process *TCPHandlerProcess, conn *TCPConnection) TCPHandlerStatus
    30  	HandleDisconnect(process *TCPHandlerProcess, conn *TCPConnection)
    31  	HandleTimeout(process *TCPHandlerProcess, conn *TCPConnection) TCPHandlerStatus
    32  
    33  	HandleTCPHandlerCall(process *TCPHandlerProcess, from ServerFrom, message etf.Term) (etf.Term, ServerStatus)
    34  	HandleTCPHandlerCast(process *TCPHandlerProcess, message etf.Term) ServerStatus
    35  	HandleTCPHandlerInfo(process *TCPHandlerProcess, message etf.Term) ServerStatus
    36  	HandleTCPHandlerTerminate(process *TCPHandlerProcess, reason string)
    37  }
    38  
    39  type TCPHandler struct {
    40  	Server
    41  
    42  	behavior TCPHandlerBehavior
    43  }
    44  
    45  type TCPHandlerProcess struct {
    46  	ServerProcess
    47  	behavior TCPHandlerBehavior
    48  
    49  	lastPacket  int64
    50  	idleTimeout int
    51  	id          int
    52  }
    53  
    54  type optsTCPHandler struct {
    55  	id          int
    56  	idleTimeout int
    57  }
    58  
    59  type TCPConnection struct {
    60  	Addr   net.Addr
    61  	Socket io.Writer
    62  	State  interface{}
    63  }
    64  
    65  type messageTCPHandlerIdleCheck struct{}
    66  type messageTCPHandlerPacket struct {
    67  	packet     []byte
    68  	connection *TCPConnection
    69  }
    70  type messageTCPHandlerPacketResult struct {
    71  	left  int
    72  	await int
    73  }
    74  type messageTCPHandlerConnect struct {
    75  	connection *TCPConnection
    76  }
    77  type messageTCPHandlerDisconnect struct {
    78  	connection *TCPConnection
    79  }
    80  
    81  type messageTCPHandlerTimeout struct {
    82  	connection *TCPConnection
    83  }
    84  
    85  func (tcph *TCPHandler) Init(process *ServerProcess, args ...etf.Term) error {
    86  	behavior, ok := process.Behavior().(TCPHandlerBehavior)
    87  	if !ok {
    88  		return fmt.Errorf("TCP: not a TCPHandlerBehavior")
    89  	}
    90  	handlerProcess := &TCPHandlerProcess{
    91  		ServerProcess: *process,
    92  		behavior:      behavior,
    93  	}
    94  	if len(args) == 0 {
    95  		return fmt.Errorf("TCP: can not start with no args")
    96  	}
    97  
    98  	if a, ok := args[0].(optsTCPHandler); ok {
    99  		handlerProcess.idleTimeout = a.idleTimeout
   100  		handlerProcess.id = a.id
   101  	} else {
   102  		return fmt.Errorf("TCP: wrong args for the TCPHandler")
   103  	}
   104  
   105  	// do not inherit parent State
   106  	handlerProcess.State = nil
   107  	process.State = handlerProcess
   108  
   109  	if handlerProcess.idleTimeout > 0 {
   110  		process.CastAfter(process.Self(), messageTCPHandlerIdleCheck{}, 5*time.Second)
   111  	}
   112  
   113  	return nil
   114  }
   115  
   116  func (tcph *TCPHandler) HandleCall(process *ServerProcess, from ServerFrom, message etf.Term) (etf.Term, ServerStatus) {
   117  	tcpp := process.State.(*TCPHandlerProcess)
   118  	return tcpp.behavior.HandleTCPHandlerCall(tcpp, from, message)
   119  }
   120  
   121  func (tcph *TCPHandler) HandleCast(process *ServerProcess, message etf.Term) ServerStatus {
   122  	tcpp := process.State.(*TCPHandlerProcess)
   123  	switch message.(type) {
   124  	case messageTCPHandlerIdleCheck:
   125  		if time.Now().Unix()-tcpp.lastPacket > int64(tcpp.idleTimeout) {
   126  			return ServerStatusStop
   127  		}
   128  		process.CastAfter(process.Self(), messageTCPHandlerIdleCheck{}, 5*time.Second)
   129  
   130  	default:
   131  		return tcpp.behavior.HandleTCPHandlerCast(tcpp, message)
   132  	}
   133  	return ServerStatusOK
   134  }
   135  
   136  func (tcph *TCPHandler) HandleInfo(process *ServerProcess, message etf.Term) ServerStatus {
   137  	tcpp := process.State.(*TCPHandlerProcess)
   138  	return tcpp.behavior.HandleTCPHandlerInfo(tcpp, message)
   139  }
   140  
   141  func (tcph *TCPHandler) HandleDirect(process *ServerProcess, ref etf.Ref, message interface{}) (interface{}, DirectStatus) {
   142  	tcpp := process.State.(*TCPHandlerProcess)
   143  	switch m := message.(type) {
   144  	case *messageTCPHandlerPacket:
   145  		tcpp.lastPacket = time.Now().Unix()
   146  		left, await, err := tcpp.behavior.HandlePacket(tcpp, m.packet, m.connection)
   147  		res := messageTCPHandlerPacketResult{
   148  			left:  left,
   149  			await: await,
   150  		}
   151  		return res, err
   152  	case messageTCPHandlerConnect:
   153  		return nil, tcpp.behavior.HandleConnect(tcpp, m.connection)
   154  	case messageTCPHandlerDisconnect:
   155  		tcpp.behavior.HandleDisconnect(tcpp, m.connection)
   156  		return nil, TCPHandlerStatusClose
   157  	case messageTCPHandlerTimeout:
   158  		return nil, tcpp.behavior.HandleTimeout(tcpp, m.connection)
   159  	default:
   160  		return nil, DirectStatusOK
   161  	}
   162  }
   163  
   164  func (tcph *TCPHandler) Terminate(process *ServerProcess, reason string) {
   165  	tcpp := process.State.(*TCPHandlerProcess)
   166  	tcpp.behavior.HandleTCPHandlerTerminate(tcpp, reason)
   167  }
   168  
   169  //
   170  // default callbacks
   171  //
   172  
   173  func (tcph *TCPHandler) HandleConnect(process *TCPHandlerProcess, conn *TCPConnection) TCPHandlerStatus {
   174  	return TCPHandlerStatusOK
   175  }
   176  func (tcph *TCPHandler) HandleDisconnect(process *TCPHandlerProcess, conn *TCPConnection) {
   177  	return
   178  }
   179  func (tcph *TCPHandler) HandleTimeout(process *TCPHandlerProcess, conn *TCPConnection) TCPHandlerStatus {
   180  	return TCPHandlerStatusOK
   181  }
   182  
   183  // HandleTCPHandlerCall
   184  func (tcph *TCPHandler) HandleTCPHandlerCall(process *TCPHandlerProcess, from ServerFrom, message etf.Term) (etf.Term, ServerStatus) {
   185  	lib.Warning("HandleTCPHandlerCall: unhandled message (from %#v) %#v", from, message)
   186  	return etf.Atom("ok"), ServerStatusOK
   187  }
   188  
   189  // HandleTCPHandlerCast
   190  func (tcph *TCPHandler) HandleTCPHandlerCast(process *TCPHandlerProcess, message etf.Term) ServerStatus {
   191  	lib.Warning("HandleTCPHandlerCast: unhandled message %#v", message)
   192  	return ServerStatusOK
   193  }
   194  
   195  // HandleTCPHandlerInfo
   196  func (tcph *TCPHandler) HandleTCPHandlerInfo(process *TCPHandlerProcess, message etf.Term) ServerStatus {
   197  	lib.Warning("HandleTCPHandlerInfo: unhandled message %#v", message)
   198  	return ServerStatusOK
   199  }
   200  func (tcph *TCPHandler) HandleTCPHandlerTerminate(process *TCPHandlerProcess, reason string) {
   201  	return
   202  }
   203  
   204  // we should disable SetTrapExit for the TCPHandlerProcess by overriding it.
   205  func (tcpp *TCPHandlerProcess) SetTrapExit(trap bool) {
   206  	lib.Warning("[%s] method 'SetTrapExit' is disabled for TCPHandlerProcess", tcpp.Self())
   207  }