gossiperl_client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,9 @@
1
+ # encoding: ascii-8bit
2
+ module Gossiperl
3
+ module Client
4
+ module Version
5
+ VERSION = '0.1.0'
6
+ MAJOR, MINOR, TINY = VERSION.split('.')
7
+ end
8
+ end
9
+ 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