github.com/15mga/kiwi@v0.0.2-0.20240324021231-b95d5c3ac751/core/node_dialer.go (about) 1 package core 2 3 import ( 4 "context" 5 "time" 6 7 "github.com/15mga/kiwi" 8 "github.com/15mga/kiwi/util" 9 ) 10 11 var ( 12 _NetReconnectDur = time.Second 13 MaxReconnect = 5 14 MaxSendRetry = uint8(3) 15 SendRetryDur = time.Second 16 ) 17 18 type ( 19 OnNetDialerConnected func(*nodeDialer) 20 OnNetDialerDisconnected func(*nodeDialer, *util.Err) 21 ) 22 23 func newNodeDialer(dialer kiwi.IDialer, svc kiwi.TSvc, nodeId int64, ver string, head util.M, 24 onConnected OnNetDialerConnected, onDisconnected OnNetDialerDisconnected) *nodeDialer { 25 d := &nodeDialer{ 26 svc: svc, 27 nodeId: nodeId, 28 ver: ver, 29 head: head, 30 dialer: dialer, 31 onConnected: onConnected, 32 onDisconnected: onDisconnected, 33 } 34 d.ctx, d.cancel = context.WithCancel(util.Ctx()) 35 dialer.Agent().BindConnected(d.onConn) 36 dialer.Agent().BindDisconnected(d.onDisConn) 37 return d 38 } 39 40 type nodeDialer struct { 41 svc kiwi.TSvc 42 nodeId int64 43 ver string 44 head util.M 45 dialer kiwi.IDialer 46 currReconnect int 47 onConnected OnNetDialerConnected 48 onDisconnected OnNetDialerDisconnected 49 ctx context.Context 50 cancel context.CancelFunc 51 } 52 53 func (d *nodeDialer) heartbeat() { 54 go func() { 55 ticker := time.NewTicker(time.Second * 10) 56 for { 57 select { 58 case <-d.ctx.Done(): 59 ticker.Stop() 60 return 61 case <-ticker.C: 62 d.Send(Heartbeat, nil) 63 } 64 } 65 }() 66 } 67 68 func (d *nodeDialer) onConn(_ kiwi.IAgent) { 69 d.onConnected(d) 70 if kiwi.GetNodeMeta().Mode == kiwi.ModeDebug { 71 return 72 } 73 d.heartbeat() 74 } 75 76 func (d *nodeDialer) onDisConn(_ kiwi.IAgent, err *util.Err) { 77 d.onDisconnected(d, err) 78 d.cancel() 79 } 80 81 func (d *nodeDialer) Svc() kiwi.TSvc { 82 return d.svc 83 } 84 85 func (d *nodeDialer) NodeId() int64 { 86 return d.nodeId 87 } 88 89 func (d *nodeDialer) Dialer() kiwi.IDialer { 90 return d.dialer 91 } 92 93 func (d *nodeDialer) Head() util.M { 94 return d.head 95 } 96 97 func (d *nodeDialer) connect() { 98 err := d.dialer.Connect(util.Ctx()) 99 if err == nil { 100 d.currReconnect = 0 101 return 102 } 103 err.AddParams(util.M{ 104 "service": d.svc, 105 "node id": d.nodeId, 106 "reconnect": d.currReconnect, 107 }) 108 kiwi.Error(err) 109 d.reconnect() 110 } 111 112 func (d *nodeDialer) reconnect() { 113 d.currReconnect++ 114 if d.currReconnect >= MaxReconnect { 115 kiwi.Error2(util.EcConnectErr, util.M{ 116 "error": "connect failed", 117 "service": d.svc, 118 "node id": d.nodeId, 119 }) 120 return 121 } 122 time.Sleep(_NetReconnectDur) 123 _ = d.dialer.Agent().Enable().IfEnable(d.connect) 124 } 125 126 func (d *nodeDialer) Send(bytes []byte, fnErr util.FnErr) { 127 d.sendWithCount(bytes, fnErr, 0) 128 } 129 130 func (d *nodeDialer) sendWithCount(bytes []byte, fnErr util.FnErr, count uint8) { 131 err := d.dialer.Agent().Send(bytes) 132 if err == nil { 133 fnErr.Invoke(nil) 134 return 135 } 136 if err.Code() != util.EcClosed { 137 kiwi.Error(err) 138 fnErr.Invoke(err) 139 return 140 } 141 if count >= MaxSendRetry { 142 fnErr.Invoke(err) 143 return 144 } 145 time.AfterFunc(SendRetryDur, func() { 146 d.sendWithCount(bytes, fnErr, count+1) 147 }) 148 }