Class: Ardtweeno::Dispatcher

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/ardtweeno/dispatcher.rb

Overview

Ardtweeno::Dispatcher system for the Ardtweeno Mesh Network

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeDispatcher

Constructor for the Ardtweeno::Dispatcher class

  • Args :

    • ++ ->

  • Returns : -

  • Raises :



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/ardtweeno/dispatcher.rb', line 55

def initialize
  @log = Ardtweeno.options[:log] ||= Logger.new(STDOUT)
  @log.level = Ardtweeno.options[:level] ||= Logger::DEBUG
  
  @running = false
  @parser = nil
  
  @statusbuffer = Ardtweeno::RingBuffer.new(90)
    
  if Ardtweeno.options[:test]
    @confdata = Ardtweeno.options[:confdata]
  else
    @log.debug "Calling bootstrap()"
    bootstrap()
  end
end

Instance Attribute Details

#authObject

Returns the value of attribute auth.



43
44
45
# File 'lib/ardtweeno/dispatcher.rb', line 43

def auth
  @auth
end

#collObject

Returns the value of attribute coll.



43
44
45
# File 'lib/ardtweeno/dispatcher.rb', line 43

def coll
  @coll
end

#confdataObject

Returns the value of attribute confdata.



43
44
45
# File 'lib/ardtweeno/dispatcher.rb', line 43

def confdata
  @confdata
end

#dbObject

Returns the value of attribute db.



43
44
45
# File 'lib/ardtweeno/dispatcher.rb', line 43

def db
  @db
end

#logObject

Returns the value of attribute log.



43
44
45
# File 'lib/ardtweeno/dispatcher.rb', line 43

def log
  @log
end

#nodedataObject

Returns the value of attribute nodedata.



43
44
45
# File 'lib/ardtweeno/dispatcher.rb', line 43

def nodedata
  @nodedata
end

#nodeManagerObject

Returns the value of attribute nodeManager.



43
44
45
# File 'lib/ardtweeno/dispatcher.rb', line 43

def nodeManager
  @nodeManager
end

#parserObject

Returns the value of attribute parser.



43
44
45
# File 'lib/ardtweeno/dispatcher.rb', line 43

def parser
  @parser
end

#postsObject

Returns the value of attribute posts.



43
44
45
# File 'lib/ardtweeno/dispatcher.rb', line 43

def posts
  @posts
end

#runningObject

Returns the value of attribute running.



43
44
45
# File 'lib/ardtweeno/dispatcher.rb', line 43

def running
  @running
end

Instance Method Details

#addWatch(params) ⇒ Object

Ardtweeno::Dispatcher#addWatch method to add a watch on a node

  • Args :

    • ++ -> 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
    


330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
# File 'lib/ardtweeno/dispatcher.rb', line 330

def addWatch(params)
  begin
    apitimer = Time.now
    
    params = params.each_with_object({}){|(k,v), h| h[k.to_sym] = v}
    
    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].to_i >= 0
        raise Ardtweeno::InvalidWatch, "Invalid Parameters"
      end
      
      @log.debug "Watch API call seems valid, passing to NodeManager"
      @nodeManager.addWatch(params)
    else
      @log.debug params.inspect
      raise Ardtweeno::InvalidWatch, "Invalid Parameters"
    end
    
    @log.debug "Duration: #{Time.now - apitimer} seconds"
    
  rescue Ardtweeno::AlreadyWatched => e
    raise e, "This node already has a watch associated with it"
  rescue Ardtweeno::InvalidWatch => e
    raise e, "Invalid Parameters"
  end
end

#authenticate?(key) ⇒ Boolean

Ardtweeno::Dispatcher#authenticate? Checks the API key provided with that in the DB

  • Args :

    • ++ -> key String

  • Returns :

    • true/false

  • Raises :

Returns:

  • (Boolean)


652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
# File 'lib/ardtweeno/dispatcher.rb', line 652

def authenticate?(key)      
  if key == @confdata["adminkey"]
    return true, {:role=>"admin"}
  else
    
    @confdata["zones"].each do |i|
      if i["zonekey"] == key
        i[:role] = "zone"
        return true, i
      end
    end
    
    return false, {}
  end
end

#configObject

Ardtweeno::Dispatcher#config returns the configuration as read in from the confg.yaml configuration file

  • Args :

    • ++ ->

  • Returns :

    • @confdata

  • Raises :



730
731
732
# File 'lib/ardtweeno/dispatcher.rb', line 730

def config()
  return @confdata
end

#construct_lineplot(params) ⇒ Object

