Skip to content

Commit

Permalink
Change DigestIO digest on read or write flags for exclusive mode enum
Browse files Browse the repository at this point in the history
  • Loading branch information
spalladino committed Apr 10, 2017
1 parent 3c67b5a commit 5bda0ef
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 13 deletions.
31 changes: 31 additions & 0 deletions bar.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
require "logger"

module Migrate::Logging
@@logger : Logger = Logger.new(STDOUT).tap do |l|
l.formatter = Logger::Formatter.new do |severity, datetime, progname, message, io|
io << severity[0] << ", [" << datetime << " #" << Process.pid << "] "
io << severity.rjust(5) << " -- " << progname << ": " << message
io << "My additional suff"
end
end

def logger
@@logger
end

def self.logger
@@logger
end
end

class Foo
include Migrate::Logging
def foo
logger.warn("Hello!")
42
end
end

Foo.new.foo


Binary file added foo
Binary file not shown.
5 changes: 5 additions & 0 deletions foo.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# puts "A"
# spawn do
# puts "B"
# end
# puts "C"
Binary file added io_deferred
Binary file not shown.
175 changes: 175 additions & 0 deletions io_deferred.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
module IO
def self.deferred(&block : IO -> Void)
IO::Deferred.new(block).reader
end
end

class IO::Deferred
include IO

@target : Bytes?
@raw : Bytes
@buffer : Bytes

@chan_reader : Channel(Int32)
@chan_writer : Channel(Int32)
@chan_block : Channel(Nil)

@started : Bool
@finished : Bool

@reader : Reader?
@writer : Writer?

def initialize(@block : IO -> Void)
@raw = Bytes.new(4096)
@buffer = Bytes.new(@raw.to_unsafe, 0)
@chan_reader = Channel(Int32).new
@chan_writer = Channel(Int32).new
@chan_block = Channel(Nil).new
@started = false
@finished = false
end

def read(target : Bytes)
puts "READING 1"

try_start
written = 0

puts "READING 2"

# Store the requested target buffer to be written in the `write` method
@target = target

# Grab what's leftover in the buffer, if any
if @buffer.size > 0
writeable_size = [@buffer.size, target.size].min
target.copy_from(@buffer.to_unsafe, writeable_size)
@buffer += writeable_size
target += writeable_size
written += writeable_size
end

# Unblock the writing fiber only if the buffer did not cover the read request,
# and block until the write method signals us that the write was completed
while target.size > 0 && !@finished
@chan_writer.send(target.size)
select
when bytes = @chan_reader.receive
written += bytes
when @chan_block.receive
@finished = true
end
end

@target = nil
return written
end

def write(source : Bytes)
# Block until the main reader fiber signals us for a write request
requested = @chan_writer.receive

# Write to the target slice
target = @target.not_nil!
writeable_size = [target.size, source.size].min
target.copy_from(source.to_unsafe, writeable_size)
source += writeable_size

# Store leftover (if any) in buffer, resizing underlying raw buffer if needed
if source.size > 0
@raw = Bytes.new(source.size) if source.size > @raw.size
@raw.copy_from(source.to_unsafe, source.size)
end

# Update buffer view of raw underlying buffer
@buffer = Bytes.new(@raw.to_unsafe, source.size)

# Signal the reader fiber that this write operation is finished,
# sending the number of bytes written to target
@chan_reader.send(writeable_size)

return nil
end

def reader
@reader ||= Reader.new(self)
puts "Yielding reader"
@reader.not_nil!
end

def writer
@writer ||= Writer.new(self)
puts "Yielding writer"
@writer.not_nil!
end

def try_start
unless @started
@started = true
spawn do
@block.call(writer)
@chan_block.send(nil)
end
end
end
end

class IO::Deferred::Reader
include IO

def initialize(@io : IO::Deferred)
end

def read(slice : Bytes)
@io.read(slice)
end

def write(slice : Bytes)
raise IO::Error.new("can't write to IO::Deferred::Reader")
end
end

class IO::Deferred::Writer
include IO

def initialize(@io : IO::Deferred)
end

def read(slice : Bytes)
raise IO::Error.new("can't read from IO::Deferred::Writer")
end

def write(slice : Bytes)
@io.write(slice)
end
end

puts "Before Starting"

reader = IO.deferred do |writer|
puts "BLOCK | Initialising writer"
4.times do
puts "BLOCK | Writing 6 bytes"
writer.write("foobar".to_slice)
end
end

