orion6_rep 0.2.6
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 +7 -0
- data/lib/orion6_rep/change_ip.rb +54 -0
- data/lib/orion6_rep/clock_time/get.rb +98 -0
- data/lib/orion6_rep/clock_time/set.rb +96 -0
- data/lib/orion6_rep/clock_time.rb +31 -0
- data/lib/orion6_rep/command.rb +176 -0
- data/lib/orion6_rep/communication.rb +89 -0
- data/lib/orion6_rep/detect_reps.rb +86 -0
- data/lib/orion6_rep/employee_get.rb +112 -0
- data/lib/orion6_rep/employee_quantity_get.rb +81 -0
- data/lib/orion6_rep/employee_set.rb +104 -0
- data/lib/orion6_rep/employer_get.rb +84 -0
- data/lib/orion6_rep/employer_set.rb +90 -0
- data/lib/orion6_rep/get_serial_number.rb +64 -0
- data/lib/orion6_rep/interface.rb +55 -0
- data/lib/orion6_rep/mockup.rb +118 -0
- data/lib/orion6_rep/multi_message_command.rb +113 -0
- data/lib/orion6_rep/record_id_get.rb +79 -0
- data/lib/orion6_rep/records_get.rb +89 -0
- data/lib/orion6_rep/version.rb +3 -0
- data/lib/orion6_rep.rb +199 -0
- data/test/afd_file +11 -0
- data/test/external/detect_reps_test.rb +28 -0
- data/test/external/employee_test.rb +100 -0
- data/test/external/employer_test.rb +57 -0
- data/test/external/get_serial_test.rb +31 -0
- data/test/external/record_get_test.rb +32 -0
- data/test/external/time_test.rb +84 -0
- data/test/test_helper.rb +25 -0
- data/test/time_clock.rb +13 -0
- data/test/unit/mockup_test.rb +154 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5395b094d49fd9ba05205ee1601a2423a0404de0
|
4
|
+
data.tar.gz: 8bd4bc765a14e7bc65b8d36661c9b79a56df12d1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7c1e613984f180b00ac2e3560efe239e87effa0e3bccf04c22beb5d63053bf285caa6f01f76e1fbd48f68e82dd03606b6e5d3708100bccefa1eca6e2fdbb9ea9
|
7
|
+
data.tar.gz: cb38f0d09d6e2eb820515b96dc5a071ef4ba0bef04201217ba0da8caf51c724f2a065349ca0b827ce7df0918d037a9dd1e34fc0961cad00e39ac305ed8c6156a
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
3
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
4
|
+
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License as
|
7
|
+
# published by the Free Software Foundation, either version 3 of the
|
8
|
+
# License, or (at your option) any later version.
|
9
|
+
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
19
|
+
# e-mail: contato@ossystems.com.br
|
20
|
+
|
21
|
+
require 'socket'
|
22
|
+
require 'ipaddr'
|
23
|
+
require 'orion6_rep/interface'
|
24
|
+
|
25
|
+
module Orion6Rep
|
26
|
+
class ChangeIp
|
27
|
+
UDP_PORT = 65535
|
28
|
+
|
29
|
+
def initialize(interface, new_ip, rep_data)
|
30
|
+
@broadcast_address = Orion6Rep::Interface.broadcast_address(interface)
|
31
|
+
raise "Network interface '#{interface}' not found or doesn't have a broadcast address" if @broadcast_address.nil?
|
32
|
+
|
33
|
+
@new_ip = IPAddr.new(new_ip)
|
34
|
+
# TODO: find what the REP data actually is
|
35
|
+
@rep_data = rep_data
|
36
|
+
@payload = prepare_payload_data
|
37
|
+
@socket = UDPSocket.new
|
38
|
+
@socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
|
39
|
+
end
|
40
|
+
|
41
|
+
def execute
|
42
|
+
@socket.send(@payload, 0, @broadcast_address, UDP_PORT)
|
43
|
+
responses = IO.select([@socket], nil, nil, 1)
|
44
|
+
raw_data, socket_data = responses.first.first.recvfrom(1)
|
45
|
+
rep_current_ip = IPAddr.new(socket_data.last)
|
46
|
+
return (rep_current_ip == @new_ip ? true : execute)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def prepare_payload_data
|
51
|
+
@rep_data + "//" + @new_ip.to_s
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
3
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
4
|
+
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License as
|
7
|
+
# published by the Free Software Foundation, either version 3 of the
|
8
|
+
# License, or (at your option) any later version.
|
9
|
+
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
19
|
+
# e-mail: contato@ossystems.com.br
|
20
|
+
|
21
|
+
require "orion6_rep/clock_time"
|
22
|
+
|
23
|
+
module Orion6Rep
|
24
|
+
class ClockTime::Get < ClockTime
|
25
|
+
def initialize(equipment_number, host_address, tcp_port = 3000)
|
26
|
+
@equipment_number = equipment_number
|
27
|
+
@host_address = host_address
|
28
|
+
@tcp_port = tcp_port
|
29
|
+
@reponse_size = 12
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
GET_TIME_COMMAND = 146
|
34
|
+
GET_TIME_FIELD_QUANTITY = 0
|
35
|
+
|
36
|
+
def get_command
|
37
|
+
GET_TIME_COMMAND
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_field_quantity
|
41
|
+
GET_TIME_FIELD_QUANTITY
|
42
|
+
end
|
43
|
+
|
44
|
+
def generate_command_data
|
45
|
+
[]
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_data_from_response(payload)
|
49
|
+
# the time comes in a array of unsigned integers, using the following
|
50
|
+
# format. The purpose of the last byte is unknown, but it is probably
|
51
|
+
# some form of data check.
|
52
|
+
#
|
53
|
+
# Example:
|
54
|
+
# | current time | DST Start | DST End |
|
55
|
+
# [yy, mm, dd, hh, mm, yy, mm, dd, yy, mm, dd]
|
56
|
+
# [11, 1, 21, 15, 17, 10, 10, 17, 11, 2, 20]
|
57
|
+
#
|
58
|
+
# These would be:
|
59
|
+
# - Current Time: 21/01/2011 15:17
|
60
|
+
# - DST Start: 17/10/2010
|
61
|
+
# - DST Start: 20/02/2011
|
62
|
+
|
63
|
+
time_payload = payload.unpack("C5")
|
64
|
+
dst_start_payload = payload[5..-1].unpack("C3")
|
65
|
+
dst_end_payload = payload[8..-1].unpack("C3")
|
66
|
+
|
67
|
+
time = parse_time(time_payload)
|
68
|
+
|
69
|
+
isDstOn = dst_start_payload.any?{|d| d > 0}
|
70
|
+
|
71
|
+
if isDstOn
|
72
|
+
start_dst = parse_date(dst_start_payload)
|
73
|
+
end_dst = parse_date(dst_end_payload)
|
74
|
+
end
|
75
|
+
[time, start_dst, end_dst]
|
76
|
+
end
|
77
|
+
|
78
|
+
def parse_date(date_array)
|
79
|
+
year = defineCentury(date_array[0].ord)
|
80
|
+
month = date_array[1].ord
|
81
|
+
day = date_array[2].ord
|
82
|
+
Date.civil(year,month,day)
|
83
|
+
end
|
84
|
+
|
85
|
+
def parse_time(date_array)
|
86
|
+
year = defineCentury(date_array[0].ord)
|
87
|
+
month = date_array[1].ord
|
88
|
+
day = date_array[2].ord
|
89
|
+
hour = date_array[3].ord
|
90
|
+
minute = date_array[4].ord
|
91
|
+
Time.local(year,month,day,hour,minute)
|
92
|
+
end
|
93
|
+
|
94
|
+
def defineCentury(year)
|
95
|
+
year > 79 ? year + 1900 : year + 2000
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
2
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
3
|
+
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
18
|
+
# e-mail: contato@ossystems.com.br
|
19
|
+
|
20
|
+
require "orion6_rep/clock_time"
|
21
|
+
|
22
|
+
module Orion6Rep
|
23
|
+
class ClockTime::Set < ClockTime
|
24
|
+
def initialize(time, start_dst, end_dst, equipment_number, host_address, tcp_port = 3000)
|
25
|
+
if (start_dst.nil? and end_dst.is_a?(Date) or
|
26
|
+
start_dst.is_a?(Date) and end_dst.nil?)
|
27
|
+
raise "Both start and end DST dates must be dates or nil"
|
28
|
+
end
|
29
|
+
|
30
|
+
@time = time
|
31
|
+
@start_dst = start_dst
|
32
|
+
@end_dst = end_dst
|
33
|
+
@equipment_number = equipment_number
|
34
|
+
@host_address = host_address
|
35
|
+
@tcp_port = tcp_port
|
36
|
+
@reponse_size = 0
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
SET_TIME_COMMAND = 130
|
41
|
+
SET_TIME_FIELD_QUANTITY = 1
|
42
|
+
|
43
|
+
def get_time
|
44
|
+
@time
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_start_dst
|
48
|
+
@start_dst
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_end_dst
|
52
|
+
@end_dst
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_command
|
56
|
+
SET_TIME_COMMAND
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_field_quantity
|
60
|
+
SET_TIME_FIELD_QUANTITY
|
61
|
+
end
|
62
|
+
|
63
|
+
def generate_command_data
|
64
|
+
data = get_time_as_data_param(get_time)
|
65
|
+
|
66
|
+
start_dst = get_start_dst
|
67
|
+
end_dst = get_end_dst
|
68
|
+
if start_dst and end_dst
|
69
|
+
data += get_date_as_data_param(start_dst)
|
70
|
+
data += get_date_as_data_param(end_dst)
|
71
|
+
else
|
72
|
+
data += [0, 0, 0, 0, 0, 0] # if no DST is specified just send zeros
|
73
|
+
end
|
74
|
+
data << crc_check(data)
|
75
|
+
data
|
76
|
+
end
|
77
|
+
|
78
|
+
def get_date_as_data_param(date)
|
79
|
+
year = date.year % 100 # years must be of 2 digits in the clock
|
80
|
+
month = date.month
|
81
|
+
day = date.day
|
82
|
+
[year, month, day]
|
83
|
+
end
|
84
|
+
|
85
|
+
def get_time_as_data_param(time)
|
86
|
+
data = get_date_as_data_param(time)
|
87
|
+
data << time.hour
|
88
|
+
data << time.min
|
89
|
+
data
|
90
|
+
end
|
91
|
+
|
92
|
+
def get_data_from_response(payload)
|
93
|
+
true
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
2
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
3
|
+
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
18
|
+
# e-mail: contato@ossystems.com.br
|
19
|
+
|
20
|
+
require "orion6_rep/command"
|
21
|
+
|
22
|
+
module Orion6Rep
|
23
|
+
class ClockTime < Command
|
24
|
+
private
|
25
|
+
TIME_FIELD_SIZE = 11
|
26
|
+
|
27
|
+
def get_field_size
|
28
|
+
TIME_FIELD_SIZE
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
3
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
4
|
+
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License as
|
7
|
+
# published by the Free Software Foundation, either version 3 of the
|
8
|
+
# License, or (at your option) any later version.
|
9
|
+
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
19
|
+
# e-mail: contato@ossystems.com.br
|
20
|
+
|
21
|
+
require "orion6_rep/communication"
|
22
|
+
|
23
|
+
module Orion6Rep
|
24
|
+
class Command
|
25
|
+
def execute
|
26
|
+
# first set the header:
|
27
|
+
command_data = generate_header
|
28
|
+
|
29
|
+
# now comes the data:
|
30
|
+
command_data += generate_command_data
|
31
|
+
|
32
|
+
# now send it!
|
33
|
+
response = Communication.communicate(get_host_address, get_tcp_port, command_data, get_expected_response_size, get_timeout_time, get_max_attempts)
|
34
|
+
|
35
|
+
# check everything:
|
36
|
+
check_response_header(response)
|
37
|
+
check_response_payload(response)
|
38
|
+
|
39
|
+
# and then get and process the response payload:
|
40
|
+
payload = get_response_payload(response)
|
41
|
+
return get_data_from_response(payload)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
# TODO: find what is this constant. It's the size of something, perhaps?
|
46
|
+
UNKNOWN_CONSTANT = 113
|
47
|
+
|
48
|
+
HEADER_SIZE = 8
|
49
|
+
@reponse_size = 0
|
50
|
+
|
51
|
+
def get_timeout_time
|
52
|
+
3
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_max_attempts
|
56
|
+
3
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_expected_response_size
|
60
|
+
HEADER_SIZE + @reponse_size
|
61
|
+
end
|
62
|
+
|
63
|
+
def get_unknown_constant
|
64
|
+
UNKNOWN_CONSTANT
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_equipment_number
|
68
|
+
@equipment_number
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_host_address
|
72
|
+
@host_address
|
73
|
+
end
|
74
|
+
|
75
|
+
def get_tcp_port
|
76
|
+
@tcp_port
|
77
|
+
end
|
78
|
+
|
79
|
+
def check_response_header(response)
|
80
|
+
crc_check(response[0..6]) == response[7].ord
|
81
|
+
end
|
82
|
+
|
83
|
+
def check_response_payload(response)
|
84
|
+
crc_check(response[8..-2]) == response[-1].ord
|
85
|
+
end
|
86
|
+
|
87
|
+
def get_response_payload(response)
|
88
|
+
# TODO: other payloads might be different
|
89
|
+
response[8..-2]
|
90
|
+
end
|
91
|
+
|
92
|
+
def convert_to_integer_as_little_endian(integer_array)
|
93
|
+
self.class.convert_to_integer_as_little_endian(integer_array)
|
94
|
+
end
|
95
|
+
|
96
|
+
def convert_to_integer_as_big_endian(integer_array)
|
97
|
+
self.class.convert_to_integer_as_big_endian(integer_array)
|
98
|
+
end
|
99
|
+
|
100
|
+
def crc_size
|
101
|
+
1
|
102
|
+
end
|
103
|
+
|
104
|
+
def generate_header
|
105
|
+
field_quantity = get_field_quantity
|
106
|
+
|
107
|
+
header = [get_equipment_number^255] # TODO: find why this is needed
|
108
|
+
header << get_command
|
109
|
+
header << get_unknown_constant
|
110
|
+
header << divide_by_256(get_field_size)
|
111
|
+
header << (get_field_size & 255)
|
112
|
+
header << field_quantity
|
113
|
+
header << divide_by_256(field_quantity)
|
114
|
+
header << crc_check(header) # TODO: find why this is needed; maybe a data check?
|
115
|
+
header
|
116
|
+
end
|
117
|
+
|
118
|
+
def get_command
|
119
|
+
raise_not_implemented_error
|
120
|
+
end
|
121
|
+
|
122
|
+
def get_field_size
|
123
|
+
raise_not_implemented_error
|
124
|
+
end
|
125
|
+
|
126
|
+
def get_field_quantity
|
127
|
+
raise_not_implemented_error
|
128
|
+
end
|
129
|
+
|
130
|
+
def generate_command_data
|
131
|
+
raise_not_implemented_error
|
132
|
+
end
|
133
|
+
|
134
|
+
def get_data_from_response(payload)
|
135
|
+
raise_not_implemented_error
|
136
|
+
end
|
137
|
+
|
138
|
+
def crc_check(data)
|
139
|
+
self.class.xor(data)
|
140
|
+
end
|
141
|
+
|
142
|
+
def divide_by_256(value)
|
143
|
+
return (value >> 8 & 255)
|
144
|
+
end
|
145
|
+
|
146
|
+
class << self
|
147
|
+
def xor(data)
|
148
|
+
value = 0;
|
149
|
+
data = data.unpack("C*") if data.is_a?(String)
|
150
|
+
data.each do |integer|
|
151
|
+
value ^= integer
|
152
|
+
end
|
153
|
+
value
|
154
|
+
end
|
155
|
+
|
156
|
+
def convert_to_integer_as_little_endian(integer_array)
|
157
|
+
value = 0
|
158
|
+
integer_array.each_with_index do |byte, index|
|
159
|
+
value += (byte.to_i << 8*index)
|
160
|
+
end
|
161
|
+
value
|
162
|
+
end
|
163
|
+
|
164
|
+
# This method is the same of the little-endian one above, just with the
|
165
|
+
# input data reversed.
|
166
|
+
def convert_to_integer_as_big_endian(integer_array)
|
167
|
+
convert_to_integer_as_little_endian(integer_array.reverse)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
private
|
172
|
+
def raise_not_implemented_error
|
173
|
+
raise NotImplementedError.new "This method should be overriden by the subclass #{self.class.to_s}"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
3
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
4
|
+
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Affero General Public License as
|
7
|
+
# published by the Free Software Foundation, either version 3 of the
|
8
|
+
# License, or (at your option) any later version.
|
9
|
+
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Affero General Public License for more details.
|
14
|
+
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
19
|
+
# e-mail: contato@ossystems.com.br
|
20
|
+
|
21
|
+
require 'socket'
|
22
|
+
require 'timeout'
|
23
|
+
|
24
|
+
module Orion6Rep
|
25
|
+
module Communication
|
26
|
+
include Timeout
|
27
|
+
|
28
|
+
class << self
|
29
|
+
def communicate(host_address, port, payload, expected_response_size, timeout_time=60, max_attempts = 3)
|
30
|
+
attempt = 0
|
31
|
+
|
32
|
+
while attempt < max_attempts do
|
33
|
+
socket = nil
|
34
|
+
begin
|
35
|
+
timeout(timeout_time) {
|
36
|
+
socket = TCPSocket.open(host_address, port)
|
37
|
+
}
|
38
|
+
rescue Timeout::Error => e
|
39
|
+
socket = nil
|
40
|
+
end
|
41
|
+
|
42
|
+
received_data = nil
|
43
|
+
|
44
|
+
if socket
|
45
|
+
begin
|
46
|
+
received_data = send_receive_data(socket, payload, expected_response_size, timeout_time)
|
47
|
+
rescue Timeout::Error => e
|
48
|
+
socket.close
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
break unless received_data.nil?
|
53
|
+
attempt += 1
|
54
|
+
end
|
55
|
+
|
56
|
+
raise "Timeout error" if attempt >= max_attempts
|
57
|
+
received_data
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
def send_receive_data(socket, data_to_send, expected_response_size, timeout_time)
|
62
|
+
socket.write(data_to_send.pack("C*"))
|
63
|
+
socket.flush
|
64
|
+
data_to_receive = ""
|
65
|
+
|
66
|
+
# expected_response_size can be a Fixnum, for fixed responses sizes, or
|
67
|
+
# a proc, where the response size comes inside the response itself.
|
68
|
+
if expected_response_size.is_a?(Proc)
|
69
|
+
expected_size = expected_response_size.call(data_to_receive)
|
70
|
+
else
|
71
|
+
expected_size = expected_response_size
|
72
|
+
end
|
73
|
+
|
74
|
+
while data_to_receive.size < expected_size
|
75
|
+
bytes_to_be_read = expected_size - data_to_receive.size
|
76
|
+
bytes_to_be_read = 100 if bytes_to_be_read > 100
|
77
|
+
|
78
|
+
timeout(timeout_time) {
|
79
|
+
data_to_receive += socket.readpartial( bytes_to_be_read )
|
80
|
+
}
|
81
|
+
if expected_response_size.is_a?(Proc)
|
82
|
+
expected_size = expected_response_size.call(data_to_receive)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
data_to_receive
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# Controle de Horas - Sistema para gestão de horas trabalhadas
|
2
|
+
# Copyright (C) 2009 O.S. Systems Softwares Ltda.
|
3
|
+
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
7
|
+
# License, or (at your option) any later version.
|
8
|
+
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
# Rua Clóvis Gularte Candiota 132, Pelotas-RS, Brasil.
|
18
|
+
# e-mail: contato@ossystems.com.br
|
19
|
+
|
20
|
+
require 'socket'
|
21
|
+
require 'orion6_rep/interface'
|
22
|
+
|
23
|
+
module Orion6Rep
|
24
|
+
class DetectReps
|
25
|
+
UDP_DETECTION_PORT = 65535
|
26
|
+
UDP_DETECTION_DATA = [0x58].pack("C")
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
ifaces_names = Orion6Rep::Interface.get_active_interfaces_names
|
30
|
+
# it's useless to try to detect REPs in the localhost
|
31
|
+
ifaces_names.delete("lo")
|
32
|
+
|
33
|
+
@interfaces = {}
|
34
|
+
@responses = {}
|
35
|
+
ifaces_names.each do |name|
|
36
|
+
broadcast_address = Orion6Rep::Interface.broadcast_address(name)
|
37
|
+
@interfaces[name] = {}
|
38
|
+
@interfaces[name][:broadcast_addr] = broadcast_address
|
39
|
+
end
|
40
|
+
raise "No active network interfaces found" if @interfaces.empty?
|
41
|
+
|
42
|
+
@interfaces.each_key do |name|
|
43
|
+
socket = UDPSocket.new
|
44
|
+
socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
|
45
|
+
@interfaces[name][:socket] = socket
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def execute
|
50
|
+
@interfaces.each do |_, data|
|
51
|
+
data[:socket].send(UDP_DETECTION_DATA, 0, data[:broadcast_addr], UDP_DETECTION_PORT)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def pool
|
56
|
+
rep_responses = IO.select(get_sockets, nil, nil, 1)
|
57
|
+
|
58
|
+
unless rep_responses.nil? or rep_responses.empty?
|
59
|
+
rep_responses.first.each do |socket|
|
60
|
+
raw_data, socket_data = socket.recvfrom(33)
|
61
|
+
rep_data, tcp_port = raw_data.unpack("a18a4")
|
62
|
+
ip = socket_data.last
|
63
|
+
interface = get_assossiated_interface(socket)
|
64
|
+
@responses[interface] = {} if @responses[interface].nil?
|
65
|
+
@responses[interface][ip] = {:port => tcp_port.to_i, :rep_data => rep_data}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
return @responses
|
70
|
+
end
|
71
|
+
|
72
|
+
def stop
|
73
|
+
get_sockets.each{|socket| socket.close}
|
74
|
+
true
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
def get_sockets
|
79
|
+
@interfaces.collect{|_, data| data[:socket]}
|
80
|
+
end
|
81
|
+
|
82
|
+
def get_assossiated_interface(socket)
|
83
|
+
@interfaces.each{|interface, data| return interface if data[:socket] == socket}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|