Ardtweeno::Dispatcher#constructLineplot method for constructing the line plot graph

  • Args :

    • ++ ->

  • Returns :

    • Array data containing the 168 hourly packet totals for the last week, Array of strings containing the names of the last 7 days

  • Raises :



104
105
106
107
108
# File 'lib/ardtweeno/dispatcher.rb', line 104

def construct_lineplot(params)
  theData = Ardtweeno::API.buildLineplot(@nodeManager.nodeList, params)
  
  return theData
end

#constructPunchcard(params) ⇒ Object

Ardtweeno::Dispatcher#constructPunchcard method for constructing the punchcard graph

  • Args :

    • ++ ->

  • Returns :

    • Array data containing the 168 hourly packet totals for the last week, Array of strings containing the names of the last 7 days

  • Raises :



85
86
87
88
89
# File 'lib/ardtweeno/dispatcher.rb', line 85

def constructPunchcard(params)
  theData, theDays, theDateRange = Ardtweeno::API.buildPunchcard(@nodeManager.nodeList, params)
  
  return theData, theDays, theDateRange
end

#constructTopology(params = nil) ⇒ Object

Ardtweeno::Dispatcher#constructTopology method for constructing the topology graph

  • Args :

    • ++ -> Hash params, not really used for the moment

  • Returns :

    • String containing the Raphael.js code to generate the graph

  • Raises :



121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/ardtweeno/dispatcher.rb', line 121

def constructTopology(params=nil)
  apitimer = Time.now
  
  nodes = Ardtweeno::API.retrievenodes(@nodeManager.nodeList, params)
  zones = Ardtweeno::API.retrievezones(@confdata, params)
  
  topology = Ardtweeno::API.parseTopology(zones, nodes)
  result = Ardtweeno::API.buildTopology(topology)
  
  @log.debug "Duration: #{Time.now - apitimer} seconds"
  return result
end

#diskUsageObject

Ardtweeno::Dispatcher#bootstrap which configures the Dispatcher instance for initial operation

  • Args :

    • ++ ->

  • Returns : -

  • Raises :



548
549
550
# File 'lib/ardtweeno/dispatcher.rb', line 548

def diskUsage()
  return Ardtweeno::API.diskUsage
end

#flushObject

Ardtweeno::Dispatcher#flush method for flushing packet data to the Database



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
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
# File 'lib/ardtweeno/dispatcher.rb', line 145

def flush()
  begin
    @log.debug "Ardtweeno::Dispatcher#flush called"
  
    db_host = @confdata["db"]["dbHost"]
    db_port = @confdata["db"]["dbPort"]
    db_name = @confdata["db"]["dbName"]
    db_username = @confdata["db"]["dbUser"]
    db_password = @confdata["db"]["dbPass"]
    db_collection = @confdata["db"]["dbPacketsColl"]
            
    if @db == nil
      @log.warn "The database connector is not connected to a database!"
      @log.debug "Attempting to construct the MongoDB driver instance"
      
      begin
        @db = Mongo::Connection.new(db_host, db_port).db(db_name)

      rescue Mongo::ConnectionFailure => e
        raise Ardtweeno::DBError, e
      end
    end
    
    
    # Ensure we are authenticated to use the MongoDB DB
    begin
      @auth = @db.authenticate(db_username, db_password)
      @coll = @db.collection(db_collection)
    rescue Mongo::AuthenticationError => e
      raise Ardtweeno::DBError, e
    end
    
    
    nodeList = @nodeManager.nodeList
    packetqueue = Array.new
    
    nodeList.each do |i|
    
      i.packetqueue.each do |j|
      
        data = {
          :key=>j.key,
          :seqNo=>j.seqNo,
          :date=>j.date,
          :hour=>j.hour,
          :minute=>j.minute,
          :node=>j.node,
          :data=>j.data 
        }
      
        packetqueue << data
      end
      
      # Sorted the packetqueue by the sequence number sequentially
      packetqueue = packetqueue.sort_by {|x| x[:seqNo]} # Not exactly ideal.. but it works ;p
    end
    
    @log.debug "Packetqueue size: #{packetqueue.size}"
    @log.debug "Saving packetqueue to the Database"
    @nodeManager.flush()
    
    
    begin
      packetqueue.each do |i|
        @coll.insert(i)
      end
    rescue Exception => e
      raise e
    end
    
    
  rescue Ardtweeno::DBError => e
    raise e
  end  
  
  return true
end

#getPostsObject

