lib/ardtweeno/dispatcher.rb in ardtweeno-0.2.5 vs lib/ardtweeno/dispatcher.rb in ardtweeno-0.3.0
- old
+ new
@@ -1,10 +1,10 @@
####################################################################################################
-# @author David Kirwan <davidkirwanirl@gmail.com>
-# @description Dispatcher system for the Ardtweeno Mesh Network
+# @author David Kirwan https://github.com/davidkirwan/ardtweeno
+# @description Ardtweeno dispatcher system
#
-# @date 30-03-2013
+# @date 14-06-2013
####################################################################################################
# Imports
require 'rubygems'
require 'serialport'
@@ -22,11 +22,11 @@
#
class Dispatcher
include Singleton
- attr_accessor :nodeManager, :parser, :confdata, :nodedata, :db, :auth, :coll, :log, :running
+ attr_accessor :nodeManager, :parser, :confdata, :nodedata, :db, :auth, :coll, :log, :running, :posts
##
# Constructor for the Ardtweeno::Dispatcher class
#
@@ -41,11 +41,13 @@
@log.level = Ardtweeno.options[:level] ||= Logger::DEBUG
@running = false
@parser = nil
- unless Ardtweeno.options[:test] ||= false
+ if Ardtweeno.options[:test]
+ @confdata = Ardtweeno.options[:confdata]
+ else
@log.debug "Calling bootstrap()"
bootstrap()
end
end
@@ -199,32 +201,49 @@
##
# Ardtweeno::Dispatcher#addWatch method to add a watch on a node
#
# * *Args* :
- # - ++ -> params Hash
+ # - ++ -> params Hash containing: {:node String name of the node,
+ # :notifyURL String URL to post a push notification to
+ # :method String either GET or PUSH to indicate HTTP methods
+ # :timeout Fixnum the timeout in seconds between push notifications }
# * *Returns* :
# -
# * *Raises* :
- #
+ # Ardtweeno::InvalidWatch if params do not adhere to specification
+ # Ardtweeno::AlreadyWatched if node is already on a watchlist
+ #
def addWatch(params)
begin
apitimer = Time.now
- if params.has_key? "node" and
- params.has_key? "notifyURL" and
- params.has_key? "method" and
- params.has_key? "timeout"
-
+ if params.has_key? :node and
+ params.has_key? :notifyURL and
+ params.has_key? :method and
+ params.has_key? :timeout
+
+
+ unless params[:method] == "GET" or params[:method] == "POST"
+ raise Ardtweeno::InvalidWatch, "Invalid Parameters"
+ end
+
+ unless params[:timeout] >= 0
+ raise Ardtweeno::InvalidWatch, "Invalid Parameters"
+ end
+
@log.debug "Watch API call seems valid, passing to NodeManager"
@nodeManager.addWatch(params)
else
- raise Exception, "Invalid Parameters"
+ raise Ardtweeno::InvalidWatch, "Invalid Parameters"
end
@log.debug "Duration: #{Time.now - apitimer} seconds"
- rescue Exception => e
+
+ rescue Ardtweeno::AlreadyWatched => e
+ raise e, "This node already has a watch associated with it"
+ rescue Ardtweeno::InvalidWatch => e
raise e
end
end
@@ -241,13 +260,15 @@
begin
@log.debug "Payload recieved, processing.."
payload = JSON.parse(origionalPayload)
- if payload["data"].nil? then raise Ardtweeno::InvalidData, "Packet missing data" end
+ if payload["data"].nil? then raise Ardtweeno::InvalidData, "Packet missing data"; end
@log.debug "Payload contains a :data key, continuing.."
- if payload["key"].nil? then raise Ardtweeno::InvalidData, "Packet missing key" end
+ if payload["data"].empty? then raise Ardtweeno::InvalidData, "Packet data empty"; end
+ @log.debug "Payload data is not empty, continuing.."
+ if payload["key"].nil? then raise Ardtweeno::InvalidData, "Packet missing key"; end
@log.debug "Payload contains a :key key, continuing.."
@log.debug "Searching for the corresponding Ardtweeno::Node in the system.."
node = @nodeManager.search({:key=>payload["key"]})
@log.debug "This packet belongs to a valid node.."
@@ -299,16 +320,34 @@
dev = @confdata["dev"]
speed = @confdata["speed"]
key = @confdata["adminkey"]
- cmd = "/bin/bash -c '/usr/local/bin/node resources/serialparser.js #{dev} #{speed} #{key}'"
-
- @parser = fork do
- Signal.trap("SIGTERM") { `killall node`; exit }
- `#{cmd}`
+ begin
+ serialparser = Ardtweeno::SerialParser.new(dev, speed, 100, {:log=>@log, :level=>@log.level})
+ rescue Exception => e
+ @log.fatal "Ardtweeno::Dispatcher#start Fatal Error constructing the SerialParser:"
+ @running = false
+ return false
end
+
+ @parser = Thread.new do
+
+ begin
+ loop do
+ serialparser.listen(key)
+ end
+
+ rescue Exception => e
+ @log.debug e.message
+ serialparser.close
+ @running = false
+ @parser.kill
+ @parser = nil
+
+ end
+ end
@log.debug "Dispatcher#start has been called starting the system up.."
@running = true
return true
@@ -319,11 +358,12 @@
@running = true
return true
end
end
rescue Exception => e
- `killall node`
+ @parser.kill
+ @parser = nil
raise e
end
@log.debug "The SerialParser system is already running.. ignoring.."
return false
@@ -344,28 +384,27 @@
begin
unless Ardtweeno.options[:test]
unless @running == false
- @log.debug "Dispatcher#stop has been called shutting system down.."
-
- Process.kill("SIGTERM", @parser)
- Process.wait
+ @parser.kill
@parser = nil
@running = false
+ @log.debug "Dispatcher#stop has been called shutting system down.."
+
return true
end
else
unless @running == false
@running = false
return true
end
end
rescue Exception => e
- `killall node`
+ @parser.kill
@parser = nil
raise e
end
@log.debug "SerialParser system is inactive.. ignoring.."
@@ -391,11 +430,62 @@
Signal.trap("SIGTERM") { exit }
`#{cmd}`
end
end
+
+ ##
+ # Ardtweeno::Dispatcher#status? returns the system status of the Ardtweeno Gateway host
+ #
+ # * *Args* :
+ # - ++ ->
+ # * *Returns* :
+ # - Hash theResponse containing: bool running, String cpuload, String memload
+ # * *Raises* :
+ #
+ def status?()
+ @log.debug "Ardtweeno::Dispatcher#status? executing"
+ begin
+ unless Ardtweeno.options[:test] ||= false
+ # Get CPU
+ maxLoad = calculateCPUCores()
+
+ # Get Avgload
+ currentLoadPercentage = calculateAvgLoad(maxLoad)
+
+ # Get MEM Usage
+ usedMem, totalMem = calculateMemLoad()
+
+
+ thecpuload = '%.2f' % currentLoadPercentage
+ thememload = '%.2f' % ((usedMem / totalMem.to_f) * 100)
+
+ theResponse = {:running=>@running,
+ :cpuload=>thecpuload,
+ :memload=>thememload}
+
+ @log.debug theResponse.inspect
+
+ return theResponse
+
+ else # When in testing mode, return blank data
+ theResponse = {:running=>@running,
+ :cpuload=>0.0,
+ :memload=>0.0}
+
+ @log.debug theResponse.inspect
+
+ return theResponse
+ end
+
+ rescue Exception => e
+
+ end
+ end
+
+
##
# Ardtweeno::Dispatcher#running? checks to see if the SerialParser is running
#
# * *Args* :
# - ++ ->
@@ -432,15 +522,64 @@
end
end
##
- # Ardtweeno::Dispatcher#config returns the configuration as read in from the DB
+ # Ardtweeno::Dispatcher#getPostsURI returns the front page news URI ~/.ardtweeno/conf.yaml
#
# * *Args* :
# - ++ ->
# * *Returns* :
+ # - String which makes up the news post URI ie "/randomhash/create/post"
+ # * *Raises* :
+ #
+ def getPostsURI()
+ return @confdata["newsURI"]
+ end
+
+
+
+ ##
+ # Ardtweeno::Dispatcher#getPosts returns the front page news posts loaded from ~/.ardtweeno/posts.yaml
+ #
+ # * *Args* :
+ # - ++ ->
+ # * *Returns* :
+ # - Array of Hash containing post data
+ # * *Raises* :
+ #
+ def getPosts()
+ unless @posts.nil? or @posts.empty?
+ return @posts["posts"]
+ else
+ return Array.new
+ end
+ end
+
+
+ ##
+ # Ardtweeno::Dispatcher#savePosts saves a post to ~/.ardtweeno/posts.yaml
+ #
+ # * *Args* :
+ # - ++ ->
+ # * *Returns* :
+ # -
+ # * *Raises* :
+ #
+ def savePosts(newPosts)
+ @posts["posts"] = newPosts
+ Ardtweeno::ConfigReader.save(@posts, Ardtweeno::POSTPATH)
+ end
+
+
+ ##
+ # Ardtweeno::Dispatcher#config returns the configuration as read in from the confg.yaml configuration
+ # file
+ #
+ # * *Args* :
+ # - ++ ->
+ # * *Returns* :
# - @confdata
# * *Raises* :
#
def config()
return @confdata
@@ -454,19 +593,19 @@
# - ++ ->
# * *Returns* :
# -
# * *Raises* :
#
- private
- def bootstrap()
+ def bootstrap
# Read in the configuration files
begin
@log.debug "Reading in the configuration files"
@confdata = Ardtweeno::ConfigReader.load(Ardtweeno::DBPATH)
@nodedata = Ardtweeno::ConfigReader.load(Ardtweeno::NODEPATH)
+ @posts = Ardtweeno::ConfigReader.load(Ardtweeno::POSTPATH)
rescue Exception => e
@log.fatal e.message
@log.fatal e.backtrace
raise e
@@ -498,11 +637,11 @@
@nodeManager = Ardtweeno::NodeManager.new(nmoptions)
rescue Exception => e
@log.debug e.message
@log.debug e.backtrace
raise e
- end
+ end
# Create the MongoDB connector instance
begin
@log.debug @confdata["db"]["dbHost"]
@@ -530,9 +669,92 @@
raise e
end
end # End of the bootstrap()
+
+
+ def calculateMemLoad()
+ begin
+ memhash = Hash.new
+ meminfo = File.read('/proc/meminfo')
+ meminfo.each_line do |i|
+ key, val = i.split(':')
+ if val.include?('kB') then val = val.gsub(/\s+kB/, ''); end
+ memhash["#{key}"] = val.strip
+ end
+
+ totalMem = memhash["MemTotal"].to_i
+ freeMem = memhash["MemFree"].to_i + memhash["Buffers"].to_i + memhash["Cached"].to_i
+ usedMem = totalMem - freeMem
+
+ @log.debug "Total Memory: #{totalMem} (100%)"
+ @log.debug "Used Memory: #{usedMem} (#{'%.2f' % ((usedMem / totalMem.to_f) * 100)}%)"
+ @log.debug "Free Memory: #{freeMem} (#{'%.2f' % ((freeMem / totalMem.to_f) * 100)}%)"
+
+ return usedMem, totalMem
+
+ rescue Exception => e
+ @log.debug "Some issue accessing /proc/meminfo"
+ usedMem, totalMem = 0, 0
+
+ return usedMem, totalMem
+ end
+ end
+ def calculateAvgLoad(maxLoad)
+ begin
+ loadavg = File.read('/proc/loadavg')
+ loads = loadavg.scan(/\d+.\d+/)
+ onemin = loads[0]
+ fivemin = loads[1]
+ fifteenmin = loads[2]
+
+ @log.debug "LoadAvg are as follows: 1min #{onemin}, 5min #{fivemin}, 15min #{fifteenmin}"
+
+ loadval = (onemin.to_f / maxLoad)
+ currentLoadPercentage = loadval * 100
+
+ @log.debug "Currently running at #{'%.2f' % currentLoadPercentage}% of max load"
+
+ return currentLoadPercentage
+
+ rescue Exception => e
+ @log.debug "Some issue accessing /proc/loadavg"
+ onemin, fivemin, fifteenmin = 0, 0, 0
+
+ loadval = (onemin.to_f / maxLoad)
+ currentLoadPercentage = loadval * 100
+
+ return currentLoadPercentage
+ end
+ end
+
+
+ def calculateCPUCores()
+ begin # Checking for multi-core CPU
+ cpuinfo = File.read('/proc/cpuinfo')
+ coreinfo = cpuinfo.scan(/cpu cores\s+:\s+\d+/)
+
+ tempVal = coreinfo[0]
+ numOfCores = tempVal.scan(/\d+/)[0].to_i
+ numOfThreadsPerCore = coreinfo.size / numOfCores
+ maxLoad = (numOfThreadsPerCore * numOfCores).to_f
+
+ @log.debug "Found #{numOfCores} cores with #{numOfThreadsPerCore} threads per core"
+ @log.debug "Max desirable cpu load: #{maxLoad}"
+
+ return maxLoad
+
+ rescue Exception => e
+ @log.debug "Unable to find cpu core info in /proc/cpuinfo, assuming system has a single core"
+ maxLoad = 1.0
+
+ return maxLoad
+ end
+ end
+
+
+ private :bootstrap, :calculateMemLoad, :calculateAvgLoad, :calculateCPUCores
end
end