go-mqtt 0.0.1

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/lib/mqtt/proxy.rb ADDED
@@ -0,0 +1,115 @@
1
+ module MQTT
2
+ # Class for implementing a proxy to filter/mangle MQTT packets.
3
+ class Proxy
4
+ # Address to bind listening socket to
5
+ attr_reader :local_host
6
+
7
+ # Port to bind listening socket to
8
+ attr_reader :local_port
9
+
10
+ # Address of upstream server to send packets upstream to
11
+ attr_reader :server_host
12
+
13
+ # Port of upstream server to send packets upstream to.
14
+ attr_reader :server_port
15
+
16
+ # Time in seconds before disconnecting an idle connection
17
+ attr_reader :select_timeout
18
+
19
+ # Ruby Logger object to send informational messages to
20
+ attr_reader :logger
21
+
22
+ # A filter Proc for packets coming from the client (to the server).
23
+ attr_writer :client_filter
24
+
25
+ # A filter Proc for packets coming from the server (to the client).
26
+ attr_writer :server_filter
27
+
28
+ # Create a new MQTT Proxy instance.
29
+ #
30
+ # Possible argument keys:
31
+ #
32
+ # :local_host Address to bind listening socket to.
33
+ # :local_port Port to bind listening socket to.
34
+ # :server_host Address of upstream server to send packets upstream to.
35
+ # :server_port Port of upstream server to send packets upstream to.
36
+ # :select_timeout Time in seconds before disconnecting a connection.
37
+ # :logger Ruby Logger object to send informational messages to.
38
+ #
39
+ # NOTE: be careful not to connect to yourself!
40
+ def initialize(args = {})
41
+ @local_host = args[:local_host] || '0.0.0.0'
42
+ @local_port = args[:local_port] || MQTT::DEFAULT_PORT
43
+ @server_host = args[:server_host]
44
+ @server_port = args[:server_port] || 18_830
45
+ @select_timeout = args[:select_timeout] || 60
46
+
47
+ # Setup a logger
48
+ @logger = args[:logger]
49
+ if @logger.nil?
50
+ @logger = Logger.new(STDOUT)
51
+ @logger.level = Logger::INFO
52
+ end
53
+
54
+ # Default is not to have any filters
55
+ @client_filter = nil
56
+ @server_filter = nil
57
+
58
+ # Create TCP server socket
59
+ @server = TCPServer.open(@local_host, @local_port)
60
+ @logger.info "MQTT::Proxy listening on #{@local_host}:#{@local_port}"
61
+ end
62
+
63
+ # Start accepting connections and processing packets.
64
+ def run
65
+ loop do
66
+ # Wait for a client to connect and then create a thread for it
67
+ Thread.new(@server.accept) do |client_socket|
68
+ logger.info "Accepted client: #{client_socket.peeraddr.join(':')}"
69
+ server_socket = TCPSocket.new(@server_host, @server_port)
70
+ begin
71
+ process_packets(client_socket, server_socket)
72
+ rescue Exception => exp
73
+ logger.error exp.to_s
74
+ end
75
+ logger.info "Disconnected: #{client_socket.peeraddr.join(':')}"
76
+ server_socket.close
77
+ client_socket.close
78
+ end
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ def process_packets(client_socket, server_socket)
85
+ loop do
86
+ # Wait for some data on either socket
87
+ selected = IO.select([client_socket, server_socket], nil, nil, @select_timeout)
88
+
89
+ # Timeout
90
+ raise 'Timeout in select' if selected.nil?
91
+
92
+ # Iterate through each of the sockets with data to read
93
+ if selected[0].include?(client_socket)
94
+ packet = MQTT::Packet.read(client_socket)
95
+ logger.debug "client -> <#{packet.type_name}>"
96
+ packet = @client_filter.call(packet) unless @client_filter.nil?
97
+ unless packet.nil?
98
+ server_socket.write(packet)
99
+ logger.debug "<#{packet.type_name}> -> server"
100
+ end
101
+ elsif selected[0].include?(server_socket)
102
+ packet = MQTT::Packet.read(server_socket)
103
+ logger.debug "server -> <#{packet.type_name}>"
104
+ packet = @server_filter.call(packet) unless @server_filter.nil?
105
+ unless packet.nil?
106
+ client_socket.write(packet)
107
+ logger.debug "<#{packet.type_name}> -> client"
108
+ end
109
+ else
110
+ logger.error 'Problem with select: socket is neither server or client'
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end