Skip to content

Commit

Permalink
Modernize gem.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed Sep 8, 2024
1 parent f95fd5b commit ef5d49d
Show file tree
Hide file tree
Showing 19 changed files with 166 additions and 36 deletions.
3 changes: 3 additions & 0 deletions examples/streaming/bidirectional.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2024, by Samuel Williams.

require 'async'
require 'async/http/client'
require 'async/http/server'
Expand Down
4 changes: 4 additions & 0 deletions examples/streaming/gems.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2024, by Samuel Williams.

source "https://rubygems.org"

gem "async"
Expand Down
3 changes: 3 additions & 0 deletions examples/streaming/unidirectional.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2024, by Samuel Williams.

require 'async'
require 'async/http/client'
require 'async/http/server'
Expand Down
18 changes: 16 additions & 2 deletions fixtures/protocol/http/body/a_readable_body.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2024, by Samuel Williams.

module Protocol
module HTTP
module Body
AReadableBody = Sus::Shared("a readable body") do
with "#close" do
it "should close the body" do
with "#read" do
it "after closing, returns nil" do
body.close

expect(body.read).to be_nil
end
end

with "empty?" do
it "returns true after closing" do
body.close

expect(body).to be(:empty?)
end
end
end
end
end
Expand Down
41 changes: 41 additions & 0 deletions fixtures/protocol/http/body/a_writable_body.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2024, by Samuel Williams.

module Protocol
module HTTP
module Body
AWritableBody = Sus::Shared("a readable body") do
with "#read" do
it "after closing the write end, returns all chunks" do
body.write("Hello ")
body.write("World!")
body.close_write

expect(body.read).to be == "Hello "
expect(body.read).to be == "World!"
expect(body.read).to be_nil
end
end

with "empty?" do
it "returns false before writing" do
expect(body).not.to be(:empty?)
end

it "returns true after all chunks are consumed" do
body.write("Hello")
body.close_write

expect(body).not.to be(:empty?)
expect(body.read).to be == "Hello"
expect(body.read).to be_nil

expect(body).to be(:empty?)
end
end
end
end
end
end
28 changes: 25 additions & 3 deletions lib/protocol/http/body/buffered.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,18 @@ def initialize(chunks = [], length = nil)

attr :chunks

def finish
self
end

def close(error = nil)
@chunks = []
@index = @chunks.length
end

def clear
@chunks.clear
@length = 0
@index = 0
end

def length
Expand All @@ -70,6 +80,8 @@ def ready?
end

def read
return nil unless @chunks

if chunk = @chunks[@index]
@index += 1

Expand All @@ -81,18 +93,28 @@ def write(chunk)
@chunks << chunk
end

def close_write(error)
# Nothing to do.
end

def rewindable?
true
@chunks != nil
end

def rewind
return false unless @chunks

@index = 0

return true
end

def inspect
"\#<#{self.class} #{@chunks.size} chunks, #{self.length} bytes>"
if @chunks
"\#<#{self.class} #{@chunks.size} chunks, #{self.length} bytes>"
else
"\#<#{self.class} closed>"
end
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/protocol/http/body/deflate.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2019-2023, by Samuel Williams.
# Copyright, 2019-2024, by Samuel Williams.

require_relative 'wrapper'

Expand Down
2 changes: 1 addition & 1 deletion lib/protocol/http/body/digestable.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2020-2023, by Samuel Williams.
# Copyright, 2020-2024, by Samuel Williams.

require_relative 'wrapper'

Expand Down
2 changes: 1 addition & 1 deletion lib/protocol/http/body/file.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2019-2023, by Samuel Williams.
# Copyright, 2019-2024, by Samuel Williams.

require_relative 'readable'

Expand Down
2 changes: 1 addition & 1 deletion lib/protocol/http/body/inflate.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2019-2023, by Samuel Williams.
# Copyright, 2019-2024, by Samuel Williams.

require 'zlib'

Expand Down
14 changes: 8 additions & 6 deletions lib/protocol/http/body/readable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,15 @@ def read
def each
return to_enum unless block_given?

