nova 0.0.2

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 (55) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +19 -0
  3. data/README.md +29 -0
  4. data/bin/nova +8 -0
  5. data/lib/generator/template/new_install/galaxy/some_star.rb +3 -0
  6. data/lib/generator/template/new_install/supernova.yml +16 -0
  7. data/lib/nova.rb +49 -0
  8. data/lib/nova/cli.rb +62 -0
  9. data/lib/nova/commands/server.rb +71 -0
  10. data/lib/nova/common.rb +17 -0
  11. data/lib/nova/common/event_handler.rb +165 -0
  12. data/lib/nova/common/event_handler/event.rb +147 -0
  13. data/lib/nova/common/features.rb +93 -0
  14. data/lib/nova/common/features/feature.rb +65 -0
  15. data/lib/nova/common/metadata.rb +65 -0
  16. data/lib/nova/common/metadata/data.rb +171 -0
  17. data/lib/nova/common/star_management.rb +164 -0
  18. data/lib/nova/constructor.rb +84 -0
  19. data/lib/nova/exceptions.rb +16 -0
  20. data/lib/nova/project.rb +199 -0
  21. data/lib/nova/remote.rb +10 -0
  22. data/lib/nova/remote/fake.rb +51 -0
  23. data/lib/nova/remote/fake/commands.rb +44 -0
  24. data/lib/nova/remote/fake/file_system.rb +76 -0
  25. data/lib/nova/remote/fake/operating_system.rb +52 -0
  26. data/lib/nova/remote/fake/platform.rb +89 -0
  27. data/lib/nova/star.rb +25 -0
  28. data/lib/nova/starbound.rb +14 -0
  29. data/lib/nova/starbound/client.rb +59 -0
  30. data/lib/nova/starbound/encryptor.rb +134 -0
  31. data/lib/nova/starbound/encryptors.rb +13 -0
  32. data/lib/nova/starbound/encryptors/openssl.rb +122 -0
  33. data/lib/nova/starbound/encryptors/plaintext.rb +64 -0
  34. data/lib/nova/starbound/encryptors/rbnacl.rb +67 -0
  35. data/lib/nova/starbound/protocol.rb +81 -0
  36. data/lib/nova/starbound/protocol/encryption.rb +48 -0
  37. data/lib/nova/starbound/protocol/exceptions.rb +38 -0
  38. data/lib/nova/starbound/protocol/messages.rb +116 -0
  39. data/lib/nova/starbound/protocol/packet.rb +267 -0
  40. data/lib/nova/starbound/protocol/socket.rb +231 -0
  41. data/lib/nova/starbound/server.rb +182 -0
  42. data/lib/nova/version.rb +5 -0
  43. data/spec/constructor_spec.rb +20 -0
  44. data/spec/local_spec.rb +26 -0
  45. data/spec/nova_spec.rb +7 -0
  46. data/spec/spec_helper.rb +19 -0
  47. data/spec/star/some_type.rb +27 -0
  48. data/spec/star_spec.rb +107 -0
  49. data/spec/starbound/encryptor_spec.rb +33 -0
  50. data/spec/starbound/openssl_encryptor_spec.rb +80 -0
  51. data/spec/starbound/packet_spec.rb +61 -0
  52. data/spec/starbound/plaintext_encryptor_spec.rb +27 -0
  53. data/spec/starbound/protocol_spec.rb +163 -0
  54. data/spec/starbound/rbnacl_encryptor_spec.rb +70 -0
  55. metadata +166 -0
