🎉 100% coverage. NEXT: Verify message chain creation via tests.

Currently, it is not working correctly.
Take a look at scratchpad.sh. The `prev:` values are wrong.

It is probably as simple as updating local indexes when
Pigeon::Storage#save_message is called. Re run the indexes
at that time. Or heck, add a map/reduce ability?
This commit is contained in:
Netscape Navigator 2020-03-07 09:38:34 -06:00
parent f4b6ddbf51
commit be5dfc982a
10 changed files with 70 additions and 57 deletions

View File

@ -23,16 +23,18 @@ Eg: `pigeon identity show` becomes `./pigeon-cli show`.
- [X] pigeon peer remove
- [X] pigeon peer block
- [X] pigeon peer all
- [ ] pigeon message create
- [ ] pigeon message append
- [ ] pigeon message current
- [ ] pigeon message save
- [ ] pigeon message find
- [ ] pigeon message find-all
- [X] 100% coverage
- [ ] Rename numerous "pigeon message ..." commands to "pigeon draft ..."
- [ ] pigeon bundle create
- [ ] pigeon bundle consume
- [ ] pigeon draft create
- [ ] pigeon draft append
- [ ] pigeon draft current
- [ ] pigeon draft save
- [ ] pigeon message find
- [ ] pigeon message find-all
- [ ] Map/reduce plugin support for custom indices?
- [ ] 100% documentation
- [ ] 100% coverage
- [ ] add parsers and validators for all CLI inputs
- [ ] Performance benchmarks
- [ ] Performance tuning (DO THIS LAST!)

4
dist/pigeon.rb vendored
View File

@ -48,7 +48,7 @@ end
require_relative File.join("pigeon", "key_pair.rb")
require_relative File.join("pigeon", "storage.rb")
require_relative File.join("pigeon", "draft_template.rb")
require_relative File.join("pigeon", "message_template.rb")
require_relative File.join("pigeon", "draft_serializer.rb")
require_relative File.join("pigeon", "message_serializer.rb")
require_relative File.join("pigeon", "message.rb")
require_relative File.join("pigeon", "draft.rb")

16
dist/pigeon/draft.rb vendored
View File

@ -2,25 +2,30 @@ require "digest"
module Pigeon
class Draft
attr_reader :kind, :body
attr_reader :kind, :body, :internal_id
def self.create(kind:, body: {})
self.new(kind: kind, body: body).save
end
def self.current
@current ||=
(Pigeon::Storage.current.get_config(CURRENT_DRAFT) || new.save)
Pigeon::Storage.current.get_config(CURRENT_DRAFT)
end
def self.reset_current
Pigeon::Storage.current.set_config(CURRENT_DRAFT, nil)
@current = nil
end
def discard
if Draft.current&.internal_id == @internal_id
Draft.reset_current
end
end
def initialize(kind:, body: {})
@kind = kind
@body = body
@internal_id = SecureRandom.uuid
end
def [](key)
@ -38,14 +43,13 @@ module Pigeon
return self.body[key]
end
# NOT the same thing as #sign/0
def save
Pigeon::Storage.current.set_config(CURRENT_DRAFT, self)
self
end
def render
DraftTemplate.new(self).render
DraftSerializer.new(self).render
end
end
end

View File

@ -3,7 +3,7 @@ require "erb"
module Pigeon
# Wrapper around a Pigeon::Draft to perform string templating.
# Renders a string that contains most (but not all) of a Pigeon message.
class DraftTemplate
class DraftSerializer
attr_reader :message
def initialize(message)
@ -11,13 +11,13 @@ module Pigeon
end
def render
body = message.body
kind = message.kind
author = DRAFT_PLACEHOLDER
depth = DRAFT_PLACEHOLDER
prev = DRAFT_PLACEHOLDER
body = message.body
kind = message.kind
author = DRAFT_PLACEHOLDER
depth = DRAFT_PLACEHOLDER
prev = DRAFT_PLACEHOLDER
signature = DRAFT_PLACEHOLDER
ERB.new([HEADER_TPL, BODY_TPL].join("")).result(binding)
end
end

View File