puts "Starting"
# puts reader.read_string(6)
# puts "1"
# puts reader.read_string(6)
# puts "2"
# puts reader.read_string(6)
# puts "3"
# puts reader.read_string(6)
# puts "4"
# puts reader.read_string(6)
# puts "5"
# puts reader.read_string(6)
# puts "6"
# # puts reader.read_string(1)
# # puts reader.read_string(1)
# # puts reader.read_string(16)
# # puts reader.gets_to_end
10 changes: 5 additions & 5 deletions spec/std/openssl/digest_io_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe OpenSSL::DigestIO do
base_io = IO::Memory.new("foo")
base_digest = OpenSSL::Digest.new("SHA256")
empty_digest = OpenSSL::Digest.new("SHA256").digest
io = OpenSSL::DigestIO.new(base_io, base_digest, digest_on_read: false)
io = OpenSSL::DigestIO.new(base_io, base_digest, OpenSSL::DigestIO::DigestMode::Write)
slice = Bytes.new(256)
io.read(slice).should eq(3)
slice[0, 3].should eq("foo".to_slice)
Expand All @@ -41,7 +41,7 @@ describe OpenSSL::DigestIO do
it "calculates digest from writing" do
base_io = IO::Memory.new
base_digest = OpenSSL::Digest.new("SHA256")
io = OpenSSL::DigestIO.new(base_io, base_digest)
io = OpenSSL::DigestIO.new(base_io, base_digest, OpenSSL::DigestIO::DigestMode::Write)
io.write("foo".to_slice)

base_io.to_slice[0, 3].should eq("foo".to_slice)
Expand All @@ -51,7 +51,7 @@ describe OpenSSL::DigestIO do
it "calculates digest from writing a string" do
base_io = IO::Memory.new
base_digest = OpenSSL::Digest.new("SHA256")
io = OpenSSL::DigestIO.new(base_io, base_digest)
io = OpenSSL::DigestIO.new(base_io, base_digest, OpenSSL::DigestIO::DigestMode::Write)
io.print("foo")

base_io.to_slice[0, 3].should eq("foo".to_slice)
Expand All @@ -61,7 +61,7 @@ describe OpenSSL::DigestIO do
it "calculates digest from multiple writes" do
base_io = IO::Memory.new
base_digest = OpenSSL::Digest.new("SHA256")
io = OpenSSL::DigestIO.new(base_io, base_digest)
io = OpenSSL::DigestIO.new(base_io, base_digest, OpenSSL::DigestIO::DigestMode::Write)
io.write("fo".to_slice)
io.write("o".to_slice)
base_io.to_slice[0, 3].should eq("foo".to_slice)
Expand All @@ -73,7 +73,7 @@ describe OpenSSL::DigestIO do
base_io = IO::Memory.new
base_digest = OpenSSL::Digest.new("SHA256")
empty_digest = OpenSSL::Digest.new("SHA256").digest
io = OpenSSL::DigestIO.new(base_io, base_digest, digest_on_write: false)
io = OpenSSL::DigestIO.new(base_io, base_digest, OpenSSL::DigestIO::DigestMode::Read)
io.write("foo".to_slice)

base_io.to_slice[0, 3].should eq("foo".to_slice)
Expand Down
19 changes: 11 additions & 8 deletions src/openssl/digest/digest_io.cr
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require "./digest_base"

# Wraps an IO by calculating a specified digest on read and/or write operations
# Wraps an IO by calculating a specified digest on read or write operations
#
# ### Example
#
Expand All @@ -20,30 +20,33 @@ module OpenSSL

getter io : IO
getter digest_algorithm : OpenSSL::Digest
getter digest_on_read : Bool
getter digest_on_write : Bool
getter mode : DigestMode

delegate close, closed?, flush, peek, tty?, rewind, to: @io
delegate digest, to: @digest_algorithm
delegate digest, hexdigest, base64digest, to: @digest_algorithm

def initialize(@io : IO, @digest_algorithm : OpenSSL::Digest, *, @digest_on_read = true, @digest_on_write = true)
enum DigestMode
Read
Write
end

def initialize(@io : IO, algorithm : String, *, @digest_on_read = true, @digest_on_write = true)
def initialize(@io : IO, @digest_algorithm : OpenSSL::Digest, @mode = DigestMode::Read)
end

def initialize(@io : IO, algorithm : String, @mode = DigestMode::Read)
@digest_algorithm = OpenSSL::Digest.new(algorithm)
end

def read(slice : Bytes)
read_bytes = io.read(slice)
if @digest_on_read
if @mode == DigestMode::Read
digest_algorithm.update(slice[0, read_bytes])
end
read_bytes
end

def write(slice : Bytes)
if @digest_on_write
if @mode == DigestMode::Write
digest_algorithm.update(slice)
end
io.write(slice)
Expand Down

0 comments on commit 5bda0ef

Please sign in to comment.