@@ -0,0 +1,164 @@
1
+ module Nova
2
+ module Common
3
+
4
+ # Manages types of stars. Adds a +star_type+ method to subclasses
5
+ # to add it to the type list.
6
+ module StarManagement
7
+
8
+ # Class methods.
9
+ module ClassMethods
10
+
11
+ # All of the types of stars. Should be a key-value pair, with
12
+ # the key being the name, and the value being the class.
13
+ #
14
+ # @return [Hash{Symbol => Class}]
15
+ def types
16
+ @@types ||= {}
17
+ end
18
+
19
+ # When the star is subclassed, add the subclass
20
+ # automatically to the star type list, unless it doesn't
21
+ # have a proper name.
22
+ #
23
+ # @api private
24
+ def inherited(klass)
25
+ return unless klass.name
26
+
27
+ type = klass.name.gsub(/([A-Z])/) { |a| "_#{a.downcase}" }.gsub("::", "/")[1..-1].intern
28
+ klass.star_type(type)
29
+ end
30
+
31
+ # Adds the Star to the type list.
32
+ #
33
+ # @param name [Symbol] the name of the star.
34
+ # @return [self]
35
+ def star_type(name)
36
+ types.delete_if { |_, v| v == self }
37
+ types[name] = self
38
+ self.type = name
39
+ stars[name] = {}
40
+ self
41
+ end
42
+
43
+ # All of the stars that have been defined. These are
44
+ # different from star types because they contain information
45
+ # such as events.
46
+ #
47
+ # @return [Hash{Symbol => Class}]
48
+ def stars
49
+ @@stars ||= {}
50
+ end
51
+
52
+ # An accessor for {#stars}.
53
+ #
54
+ # @param star_name [Symbol]
55
+ # @return [Hash, Class]
56
+ def [](star_name)
57
+ stars[star_name]
58
+ end
59
+
60
+ # Cleans up the inspect a little bit.
61
+ #
62
+ # @return [String]
63
+ def inspect
64
+ @_inspect ||=
65
+ ancestors.take_while { |x| x <= Star }.map(&:name).reverse.join("/").gsub(/\/\z/, "." + as.to_s)
66
+ end
67
+
68
+ # Just a way to write it; syntaxic sugar. It returns what
69
+ # was passed.
70
+ #
71
+ # @example
72
+ # Nova::Star/Type.something
73
+ # @param other_class [Class]
74
+ # @return [Class] other_class.
75
+ def /(other_class)
76
+ other_class
77
+ end
78
+
79
+ # The remote to use, by default, for stars.
80
+ #
81
+ # @!parse attr_reader :remote
82
+ # @return [Module]
83
+ def remote
84
+ @remote ||= Remote::Fake
85
+ end
86
+
87
+ attr_writer :remote
88
+
89
+ # The name of the star.
90
+ #
91
+ # @return [Symbol]
92
+ attr_accessor :as
93
+
94
+ # The type of the star.
95
+ #
96
+ # @return [Symbol]
97
+ attr_accessor :type
98
+
99
+ # Retrieves the star with the given name.
100
+ #
101
+ # @example
102
+ # Nova::Star/Type.klass
103
+ # @return [Class]
104
+ def method_missing(method, *args, &block)
105
+ if (stars.key?(method) || stars[type].key?(method)) && args.length == 0
106
+ stars[method] || stars[type][method]
107
+ else
108
+ super
109
+ end
110
+ end
111
+ end
112
+
113
+ # Instance methods.
114
+ module InstanceMethods
115
+
116
+ # Checks for the correct platforms in initialization. If
117
+ # it's not on the right platform, raises an error.
118
+ #
119
+ # @raise [NoPlatformError] if it's not available on the
120
+ # platform.
121
+ def initialize(remote = nil)
122
+ @remote = (remote || self.remote).new
123
+ super(@remote)
124
+ end
125
+
126
+ # Cleans up the inspect a little bit.
127
+ #
128
+ # @return [String]
129
+ def inspect
130
+ @_inspect ||= begin
131
+ "#<" <<
132
+ self.class.inspect <<
133
+ (":0x%014x" % object_id) <<
134
+ ">"
135
+ end
136
+ end
137
+
138
+ # The remote this star is using. Can be set locally, but
139
+ # uses the global remote by default.
140
+ #
141
+ # @see ClassMethods#remote
142
+ # @!parse attr_reader :remote
143
+ # @return [Module]
144
+ def remote
145
+ @remote || self.class.remote
146
+ end
147
+
148
+ attr_writer :remote
149
+
150
+ end
151
+
152
+ # Called when {StarManagement} is included. Extends what included
153
+ # it by {ClassMethods}, and includes {InstanceMethods}.
154
+ #
155
+ # @param receiver [Object]
156
+ # @return [void]
157
+ # @api private
158
+ def self.included(receiver)
159
+ receiver.send :include, InstanceMethods
160
+ receiver.extend ClassMethods
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,84 @@
1
+ module Nova
2
+
3
+ # Creates a star from a {Nova.create} call.
4
+ class Constructor
5
+
6
+ # Initialize the constructor.
7
+ #
8
+ # @param options [Hash] the definition of the star. It should
9
+ # be a single key-value pair, with the first key being the
10
+ # type of star, and the first value being the name of the
11
+ # star.
12
+ # @yield for the construction of the new Star.
13
+ # @example
14
+ # Constructor.new(some_star: :another_star) do
15
+ # on :some_event do; end
16
+ # end.create # => Nova::Star/SomeStar.another_star
17
+ def initialize(options, &block)
18
+ @options = options
19
+ @block = block
20
+ end
21
+
22
+ # Modifies an already existing star if it exists, or creates it
23
+ # if it doesn't.
24
+ #
25
+ # @raise [NoStarError] when the star type couldn't be found.
26
+ # @return [Class] a subclass of the star type.
27
+ def modify_or_create
28
+ star_type = Star.types[data[:type]]
29
+
30
+ raise NoStarError,
31
+ "Could not find star type #{data[:type]}." unless star_type
32
+
33
+ if Star.stars[data[:type]][data[:as]]
34
+ handle_existing
35
+ else
36
+ handle_new star_type
37
+ end
38
+ end
39
+
40
+
41
+ # Returns information about the star, like the type, the required
42
+ # platforms, and what it's named.
43
+ #
44
+ # @return [Hash<Symbol, Object>]
45
+ def data
46
+ @_data ||= {
47
+ :as => @options.values.first,
48
+ :type => @options.keys.first
49
+ }
50
+ end
51
+
52
+ private
53
+
54
+ # Handles an existing star. Executes the block in the instance of
55
+ # the star, adds the definition's required_platforms to the stars,
56
+ # and then returns the star.
57
+ #
58
+ # @return [Class]
59
+ def handle_existing
60
+ star = Star.stars[data[:type]][data[:as]]
61
+
62
+ star.class_exec &@block
63
+
64
+ star
65
+ end
66
+
67
+ # Handles defining a new star. Creates a class as a subclass of
68
+ # the star, sets its name and type, and executes the block in the
69
+ # instance of the star. Adds the required_platform to the star,
70
+ # sets the star to {Star.stars}, and returns the new star.
71
+ #
72
+ # @param star_type [Class] the type of star it is.
73
+ # @return [Class]
74
+ def handle_new(star_type)
75
+ new_star = Class.new(star_type)
76
+ new_star.as = data[:as]
77
+ new_star.type = data[:type]
78
+ new_star.class_exec &@block
79
+
80
+ Star.stars[data[:type]][data[:as]] = new_star
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,16 @@
1
+ module Nova
2
+
3
+ # Raised when an Event cannot be found.
4
+ class NoEventError < StandardError; end
5
+
6
+ # Raised when options were passed that were not valid.
7
+ class InvalidOptionsError < StandardError; end
8
+
9
+ # Raised when a Star is tried to be created from a non-existant
10
+ # star type.
11
+ class NoStarError < StandardError; end
12
+
13
+ # Raised when a Star is tried to be instantized on a non-compliant
14
+ # platform.
15
+ class NoPlatformError < StandardError; end
16
+ end
@@ -0,0 +1,199 @@
1
+ require 'yaml'
2
+
3
+ module Nova
4
+
5
+ # A Nova project, containing the galaxy and configuration
6
+ # settings for that project.
7
+ class Project
8
+
9
+ # The default paths to load from.
10
+ DEFAULT_PATHS = [File.absolute_path("../../../galaxy", __FILE__)]
11
+
12
+ # Whether or not the given directory is deemable as a Nova
13
+ # project.
14
+ #
15
+ # @param dir [String] the directory to test.
16
+ # @return [Boolean]
17
+ def self.valid?(dir)
18
+ Dir.new(dir).each.include?("nova.yml")
19
+ end
20
+
21
+ # The directory the project is based in.
22
+ #
23
+ # @return [Directory]
24
+ attr_reader :directory
25
+
26
+ # The load paths for this project.
27
+ #
28
+ # @return [Array<String>]
29
+ attr_reader :load_paths
30
+
31
+ # The options that were loaded from the config for this project.
32
+ #
33
+ # @return [Hash]
34
+ attr_reader :options
35
+
36
+ # Initializes the project. Loads the configuration file by
37
+ # default.
38
+ #
39
+ # @param dir [String] the path to the directory for the project.
40
+ # @param load_config [Boolean] whether or not to load the
41
+ # configuration file.
42
+ def initialize(dir, load_config = true)
43
+ @directory = Dir.new(dir)
44
+ @load_paths = DEFAULT_PATHS.dup
45
+ @options = {}
46
+
47
+ if load_config
48
+ load_config!
49
+ end
50
+ end
51
+
52
+
53
+ # Loads the configuration file.
54
+ #
55
+ # @return [Hash] the data.
56
+ def load_config!
57
+ return unless options.empty?
58
+
59
+ data = ::YAML.load_file(File.open("#{directory.path}/nova.yml", "r"))
60
+ load_paths.push(*data.fetch("load_paths", []))
61
+
62
+ load_paths.map! do |path|
63
+ File.absolute_path(path, directory.path)
64
+ end
65
+
66
+ @options = data
67
+ end
68
+
69
+ # Requires all of the star files that is in the project.
70
+ #
71
+ # @return [void]
72
+ def require_files
73
+ @load_paths.each do |path|
74
+ Dir["#{path}/**/*"].each do |f|
75
+ require f
76
+ end
77
+ end
78
+ end
79
+
80
+ # Runs the servers defined in the options.
81
+ #
82
+ # @note If do_fork is false, only the first server in the config
83
+ # file will actually be created.
84
+ # @param do_fork [Boolean] whether or not to actually fork the
85
+ # process when creating servers.
86
+ # @param which [Array<String>] which servers to run. Defaults to
87
+ # all of them.
88
+ # @return [void]
89
+ def run_servers(do_fork = true, which = [])
90
+ each_server(which) do |server, name|
91
+ puts name
92
+
93
+ if File.exists?(server[:files][:pid])
94
+ Nova.logger.warn {
95
+ "PID file #{server[:files][:pid]} already exists. " +
96
+ "Ignoring server definition."
97
+ }
98
+ next
99
+ end
100
+
101
+ if do_fork
102
+ process_id = fork
103
+ end
104
+
105
+ if process_id
106
+ File.open(server[:files][:pid], "w") { |f| f.write process_id }
107
+ Process.detach(process_id)
108
+ else
109
+ return build_server(server, do_fork)
110
+ end
111
+ end
112
+ end
113
+
114
+ # Takes down running servers.
115
+ #
116
+ # @param which [Array<String>] which servers to take down.
117
+ # Defaults to all of them.
118
+ # @return [void]
119
+ def shoot(which = [])
120
+ each_server do |server, name|
121
+ if File.exists?(server[:files][:pid])
122
+ pid = File.open(server[:files][:pid], "r") { |f| f.read }.to_i
123
+
124
+ puts "Sending INT to #{pid}..."
125
+
126
+ Process.kill :INT, pid rescue Errno::ESRCH
127
+
128
+ File.delete(server[:files][:pid]) rescue Errno::ENOENT
129
+
130
+ puts "OK!"
131
+ end
132
+ end
133
+ end
134
+
135
+ private
136
+
137
+ # Loops over all of the defined servers, yielding the server
138
+ # definition and the index for that server.
139
+ #
140
+ # @yieldparam server [Hash<Symbol, Object>] the server data
141
+ # @yieldparam server_name [String] the name of the server.
142
+ # @yieldparam index [Numeric] the index of the server in the
143
+ # definition file.
144
+ # @return [void]
145
+ def each_server(only = [])
146
+ server_list = [options["servers"], options["server"]].flatten.compact
147
+
148
+ server_list.each_with_index do |srv, i|
149
+ srv_name = srv.fetch(:name, "server#{i}")
150
+ srv[:files] ||= {}
151
+
152
+ files = {}
153
+ {:log => :log, :pid => :pid, :client => :rb}.each do |f, n|
154
+ files[f] = File.absolute_path(
155
+ srv[:files].fetch(f, "./#{srv_name}.#{n}"),
156
+ directory.path
157
+ )
158
+ end
159
+ srv[:files] = files
160
+
161
+ next unless only.empty? or only.include?(srv_name)
162
+
163
+ yield srv, srv_name, i
164
+ end
165
+ end
166
+
167
+ # Creates a server, with the given server options.
168
+ #
169
+ # @param server [Hash<Symbol, Object>] the server information to
170
+ # base the server instance off of.
171
+ # @param redirect [Boolean] whether or not to redirect the
172
+ # {Nova.logger} and the stdin, stdout, and stderr for the
173
+ # server.
174
+ # @return [void]
175
+ def build_server(server, redirect = true)
176
+ if redirect
177
+ Nova.logger = Logger.new(server[:files][:log], 10, 1_024_000)
178
+ $stdin = $stdout = $stderr = File.open("/dev/null", "a")
179
+ end
180
+
181
+ begin
182
+ s = Nova::Starbound::Server.new(server)
183
+ s.read_client_file server[:files][:client]
184
+
185
+ trap :INT do
186
+ s.shutdown
187
+ File.delete(server[:files][:pid]) rescue Errno::ENOENT
188
+ end
189
+
190
+ return s.listen
191
+ rescue => e
192
+ Nova.logger.fatal { "#{e}: #{e.message}; #{e.backtrace[0]}" }
193
+ File.delete(server[:files][:pid]) rescue Errno::ENOENT
194
+ exit
195
+ end
196
+ end
197
+
198
+ end
199
+ end