wine 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,38 @@
1
+ Wine for Ruby
2
+ =============
3
+
4
+ Wine is a protocol for configuring and monitoring agents. Wine for Ruby is an
5
+ implementation of the protocol for Ruby agents, and there is [Wine for Java][]
6
+ for the JVM as well.
7
+
8
+ [Wine for Java]: http://github.com/valotrading/wine-java
9
+
10
+
11
+ Installation
12
+ ------------
13
+
14
+ Install Wine for Ruby:
15
+
16
+ gem install wine
17
+
18
+
19
+ Development
20
+ -----------
21
+
22
+ Install the dependencies:
23
+
24
+ bundle install
25
+
26
+ Run the tests:
27
+
28
+ bundle exec rake
29
+
30
+ Run the test server:
31
+
32
+ bundle exec bin/wine-test-server
33
+
34
+
35
+ License
36
+ -------
37
+
38
+ Wine for Ruby is released under the Apache License, Version 2.0.
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'wine'
4
+
5
+ begin
6
+ Wine::TestServer.start(ARGV)
7
+ rescue Interrupt
8
+ exit
9
+ end
@@ -0,0 +1,6 @@
1
+ require 'wine/connection'
2
+ require 'wine/error'
3
+ require 'wine/message'
4
+ require 'wine/session'
5
+ require 'wine/test_server'
6
+ require 'wine/version'
@@ -0,0 +1,45 @@
1
+ require 'wine/error'
2
+ require 'wine/message'
3
+
4
+ module Wine
5
+ class Connection
6
+
7
+ DEFAULT_TIMEOUT = 5000
8
+
9
+ attr_reader :socket
10
+
11
+ def initialize(socket)
12
+ @socket = socket
13
+ end
14
+
15
+ def send(message)
16
+ message.write(@socket)
17
+ end
18
+
19
+ def recv(timeout = DEFAULT_TIMEOUT)
20
+ readable = IO.select([ @socket ], nil, nil, timeout / 1000.0)
21
+ return nil unless readable
22
+
23
+ msg_type = @socket.recv(1, Socket::MSG_PEEK)
24
+ raise ConnectionClosed unless msg_type.length == 1
25
+
26
+ Message.read(@socket)
27
+ end
28
+
29
+ def recv_nonblock
30
+ begin
31
+ msg_type = @socket.recv_nonblock(1, Socket::MSG_PEEK)
32
+ raise ConnectionClosed unless msg_type.length == 1
33
+
34
+ Message.read(@socket)
35
+ rescue IO::WaitReadable
36
+ nil
37
+ end
38
+ end
39
+
40
+ def close
41
+ @socket.close
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,18 @@
1
+ module Wine
2
+
3
+ class Error < StandardError
4
+ end
5
+
6
+ class ConnectionRefused < Error
7
+ end
8
+
9
+ class ConnectionClosed < Error
10
+ end
11
+
12
+ class ResponseTimeout < Error
13
+ end
14
+
15
+ class ProtocolError < Error
16
+ end
17
+
18
+ end
@@ -0,0 +1,71 @@
1
+ require 'bindata'
2
+ require 'wine/error'
3
+
4
+ module Wine
5
+ module Message
6
+
7
+ LOGIN = 'L'
8
+ LOGIN_ACCEPTED = 'A'
9
+ LOGIN_REJECTED = 'J'
10
+ GET = 'G'
11
+ VALUE = 'V'
12
+ SET = 'S'
13
+
14
+ class Login < BinData::Record
15
+ string :msg_type, :value => LOGIN
16
+ string :username, :length => 8, :pad_byte => ' '
17
+ string :password, :length => 20, :pad_byte => ' '
18
+ end
19
+
20
+ class LoginAccepted < BinData::Record
21
+ string :msg_type, :value => LOGIN_ACCEPTED
22
+ end
23
+
24
+ class LoginRejected < BinData::Record
25
+ string :msg_type, :value => LOGIN_REJECTED
26
+ end
27
+
28
+ class Get < BinData::Record
29
+ string :msg_type, :value => GET
30
+ int32be :key_length, :value => lambda { key_data.length }
31
+ string :key_data, :read_length => :key_length
32
+ end
33
+
34
+ class Value < BinData::Record
35
+ string :msg_type, :value => VALUE
36
+ int32be :key_length, :value => lambda { key_data.length }
37
+ int32be :value_length, :value => lambda { value_data.length }
38
+ string :key_data, :read_length => :key_length
39
+ string :value_data, :read_length => :value_length
40
+ end
41
+
42
+ class Set < BinData::Record
43
+ string :msg_type, :value => SET
44
+ int32be :key_length, :value => lambda { key_data.length }
45
+ int32be :value_length, :value => lambda { value_data.length }
46
+ string :key_data, :read_length => :key_length
47
+ string :value_data, :read_length => :value_length
48
+ end
49
+
50
+ def self.read(io)
51
+ begin
52
+ type = Types[io.read(1)]
53
+ type.read(io)
54
+ rescue StandardError
55
+ raise ProtocolError
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ Types = {
62
+ LOGIN => Login,
63
+ LOGIN_ACCEPTED => LoginAccepted,
64
+ LOGIN_REJECTED => LoginRejected,
65
+ GET => Get,
66
+ VALUE => Value,
67
+ SET => Set
68
+ }
69
+
70
+ end
71
+ end
@@ -0,0 +1,66 @@
1
+ require 'socket'
2
+ require 'wine/connection'
3
+ require 'wine/error'
4
+ require 'wine/message'
5
+
6
+ module Wine
7
+ class Session
8
+
9
+ def self.connect(host, port)
10
+ begin
11
+ socket = TCPSocket.new(host, port)
12
+ connection = Connection.new(socket)
13
+
14
+ new(connection)
15
+ rescue Errno::ECONNREFUSED
16
+ raise ConnectionRefused
17
+ end
18
+ end
19
+
20
+ def initialize(connection)
21
+ @connection = connection
22
+ end
23
+
24
+ def login(username, password, timeout = Connection::DEFAULT_TIMEOUT)
25
+ request = Message::Login.new(:username => username, :password => password)
26
+ @connection.send(request)
27
+
28
+ response = @connection.recv(timeout)
29
+ raise ResponseTimeout unless response
30
+
31
+ case response.msg_type
32
+ when Message::LOGIN_ACCEPTED
33
+ true
34
+ when Message::LOGIN_REJECTED
35
+ false
36
+ else
37
+ raise ProtocolError
38
+ end
39
+ end
40
+
41
+ def get(key, timeout = Connection::DEFAULT_TIMEOUT)
42
+ request = Message::Get.new(:key_data => key)
43
+ @connection.send(request)
44
+
45
+ response = @connection.recv(timeout)
46
+ raise ResponseTimeout unless response
47
+
48
+ case response.msg_type
49
+ when Message::VALUE
50
+ response.value_data
51
+ else
52
+ raise ProtocolError
53
+ end
54
+ end
55
+
56
+ def set(key, value)
57
+ request = Message::Set.new(:key_data => key, :value_data => value)
58
+ @connection.send(request)
59
+ end
60
+
61
+ def close
62
+ @connection.close
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,137 @@
1
+ require 'logger'
2
+ require 'socket'
3
+ require 'wine/connection'
4
+ require 'wine/error'
5
+ require 'wine/message'
6
+
7
+ module Wine
8
+ class TestServer
9
+
10
+ Timeout = 100.0 / 1000.0
11
+
12
+ def self.start(args)
13
+ usage unless args.length == 1
14
+
15
+ port = args[0].to_i
16
+ usage if port == 0
17
+
18
+ log = Logger.new(STDERR)
19
+
20
+ server = new(port, log)
21
+ server.run
22
+ end
23
+
24
+ def self.usage
25
+ abort "Usage: wine-test-server <port>"
26
+ end
27
+
28
+ def initialize(port, logger)
29
+ @port = port
30
+ @log = logger
31
+
32
+ @stopped = false
33
+
34
+ @config = {}
35
+
36
+ @server_socket = nil
37
+ @connections = {}
38
+
39
+ @log.progname = "wine-test-server"
40
+ @log.formatter = Proc.new do |severity, time, progname, msg|
41
+ "#{progname}: #{severity.downcase}: #{msg}\n"
42
+ end
43
+ end
44
+
45
+ def run
46
+ listen
47
+
48
+ @log.info("Listening on port #{@port}")
49
+
50
+ until @stopped do
51
+ readable, writable, erroneous = IO.select(sockets, [], [], Timeout)
52
+ next unless readable
53
+
54
+ readable.each do |socket|
55
+ if socket == @server_socket
56
+ accept
57
+ else
58
+ recv(@connections[socket])
59
+ end
60
+ end
61
+ end
62
+
63
+ sockets.each do |socket|
64
+ socket.close
65
+ end
66
+ end
67
+
68
+ def stop
69
+ @stopped = true
70
+ end
71
+
72
+ private
73
+
74
+ def listen
75
+ @server_socket = Socket.new(:INET, :SOCK_STREAM)
76
+ @server_socket.setsockopt(:SOL_SOCKET, :SO_REUSEADDR, true)
77
+ @server_socket.bind(Socket.sockaddr_in(@port, "127.0.0.1"))
78
+ @server_socket.listen(5)
79
+ end
80
+
81
+ def sockets
82
+ [ @server_socket ] + client_sockets
83
+ end
84
+
85
+ def client_sockets
86
+ @connections.keys
87
+ end
88
+
89
+ def accept
90
+ begin
91
+ client_socket, client_addrinfo = @server_socket.accept_nonblock
92
+
93
+ @connections[client_socket] = Connection.new(client_socket)
94
+ rescue IO::WaitReadable
95
+ # Do nothing.
96
+ end
97
+ end
98
+
99
+ def recv(connection)
100
+ begin
101
+ message = connection.recv_nonblock
102
+ if message
103
+ @log.info("Received #{message}")
104
+
105
+ handle(connection, message)
106
+ end
107
+ rescue ConnectionClosed
108
+ @log.info("Connection closed")
109
+
110
+ close(connection)
111
+ rescue Error
112
+ @log.warn("Closing connection")
113
+
114
+ close(connection)
115
+ end
116
+ end
117
+
118
+ def handle(connection, message)
119
+ case message.msg_type
120
+ when Message::LOGIN
121
+ connection.send(Message::LoginAccepted.new)
122
+ when Message::GET
123
+ value = @config.fetch(message.key_data, '')
124
+ connection.send(Message::Value.new(:key_data => message.key_data, :value_data => value))
125
+ when Message::SET
126
+ @config[message.key_data] = message.value_data
127
+ end
128
+ end
129
+
130
+ def close(connection)
131
+ @connections.delete(connection.socket)
132
+
133
+ connection.close
134
+ end
135
+
136
+ end
137
+ end
@@ -0,0 +1,3 @@
1
+ module Wine
2
+ VERSION = '0.1.0'
3
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wine
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Pekka Enberg
9
+ - Jussi Virtanen
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2013-05-15 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: bindata
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '1.4'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: '1.4'
31
+ - !ruby/object:Gem::Dependency
32
+ name: rake
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: '10.0'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: '10.0'
47
+ description: ! "Wine for Ruby\n=============\n\nWine is a protocol for configuring
48
+ and monitoring agents. Wine for Ruby is an\nimplementation of the protocol for Ruby
49
+ agents, and there is [Wine for Java][]\nfor the JVM as well.\n\n [Wine for Java]:
50
+ http://github.com/valotrading/wine-java\n\n\nInstallation\n------------\n\nInstall
51
+ Wine for Ruby:\n\n gem install wine\n\n\nDevelopment\n-----------\n\nInstall
52
+ the dependencies:\n\n bundle install\n\nRun the tests:\n\n bundle exec rake\n\nRun
53
+ the test server:\n\n bundle exec bin/wine-test-server\n\n\nLicense\n-------\n\nWine
54
+ for Ruby is released under the Apache License, Version 2.0.\n"
55
+ email: engineering@valotrading.com
56
+ executables:
57
+ - wine-test-server
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - README.md
62
+ - bin/wine-test-server
63
+ - lib/wine.rb
64
+ - lib/wine/version.rb
65
+ - lib/wine/error.rb
66
+ - lib/wine/connection.rb
67
+ - lib/wine/session.rb
68
+ - lib/wine/message.rb
69
+ - lib/wine/test_server.rb
70
+ homepage: http://github.com/valotrading/wine-ruby
71
+ licenses:
72
+ - Apache License, Version 2.0
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 1.8.23
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: A protocol for configuring and monitoring agents
95
+ test_files: []