Ardtweeno::Dispatcher#getPosts returns the front page news posts loaded from ~/.ardtweeno/posts.yaml

  • Args :

    • ++ ->

  • Returns :

    • Array of Hash containing post data

  • Raises :



694
695
696
697
698
699
700
# File 'lib/ardtweeno/dispatcher.rb', line 694

def getPosts()
  unless @posts.nil? or @posts.empty?
    return @posts["posts"]
  else
    return Array.new
  end
end

#getPostsURIObject

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 :



679
680
681
# File 'lib/ardtweeno/dispatcher.rb', line 679

def getPostsURI()
  return @confdata["newsURI"]
end

#retrieve_nodes(params) ⇒ Object

Ardtweeno::Dispatcher#retrieve_nodes method for retrieving node data from the system

  • Args :

    • ++ -> params Hash

  • Returns :

    • String in JSON form

  • Raises :



254
255
256
257
258
259
260
261
# File 'lib/ardtweeno/dispatcher.rb', line 254

def retrieve_nodes(params)
  apitimer = Time.now
  
  result = Ardtweeno::API.retrievenodes(@nodeManager.nodeList, params)
  
  @log.debug "Duration: #{Time.now - apitimer} seconds"
  return result
end

#retrieve_packets(params) ⇒ Object

Ardtweeno::Dispatcher#retrieve_packets method for retrieving packet data from the system

  • Args :

    • ++ -> params Hash

  • Returns :

    • String in JSON form

  • Raises :



274
275
276
277
278
279
280
281
# File 'lib/ardtweeno/dispatcher.rb', line 274

def retrieve_packets(params)
  apitimer = Time.now
  
  result = Ardtweeno::API.retrievepackets(@nodeManager.nodeList, params)
  
  @log.debug "Duration: #{Time.now - apitimer} seconds"
  return result
end

#retrieve_zones(params) ⇒ Object

Ardtweeno::Dispatcher#retrieve_zones method for retrieving zone data from the system

  • Args :

    • ++ -> params Hash

  • Returns :

    • String in JSON form

  • Raises :



234
235
236
237
238
239
240
241
# File 'lib/ardtweeno/dispatcher.rb', line 234

def retrieve_zones(params)
  apitimer = Time.now
  
  result = Ardtweeno::API.retrievezones(@confdata, params)
  
  @log.debug "Duration: #{Time.now - apitimer} seconds"
  return result
end

#running?Boolean

Ardtweeno::Dispatcher#running? checks to see if the SerialParser is running

  • Args :

    • ++ ->

  • Returns :

    • true/false

  • Raises :

Returns:

  • (Boolean)


637
638
639
# File 'lib/ardtweeno/dispatcher.rb', line 637

def running?()
  return @running
end

#savePosts(newPosts) ⇒ Object

Ardtweeno::Dispatcher#savePosts saves a post to ~/.ardtweeno/posts.yaml

  • Args :

    • ++ ->

  • Returns : -

  • Raises :



713
714
715
716
# File 'lib/ardtweeno/dispatcher.rb', line 713

def savePosts(newPosts)
  @posts["posts"] = newPosts
  Ardtweeno::ConfigReader.save(@posts, Ardtweeno::POSTPATH)
end

#startObject

Ardtweeno::Dispatcher#start which launches the Ardtweeno Mesh Network Router

  • Args :

    • ++ ->

  • Returns :

    • true/false

  • Raises :



436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
# File 'lib/ardtweeno/dispatcher.rb', line 436

def start()
  
  begin
    unless Ardtweeno.options[:test]   
      unless @running == true
        
        dev = @confdata["dev"]
        speed = @confdata["speed"]
        key = @confdata["adminkey"]
        
        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
        
      end
    else
      unless @running == true
        @running = true
        return true
      end
    end
  rescue Exception => e
    @parser.kill
    @parser = nil
    raise e
  end
  
  @log.debug "The SerialParser system is already running.. ignoring.."
  return false
  
end

#status?Boolean

Ardtweeno::Dispatcher#status? returns the system status of the Ardtweeno Gateway host

  • Args :

    • ++ ->

  • Returns :

    • Hash running, String cpuload, String memload

  • Raises :

Returns:

  • (Boolean)


606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
# File 'lib/ardtweeno/dispatcher.rb', line 606

def status?()
  @log.debug "Ardtweeno::Dispatcher#status? executing"
  begin
    unless Ardtweeno.options[:test] ||= false
      theResponse = Ardtweeno::API.status
      theResponse[:running] = @running
      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
    raise e
  end
end

#statuslistObject

Ardtweeno::Dispatcher#statuslist returns a Array of Hash containing system statuses for

