@@ -12,29 +12,6 @@ import (
1212 "time"
1313
1414 "github.com/yomorun/yomo/pkg/quic"
15- "github.com/yomorun/yomo/pkg/rx"
16- )
17-
18- const (
19- // ClientTypeSource represents the client type of Source.
20- ClientTypeSource = "source"
21-
22- // ClientTypeServerless represents the client type of Serverless.
23- ClientTypeServerless = "serverless"
24-
25- // ClientTypeZipperSender represents the client type of ZipperSender.
26- ClientTypeZipperSender = "zipper-sender"
27- )
28-
29- var (
30- // SignalHeartbeat represents the signal of Heartbeat.
31- SignalHeartbeat = []byte {0 }
32-
33- // SignalAccepted represents the signal of Accpeted.
34- SignalAccepted = []byte {1 }
35-
36- // SignalFlowSink represents the signal for flow/sink.
37- SignalFlowSink = []byte {0 , 0 }
3815)
3916
4017// NegotiationPayload represents the payload for negotiation.
@@ -56,69 +33,44 @@ type client interface {
5633 RetryWithCount (count int ) bool
5734}
5835
59- // SourceClient is the client for YoMo-Source.
60- // https://yomo.run/source
61- type SourceClient interface {
62- client
63-
64- // Connect to YoMo-Zipper
65- Connect (ip string , port int ) (SourceClient , error )
66- }
67-
68- // ServerlessClient is the client for YoMo-Serverless.
69- type ServerlessClient interface {
70- client
71-
72- // Connect to YoMo-Zipper
73- Connect (ip string , port int ) (ServerlessClient , error )
74-
75- // Pipe the Handler function.
76- Pipe (f func (rxstream rx.RxStream ) rx.RxStream )
77- }
78-
79- // ZipperSenderClient is the client for Zipper-Sender to connect the downsteam Zipper-Receiver in edge-mesh.
80- type ZipperSenderClient interface {
81- client
82-
83- // Connect to downsteam Zipper-Receiver
84- Connect (ip string , port int ) (ZipperSenderClient , error )
85- }
86-
8736type clientImpl struct {
37+ conn * quic.QuicConn
8838 zipperIP string
8939 zipperPort int
90- name string
91- clientType string
9240 readers chan io.Reader
9341 writer io.Writer
9442 session quic.Client
95- signal quic.Stream
96- stream quic.Stream
97- heartbeat chan byte
9843 once * sync.Once
9944}
10045
101- type sourceClientImpl struct {
102- * clientImpl
103- }
104-
105- type serverlessClientImpl struct {
106- * clientImpl
107- }
108-
109- type zipperSenderClientImpl struct {
110- * clientImpl
111- }
112-
11346// newClient creates a new client.
11447func newClient (appName string , clientType string ) * clientImpl {
11548 c := & clientImpl {
116- name : appName ,
117- clientType : clientType ,
118- readers : make (chan io.Reader , 1 ),
119- heartbeat : make (chan byte ),
120- once : new (sync.Once ),
49+ conn : quic .NewQuicConn (appName , clientType ),
50+ readers : make (chan io.Reader , 1 ),
51+ once : new (sync.Once ),
52+ }
53+
54+ c .conn .OnHeartbeatReceived = func () {
55+ // when the client received the heartbeat from server, send it back back to server (ping/pong).
56+ c .conn .SendSignal (quic .SignalHeartbeat )
12157 }
58+
59+ c .conn .OnHeartbeatExpired = func () {
60+ c .once .Do (func () {
61+ // reset stream to nil.
62+ c .conn .Stream = nil
63+
64+ // reconnect when the heartbeat is expired.
65+ c .connect (c .zipperIP , c .zipperPort )
66+
67+ // reset the sync.Once after 5s.
68+ time .AfterFunc (5 * time .Second , func () {
69+ c .once = new (sync.Once )
70+ })
71+ })
72+ }
73+
12274 return c
12375}
12476
@@ -129,65 +81,78 @@ func (c *clientImpl) connect(ip string, port int) (*clientImpl, error) {
12981 c .zipperPort = port
13082 addr := fmt .Sprintf ("%s:%d" , ip , port )
13183 log .Println ("Connecting to zipper" , addr , "..." )
84+
13285 // connect to yomo-zipper
13386 quic_cli , err := quic .NewClient (addr )
13487 if err != nil {
13588 fmt .Println ("client [NewClient] Error:" , err )
13689 return c , err
13790 }
91+
13892 // create stream
13993 quic_stream , err := quic_cli .CreateStream (context .Background ())
14094 if err != nil {
14195 fmt .Println ("client [CreateStream] Error:" , err )
14296 return c , err
14397 }
14498
99+ // set session and signal
145100 c .session = quic_cli
146- c .signal = quic_stream
101+ c .conn . Signal = quic_stream
147102
148103 // send negotiation payload to zipper
149104 payload := NegotiationPayload {
150- AppName : c .name ,
151- ClientType : c .clientType ,
105+ AppName : c .conn . Name ,
106+ ClientType : c .conn . Type ,
152107 }
153108 buf , _ := json .Marshal (payload )
154- _ , err = c .signal . Write (buf )
109+ err = c .conn . SendSignal (buf )
155110
156111 if err != nil {
157112 fmt .Println ("client [Write] Error:" , err )
158113 return c , err
159114 }
160115
161- // flow, sink create stream or heartbeat
162116 accepted := make (chan bool )
163117
118+ c .handleSignal (accepted )
119+ c .conn .Healthcheck ()
120+
121+ // waiting when the connection is accepted.
122+ <- accepted
123+ log .Print ("✅ Connected to zipper " , addr )
124+ return c , nil
125+ }
126+
127+ // handleSignal handles the logic when receiving signal from server.
128+ func (c * clientImpl ) handleSignal (accepted chan bool ) {
164129 go func () {
165130 defer close (accepted )
166131 for {
167132 buf := make ([]byte , 2 )
168- n , err := c .signal .Read (buf )
133+ n , err := c .conn . Signal .Read (buf )
169134 if err != nil {
170135 break
171136 }
172137 value := buf [:n ]
173138
174- if bytes .Equal (value , SignalHeartbeat ) {
139+ if bytes .Equal (value , quic . SignalHeartbeat ) {
175140 // heartbeart
176- c .heartbeat <- buf [0 ]
177- } else if bytes .Equal (value , SignalAccepted ) {
141+ c .conn . Heartbeat <- buf [0 ]
142+ } else if bytes .Equal (value , quic . SignalAccepted ) {
178143 // accepted
179- if c .clientType == ClientTypeSource || c .clientType == ClientTypeZipperSender {
180- // create the stream from source.
144+ if c .conn . Type == quic . ConnTypeSource || c .conn . Type == quic . ConnTypeZipperSender {
145+ // create stream for source.
181146 stream , err := c .session .CreateStream (context .Background ())
182147 if err != nil {
183148 fmt .Println ("client [session.CreateStream] Error:" , err )
184149 break
185150 }
186- c .stream = stream
151+ c .conn . Stream = stream
187152 }
188153 accepted <- true
189- } else if bytes .Equal (value , SignalFlowSink ) {
190- // create stream
154+ } else if bytes .Equal (value , quic . SignalFlowSink ) {
155+ // create stream for flow/sink.
191156 stream , err := c .session .CreateStream (context .Background ())
192157
193158 if err != nil {
@@ -197,49 +162,16 @@ func (c *clientImpl) connect(ip string, port int) (*clientImpl, error) {
197162
198163 c .readers <- stream
199164 c .writer = stream
200- stream .Write (SignalHeartbeat )
201- }
202- }
203- }()
204-
205- go func () {
206- defer c .Close ()
207- for {
208- select {
209- case item , ok := <- c .heartbeat :
210- if ! ok {
211- return
212- }
213- _ , err := c .signal .Write ([]byte {item })
214-
215- if err != nil {
216- return
217- }
218- case <- time .After (5 * time .Second ):
219- // reconnect if didn't receive the heartbeat after 5s.
220- c .once .Do (func () {
221- c .connect (c .zipperIP , c .zipperPort )
222-
223- // reset the sync.Once after 5s.
224- time .AfterFunc (5 * time .Second , func () {
225- c .once = new (sync.Once )
226- })
227- })
165+ stream .Write (quic .SignalHeartbeat )
228166 }
229167 }
230-
231168 }()
232-
233- // waiting when the connection is accepted.
234- <- accepted
235- log .Print ("✅ Connected to zipper " , addr )
236- return c , nil
237169}
238170
239171// Write the data to downstream.
240172func (c * clientImpl ) Write (b []byte ) (int , error ) {
241- if c .stream != nil {
242- return c .stream .Write (b )
173+ if c .conn . Stream != nil {
174+ return c .conn . Stream .Write (b )
243175 } else {
244176 return 0 , errors .New ("not found stream" )
245177 }
@@ -273,85 +205,7 @@ func (c *clientImpl) RetryWithCount(count int) bool {
273205// Close the client.
274206func (c * clientImpl ) Close () error {
275207 err := c .session .Close ()
276- c .heartbeat = make (chan byte )
277- c .signal = nil
208+ c .conn . Heartbeat = make (chan byte )
209+ c .conn . Signal = nil
278210 return err
279211}
280-
281- // NewSource setups the client of YoMo-Source.
282- func NewSource (appName string ) SourceClient {
283- c := & sourceClientImpl {
284- clientImpl : newClient (appName , ClientTypeSource ),
285- }
286- return c
287- }
288-
289- // Connect to yomo-zipper.
290- func (c * sourceClientImpl ) Connect (ip string , port int ) (SourceClient , error ) {
291- cli , err := c .connect (ip , port )
292- return & sourceClientImpl {
293- cli ,
294- }, err
295- }
296-
297- // NewServerless setups the client of YoMo-Serverless.
298- // The "appName" should match the name of flows (or sinks) in workflow.yaml in zipper.
299- func NewServerless (appName string ) ServerlessClient {
300- c := & serverlessClientImpl {
301- clientImpl : newClient (appName , ClientTypeServerless ),
302- }
303- return c
304- }
305-
306- // Connect to yomo-zipper.
307- func (c * serverlessClientImpl ) Connect (ip string , port int ) (ServerlessClient , error ) {
308- cli , err := c .connect (ip , port )
309- return & serverlessClientImpl {
310- cli ,
311- }, err
312- }
313-
314- // Pipe the handler function in flow/sink serverless.
315- func (c * serverlessClientImpl ) Pipe (f func (rxstream rx.RxStream ) rx.RxStream ) {
316- rxstream := rx .FromReaderWithDecoder (c .readers )
317- stream := f (rxstream )
318-
319- rxstream .Connect (context .Background ())
320-
321- for customer := range stream .Observe () {
322- if customer .Error () {
323- panic (customer .E )
324- } else if customer .V != nil {
325- if c .writer == nil {
326- continue
327- }
328-
329- buf , ok := (customer .V ).([]byte )
330- if ! ok {
331- log .Print ("❌ Please add the encode/marshal operator in the end of your Serverless handler." )
332- continue
333- }
334- _ , err := c .writer .Write (buf )
335- if err != nil {
336- log .Print ("❌ Send data to zipper failed. " , err )
337- }
338- }
339-
340- }
341- }
342-
343- // NewZipperSender setups the client of Zipper-Sender.
344- func NewZipperSender (appName string ) ZipperSenderClient {
345- c := & zipperSenderClientImpl {
346- clientImpl : newClient (appName , ClientTypeZipperSender ),
347- }
348- return c
349- }
350-
351- // Connect to downstream zipper-receiver in edge-mesh.
352- func (c * zipperSenderClientImpl ) Connect (ip string , port int ) (ZipperSenderClient , error ) {
353- cli , err := c .connect (ip , port )
354- return & zipperSenderClientImpl {
355- cli ,
356- }, err
357- }
0 commit comments