Since I attended Flomesh’s workshop, I have learned about programmable gateway Pipy. Full of curiosity about this “little thing”, wrote two articles before and after, saw part of the source unlocked its part of the veil. But never see the full picture, never touch its core design.
There’s a saying, “Curiosity killed the cat.” There should be a second sentence, “Satisfied is fine” (see Wikipedia).
So there is this article today, those who are interested in the first two can jump to read.
- A preliminary study on programmable gateway Pipy
- Programmable gateway Pipy second bullet: programming Metrics and source code interpretation
Back to the point.
The event model
I wrote about Pipy’s event-based information flow, but I didn’t get into the core event model. Since it’s an event model, let’s look at events first.
SRC /event.hpp:41 defines four kinds of Pipy events:
Data
MessageStart
MessageEnd
SessionEnd
MessageStart -> Data -> MessageEnd -> SessionEnd
In this event-oriented model, there must be producers and consumers. Both producers and consumers are pipy:: filters. As we discussed in the previous article, each Pipeline has a filter chain, which is a one-way linked list of data structures.
Does it follow that events flow from one Filter to the next? Yes and no.
Contradiction?
At SRC /session. CPP :55, Filter holds output, similar to Event::Receiver (STD ::function alias for Event, STD ::function, STD ::function, STD ::function). As a layman, I don’t know c++, but that doesn’t prevent me from understanding programming. The #process method of the next Filter is called through the Receiver.
#process(Context * CTX, Event * inP) is the window for receiving events.
This is why the previous statement that “events flow from one Filter to the next” is correct.
Why not? First, a Filter will generate multiple events, such as decodeHttpRequest may generate MessageStart, Data and MessageEnd events, and each event generated will be passed down through the Receiver. Do not wait for the #process process to finish before passing events; The next Filter may not be interested in an event (the next Filter’s #process method returns without doing any processing).
It may be easier to understand by looking at the following figure (no Output indicates that events are not passed down) :
The simplest example
An example in test/001-echo/pipy.js is provided:
pipy()
.listen(6080)
.decodeHttpRequest()
.encodeHttpResponse()
Copy the code
The initiating
$ curl -X POST localhost:6080 -d '{}'
{}
Copy the code
The HTTP message body
#request
POST / HTTP / 1.1
Content-Type: application/javascript
User-Agent: PostmanRuntime / 7.28.1Accept: * / *Postman-Token: fc84b575-7fea-487b-a55d-f6085bc62cf7
Host: localhost:6080
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 2
{}
#response
HTTP/1.1 200 OK
postman-token: fc84b575-7fea-487b-a55d-f6085bc62cf7
accept-encoding: gzip, deflate, br
host: localhost:6080
accept: * / *user-agent: PostmanRuntime / 7.28.1content-type: application/javascript
Connection: keep-alive
Content-Length: {2}Copy the code
Here we use decodeHttpRequest as an example, the official description is Deframes an HTTP request message. As mentioned earlier, it produces three events, all emitted during the deframe process.
When Session calls the first Filter, the event type passed in is Event ::Data. DecodeHttpRequest follows the event and begins parsing according to the HTTP protocol.
In the figure above you can see that different events are emitted at different stages of parsing. Call Receiver to transfer the event, calling encodeHttpResponse’s #process() method.
Again, would the above example work if either, or both, of the two filters were removed?
The answer is neither! The response status codes are 502 Bad Gateway (curl/ Httpie).
Analysis of the
You need to combine this with the first figure of this article, event-handlings-flow.
Remove two filters
If both are removed, the HTTP Request message will be sent directly back to the client, with the wrong protocol.
Remove decodeHttpRequest
The event that Session passes to the first Filter is event::Data. EncodeHttpResponse will only save the event to the buffer.
The entire link then ends without any data being sent back. The client waits for a response and exits with curl.
Remove encodeHttpResponse
Let’s start with the result, and we’re going to timeout out as before.
The decodeHttpRequest generated three times, and the Session Receiver received the {} in the body of the request.
The encodeHttpResponse filter has a write back response header. Without this information, the response is not a legitimate HTTP protocol, but a normal TCP protocol.
conclusion
Pipy’s event model-based design provides great flexibility. Allows us to use different filters in “rules” to process request and response information for different events.
The “rules” are at the heart of the business logic, and Pipy is the execution engine for that logic.
Finally, “Curiosity is a driving force for growth. Always be curious.”