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 }