@ -5,37 +5,38 @@ module Pigeon
attr_reader :author, :kind, :body, :signature, :depth, :prev
def self.from_draft(draft, author: KeyPair.current)
self.new(author: KeyPair.current,
kind: draft.kind,
body: draft.body)
msg = self.new(author: KeyPair.current,
kind: draft.kind,
body: draft.body)
# We might need to add conditional logic here
# Currently YAGNI since all Drafts we handle today
# are authored by KeyPair.current
draft.discard
msg
end
def sign
def render
Serializer.new(self).render
end
private
def initialize(author:, kind:, body:)
raise "BODY CANT BE EMPTY" if body.empty?
@author = author
@kind = kind
@body = body
# Side effects in a constructor? Hmm...
store = Pigeon::Storage.current
@signature = calculate_signature
@depth = store.message_count
@prev = store.get_message_by_depth(@depth - 1)
self.freeze
store.save_message(self)
self
end
def render
Template.new(self).render
end
private
def initialize(author:, kind:, body:)
@author = author
@kind = kind
@body = body
# Side effects in a constructor? Hmm...
sign
end
def calculate_signature
template = Template.new(self)
template = Serializer.new(self)
string = template.render_without_signature
KeyPair.current.sign(string)
end

View File

@ -3,7 +3,7 @@ require "erb"
module Pigeon
# Wrapper around a message to perform string templating.
# Renders a string that is a Pigeon-compliant message.
class Template
class Serializer
attr_reader :message
def initialize(message)

View File

@ -97,7 +97,9 @@ module Pigeon
desc "sign", "Commit current DRAFT to local feed."
def sign
raise "Work in progress! under_construction.gif"
draft = Pigeon::Draft.current
message = Pigeon::Message.from_draft(draft)
puts message.render
end
end
@ -106,15 +108,13 @@ module Pigeon
def status
puts "
,.------------------------------------
| -`. Pigeon Protocol Ruby Client
| '( @ > Version: #{Pigeon::VERSION}
| _) ( Peers: #{Pigeon::Storage.current.all_peers.count}
| / ) Blocked: #{Pigeon::Storage.current.all_blocks.count}
| /_,' /
| \ /
|===m" "m===
'-,___________________________________
-`. Pigeon Protocol Ruby Client
'( @ > Version: #{Pigeon::VERSION}
_) ( Peers: #{Pigeon::Storage.current.all_peers.count}
/ ) Blocked: #{Pigeon::Storage.current.all_blocks.count}
/_,' / Logs: #{Pigeon::Storage.current.message_count}
\ /
===m" "m===
"
end

View File

@ -73,8 +73,8 @@ echo "=== add a second message to the db"
echo "=== append hello:'world' to message:"
./pigeon-cli message append hello "world"
# echo "=== Sign message #2"
# ./pigeon-cli message sign
echo "=== Sign message #2"
./pigeon-cli message sign
echo "=== getting status:"
./pigeon-cli status

View File

@ -14,6 +14,12 @@ RSpec.describe Pigeon::Message do
draft
end
it "discards a draft after signing" do
expect(draft.internal_id).to eq(Pigeon::Draft.current.internal_id)
Pigeon::Message.from_draft(draft)
expect(Pigeon::Draft.current).to be nil
end
it "creates a single message" do
message = Pigeon::Message.from_draft(draft)
expect(message.author).to eq(Pigeon::KeyPair.current)

View File

@ -1,6 +1,6 @@
require "spec_helper"
RSpec.describe Pigeon::Template do
RSpec.describe Pigeon::Serializer do
SHIM_ATTRS = [:author, :body, :kind, :depth, :prev, :signature, :saved?]
MessageShim = Struct.new(*SHIM_ATTRS)
TOP_HALF = ["author FAKE_AUTHOR",
@ -26,7 +26,7 @@ RSpec.describe Pigeon::Template do
"XYZ.sig.sha256",
false]
message = MessageShim.new(*args)
template = Pigeon::Template.new(message)
template = Pigeon::Serializer.new(message)
expect(template.render).to eq(EXPECTED_DRAFT)
expect(template.render_without_signature).to eq(TOP_HALF)
end