gossiperl_client 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +151 -0
- data/gossiperl_client.gemspec +44 -0
- data/lib/gossiperl_client.rb +5 -0
- data/lib/gossiperl_client/encryption/aes256.rb +44 -0
- data/lib/gossiperl_client/headers.rb +46 -0
- data/lib/gossiperl_client/messaging.rb +120 -0
- data/lib/gossiperl_client/overlay_worker.rb +73 -0
- data/lib/gossiperl_client/requirements.rb +15 -0
- data/lib/gossiperl_client/resolution.rb +38 -0
- data/lib/gossiperl_client/serialization/serializer.rb +128 -0
- data/lib/gossiperl_client/state.rb +73 -0
- data/lib/gossiperl_client/supervisor.rb +81 -0
- data/lib/gossiperl_client/thrift/gossiperl_constants.rb +15 -0
- data/lib/gossiperl_client/thrift/gossiperl_types.rb +378 -0
- data/lib/gossiperl_client/transport/udp.rb +52 -0
- data/lib/gossiperl_client/util/validation.rb +37 -0
- data/lib/gossiperl_client/version.rb +9 -0
- data/tests/process_tests.rb +63 -0
- data/tests/thrift_tests.rb +45 -0
- metadata +129 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
require 'socket'
|
3
|
+
module Gossiperl
|
4
|
+
module Client
|
5
|
+
module Transport
|
6
|
+
class Udp < Gossiperl::Client::Resolution
|
7
|
+
|
8
|
+
field :worker, Gossiperl::Client::OverlayWorker
|
9
|
+
field :socket, UDPSocket, nil
|
10
|
+
field :recv_buf_size, Fixnum, 16777216
|
11
|
+
|
12
|
+
field :serializer, Gossiperl::Client::Serialization::Serializer
|
13
|
+
field :encryption, Gossiperl::Client::Encryption::Aes256
|
14
|
+
|
15
|
+
def initialize worker
|
16
|
+
self.worker = worker
|
17
|
+
self.serializer = Gossiperl::Client::Serialization::Serializer.new
|
18
|
+
self.encryption = Gossiperl::Client::Encryption::Aes256.new( self.worker.options[:symkey].to_s )
|
19
|
+
end
|
20
|
+
|
21
|
+
def handle &block
|
22
|
+
worker = Thread.new ({ :proto => self, :block => block }) do |args|
|
23
|
+
begin
|
24
|
+
args[:proto].socket = UDPSocket.new
|
25
|
+
args[:proto].socket.bind '127.0.0.1', args[:proto].worker.options[:client_port]
|
26
|
+
while args[:proto].worker.working
|
27
|
+
begin
|
28
|
+
data, address = args[:proto].socket.recvfrom args[:proto].recv_buf_size
|
29
|
+
decrypted = args[:proto].encryption.decrypt(data)
|
30
|
+
deserialized = args[:proto].serializer.deserialize(decrypted)
|
31
|
+
args[:block].call deserialized
|
32
|
+
rescue Exception => ex
|
33
|
+
args[:block].call({ :error => ex })
|
34
|
+
end
|
35
|
+
end
|
36
|
+
self.socket.close unless self.socket.nil?
|
37
|
+
args[:proto].worker.logger.debug("Stopping UDP services for client #{args[:proto].worker.options[:client_name]}.")
|
38
|
+
rescue Exception => e
|
39
|
+
args[:proto].worker.logger.error("Could not bind UDP service for client #{args[:proto].worker.options[:client_name]}.")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def send digest
|
45
|
+
serialized = self.serializer.serialize digest
|
46
|
+
encrypted = self.encryption.encrypt serialized
|
47
|
+
self.socket.send encrypted, 0, '127.0.0.1', self.worker.options[:overlay_port]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
module Gossiperl
|
3
|
+
module Client
|
4
|
+
module Util
|
5
|
+
|
6
|
+
class Validation
|
7
|
+
|
8
|
+
def self.validate_connect options
|
9
|
+
raise ArgumentError.new('Options must be a Hash.') unless options.kind_of?(Hash)
|
10
|
+
[ :overlay_name, :client_name, :client_secret, :overlay_port, :client_port, :symkey ].each {|opt|
|
11
|
+
raise ArgumentError.new("Required option #{opt} missing.") unless options.has_key?(opt)
|
12
|
+
}
|
13
|
+
[ :overlay_name, :client_name, :client_secret, :symkey ].each {|str_opt|
|
14
|
+
raise TypeError.new("Option #{str_opt} must be a String or Symbol.") unless [String, Symbol].include?( options[str_opt].class )
|
15
|
+
}
|
16
|
+
[ :overlay_port, :client_port ].each {|fixnum_opt|
|
17
|
+
raise TypeError.new("Option #{str_opt} must be a Fixnum.") unless [Fixnum].include?( options[fixnum_opt].class )
|
18
|
+
}
|
19
|
+
if options.has_key?(:thrift_window) and not options[:thrift_window].is_a?(Fixnum)
|
20
|
+
raise TypeError.new('Option thrift_window has to be a Fixnum.')
|
21
|
+
end
|
22
|
+
if options.has_key?(:logger) and not options[:logger].kind_of?(Logger)
|
23
|
+
raise TypeError.new('Option logger must be an instance of Logger.')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.validate_event_types event_types
|
28
|
+
event_types.each {|et|
|
29
|
+
raise TypeError.new("Event type #{et.inspect} must be a String or Symbol.") unless [String, Symbol].include?( et.class )
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
require "#{File.expand_path(File.dirname(__FILE__))}/../lib/gossiperl_client/requirements.rb"
|
3
|
+
Shindo.tests('[Gossiperl] connect process') do
|
4
|
+
|
5
|
+
@supervisor = Gossiperl::Client::Supervisor.new
|
6
|
+
@options = {
|
7
|
+
:overlay_name => :gossiper_overlay_remote,
|
8
|
+
:overlay_port => 6666,
|
9
|
+
:client_port => 54321,
|
10
|
+
:client_name => :'ruby-client',
|
11
|
+
:client_secret => :'ruby-client-secret',
|
12
|
+
:symkey => :v3JElaRswYgxOt4b }
|
13
|
+
@subscriptions = [ :member_in, :digestForwardableTest ]
|
14
|
+
|
15
|
+
tests('success') do
|
16
|
+
|
17
|
+
tests('connect goes to connected').returns(true) do
|
18
|
+
Thread.new(@supervisor) do |sup|
|
19
|
+
sup.connect( @options ) do |event|
|
20
|
+
if event[:event] == :connected
|
21
|
+
self.logger.info "Connected to overlay #{event[:options][:overlay_name]}..."
|
22
|
+
elsif event[:event] == :disconnected
|
23
|
+
self.logger.info "Disconnected from overlay #{event[:options][:overlay_name]}..."
|
24
|
+
elsif event[:event] == :subscribed
|
25
|
+
self.logger.info "Received subscription confirmation for #{event[:details][:types]}"
|
26
|
+
elsif event[:event] == :unsubscribed
|
27
|
+
self.logger.info "Received unsubscription confirmation for #{event[:details][:types]}"
|
28
|
+
elsif event[:event] == :event
|
29
|
+
self.logger.info "Received member related event #{event[:details][:type]} for member #{event[:details][:member]}."
|
30
|
+
elsif event[:event] == :forwarded_ack
|
31
|
+
self.logger.info "Received confirmation of forwarded message. Message ID: #{event[:details][:reply_id]}"
|
32
|
+
elsif event[:event] == :forwarded
|
33
|
+
self.logger.info "Received forwarded digest #{event[:digest]} of type #{event[:digest_type]}"
|
34
|
+
elsif event[:event] == :failed
|
35
|
+
self.logger.info "Received an error from the client. Reason: #{event[:error]}."
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
sleep 3
|
40
|
+
@supervisor.state( @options[:overlay_name] ) == :connected
|
41
|
+
end
|
42
|
+
|
43
|
+
tests('subscribe').returns(true) do
|
44
|
+
result = @supervisor.subscribe( @options[:overlay_name], @subscriptions ) == @subscriptions
|
45
|
+
sleep 3
|
46
|
+
result
|
47
|
+
end
|
48
|
+
|
49
|
+
tests('unsubscribe').returns(true) do
|
50
|
+
result = @supervisor.unsubscribe( @options[:overlay_name], @subscriptions ) == []
|
51
|
+
sleep 3
|
52
|
+
result
|
53
|
+
end
|
54
|
+
|
55
|
+
tests('disconnect').returns(true) do
|
56
|
+
@supervisor.disconnect( @options[:overlay_name] )
|
57
|
+
sleep 1.5
|
58
|
+
@supervisor.connections == {}
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
require "#{File.expand_path(File.dirname(__FILE__))}/../lib/gossiperl_client/requirements.rb"
|
3
|
+
Shindo.tests('[Thrift] Serialize / deserialize') do
|
4
|
+
|
5
|
+
@digest = digest = ::Gossiperl::Client::Thrift::Digest.new
|
6
|
+
@digest.name = "test-client"
|
7
|
+
@digest.port = 54321
|
8
|
+
@digest.heartbeat = Time.now.to_i
|
9
|
+
@digest.secret = "test-client-secret"
|
10
|
+
@digest.id = "test-digest-id"
|
11
|
+
|
12
|
+
@enc_key = "SomeEncryptionKe"
|
13
|
+
|
14
|
+
tests('success') do
|
15
|
+
|
16
|
+
tests('serialize / deserialize').returns(true) do
|
17
|
+
envelope = Gossiperl::Client::Serialization::Serializer.new.serialize(@digest)
|
18
|
+
read = Gossiperl::Client::Serialization::Serializer.new.deserialize(envelope)
|
19
|
+
read.id == @digest.id
|
20
|
+
end
|
21
|
+
|
22
|
+
tests('encrypt / decrypt').returns(true) do
|
23
|
+
envelope = Gossiperl::Client::Serialization::Serializer.new.serialize(@digest)
|
24
|
+
encrypted = Gossiperl::Client::Encryption::Aes256.new(@enc_key).encrypt(envelope)
|
25
|
+
decrypted = Gossiperl::Client::Encryption::Aes256.new(@enc_key).decrypt(encrypted)
|
26
|
+
read = Gossiperl::Client::Serialization::Serializer.new.deserialize(decrypted)
|
27
|
+
read.id == @digest.id
|
28
|
+
end
|
29
|
+
|
30
|
+
tests('serialize / deserialize arbitrary').returns(true) do
|
31
|
+
serializer = Gossiperl::Client::Serialization::Serializer.new
|
32
|
+
serialized_data = serializer.serialize_arbitrary :digestForwardableTest, {
|
33
|
+
:string_property => { :value => "some string",
|
34
|
+
:type => :string,
|
35
|
+
:field_id => 1 },
|
36
|
+
:some_port => { :value => 1234567890,
|
37
|
+
:type => :i32,
|
38
|
+
:field_id => 2 },
|
39
|
+
}
|
40
|
+
true
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: !binary |-
|
3
|
+
Z29zc2lwZXJsX2NsaWVudA==
|
4
|
+
version: !ruby/object:Gem::Version
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- !binary |-
|
9
|
+
UmFkIEdydWNoYWxza2k=
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2014-12-15 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: !binary |-
|
17
|
+
dGhyaWZ0
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - !binary |-
|
21
|
+
Pj0=
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.9.2.0
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
requirements:
|
28
|
+
- - !binary |-
|
29
|
+
Pj0=
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: 0.9.2.0
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: !binary |-
|
34
|
+
c2hpbmRv
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
description: !binary |-
|
48
|
+
V29yayB3aXRoIGdvc3NpcGVybCBmcm9tIFJ1Ynku
|
49
|
+
email:
|
50
|
+
- !binary |-
|
51
|
+
cmFkZWtAZ3J1Y2hhbHNraS5jb20=
|
52
|
+
executables: []
|
53
|
+
extensions: []
|
54
|
+
extra_rdoc_files: []
|
55
|
+
files:
|
56
|
+
- !binary |-
|
57
|
+
R2VtZmlsZQ==
|
58
|
+
- !binary |-
|
59
|
+
UkVBRE1FLm1k
|
60
|
+
- !binary |-
|
61
|
+
TElDRU5TRQ==
|
62
|
+
- !binary |-
|
63
|
+
bGliL2dvc3NpcGVybF9jbGllbnQucmI=
|
64
|
+
- !binary |-
|
65
|
+
bGliL2dvc3NpcGVybF9jbGllbnQvZW5jcnlwdGlvbi9hZXMyNTYucmI=
|
66
|
+
- !binary |-
|
67
|
+
bGliL2dvc3NpcGVybF9jbGllbnQvc2VyaWFsaXphdGlvbi9zZXJpYWxpemVy
|
68
|
+
LnJi
|
69
|
+
- !binary |-
|
70
|
+
bGliL2dvc3NpcGVybF9jbGllbnQvdGhyaWZ0L2dvc3NpcGVybF9jb25zdGFu
|
71
|
+
dHMucmI=
|
72
|
+
- !binary |-
|
73
|
+
bGliL2dvc3NpcGVybF9jbGllbnQvdGhyaWZ0L2dvc3NpcGVybF90eXBlcy5y
|
74
|
+
Yg==
|
75
|
+
- !binary |-
|
76
|
+
bGliL2dvc3NpcGVybF9jbGllbnQvdHJhbnNwb3J0L3VkcC5yYg==
|
77
|
+
- !binary |-
|
78
|
+
bGliL2dvc3NpcGVybF9jbGllbnQvdXRpbC92YWxpZGF0aW9uLnJi
|
79
|
+
- !binary |-
|
80
|
+
bGliL2dvc3NpcGVybF9jbGllbnQvaGVhZGVycy5yYg==
|
81
|
+
- !binary |-
|
82
|
+
bGliL2dvc3NpcGVybF9jbGllbnQvbWVzc2FnaW5nLnJi
|
83
|
+
- !binary |-
|
84
|
+
bGliL2dvc3NpcGVybF9jbGllbnQvb3ZlcmxheV93b3JrZXIucmI=
|
85
|
+
- !binary |-
|
86
|
+
bGliL2dvc3NpcGVybF9jbGllbnQvcmVxdWlyZW1lbnRzLnJi
|
87
|
+
- !binary |-
|
88
|
+
bGliL2dvc3NpcGVybF9jbGllbnQvcmVzb2x1dGlvbi5yYg==
|
89
|
+
- !binary |-
|
90
|
+
bGliL2dvc3NpcGVybF9jbGllbnQvc3RhdGUucmI=
|
91
|
+
- !binary |-
|
92
|
+
bGliL2dvc3NpcGVybF9jbGllbnQvc3VwZXJ2aXNvci5yYg==
|
93
|
+
- !binary |-
|
94
|
+
bGliL2dvc3NpcGVybF9jbGllbnQvdmVyc2lvbi5yYg==
|
95
|
+
- !binary |-
|
96
|
+
Z29zc2lwZXJsX2NsaWVudC5nZW1zcGVj
|
97
|
+
- !binary |-
|
98
|
+
dGVzdHMvcHJvY2Vzc190ZXN0cy5yYg==
|
99
|
+
- !binary |-
|
100
|
+
dGVzdHMvdGhyaWZ0X3Rlc3RzLnJi
|
101
|
+
homepage: !binary |-
|
102
|
+
aHR0cHM6Ly9naXRodWIuY29tL3JhZGVrZy9nb3NzaXBlcmwtY2xpZW50LXJ1
|
103
|
+
Ynk=
|
104
|
+
licenses: []
|
105
|
+
metadata: {}
|
106
|
+
post_install_message:
|
107
|
+
rdoc_options: []
|
108
|
+
require_paths:
|
109
|
+
- !binary |-
|
110
|
+
bGli
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ! '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
requirements: []
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 2.1.5
|
124
|
+
signing_key:
|
125
|
+
specification_version: 4
|
126
|
+
summary: !binary |-
|
127
|
+
R29zc2lwZXJsIFJ1YnkgY2xpZW50
|
128
|
+
test_files: []
|
129
|
+
has_rdoc: false
|