Skip to content

Latest commit

 

History

History
53 lines (39 loc) · 2.79 KB

IMPLEMENTATION.md

File metadata and controls

53 lines (39 loc) · 2.79 KB

Implementation

A document that explains in detail how the client and the server works.

Client implementation

The client holds (0, N) connections to a single host. A connection is created in the following cases:

  • There are no previous existing connections.
  • All the connections are busy (aka not able to open more streams).

Connections are stored in a list because it's the easiest way to keep elements.

When a connection is created 2 goroutines are spawned. One for reading and dispatching events, and another for writing (either frames and requests).

The read loop will read all the frames and handling only the ones carrying a StreamID. Lower layers will handle everything related to Settings, WindowUpdate, Ping and/or disconnection.

The write loop will write the requests and frames. I like to separate both terms because the request comes from fasthttp, and the frames is a term related to http2.

Why having 2 coroutines? As HTTP/2 is a replacement of HTTP/1.1, the equivalent to opening a connection per request in HTTP/1 is the figure of the frame in HTTP/2. As writing to the same connection might happen concurrently and thus, can invoke errors, 2 coroutines are required, one for writing and another for reading synchronously.

How sending a request works?

When we send a request we write to a channel to the writeLoop coroutine with all the data required, in this case we make use of the Ctx structure.

That being sent, it gets received by the writeLoop coroutine, and then it proceeds to serialize and write into the connection the required frames, and after that registers the StreamID into a shared map. This map is shared among the 'write' and 'read' loops.

In the meantime, the client waits on a channel for any error.

When we receive the response from the server, the readLoop will check if the StreamID is on the shared map, and if so, it will handle the response. After the server finished sending the request, the readLoop will end the request sending the result to the client. That result might be an error or just a nil over the channel provided by the client.

After the request/response finished, the client will continue thus exiting the Do function.