motel 0.2 → 0.3

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.
Files changed (39) hide show
  1. data/README.rdoc +35 -0
  2. data/Rakefile +48 -0
  3. data/bin/clients/simple/main.rb +131 -0
  4. data/bin/server/main.rb +61 -0
  5. data/conf/motel-schema.xml +72 -0
  6. data/lib/motel/common.rb +35 -11
  7. data/lib/motel/dsl.rb +12 -0
  8. data/lib/motel/exceptions.rb +14 -0
  9. data/lib/motel/location.rb +100 -0
  10. data/lib/motel/{models → movement_strategies}/elliptical.rb +51 -89
  11. data/lib/motel/movement_strategies/linear.rb +54 -0
  12. data/lib/motel/movement_strategies/stopped.rb +18 -0
  13. data/lib/motel/movement_strategy.rb +29 -0
  14. data/lib/motel/runner.rb +94 -108
  15. data/lib/motel/simrpc.rb +131 -0
  16. data/lib/motel/thread_pool.rb +51 -0
  17. data/lib/motel.rb +9 -5
  18. data/spec/common_spec.rb +77 -0
  19. data/spec/dsl_spec.rb +27 -0
  20. data/spec/location_spec.rb +109 -0
  21. data/spec/movement_strategies/elliptical_spec.rb +90 -0
  22. data/spec/movement_strategies/linear_spec.rb +51 -0
  23. data/spec/movement_strategies/stopped_spec.rb +39 -0
  24. data/spec/movement_strategy_spec.rb +24 -0
  25. data/spec/runner_spec.rb +45 -0
  26. data/spec/simrpc_spec.rb +85 -0
  27. data/spec/spec_helper.rb +26 -0
  28. metadata +36 -34
  29. data/README +0 -0
  30. data/conf/amqp.yml +0 -13
  31. data/conf/database.yml +0 -41
  32. data/db/migrate/001_create_locations_and_movement_strategies.rb +0 -45
  33. data/db/migrate/002_create_linear_movement_strategy.rb +0 -23
  34. data/db/migrate/003_create_elliptical_movement_strategy.rb +0 -52
  35. data/lib/motel/loader.rb +0 -47
  36. data/lib/motel/models/linear.rb +0 -76
  37. data/lib/motel/models/location.rb +0 -109
  38. data/lib/motel/models/movement_strategy.rb +0 -82
  39. data/lib/motel/models/stopped.rb +0 -16
