Class: KineticRuby::Server

Inherits:
Object
  • Object
show all
Defined in:
lib/kinetic_server.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(port = DEFAULT_KINETIC_PORT, log_level = Logger::LOG_LEVEL_INFO) ⇒ Server

Returns a new instance of Server.



147
148
149
150
151
152
153
154
155
# File 'lib/kinetic_server.rb', line 147

def initialize(port = DEFAULT_KINETIC_PORT, log_level=Logger::LOG_LEVEL_INFO)
  @host = 'localhost'
  @port ||= DEFAULT_KINETIC_PORT
  raise "Invalid server port specified: #{port}" if !@port || @port < 0
  @logger = Logger.new(log_level)
  @logger.prefix = 'KineticSim: '
  @worker = nil
  @logger.log 'Kinetic device test server started!'
end

Instance Attribute Details

#connectedObject (readonly)

Returns the value of attribute connected.



145
146
147
# File 'lib/kinetic_server.rb', line 145

def connected
  @connected
end

#hostObject (readonly)

Returns the value of attribute host.



145
146
147
# File 'lib/kinetic_server.rb', line 145

def host
  @host
end

#portObject (readonly)

Returns the value of attribute port.



145
146
147
# File 'lib/kinetic_server.rb', line 145

def port
  @port
end

Instance Method Details

#report_buffer(buf) ⇒ Object



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/kinetic_server.rb', line 157

def report_buffer(buf)
  bytes = buf.bytes
  row_len = 16
  @logger.log "Raw Data (length=#{buf.count}):"
  while !bytes.empty?
    row_len = bytes.count >= row_len ? row_len : bytes.count
    @logger.log "  row_len: #{row_len}"
    row = bytes.slice!(row_len)
    @logger.log "  row: #{row.inspect}"
    msg = "  "
    row.each do |b|
      msg += sprintf("0x%02X", b)
    end
    @logger.log msg
  end
  report
end

#shutdownObject



269
270
271
272
273
274
275
276
277
278
# File 'lib/kinetic_server.rb', line 269

def shutdown
  return if @worker.nil?
  @logger.log 'shutting down...'
  if @worker
    @worker.exit
    @worker.join 2.0
    @worker = nil
  end
  @logger.log 'shutdown complete'
end

#startObject



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
# File 'lib/kinetic_server.rb', line 175

def start
  return unless @worker.nil?

  # Setup handler for signaled shutdown (via ctrl+c)
  trap("INT") do
    @logger.log "INT triggered shutdown"
    shutdown
  end

  # Create background thread for processing client requests
  @worker = Thread.new do
    
    # Service client connections (sequentially)
    ClientProvider.each_client(@host, @port, @logger) do |client|

      request = ''
      pdu = nil
      connected = true
      raw_proto = []

      # Process requests while client available
      while connected && (data = client.receive)
        if data.nil? || data.empty?
          connected = false
          break
        end

        # Append received data to request for processing
        request += data

        # Incrementally parse PDU until complete
        if PDU.valid_header? request
          @logger.log 'Receiving a PDU...'
          raw_pdu = request.bytes.map{|b| sprintf("%02X", b)}.join('')
          @logger.log "  request[#{request.length}]: #{raw_pdu}"
          pdu ||= PDU.new(@logger)
          if pdu.parse(request)
            @logger.log "Received PDU successfully!"
          else
            @logger.log "Waiting on remainder of PDU..."
          end

        # Otherwise, handle custom test requests
        elsif pdu.nil?
          @logger.logv "Checking for custom request: '#{request}'"
          
          # Handle raw protobuf.. for tests
          if !raw_proto.empty? || request.match(/^\n/)
            @logger.log "Appears to be a standalone protobuf incoming..."
            raw_proto ||= []
            raw_proto += request.bytes
            @logger.log "  protobuf: (#{raw_proto.length} bytes)"
            request = ''
          
          # Handle request for read(num_bytes), and respond with num_bytes of dummy data
          elsif request_match = request.match(/^read\((\d+)\)/)
            len = request_match[1].to_i
            response = 'G'*len
            @logger.log "Responding to 'read(#{len})' w/ '#{response}'"
            client.send response
            request = ''
          
          # Handle request for readProto(), and respond with canned Kinetic protobuf
          elsif request =~ /^readProto()/
            response = Proto.new(@logger).test_encode
            @logger.log "Responding to 'read(#{len})' w/ dummy protobuf (#{response.length} bytes)"
            client.send response
            request = ''
          
          # Report not enough data yet to make a call...
          elsif request.match(/^read/) && data.length < 7
            @logger.log "no command match for request: '#{request}' (...yet)";

          # Otherwise, report unknown request received!
          else
            @logger.log "Unknown request! Aborting..."
            request = ''
            connected = false
          end
        end

      end #request service loop pass

      @logger.log "Disconnecting from client..."

    end #client connection

    @logger.log "Client listener shutting down..."
  end #worker thread

  @logger.log "Listener shutdown successfully!"

end