while chunk = self.read
yield chunk
begin
while chunk = self.read
yield chunk
end
rescue => error
raise
ensure
self.close(error)
end
rescue => error
raise
ensure
self.close(error)
end

# Read all remaining chunks into a single binary string using `#each`.
Expand Down
10 changes: 3 additions & 7 deletions lib/protocol/http/body/stream.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def initialize(input = nil, output = Buffered.new)

# Will hold remaining data in `#read`.
@buffer = nil

@closed = false
@closed_read = false
end
Expand Down Expand Up @@ -257,7 +258,7 @@ def close_read(error = nil)
@closed_read = true
@buffer = nil

input&.close(error)
input.close(error)
end
end

Expand All @@ -266,12 +267,7 @@ def close_write(error = nil)
if output = @output
@output = nil

# This is a compatibility hack to work around limitations in protocol-rack and can be removed when external tests are passing without it.
if output.method(:close).arity == 1
output.close(error)
else
output.close
end
output.close_write(error)
end
end

Expand Down
3 changes: 1 addition & 2 deletions lib/protocol/http/body/streamable.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2022, by Samuel Williams.
# Copyright, 2019-2024, by Samuel Williams.

require_relative 'readable'
require_relative 'writable'
Expand Down Expand Up @@ -137,7 +137,6 @@ def call(stream)

# Closing a stream indicates we are no longer interested in reading from it.
def close(error = nil)
$stderr.puts "Closing input: #{@input.inspect}"
if input = @input
@input = nil
input.close(error)
Expand Down
53 changes: 50 additions & 3 deletions lib/protocol/http/body/writable.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2018-2023, by Samuel Williams.
# Copyright, 2024, by Samuel Williams.

require_relative 'readable'

Expand Down Expand Up @@ -65,17 +65,64 @@ def read
# Write a single chunk to the body. Signal completion by calling `#finish`.
def write(chunk)
# If the reader breaks, the writer will break.
# The inverse of this is less obvious (*)
if @closed
raise(@error || Closed)
end

@count += 1
@queue.push(chunk)
@count += 1
end

# This alias is provided for compatibility with template generation.
alias << write

def close_write(error = nil)
@error ||= error
@queue.close
end

class Output
def initialize(writable)
@writable = writable
@closed = false
end

def closed?
@closed || @writable.closed?
end

def write(chunk)
@writable.write(chunk)
end

def close(error = nil)
@closed = true

if error
@writable.close(error)
else
@writable.close_write
end
end
end

# Create an output wrapper which can be used to write chunks to the body.
def output
output = Output.new(self)

unless block_given?
return output
end

begin
yield output
rescue => error
raise error
ensure
output.close(error)
end
end

def inspect
"\#<#{self.class} #{@count} chunks written, #{status}>"
end
Expand Down
5 changes: 1 addition & 4 deletions test/protocol/http/body/deflate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2019-2023, by Samuel Williams.
# Copyright, 2019-2024, by Samuel Williams.

require 'protocol/http/body/buffered'
require 'protocol/http/body/deflate'
Expand All @@ -17,7 +17,6 @@

it "should round-trip data" do
body.write("Hello World!")
body.close

expect(decompressed_body.join).to be == "Hello World!"
end
Expand All @@ -26,7 +25,6 @@

it "should round-trip data" do
body.write(data)
body.close

expect(decompressed_body.read).to be == data
expect(decompressed_body.read).to be == nil
Expand All @@ -39,7 +37,6 @@
10.times do
body.write("Hello World!")
end
body.close

10.times do
expect(decompressed_body.read).to be == "Hello World!"
Expand Down
2 changes: 1 addition & 1 deletion test/protocol/http/body/digestable.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2020-2023, by Samuel Williams.
# Copyright, 2020-2024, by Samuel Williams.

require 'protocol/http/body/digestable'
require 'protocol/http/body/buffered'
Expand Down
2 changes: 1 addition & 1 deletion test/protocol/http/body/file.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2019-2023, by Samuel Williams.
# Copyright, 2019-2024, by Samuel Williams.

require 'protocol/http/body/file'

Expand Down
Loading

0 comments on commit ef5d49d

Please sign in to comment.