the last 15 minutes
  • Args :

    • ++ ->

  • Returns :

    • Array [Hash running, String cpuload, String memload]

  • Raises :



564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
# File 'lib/ardtweeno/dispatcher.rb', line 564

def statuslist()
  @log.debug "Ardtweeno::Dispatcher#statuslist executing"
  begin
    rawdata = @statusbuffer.to_a
    
    cpu = Array.new
    mem = Array.new
    running = Array.new
    
    now = (Time.now.to_i * 1000) # Get the milliseconds since the epoch
    start = now - (rawdata.size * 10000) # Get the milliseconds from the start of the buffer
    
    rawdata.each do |i|
      cpu << [start, i[:cpuload]]
      mem << [start, i[:memload]]
      if i[:running] then running << [start, 100]; else running << [start, 0]; end
      
      start += 10000
    end
    
    cpuseries = {:label=>"CPU &#37;", :data=>cpu, :color=>"#ED0E0E"}
    memseries = {:label=>"MEM &#37;", :data=>mem, :color=>"#0E7AED"}
    runningseries = {:label=>"Parser Active", :data=>running, :color=>"#088A08"}
    
    return [cpuseries, memseries, runningseries]
    
  rescue Exception => e
    raise e
  end
end

#stopObject

Ardtweeno::Dispatcher#stop which stops the Ardtweeno Mesh Network Router

  • Args :

    • ++ ->

  • Returns :

    • true/false

  • Raises :



505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
# File 'lib/ardtweeno/dispatcher.rb', line 505

def stop()
  
  begin
    unless Ardtweeno.options[:test]        
      unless @running == false
        
        @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
    @parser.kill
    @parser = nil
    raise e
  end
  
  @log.debug "SerialParser system is inactive.. ignoring.."
  return false

end

#store(origionalPayload) ⇒ Object

Ardtweeno::Dispatcher#store stores a packet retrieved by the API into the system

  • Args :

    • ++ -> payload String - containing JSON data to match structure of Ardtweeno::Packet

  • Returns :

    • true

  • Raises :

    Ardtweeno::InvalidData if data is invalid or TypeError if not valid JSON
    


377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
# File 'lib/ardtweeno/dispatcher.rb', line 377

def store(origionalPayload)
  begin
    
    @log.debug "Payload recieved, processing.."
    payload = JSON.parse(origionalPayload)
      
    if payload["data"].nil? then raise Ardtweeno::InvalidData, "Packet missing data"; end
    @log.debug "Payload contains a :data key, continuing.."
    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.."
   
    @log.debug "Constructing a new Ardtweeno::Packet from the payload.."
    packet = Ardtweeno::Packet.new(Ardtweeno.nextSeq(), payload["key"], payload["data"])
    
	if packet.data.size > node.sensors.size then raise Ardtweeno::SensorException, "Mismatch between sensors and sensor data counts"; end

    @log.debug "Adding packet to the node.."
    node.enqueue(packet)
    
    @log.debug "Check if its being watched"
    if @nodeManager.watched?(node.node)
      @log.debug "There is a watch on this node, pushing notifications"
      @nodeManager.pushNotification(node.node)
    else
      @log.debug "There is no watch associated with this node"
    end
    
    @log.debug "Success!"
    
  rescue Ardtweeno::NotInNodeList => e
    @log.debug "Node is not authorised to communicate with the gateway.."
    raise Ardtweeno::NodeNotAuthorised, "Node is not authorised for this network, ignoring"
  rescue Ardtweeno::InvalidData => e
    raise Ardtweeno::InvalidData, "Data is invalid, ignoring"
  rescue Exception => e
    @log.debug e
    raise e
  end
  
  return true 
end

#watched?(params) ⇒ Boolean

Ardtweeno::Dispatcher#watched? method to discover if a node is being watched

  • Args :

    • ++ -> params Hash containing: String name of the node

  • Returns :

    • Hash watched=>true|false

  • Raises :

Returns:

  • (Boolean)


310
311
312
# File 'lib/ardtweeno/dispatcher.rb', line 310

def watched?(params)
  return {:watched=>@nodeManager.watched?(params[:node])}
end

#watchListObject

Ardtweeno::Dispatcher#watchList method to return Array of Hash containing watched node information

  • Args :

    • ++ ->

  • Returns :

    • Array of Hash { String :node, String :notifyURL,

      String :method, String :timeouts }
      
  • Raises :



295
296
297
# File 'lib/ardtweeno/dispatcher.rb', line 295

def watchList
  return {:watched=>@nodeManager.watchList}
end