motel 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
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