-
Notifications
You must be signed in to change notification settings - Fork 2
Devices connecting to engine
Stephen von Takach edited this page Dec 12, 2016
·
1 revision
Sometimes an external service might want to push information to Engine. Whilst this isn't explicitly supported, it is quite easy to implement.
A good example of a Web Hook protocol is the Johnson Controls - P2000 Remote Monitoring module (where the swipe card security system sends events as staff swipe their cards).
- TODO:: Example of consuming Email
class Module::Code
include ::Orchestrator::Constants
def on_load
on_update
end
def on_update
# Ensure server is re-started on update (maybe the port has changed etc)
on_unload
# Configure server - we allow the port to be defined in settings here.
port = setting(:port) || 38000
# We want to use evented IO (don't want to block the thread)
# Bind Address, bind port, connection class, arguments
@server = UV.start_server '0.0.0.0', port, SignalServer, logger, thread, self
logger.info "server started"
end
def on_unload
# It is up to you to manually stop any servers you start
if @server
@server.close
@server = nil
logger.info "server stopped"
end
end
# Process data as it is provided by the connections
# Pass back any data you want to be returned - or make information
# accessible from the @driver object in the connection class.
def parse(request)
self[:status] = ::JSON.parse(request)
return {result: 'success'}
end
# The connection 'class' that will handle new connections to the server:
# (It is converted to a class and decorated with helper functions)
module SignalServer
# I would recommend passing in at least logger and driver
# driver is a reference to your module (passed in as self above)
def post_init(logger, thread, driver)
@logger = logger
@thread = thread
@driver = driver
@buffer = ::UV::BufferedTokenizer.new({
indicator: "\x02",
delimiter: "\x03"
})
end
attr_reader :logger, :thread
# This function is called once the connection is initialised
# Transport is the raw TCP connection object and this is the place to
# grab the remote ends IP address (could whitelist IPs for security)
def on_connect(transport)
ip, port = transport.peername
logger.info "Connection from: #{ip}:#{port}"
end
# Any data the remote sends us comes in here.
# Buffering needs to happen at the connection level. Not within the module.
# It's also always good to have detailed error messages too
def on_read(data, *args)
begin
@buffer.extract(data).each do |request|
logger.debug { "remote sent: #{request}" }
begin
# This is where we pass the request back to the module
result = @driver.parse request
# We can optionally respond to the remote device using write
write "\x02#{result.to_json}\x03"
rescue => e
logger.print_error(e, "error parsing request: #{request.inspect} in on_read callback")
end
end
rescue => e
logger.print_error(e, "error extracting data: #{data.inspect} in on_read callback")
end
end
end
end