maxcube-client 0.4.1 → 0.5.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.
- checksums.yaml +4 -4
- data/.gitignore +6 -0
- data/.rubocop.yml +0 -3
- data/.yardopts +1 -0
- data/README.md +17 -2
- data/bin/maxcube-client +2 -27
- data/doc/MaxCube.html +502 -0
- data/doc/MaxCube/Messages.html +1927 -0
- data/doc/MaxCube/Messages/Handler.html +2912 -0
- data/doc/MaxCube/Messages/InvalidMessage.html +140 -0
- data/doc/MaxCube/Messages/InvalidMessageBody.html +264 -0
- data/doc/MaxCube/Messages/InvalidMessageFormat.html +247 -0
- data/doc/MaxCube/Messages/InvalidMessageLength.html +247 -0
- data/doc/MaxCube/Messages/InvalidMessageType.html +263 -0
- data/doc/MaxCube/Messages/Parser.html +520 -0
- data/doc/MaxCube/Messages/Serializer.html +701 -0
- data/doc/MaxCube/Messages/TCP.html +172 -0
- data/doc/MaxCube/Messages/TCP/Handler.html +1396 -0
- data/doc/MaxCube/Messages/TCP/Parser.html +462 -0
- data/doc/MaxCube/Messages/TCP/Parser/MessageA.html +186 -0
- data/doc/MaxCube/Messages/TCP/Parser/MessageC.html +1077 -0
- data/doc/MaxCube/Messages/TCP/Parser/MessageF.html +206 -0
- data/doc/MaxCube/Messages/TCP/Parser/MessageH.html +338 -0
- data/doc/MaxCube/Messages/TCP/Parser/MessageL.html +535 -0
- data/doc/MaxCube/Messages/TCP/Parser/MessageM.html +510 -0
- data/doc/MaxCube/Messages/TCP/Parser/MessageN.html +226 -0
- data/doc/MaxCube/Messages/TCP/Parser/MessageS.html +225 -0
- data/doc/MaxCube/Messages/TCP/Serializer.html +460 -0
- data/doc/MaxCube/Messages/TCP/Serializer/MessageA.html +186 -0
- data/doc/MaxCube/Messages/TCP/Serializer/MessageC.html +185 -0
- data/doc/MaxCube/Messages/TCP/Serializer/MessageF.html +206 -0
- data/doc/MaxCube/Messages/TCP/Serializer/MessageL.html +185 -0
- data/doc/MaxCube/Messages/TCP/Serializer/MessageM.html +428 -0
- data/doc/MaxCube/Messages/TCP/Serializer/MessageN.html +209 -0
- data/doc/MaxCube/Messages/TCP/Serializer/MessageQ.html +185 -0
- data/doc/MaxCube/Messages/TCP/Serializer/MessageS.html +1168 -0
- data/doc/MaxCube/Messages/TCP/Serializer/MessageT.html +240 -0
- data/doc/MaxCube/Messages/TCP/Serializer/MessageU.html +206 -0
- data/doc/MaxCube/Messages/TCP/Serializer/MessageZ.html +252 -0
- data/doc/MaxCube/Messages/UDP.html +164 -0
- data/doc/MaxCube/Messages/UDP/Handler.html +832 -0
- data/doc/MaxCube/Messages/UDP/Parser.html +609 -0
- data/doc/MaxCube/Messages/UDP/Parser/MessageH.html +218 -0
- data/doc/MaxCube/Messages/UDP/Parser/MessageI.html +215 -0
- data/doc/MaxCube/Messages/UDP/Parser/MessageN.html +226 -0
- data/doc/MaxCube/Messages/UDP/Serializer.html +484 -0
- data/doc/MaxCube/Network.html +167 -0
- data/doc/MaxCube/Network/TCP.html +150 -0
- data/doc/MaxCube/Network/TCP/Client.html +1930 -0
- data/doc/MaxCube/Network/TCP/Client/Commands.html +2457 -0
- data/doc/MaxCube/Network/TCP/SampleServer.html +910 -0
- data/doc/MaxCube/Network/UDP.html +150 -0
- data/doc/MaxCube/Network/UDP/Client.html +518 -0
- data/doc/MaxCube/Network/UDP/SampleSocket.html +628 -0
- data/doc/MaxCube/Runner.html +355 -0
- data/doc/_index.html +518 -0
- data/doc/class_list.html +51 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +58 -0
- data/doc/css/style.css +499 -0
- data/doc/file.README.html +140 -0
- data/doc/file_list.html +56 -0
- data/doc/frames.html +17 -0
- data/doc/index.html +140 -0
- data/doc/js/app.js +248 -0
- data/doc/js/full_list.js +216 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +1699 -0
- data/doc/top-level-namespace.html +110 -0
- data/lib/maxcube.rb +11 -0
- data/lib/maxcube/messages.rb +85 -8
- data/lib/maxcube/messages/handler.rb +138 -4
- data/lib/maxcube/messages/parser.rb +33 -2
- data/lib/maxcube/messages/serializer.rb +64 -16
- data/lib/maxcube/messages/tcp.rb +11 -7
- data/lib/maxcube/messages/tcp/handler.rb +50 -2
- data/lib/maxcube/messages/tcp/parser.rb +18 -17
- data/lib/maxcube/messages/tcp/serializer.rb +20 -21
- data/lib/maxcube/messages/tcp/type/a.rb +6 -6
- data/lib/maxcube/messages/tcp/type/c.rb +5 -3
- data/lib/maxcube/messages/tcp/type/f.rb +5 -3
- data/lib/maxcube/messages/tcp/type/h.rb +3 -2
- data/lib/maxcube/messages/tcp/type/l.rb +8 -7
- data/lib/maxcube/messages/tcp/type/m.rb +11 -7
- data/lib/maxcube/messages/tcp/type/n.rb +5 -3
- data/lib/maxcube/messages/tcp/type/q.rb +2 -2
- data/lib/maxcube/messages/tcp/type/s.rb +5 -2
- data/lib/maxcube/messages/tcp/type/t.rb +5 -4
- data/lib/maxcube/messages/tcp/type/u.rb +2 -1
- data/lib/maxcube/messages/tcp/type/z.rb +4 -2
- data/lib/maxcube/messages/udp.rb +7 -0
- data/lib/maxcube/messages/udp/handler.rb +28 -0
- data/lib/maxcube/messages/udp/parser.rb +23 -6
- data/lib/maxcube/messages/udp/serializer.rb +17 -1
- data/lib/maxcube/messages/udp/type/h.rb +2 -0
- data/lib/maxcube/messages/udp/type/i.rb +3 -0
- data/lib/maxcube/messages/udp/type/n.rb +3 -0
- data/lib/maxcube/network.rb +5 -1
- data/lib/maxcube/network/tcp.rb +3 -0
- data/lib/maxcube/network/tcp/client.rb +117 -3
- data/lib/maxcube/network/tcp/client/commands.rb +306 -239
- data/lib/maxcube/network/tcp/sample_server.rb +1 -0
- data/lib/maxcube/network/udp.rb +3 -0
- data/lib/maxcube/network/udp/client.rb +2 -0
- data/lib/maxcube/network/udp/sample_socket.rb +1 -0
- data/lib/maxcube/runner.rb +45 -0
- data/lib/maxcube/version.rb +2 -1
- data/maxcube-client.gemspec +2 -0
- metadata +84 -3
@@ -0,0 +1,110 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title>
|
7
|
+
Top Level Namespace
|
8
|
+
|
9
|
+
— Documentation by YARD 0.9.12
|
10
|
+
|
11
|
+
</title>
|
12
|
+
|
13
|
+
<link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
|
14
|
+
|
15
|
+
<link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
|
16
|
+
|
17
|
+
<script type="text/javascript" charset="utf-8">
|
18
|
+
pathId = "";
|
19
|
+
relpath = '';
|
20
|
+
</script>
|
21
|
+
|
22
|
+
|
23
|
+
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
24
|
+
|
25
|
+
<script type="text/javascript" charset="utf-8" src="js/app.js"></script>
|
26
|
+
|
27
|
+
|
28
|
+
</head>
|
29
|
+
<body>
|
30
|
+
<div class="nav_wrap">
|
31
|
+
<iframe id="nav" src="class_list.html?1"></iframe>
|
32
|
+
<div id="resizer"></div>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div id="main" tabindex="-1">
|
36
|
+
<div id="header">
|
37
|
+
<div id="menu">
|
38
|
+
|
39
|
+
<a href="_index.html">Index</a> »
|
40
|
+
|
41
|
+
|
42
|
+
<span class="title">Top Level Namespace</span>
|
43
|
+
|
44
|
+
</div>
|
45
|
+
|
46
|
+
<div id="search">
|
47
|
+
|
48
|
+
<a class="full_list_link" id="class_list_link"
|
49
|
+
href="class_list.html">
|
50
|
+
|
51
|
+
<svg width="24" height="24">
|
52
|
+
<rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
|
53
|
+
<rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
|
54
|
+
<rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
|
55
|
+
</svg>
|
56
|
+
</a>
|
57
|
+
|
58
|
+
</div>
|
59
|
+
<div class="clear"></div>
|
60
|
+
</div>
|
61
|
+
|
62
|
+
<div id="content"><h1>Top Level Namespace
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
</h1>
|
67
|
+
<div class="box_info">
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
</div>
|
80
|
+
|
81
|
+
<h2>Defined Under Namespace</h2>
|
82
|
+
<p class="children">
|
83
|
+
|
84
|
+
|
85
|
+
<strong class="modules">Modules:</strong> <span class='object_link'><a href="MaxCube.html" title="MaxCube (module)">MaxCube</a></span>
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
</p>
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
</div>
|
101
|
+
|
102
|
+
<div id="footer">
|
103
|
+
Generated on Fri Feb 16 13:44:01 2018 by
|
104
|
+
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
105
|
+
0.9.12 (ruby-2.5.0).
|
106
|
+
</div>
|
107
|
+
|
108
|
+
</div>
|
109
|
+
</body>
|
110
|
+
</html>
|
data/lib/maxcube.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'date'
|
2
|
+
require 'time'
|
2
3
|
require 'pathname'
|
3
4
|
require 'ipaddr'
|
4
5
|
|
@@ -6,19 +7,29 @@ require 'pp'
|
|
6
7
|
|
7
8
|
require 'maxcube/version'
|
8
9
|
|
10
|
+
# Root project module that contains only project-related utilities
|
9
11
|
module MaxCube
|
12
|
+
# Gets path to project root directory
|
13
|
+
# @return [String] path to project root directory
|
10
14
|
def self.root_dir
|
11
15
|
File.dirname __dir__
|
12
16
|
end
|
13
17
|
|
18
|
+
# Gets path to +bin/+ project directory with executables
|
19
|
+
# @return [String] path to +bin/+ project directory
|
14
20
|
def self.bin_dir
|
15
21
|
File.join(root_dir, 'bin')
|
16
22
|
end
|
17
23
|
|
24
|
+
# Gets path to +lib/+ project directory with Ruby source files
|
25
|
+
# @return [String] path to +lib/+ project directory
|
18
26
|
def self.lib_dir
|
19
27
|
File.join(root_dir, 'lib')
|
20
28
|
end
|
21
29
|
|
30
|
+
# Gets path to +data/+ project directory
|
31
|
+
# with input/output data for clients and servers
|
32
|
+
# @return [String] path to +data/+ project directory
|
22
33
|
def self.data_dir
|
23
34
|
File.join(root_dir, 'data')
|
24
35
|
end
|
data/lib/maxcube/messages.rb
CHANGED
@@ -1,39 +1,58 @@
|
|
1
1
|
require 'maxcube'
|
2
2
|
|
3
3
|
module MaxCube
|
4
|
+
# Encapsulates methods related to Cube messages,
|
5
|
+
# i.e. parsing and serializing of TCP/UDP messages.
|
6
|
+
# It does not provide any network features
|
7
|
+
# (this is responsibility of {Network}.
|
4
8
|
module Messages
|
9
|
+
# Device modes that determines geating scheduling.
|
5
10
|
DEVICE_MODE = %i[auto manual vacation boost].freeze
|
11
|
+
# Device types identified in Cube protocol.
|
6
12
|
DEVICE_TYPE = %i[cube
|
7
13
|
radiator_thermostat radiator_thermostat_plus
|
8
14
|
wall_thermostat
|
9
15
|
shutter_contact eco_switch].freeze
|
10
16
|
|
17
|
+
# Names of days of week in order Cube protocol uses.
|
11
18
|
DAYS_OF_WEEK = %w[Saturday Sunday Monday
|
12
19
|
Tuesday Wednesday Thursday Friday].freeze
|
13
20
|
|
14
|
-
|
15
|
-
|
21
|
+
# Base exception class
|
22
|
+
# that denotes an error during message parsing/serializing.
|
16
23
|
class InvalidMessage < RuntimeError; end
|
17
24
|
|
25
|
+
# Exception class that denotes that message is too short/long.
|
18
26
|
class InvalidMessageLength < InvalidMessage
|
27
|
+
# @param info contains context information to occured error.
|
19
28
|
def initialize(info = 'invalid message length')
|
20
29
|
super
|
21
30
|
end
|
22
31
|
end
|
23
32
|
|
33
|
+
# Exception class that denotes unrecognized message type.
|
24
34
|
class InvalidMessageType < InvalidMessage
|
35
|
+
# @param msg_type type of message that is being parsed/serialized.
|
36
|
+
# @param info contains context information to occured error.
|
25
37
|
def initialize(msg_type, info = 'invalid message type')
|
26
38
|
super("#{info}: #{msg_type}")
|
27
39
|
end
|
28
40
|
end
|
29
41
|
|
42
|
+
# Exception class that denotes invalid syntax format of message.
|
30
43
|
class InvalidMessageFormat < InvalidMessage
|
44
|
+
# @param info contains context information to occured error.
|
31
45
|
def initialize(info = 'invalid format')
|
32
46
|
super
|
33
47
|
end
|
34
48
|
end
|
35
49
|
|
50
|
+
# Exception class that denotes that an error occured
|
51
|
+
# while parsing/serializing message body,
|
52
|
+
# which is specific to message type.
|
36
53
|
class InvalidMessageBody < InvalidMessage
|
54
|
+
# @param msg_type type of message that is being parsed/serialized.
|
55
|
+
# @param info contains context information to occured error.
|
37
56
|
def initialize(msg_type, info = 'invalid format')
|
38
57
|
super("message type #{msg_type}: #{info}")
|
39
58
|
end
|
@@ -41,6 +60,17 @@ module MaxCube
|
|
41
60
|
|
42
61
|
private
|
43
62
|
|
63
|
+
# Applies a block to given arguments
|
64
|
+
# in order to perform conversion to certain type.
|
65
|
+
# If conversion fails, {InvalidMessageBody} is raised.
|
66
|
+
# Thus, this method can be used also for type checking purposes only.
|
67
|
+
# @param type [#to_s] name of the type to convert to.
|
68
|
+
# @param info [#to_s] context information to pass to raised error.
|
69
|
+
# @param args [Array] arguments to be converted into the same type.
|
70
|
+
# @yield a rule to provide
|
71
|
+
# certain type check and conversion of arguments.
|
72
|
+
# @return [Array] converted elements.
|
73
|
+
# @raise [InvalidMessageBody] if conversion fails.
|
44
74
|
def conv_args(type, info, *args, &block)
|
45
75
|
info = info.to_s.tr('_', ' ')
|
46
76
|
args.map(&block)
|
@@ -50,25 +80,44 @@ module MaxCube
|
|
50
80
|
"invalid #{type} format of arguments #{args} (#{info})")
|
51
81
|
end
|
52
82
|
|
53
|
-
#
|
54
|
-
#
|
83
|
+
# Uses {#conv_args} to convert numbers
|
84
|
+
# or string of characters (not binary data!)
|
85
|
+
# to integers in given base (radix).
|
86
|
+
# For binary data use {Parser#read}.
|
87
|
+
# @param base [Integer] integers base (radix), 0 means auto-recognition.
|
88
|
+
# @param args [Array<#Integer>] arguments to convert to integers.
|
89
|
+
# @return [Array<Integer>] converted elements.
|
55
90
|
def to_ints(base, info, *args)
|
56
91
|
base_str = base.zero? ? '' : "(#{base})"
|
57
92
|
conv_args("integer#{base_str}", info, *args) { |x| Integer(x, base) }
|
58
93
|
end
|
59
94
|
|
95
|
+
# Uses {#to_ints}, but operates with single argument.
|
96
|
+
# @param arg [#Integer] argument to convert to integer.
|
97
|
+
# @return [Integer] converted element.
|
60
98
|
def to_int(base, info, arg)
|
61
99
|
to_ints(base, info, arg).first
|
62
100
|
end
|
63
101
|
|
102
|
+
# Uses {#conv_args} to convert numbers
|
103
|
+
# or string of characters (not binary data!) to floats.
|
104
|
+
# @param args [Array<#Float>] arguments to convert to floats.
|
105
|
+
# @return [Array<Float>] converted elements.
|
64
106
|
def to_floats(info, *args)
|
65
107
|
conv_args('float', info, *args) { |x| Float(x) }
|
66
108
|
end
|
67
109
|
|
110
|
+
# Uses {#to_floats}, but operates with single argument.
|
111
|
+
# @param arg [#Float] argument to convert to float.
|
112
|
+
# @return [Float] converted element.
|
68
113
|
def to_float(info, arg)
|
69
114
|
to_floats(info, arg).first
|
70
115
|
end
|
71
116
|
|
117
|
+
# Uses {#conv_args} to convert objects to bools.
|
118
|
+
# @param args [Array] arguments to convert to bools.
|
119
|
+
# @return [Array<Boolean>] converted elements
|
120
|
+
# to +TrueClass+ or +FalseClass+.
|
72
121
|
def to_bools(info, *args)
|
73
122
|
conv_args('boolean', info, *args) do |arg|
|
74
123
|
if arg == !!arg
|
@@ -83,26 +132,47 @@ module MaxCube
|
|
83
132
|
end
|
84
133
|
end
|
85
134
|
|
135
|
+
# Uses {#to_bools}, but operates with single argument.
|
136
|
+
# @param arg argument to convert to bool.
|
137
|
+
# @return [Boolean] converted element
|
138
|
+
# to +TrueClass+ or +FalseClass+.
|
86
139
|
def to_bool(info, arg)
|
87
140
|
to_bools(info, arg).first
|
88
141
|
end
|
89
142
|
|
143
|
+
# Uses {#conv_args} to convert objects to +Time+.
|
144
|
+
# @param args [Array] arguments to convert to +Time+.
|
145
|
+
# @return [Array<Time>] converted elements.
|
90
146
|
def to_datetimes(info, *args)
|
91
147
|
conv_args('datetime', info, *args) do |arg|
|
92
|
-
if arg.is_a?(
|
148
|
+
if arg.is_a?(Time)
|
93
149
|
arg
|
94
|
-
elsif arg.
|
95
|
-
arg
|
150
|
+
elsif arg.is_a?(String)
|
151
|
+
Time.parse(arg)
|
152
|
+
elsif arg.respond_to?('to_time')
|
153
|
+
arg.to_time
|
154
|
+
elsif arg.respond_to?('to_date')
|
155
|
+
arg.to_date.to_time
|
96
156
|
else
|
97
|
-
|
157
|
+
raise ArgumentError
|
98
158
|
end
|
99
159
|
end
|
100
160
|
end
|
101
161
|
|
162
|
+
# Uses {#to_datetime}, but operates with single argument.
|
163
|
+
# @param arg argument to convert to +Time+.
|
164
|
+
# @return [Time] converted element.
|
102
165
|
def to_datetime(info, arg)
|
103
166
|
to_datetimes(info, arg).first
|
104
167
|
end
|
105
168
|
|
169
|
+
# Helper method that checks presence of index in array
|
170
|
+
# (if not, exception is raised).
|
171
|
+
# @param ary [#[]] input container (usually constant).
|
172
|
+
# @param id index of element in container.
|
173
|
+
# @param info [#to_s] context information to pass to raised error.
|
174
|
+
# @return element of container if found.
|
175
|
+
# @raise [InvalidMessageBody] if element not found.
|
106
176
|
def ary_elem(ary, id, info)
|
107
177
|
elem = ary[id]
|
108
178
|
return elem if elem
|
@@ -110,6 +180,7 @@ module MaxCube
|
|
110
180
|
.new(@msg_type, "unrecognized #{info} id: #{id}")
|
111
181
|
end
|
112
182
|
|
183
|
+
# Reverse method to {#ary_elem}.
|
113
184
|
def ary_elem_id(ary, elem, info)
|
114
185
|
id = ary.index(elem)
|
115
186
|
return id if id
|
@@ -117,26 +188,32 @@ module MaxCube
|
|
117
188
|
.new(@msg_type, "unrecognized #{info}: #{elem}")
|
118
189
|
end
|
119
190
|
|
191
|
+
# Uses {#ary_elem} with {DEVICE_TYPE}
|
120
192
|
def device_type(device_type_id)
|
121
193
|
ary_elem(DEVICE_TYPE, device_type_id, 'device type')
|
122
194
|
end
|
123
195
|
|
196
|
+
# Uses {#ary_elem_id} with {DEVICE_TYPE}
|
124
197
|
def device_type_id(device_type)
|
125
198
|
ary_elem_id(DEVICE_TYPE, device_type.to_sym, 'device type')
|
126
199
|
end
|
127
200
|
|
201
|
+
# Uses {#ary_elem} with {DEVICE_MODE}
|
128
202
|
def device_mode(device_mode_id)
|
129
203
|
ary_elem(DEVICE_MODE, device_mode_id, 'device mode')
|
130
204
|
end
|
131
205
|
|
206
|
+
# Uses {#ary_elem_id} with {DEVICE_MODE}
|
132
207
|
def device_mode_id(device_mode)
|
133
208
|
ary_elem_id(DEVICE_MODE, device_mode.to_sym, 'device mode')
|
134
209
|
end
|
135
210
|
|
211
|
+
# Uses {#ary_elem} with {DAYS_OF_WEEK}
|
136
212
|
def day_of_week(day_id)
|
137
213
|
ary_elem(DAYS_OF_WEEK, day_id, 'day of week')
|
138
214
|
end
|
139
215
|
|
216
|
+
# Uses {#ary_elem_id} with {DAYS_OF_WEEK}
|
140
217
|
def day_of_week_id(day)
|
141
218
|
if day.respond_to?('to_i') && day.to_i.between?(1, 7)
|
142
219
|
return (day.to_i + 1) % 7
|
@@ -5,74 +5,147 @@ require 'maxcube/messages'
|
|
5
5
|
|
6
6
|
module MaxCube
|
7
7
|
module Messages
|
8
|
+
# This module provides methods that handles with messages
|
9
|
+
# regardless whether it is for parse or serialize purposes.
|
10
|
+
# It mostly contains methods that validates (returns Boolean)
|
11
|
+
# or checks (raises exception on failure) some part of message.
|
8
12
|
module Handler
|
9
13
|
include Messages
|
10
14
|
|
15
|
+
# Format characters to String#unpack and Array#pack,
|
16
|
+
# for purposes to convert binary string to integer.
|
17
|
+
# Elements are sorted by integer size in bytes.
|
18
|
+
PACK_FORMAT = %w[x C n N N].freeze
|
19
|
+
|
20
|
+
# Checks whether raw data string is +String+.
|
21
|
+
# @param raw_data input raw data string.
|
22
|
+
# @return [Boolean] +true+ if argument is +String+, +false+ otherwise.
|
11
23
|
def valid_data_type(raw_data)
|
12
24
|
raw_data.is_a?(String)
|
13
25
|
end
|
14
26
|
|
27
|
+
# Checks whether {#valid_data_type} is +true+.
|
28
|
+
# If not, exception is raised.
|
29
|
+
# @return [String] input raw data string.
|
30
|
+
# @raise [TypeError] if argument is _not_ valid.
|
15
31
|
def check_data_type(raw_data)
|
16
32
|
raise TypeError unless valid_data_type(raw_data)
|
17
33
|
raw_data
|
18
34
|
end
|
19
35
|
|
36
|
+
# Validates whether message type character is valid.
|
37
|
+
# Calls {#maybe_check_valid_msg_type}.
|
38
|
+
# @param msg_type [String] input message type character.
|
39
|
+
# @return [Boolean] +true+ if argument is valid message type.
|
20
40
|
def valid_msg_type(msg_type)
|
21
41
|
maybe_check_valid_msg_type(msg_type, false)
|
22
42
|
end
|
23
43
|
|
44
|
+
# Checks whether message type character is valid.
|
45
|
+
# Calls {#maybe_check_valid_msg_type}.
|
46
|
+
# If argument is valid, it assigns the message type to internal variable.
|
47
|
+
# @param msg_type [String] input message type character.
|
48
|
+
# @return [String] message type character assigned to internal variable.
|
49
|
+
# @raise [InvalidMessageType] if validation fails.
|
24
50
|
def check_msg_type(msg_type)
|
25
51
|
maybe_check_valid_msg_type(msg_type, true)
|
26
52
|
@msg_type
|
27
53
|
end
|
28
54
|
|
55
|
+
# Validates whether message type character of message is valid.
|
56
|
+
# Calls {#valid_msg_type} and #msg_msg_type
|
57
|
+
# (this method depends on conrete end-class).
|
58
|
+
# @param msg [String] input message.
|
29
59
|
def valid_msg_msg_type(msg)
|
30
60
|
valid_msg_type(msg_msg_type(msg))
|
31
61
|
end
|
32
62
|
|
63
|
+
# Checks whether message type character of message is valid.
|
64
|
+
# Calls {#check_msg_type} and #msg_msg_type
|
65
|
+
# (this method depends on conrete end-class).
|
66
|
+
# If argument is valid, it assigns the message type to internal variable.
|
67
|
+
# @param msg [String] input message.
|
33
68
|
def check_msg_msg_type(msg)
|
34
69
|
check_msg_type(msg_msg_type(msg))
|
35
70
|
end
|
36
71
|
|
72
|
+
# Validates whether whole message is valid
|
73
|
+
# from general point of view, independently of parser/sserializer.
|
74
|
+
# Currently, it just calls {#valid_msg_msg_type}.
|
75
|
+
# @param msg [String] input message.
|
37
76
|
def valid_msg(msg)
|
38
77
|
valid_msg_msg_type(msg)
|
39
78
|
end
|
40
79
|
|
80
|
+
# As {#valid_msg}, but raises exception if message is invalid.
|
81
|
+
# Currently, it just calls {#check_msg_msg_type}.
|
82
|
+
# @param msg [String] input message.
|
41
83
|
def check_msg(msg)
|
42
84
|
check_msg_msg_type(msg)
|
43
85
|
end
|
44
86
|
|
87
|
+
# Validates whether message type character in hash is valid.
|
88
|
+
# Calls {#valid_msg_type}.
|
89
|
+
# @param hash [Hash] input hash.
|
45
90
|
def valid_hash_msg_type(hash)
|
46
91
|
valid_msg_type(hash[:type])
|
47
92
|
end
|
48
93
|
|
94
|
+
# Checks whether message type character in hash is valid.
|
95
|
+
# Calls {#check_msg_type}.
|
96
|
+
# If argument is valid, it assigns the message type to internal variable.
|
97
|
+
# @param hash [Hash] input hash.
|
49
98
|
def check_hash_msg_type(hash)
|
50
|
-
|
51
|
-
check_msg_type(msg_type)
|
52
|
-
msg_type
|
99
|
+
check_msg_type(hash[:type])
|
53
100
|
end
|
54
101
|
|
102
|
+
# Returns hash keys that are related to given message type.
|
103
|
+
# Each hash with a message type should contain these keys.
|
104
|
+
# Calls {#msg_type_which_hash_keys}.
|
105
|
+
# @param msg_type [String] message type that is being parsed/serialized.
|
55
106
|
def msg_type_hash_keys(msg_type)
|
56
107
|
msg_type_which_hash_keys(msg_type, false)
|
57
108
|
end
|
58
109
|
|
110
|
+
# Returns optional hash keys that are related to given message type.
|
111
|
+
# Calls {#msg_type_which_hash_keys}.
|
112
|
+
# @param msg_type [String] message type that is being parsed/serialized.
|
59
113
|
def msg_type_hash_opt_keys(msg_type)
|
60
114
|
msg_type_which_hash_keys(msg_type, true)
|
61
115
|
end
|
62
116
|
|
117
|
+
# Validates if given hash contain valid keys,
|
118
|
+
# depending on its message type
|
119
|
+
# (according to {#msg_type_which_hash_keys}).
|
120
|
+
# Calls {#maybe_check_valid_hash_keys}.
|
121
|
+
# @param hash [Hash] input hash.
|
63
122
|
def valid_hash_keys(hash)
|
64
123
|
maybe_check_valid_hash_keys(hash, false)
|
65
124
|
end
|
66
125
|
|
126
|
+
# As {#valid_hash_keys}, but raises exception if hash is _not_ valid.
|
127
|
+
# Calls {#maybe_check_valid_hash_keys}.
|
128
|
+
# @param hash [Hash] input hash.
|
129
|
+
# @return [Hash] input hash.
|
67
130
|
def check_hash_keys(hash)
|
68
131
|
maybe_check_valid_hash_keys(hash, true)
|
69
132
|
hash
|
70
133
|
end
|
71
134
|
|
135
|
+
# Validates if values of given hash satisfies basic conditions
|
136
|
+
# for all hashes being used with messages.
|
137
|
+
# @param hash [Hash] input hash.
|
138
|
+
# @return [Boolean] +true+ if hash values are valid
|
139
|
+
# (from general point of view).
|
72
140
|
def valid_hash_values(hash)
|
73
141
|
hash.none? { |_, v| v.nil? }
|
74
142
|
end
|
75
143
|
|
144
|
+
# As {#valid_hash_values}, but raises exception
|
145
|
+
# if hash values are _not_ valid.
|
146
|
+
# @param hash [Hash] input hash.
|
147
|
+
# @return [Hash] input hash.
|
148
|
+
# @raise [InvalidMessageBody] if hash values are _not_ valid.
|
76
149
|
def check_hash_values(hash)
|
77
150
|
return hash if valid_hash_values(hash)
|
78
151
|
hash = hash.dup
|
@@ -81,12 +154,24 @@ module MaxCube
|
|
81
154
|
.new(@msg_type, "invalid hash values: #{hash}")
|
82
155
|
end
|
83
156
|
|
157
|
+
# Validates if given hash satisfies basic conditions
|
158
|
+
# for all hashes being used with messages.
|
159
|
+
# Calls {#valid_hash_msg_type},
|
160
|
+
# {#valid_hash_keys} and {#valid_hash_values}.
|
161
|
+
# @param hash [Hash] input hash.
|
162
|
+
# @return [Boolean] +true+ if hash is valid
|
163
|
+
# (from general point of view).
|
84
164
|
def valid_hash(hash)
|
85
165
|
valid_hash_msg_type(hash) &&
|
86
166
|
valid_hash_keys(hash) &&
|
87
167
|
valid_hash_values(hash)
|
88
168
|
end
|
89
169
|
|
170
|
+
# As {#valid_hash}, but raises exception if hash is _not_ valid.
|
171
|
+
# Calls {#check_hash_msg_type},
|
172
|
+
# {#check_hash_keys} and {#check_hash_values}.
|
173
|
+
# @param hash [Hash] input hash.
|
174
|
+
# @return [Hash] input hash.
|
90
175
|
def check_hash(hash)
|
91
176
|
check_hash_msg_type(hash)
|
92
177
|
check_hash_keys(hash)
|
@@ -96,10 +181,18 @@ module MaxCube
|
|
96
181
|
|
97
182
|
private
|
98
183
|
|
184
|
+
# Gets +MSG_TYPES+ constant depending on object's end-class.
|
185
|
+
# @return [Array<String>] +MSG_TYPES+ constant
|
186
|
+
# depending on object's end-class.
|
99
187
|
def msg_types
|
100
188
|
self.class.const_get('MSG_TYPES')
|
101
189
|
end
|
102
190
|
|
191
|
+
# Helper method that is called by {#valid_msg_type} or {#check_msg_type}.
|
192
|
+
# It provides validation or check depending on input flag.
|
193
|
+
# If argument is valid, it assigns the message type to internal variable.
|
194
|
+
# @param msg_type [String] input message type character.
|
195
|
+
# @param check [Boolean] whether to check (raise exception on failure).
|
103
196
|
def maybe_check_valid_msg_type(msg_type, check)
|
104
197
|
valid = msg_type&.length == 1 &&
|
105
198
|
msg_types.include?(msg_type)
|
@@ -108,6 +201,16 @@ module MaxCube
|
|
108
201
|
raise InvalidMessageType.new(@msg_type) unless valid
|
109
202
|
end
|
110
203
|
|
204
|
+
# Checks whether given +args+
|
205
|
+
# satisfy lengths specified in input +lengths+.
|
206
|
+
# Missing positions in +lengths+ means
|
207
|
+
# that no requirement is demanded at that index.
|
208
|
+
# @param lengths [Array<Integer>] required lenghts of arguments.
|
209
|
+
# @param args [Array<#length>] arguments to be validated.
|
210
|
+
# @return [Boolean] +true+ if lengths of 'all' +args+
|
211
|
+
# fits to input +lengths+;
|
212
|
+
# +false+ otherwise, or if any +arg+ is +nil+,
|
213
|
+
# or if size of +lengths+ is higher than number of +args+.
|
111
214
|
def valid_msg_part_lengths(lengths, *args)
|
112
215
|
return false if args.any?(&:nil?) ||
|
113
216
|
args.length < lengths.length
|
@@ -116,19 +219,42 @@ module MaxCube
|
|
116
219
|
end
|
117
220
|
end
|
118
221
|
|
222
|
+
# As {#valid_msg_part_lengths}, but raises exception on failure.
|
223
|
+
# @return [Array] +args+ if +lengths+ are satisfied.
|
224
|
+
# @raise [InvalidMessageBody] if +lengths+ are _not_ satisfied.
|
119
225
|
def check_msg_part_lengths(lengths, *args)
|
120
|
-
return if valid_msg_part_lengths(lengths, *args)
|
226
|
+
return args if valid_msg_part_lengths(lengths, *args)
|
121
227
|
raise InvalidMessageBody
|
122
228
|
.new(@msg_type,
|
123
229
|
"invalid lengths of message parts #{args}" \
|
124
230
|
" (lengths should be: #{lengths})")
|
125
231
|
end
|
126
232
|
|
233
|
+
# Helper method that is called
|
234
|
+
# by {#msg_type_hash_keys} or {#msg_type_hash_opt_keys}.
|
235
|
+
# It accesses +KEYS+ or +OPT_KEYS+ (depending on input flag)
|
236
|
+
# from object's concrete end-class.
|
237
|
+
# @param msg_type [String] message type that is being parsed/serialized.
|
238
|
+
# @param optional [Boolean] whether to return optional or mandatory keys.
|
239
|
+
# @return [Array<Symbol>] mandatory or optional hash keys,
|
240
|
+
# depending on +optional+, related to message type.
|
241
|
+
# If constant is not found, empty array is returned.
|
127
242
|
def msg_type_which_hash_keys(msg_type, optional = false)
|
128
243
|
str = "Message#{msg_type.upcase}::" + (optional ? 'OPT_KEYS' : 'KEYS')
|
129
244
|
self.class.const_defined?(str) ? self.class.const_get(str) : []
|
130
245
|
end
|
131
246
|
|
247
|
+
# Helper method that is called
|
248
|
+
# by {#valid_hash_keys} or {#check_hash_keys}.
|
249
|
+
# It validates/checks whether given hash contain
|
250
|
+
# all mandatory keys ({#msg_type_hash_keys})
|
251
|
+
# and not other than optional keys ({#msg_type_hash_opt_keys}).
|
252
|
+
# @param hash [Hash] input hash.
|
253
|
+
# @param check [Boolean] whether to check (raise exception on failure).
|
254
|
+
# @return [Boolean] +true+ or +false+ for valid/invalid hash keys
|
255
|
+
# if +check+ is +false+.
|
256
|
+
# @raise [InvalidMessageBody] if +check+ is +true+
|
257
|
+
# and hash keys are invalid.
|
132
258
|
def maybe_check_valid_hash_keys(hash, check)
|
133
259
|
keys = msg_type_hash_keys(@msg_type).dup
|
134
260
|
opt_keys = msg_type_hash_opt_keys(@msg_type)
|
@@ -142,10 +268,18 @@ module MaxCube
|
|
142
268
|
"(should be: #{keys})")
|
143
269
|
end
|
144
270
|
|
271
|
+
# Encodes input binary data to only printable characters
|
272
|
+
# using Base64#strict_encode64.
|
273
|
+
# @param data [String] input raw data string.
|
274
|
+
# @return [String] Base64-encoded string.
|
145
275
|
def encode(data)
|
146
276
|
Base64.strict_encode64(data)
|
147
277
|
end
|
148
278
|
|
279
|
+
# Decodes input data with only printable characters
|
280
|
+
# to binary data using Base64#decode64.
|
281
|
+
# @param data [String] input Base64-encoded string.
|
282
|
+
# @return [String] raw data string.
|
149
283
|
def decode(data)
|
150
284
|
Base64.decode64(data)
|
151
285
|
end
|