From 2c40448d93690e086aaf58b10b9d57778adf6ba8 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Tue, 16 Apr 2024 15:14:19 +1200 Subject: [PATCH] Remove old design document. --- design.md | 167 ------------------------------------------------------ 1 file changed, 167 deletions(-) delete mode 100644 design.md diff --git a/design.md b/design.md deleted file mode 100644 index b13ad19..0000000 --- a/design.md +++ /dev/null @@ -1,167 +0,0 @@ -# Middleware Design - -`Body::Writable` is a queue of String chunks. - -## Request Response Model - -~~~ruby -class Request - attr :verb - attr :target - attr :body -end - -class Response - attr :status - attr :headers - attr :body -end - -def call(request) - return response -end - -def call(request) - return @app.call(request) -end -~~~ - -## Stream Model - -~~~ruby -class Stream - attr :verb - attr :target - - def respond(status, headers) = ... - - attr_accessor :input - attr_accessor :output -end - -class Response - def initialize(verb, target) - @input = Body::Writable.new - @output = Body::Writable.new - end - - def request(verb, target) - # Create a request stream suitable for writing into the buffered response: - Stream.new(verb, target, @input, @output) - end - - def write(...) - @input.write(...) - end - - def read - @output.read - end -end - -def call(stream) - # nothing. maybe error -end - -def call(stream) - @app.call(stream) -end -~~~ - -# Client Design - -## Request Response Model - -~~~ruby -request = Request.new("GET", url) -response = call(request) - -response.headers -response.read -~~~ - -## Stream Model - -~~~ruby -response = Response.new -call(response.request("GET", url)) - -response.headers -response.read -~~~ - -## Differences - -The request/response model has a symmetrical design which naturally uses the return value for the result of executing the request. The result encapsulates the behaviour of how to read the response status, headers and body. Because of that, streaming input and output becomes a function of the result object itself. As in: - -~~~ruby -def call(request) - body = Body::Writable.new - - Fiber.schedule do - while chunk = request.input.read - body.write(chunk.reverse) - end - end - - return Response[200, [], body] -end - -input = Body::Writable.new -response = call(... body ...) - -input.write("Hello World") -input.close -response.read -> "dlroW olleH" -~~~ - -The streaming model does not have the same symmetry, and instead opts for a uni-directional flow of information. - -~~~ruby -def call(stream) - Fiber.schedule do - while chunk = stream.read - stream.write(chunk.reverse) - end - end -end - -input = Body::Writable.new -response = Response.new(...input...) -call(response.stream) - -input.write("Hello World") -input.close -response.read -> "dlroW olleH" -~~~ - -The value of this uni-directional flow is that it is natural for the stream to be taken out of the scope imposed by the nested `call(request)` model. However, the user must explicitly close the stream, since it's no longer scoped to the client and/or server. - -## Connection Upgrade - -### HTTP/1 - -``` -GET /path/to/websocket HTTP/1.1 -connection: upgrade -upgrade: websocket -``` - -Request.new(GET, ..., protocol = websocket) --> Response.new(101, ..., protocol = websocket) - -``` -101 Switching Protocols -upgrade: websocket -``` - -### HTTP/2 - -``` -:method CONNECT -:path /path/to/websocket -:protocol websocket -``` - -Request.new(CONNECT, ..., protocol = websocket) --> Response.new(200, ..., protocol = websocket)