wine 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +38 -0
- data/bin/wine-test-server +9 -0
- data/lib/wine.rb +6 -0
- data/lib/wine/connection.rb +45 -0
- data/lib/wine/error.rb +18 -0
- data/lib/wine/message.rb +71 -0
- data/lib/wine/session.rb +66 -0
- data/lib/wine/test_server.rb +137 -0
- data/lib/wine/version.rb +3 -0
- metadata +95 -0
data/README.md
ADDED
@@ -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.
|
data/lib/wine.rb
ADDED
@@ -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
|
data/lib/wine/error.rb
ADDED
data/lib/wine/message.rb
ADDED
@@ -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
|
data/lib/wine/session.rb
ADDED
@@ -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
|
data/lib/wine/version.rb
ADDED
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: []
|