data/README.rdoc ADDED
@@ -0,0 +1,35 @@
1
+ == Motel - Movable Object Tracking Encopassing Locations
2
+
3
+ Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
4
+
5
+ Motel is made available under the GNU AFFERO GENERAL PUBLIC LICENSE
6
+ as published by the Free Software Foundation, either version 3
7
+ of the License, or (at your option) any later version.
8
+
9
+ === Intro
10
+ Motel is a simple framework for tracking 3d location written in Ruby.
11
+ A simple server is provider which handles requests which the provided client
12
+ can issue, altering heirarchies of locations and updating their coordinates
13
+ and movement strategies.
14
+
15
+ Each location is associated with a movement stategy which is used to move the location
16
+ (eg update its coordinates) in accordance to a set of rules / variables specific to each
17
+ strategy.
18
+
19
+ Multiple clients can connect to a motel server simutaneously and query for locations and
20
+ subscribe handlers to be invoked on updates.
21
+
22
+ To install motel simply run:
23
+ gem install motel
24
+
25
+ Source code is available via:
26
+ git clone http://github.com/movitto/motel
27
+
28
+ === Using
29
+ Generate documentation via
30
+ rake rdoc
31
+
32
+ Also see specs for detailed usage.
33
+
34
+ === Authors
35
+ Mohammed Morsi <movitto@yahoo.com>
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ # motel project Rakefile
2
+ #
3
+ # Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
4
+ # Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
5
+
6
+ require 'rake/rdoctask'
7
+ require 'spec/rake/spectask'
8
+ require 'rake/gempackagetask'
9
+
10
+
11
+ GEM_NAME="motel"
12
+ PKG_VERSION='0.3'
13
+ SIMRPC_SPEC='conf/motel-schema.xml'
14
+
15
+ desc "Run all specs"
16
+ Spec::Rake::SpecTask.new('spec') do |t|
17
+ t.spec_files = FileList['spec/**/*_spec.rb']
18
+ end
19
+
20
+ Rake::RDocTask.new do |rd|
21
+ rd.main = "README.rdoc"
22
+ rd.rdoc_dir = "doc/site/api"
23
+ rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
24
+ end
25
+
26
+ PKG_FILES = FileList['bin/**/*', 'conf/motel-schema.xml', 'lib/**/*.rb',
27
+ 'COPYING', 'LICENSE', 'Rakefile', 'README.rdoc', 'spec/**/*.rb' ]
28
+
29
+ SPEC = Gem::Specification.new do |s|
30
+ s.name = GEM_NAME
31
+ s.version = PKG_VERSION
32
+ s.files = PKG_FILES
33
+
34
+ s.required_ruby_version = '>= 1.8.1'
35
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.3.3")
36
+
37
+ s.author = "Mohammed Morsi"
38
+ s.email = "movitto@yahoo.com"
39
+ s.date = %q{2010-03-14}
40
+ s.description = %q{Motel is a library to track and move the locations of objects in a 3D environment.}
41
+ s.summary = %q{Motel is a library to track and move the locations of objects in a 3D environment.}
42
+ s.homepage = %q{http://morsi.org/projects/motel}
43
+ end
44
+
45
+ Rake::GemPackageTask.new(SPEC) do |pkg|
46
+ pkg.need_tar = true
47
+ pkg.need_zip = true
48
+ end
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/ruby
2
+ # A simple motel client executable
3
+ # Executable to use the motel library to perform operations on
4
+ # a remote location server, simply printing out results
5
+ #
6
+ # Flags: (see below)
7
+ #
8
+ # Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
9
+ # Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
10
+
11
+ CURRENT_DIR=File.dirname(__FILE__)
12
+ $: << File.expand_path(CURRENT_DIR + "/../../../lib")
13
+
14
+ require 'rubygems'
15
+ require 'optparse'
16
+ require 'motel'
17
+
18
+ include Motel
19
+ include Motel::MovementStrategies
20
+
21
+ ######################
22
+
23
+ # TODO movement strategy support
24
+
25
+ def main()
26
+ # command line parameters
27
+ schema_file = nil
28
+ location = {:parent_id => nil,
29
+ :x => nil,
30
+ :y => nil,
31
+ :z => nil}
32
+ request_target = nil
33
+
34
+ # setup cmd line options
35
+ opts = OptionParser.new do |opts|
36
+ opts.banner = "Usage: main.rb [command] [options]"
37
+
38
+ opts.on("-h", "--help", "Print this help message") do
39
+ puts opts
40
+ exit
41
+ end
42
+
43
+ opts.on("-s", "--schema [path]", "Motel Schema File") do |path|
44
+ schema_file = path
45
+ end
46
+
47
+ opts.separator ""
48
+ opts.separator "Commands:"
49
+ opts.on("-g", "--get", "get location specified by id")do
50
+ request_target = :get_location
51
+ end
52
+ opts.on("-c", "--create", "create location w/ id")do
53
+ request_target = :create_location
54
+ end
55
+ opts.on("-u", "--update", "update location specified by id w/ specified options")do
56
+ request_target = :update_location
57
+ end
58
+ opts.on("-b", "--subscribe", "subscribe to updates to location specified by id")do
59
+ request_target = :subscribe_to_location
60
+ end
61
+
62
+ opts.separator ""
63
+ opts.separator "Options:"
64
+ opts.on("-i", "--id [location_id]", "Target location id") do |id|
65
+ location[:id] = id
66
+ end
67
+ opts.on("-p", "--parent-id [location_id]", "Target parent location id") do |id|
68
+ location[:parent_id] = id
69
+ end
70
+ opts.on("-x", "--xcoordinate [coordinate]", "Target location x coordinate") do |x|
71
+ location[:x] = x
72
+ end
73
+ opts.on("-y", "--ycoordinate [coordinate]", "Target location y coordinate") do |y|
74
+ location[:y] = y
75
+ end
76
+ opts.on("-z", "--zcoordinate [coordinate]", "Target location z coordinate") do |z|
77
+ location[:z] = z
78
+ end
79
+
80
+ end
81
+
82
+ # parse cmd line
83
+ begin
84
+ opts.parse!(ARGV)
85
+ rescue OptionParser::InvalidOption => e
86
+ puts opts
87
+ puts e.to_s
88
+ exit
89
+ end
90
+
91
+ if request_target.nil? || location[:id].nil? || schema_file.nil? ||
92
+ request_target == :update && location[:x].nil? && location[:y].nil? && location[:z].nil? && location[:parent_id].nil?
93
+ puts opts
94
+ puts "must specify schema, a command to perform, a location id, and other required options"
95
+ exit
96
+ end
97
+
98
+ lid = location[:id]
99
+ location = Motel::Location.new :id => location[:id],
100
+ :parent_id => location[:parent_id],
101
+ :x => location[:x],
102
+ :y => location[:y],
103
+ :z => location[:z]
104
+ args = []
105
+ case(request_target)
106
+ when :get_location
107
+ args.push location.id
108
+ when :create_location
109
+ args.push location.id
110
+ when :update_location
111
+ args.push location
112
+ when :subscribe_to_location
113
+ args.push location.id
114
+ end
115
+
116
+ # FIXME need configurable amqp broker ip/port
117
+ client = Motel::Client.new :schema_file => schema_file
118
+ result = client.request request_target, *args
119
+
120
+ if request_target == :subscribe_to_location
121
+ client.on_location_received = lambda { |loc|
122
+ puts "location received:"
123
+ puts "#{loc}"
124
+ }
125
+ client.join
126
+ end
127
+
128
+ puts "server returned #{result}"
129
+ end
130
+
131
+ main()
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/ruby
2
+ # A motel server executable
3
+ # Executable to use the motel library to track locations in
4
+ # real time and provide network access to read/write location data.
5
+ #
6
+ # Flags:
7
+ # -h --help
8
+ # -s --simrpc-schema
9
+ #
10
+ # Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
11
+ # Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
12
+
13
+ CURRENT_DIR=File.dirname(__FILE__)
14
+ $: << File.expand_path(CURRENT_DIR + "/../../lib")
15
+
16
+ require 'rubygems'
17
+ require 'optparse'
18
+ require 'motel'
19
+
20
+ include Motel
21
+ include Motel::MovementStrategies
22
+
23
+ ######################
24
+
25
+
26
+ def main()
27
+ schema_file = nil
28
+
29
+ # setup cmd line options
30
+ opts = OptionParser.new do |opts|
31
+ opts.on("-h", "--help", "Print help message") do
32
+ puts opts
33
+ exit
34
+ end
35
+ opts.on("-s", "--simrpc-schema [path]", "Motel Simrpc Schema File") do |path|
36
+ schema_file = path
37
+ end
38
+ end
39
+
40
+ # parse cmd line
41
+ begin
42
+ opts.parse!(ARGV)
43
+ rescue OptionParser::InvalidOption
44
+ puts opts
45
+ exit
46
+ end
47
+
48
+ if schema_file.nil? || ! File.exists?(schema_file)
49
+ puts "motel simrpc schema file required"
50
+ exit
51
+ end
52
+
53
+ # start location runner
54
+ Motel::Runner.instance.start :async => true
55
+
56
+ # start listening for requests / block
57
+ # FIXME need configurable amqp broker ip/port
58
+ server = Motel::Server.new(:schema_file => schema_file).join
59
+ end
60
+
61
+ main()
@@ -0,0 +1,72 @@
1
+ <!-- The motel simrpc schema definition -->
2
+ <schema>
3
+
4
+ <class name="MovementStrategy" desc="paramaterized algorithm through which a location is moved">
5
+ <member name="id" type="int" desc="MovementStrategy identifier" ignore_null="true" />
6
+ <member name="type" type="str" desc="MovementStrategy type"/>
7
+ <member name="step_delay" type="float" desc="MovementStrategy movement delay"/>
8
+ </class>
9
+
10
+ <class name="Stopped" desc="stopped movement strategy" inherits="MovementStrategy">
11
+ </class>
12
+
13
+ <class name="Linear" desc="linear movement strategy" inherits="MovementStrategy">
14
+ <member name="speed" type="float" desc="Speed which location is moving" />
15
+ <member name="direction_vector_x" type="float" desc="x component of Linear direction vector" />
16
+ <member name="direction_vector_y" type="float" desc="y component of Linear direction vector" />
17
+ <member name="direction_vector_z" type="float" desc="z component of Linear direction vector" />
18
+ </class>
19
+
20
+ <class name="Elliptical" desc="elliptical movement strategy" inherits="MovementStrategy">
21
+ <member name="speed" type="float" desc="Speed which location is moving" />
22
+ <member name="relative_to" type="float" desc="how location is relative to its parent" />
23
+ <member name="eccentricity" type="float" desc="eccentricity of elliptical orbit" />
24
+ <member name="semi_latus_rectum" type="float" desc="semi latus rectum of elliptical orbit" />
25
+ <member name="direction_major_x" type="float" desc="x component of Elliptical Major direction vector" />
26
+ <member name="direction_major_y" type="float" desc="y component of Elliptical Major direction vector" />
27
+ <member name="direction_major_z" type="float" desc="z component of Elliptical Major direction vector" />
28
+ <member name="direction_minor_x" type="float" desc="x component of Elliptical Minor direction vector" />
29
+ <member name="direction_minor_y" type="float" desc="y component of Elliptical Minor direction vector" />
30
+ <member name="direction_minor_z" type="float" desc="z component of Elliptical Minor direction vector" />
31
+ </class>
32
+
33
+ <class name="Location" desc="location in 3d space w/ coordiantes & movement strategy">
34
+ <member name="id" type="int" desc="Location identifier" ignore_null="true" />
35
+ <member name="x" type="int" desc="x coordinate"/>
36
+ <member name="y" type="int" desc="y coordinate"/>
37
+ <member name="z" type="int" desc="z coordinate"/>
38
+ <member name="parent_id" type="int" desc="location id of parent, null if this is a root location" ignore_null="true" />
39
+ <member name="parent" type="obj" associated="Location" desc="parent location"/>
40
+ <member name="children" type="array" associated="Location" desc="children locations"/>
41
+ <member name="movement_strategy" type="obj" desc="associated movement strategy"/>
42
+ <member name="entity_id" type="int" desc="id of entity represented by this location" />
43
+ <member name="entity_type" type="str" desc="type of entity represented by this location" />
44
+ </class>
45
+
46
+ <method name="get_location" desc="get location from specified id">
47
+ <param name="location_id" type="int" desc="Location identifier"/>
48
+ <return_value name="location" type="obj" associated="Location" desc="Location corresponding to id or nil"/>
49
+ </method>
50
+
51
+ <method name="create_location" desc="create new location w/ specified id">
52
+ <param name="location_id" type="int" desc="Location identifier"/>
53
+ <return_value name="success" type="bool" desc="bool success"/>
54
+ </method>
55
+
56
+ <method name="update_location" desc="update running location w/ new location sharing the same id">
57
+ <param name="location" type="obj" associated="Location" desc="Location with new attributes and identifier of location to update"/>
58
+ <return_value name="success" type="bool" desc="bool success"/>
59
+ </method>
60
+
61
+ <!-- TODO delete_location -->
62
+
63
+ <method name="subscribe_to_location" desc="subscribe simrpc endpoint to updates to location of the specified id via the location_moved method">
64
+ <param name="location_id" type="int" desc="Location identifier"/>
65
+ <param name="node_id" type="str" desc="Node identifier which to update of location movements"/>
66
+ <return_value name="success" type="bool" desc="bool success"/>
67
+ </method>
68
+
69
+ <method name="location_moved" desc="inform simrpc endpoint that location was moved">
70
+ <param name="location" type="obj" associated="Location" desc="Location that was moved with new coordinates and original id"/>
71
+ </method>
72
+ </schema>
data/lib/motel/common.rb CHANGED
@@ -2,11 +2,44 @@
2
2
  #
3
3
  # Things that don't fit elsewhere
4
4
  #
5
- # Copyright (C) 2009 Mohammed Morsi <movitto@yahoo.com>
6
- # See COPYING for the License of this software
5
+ # Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
6
+ # Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
7
+
8
+ # include logger dependencies
9
+ require 'logger'
7
10
 
8
11
  module Motel
9
12
 
13
+ # Logger helper class
14
+ class Logger
15
+ private
16
+ def self._instantiate_logger
17
+ unless defined? @@logger
18
+ # FIXME need configurable log_level, out-stream
19
+ @@log_level = ::Logger::FATAL
20
+ @@logger = ::Logger.new(STDOUT)
21
+ @@logger.level = @@log_level
22
+ end
23
+ end
24
+
25
+ public
26
+
27
+ def self.method_missing(method_id, *args)
28
+ _instantiate_logger
29
+ @@logger.send(method_id, args)
30
+ end
31
+
32
+ def self.logger
33
+ _instantiate_logger
34
+ @@logger
35
+ end
36
+
37
+ def self.log_level=(level)
38
+ @@log_level = level
39
+ end
40
+ end
41
+
42
+
10
43
  # generate a random id
11
44
  def gen_uuid
12
45
  ["%02x"*4, "%02x"*2, "%02x"*2, "%02x"*2, "%02x"*6].join("-") %
@@ -43,12 +76,3 @@ class Float
43
76
  return (self * 10 ** precision).round.to_f / (10 ** precision)
44
77
  end
45
78
  end
46
-
47
- # try to find key equal to method, returning value if found
48
- #class Hash
49
- # def method_missing(method, *params)
50
- # method = method.to_sym
51
- # return self[method] if self.keys.collect{ |k| k.to_sym }.include?(method)
52
- # super
53
- # end
54
- #end
data/lib/motel/dsl.rb ADDED
@@ -0,0 +1,12 @@
1
+ # Motel DSL
2
+ #
3
+ # Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
4
+ # Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
5
+
6
+ # establish client connection w/ specified args and invoke block w/
7
+ # newly created client, returning it after block terminates
8
+ def connect(args = {}, &block)
9
+ client = Motel::Client.new(args)
10
+ block.call client unless block.nil?
11
+ return client
12
+ end
@@ -0,0 +1,14 @@
1
+ # Exceptions used in the MOTEL project
2
+ #
3
+ # Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
4
+ # Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
5
+
6
+ module Motel
7
+
8
+ class InvalidMovementStrategy < RuntimeError
9
+ def initialize(msg)
10
+ super(msg)
11
+ end
12
+ end
13
+
14
+ end
@@ -0,0 +1,100 @@
1
+ # The Location entity
2
+ #
3
+ # Copyright (C) 2010 Mohammed Morsi <movitto@yahoo.com>
4
+ # Licensed under the AGPLv3+ http://www.gnu.org/licenses/agpl.txt
5
+
6
+ require 'motel/movement_strategy'
7
+
8
+ module Motel
9
+
10
+ # A Location defines an optional parent location and the x,y,z
11
+ # cartesian coordinates of the location relative to that parent.
12
+ # If parent is not specified x,y,z are ignored and this location
13
+ # is assumed to be the 'center' of the system to which it belongs
14
+ # Also is related to a movable object defining the parameters
15
+ # of the locations movement
16
+ class Location
17
+
18
+ # id of location and parent, and coordinates relative to that parent
19
+ attr_accessor :id, :x, :y, :z, :parent_id
20
+
21
+ # handle to parent location and array of children
22
+ attr_accessor :parent, :children
23
+
24
+ # movement strategy which location move in accordance to
25
+ attr_accessor :movement_strategy
26
+
27
+ # array of callbacks to be invoked on movement
28
+ attr_accessor :movement_callbacks
29
+
30
+ # a generic association which this location can belong to
31
+ attr_accessor :entity
32
+
33
+ def initialize(args = {})
34
+ # default to the stopped movement strategy
35
+ @movement_strategy = MovementStrategies::Stopped.instance
36
+ @movement_callbacks = []
37
+ @children = []
38
+
39
+ @id = args[:id] if args.has_key? :id
40
+ @parent_id = args[:parent_id] if args.has_key? :parent_id
41
+ @x = args[:x] if args.has_key? :x
42
+ @y = args[:y] if args.has_key? :y
43
+ @z = args[:z] if args.has_key? :z
44
+ @parent = args[:parent] if args.has_key? :parent
45
+ @parent.children.push self unless @parent.nil? || @parent.children.include?(self)
46
+ @movement_strategy = args[:movement_strategy] if args.has_key? :movement_strategy
47
+
48
+ @x = 0 if @x.nil?
49
+ @y = 0 if @y.nil?
50
+ @z = 0 if @z.nil?
51
+ end
52
+
53
+ # update this location's attributes to match other's set attributes
54
+ def update(location)
55
+ @x = location.x unless location.x.nil?
56
+ @y = location.y unless location.y.nil?
57
+ @z = location.z unless location.z.nil?
58
+ @movement_strategy = location.movement_strategy unless location.movement_strategy.nil?
59
+ @parent = location.parent unless location.parent.nil?
60
+ @parent_id = location.parent_id unless location.parent_id.nil?
61
+ end
62
+
63
+ # return this location's root location
64
+ def root
65
+ return self if parent.nil?
66
+ return parent.root
67
+ end
68
+
69
+ # traverse all chilren recursively, calling block for each
70
+ def traverse_descendants(&bl)
71
+ children.each { |child|
72
+ bl.call child
73
+ child.traverse_descendants &bl
74
+ }
75
+ end
76
+
77
+ # return sum of the x values of this location and all its parents,
78
+ # eg the absolute 'x' of the location
79
+ def total_x
80
+ return 0 if parent.nil?
81
+ return parent.total_x + x
82
+ end
83
+
84
+ # return sum of the y values of this location and all its parents
85
+ # eg the absolute 'y' of the location
86
+ def total_y
87
+ return 0 if parent.nil?
88
+ return parent.total_y + y
89
+ end
90
+
91
+ # return sum of the z values of this location and all its parents
92
+ # eg the absolute 'z' of the location
93
+ def total_z
94
+ return 0 if parent.nil?
95
+ return parent.total_z + z
96
+ end
97
+
98
+ end
99
+
100
+ end # module Motel