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.
- checksums.yaml +7 -0
- data/LICENSE +19 -0
- data/README.md +29 -0
- data/bin/nova +8 -0
- data/lib/generator/template/new_install/galaxy/some_star.rb +3 -0
- data/lib/generator/template/new_install/supernova.yml +16 -0
- data/lib/nova.rb +49 -0
- data/lib/nova/cli.rb +62 -0
- data/lib/nova/commands/server.rb +71 -0
- data/lib/nova/common.rb +17 -0
- data/lib/nova/common/event_handler.rb +165 -0
- data/lib/nova/common/event_handler/event.rb +147 -0
- data/lib/nova/common/features.rb +93 -0
- data/lib/nova/common/features/feature.rb +65 -0
- data/lib/nova/common/metadata.rb +65 -0
- data/lib/nova/common/metadata/data.rb +171 -0
- data/lib/nova/common/star_management.rb +164 -0
- data/lib/nova/constructor.rb +84 -0
- data/lib/nova/exceptions.rb +16 -0
- data/lib/nova/project.rb +199 -0
- data/lib/nova/remote.rb +10 -0
- data/lib/nova/remote/fake.rb +51 -0
- data/lib/nova/remote/fake/commands.rb +44 -0
- data/lib/nova/remote/fake/file_system.rb +76 -0
- data/lib/nova/remote/fake/operating_system.rb +52 -0
- data/lib/nova/remote/fake/platform.rb +89 -0
- data/lib/nova/star.rb +25 -0
- data/lib/nova/starbound.rb +14 -0
- data/lib/nova/starbound/client.rb +59 -0
- data/lib/nova/starbound/encryptor.rb +134 -0
- data/lib/nova/starbound/encryptors.rb +13 -0
- data/lib/nova/starbound/encryptors/openssl.rb +122 -0
- data/lib/nova/starbound/encryptors/plaintext.rb +64 -0
- data/lib/nova/starbound/encryptors/rbnacl.rb +67 -0
- data/lib/nova/starbound/protocol.rb +81 -0
- data/lib/nova/starbound/protocol/encryption.rb +48 -0
- data/lib/nova/starbound/protocol/exceptions.rb +38 -0
- data/lib/nova/starbound/protocol/messages.rb +116 -0
- data/lib/nova/starbound/protocol/packet.rb +267 -0
- data/lib/nova/starbound/protocol/socket.rb +231 -0
- data/lib/nova/starbound/server.rb +182 -0
- data/lib/nova/version.rb +5 -0
- data/spec/constructor_spec.rb +20 -0
- data/spec/local_spec.rb +26 -0
- data/spec/nova_spec.rb +7 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/star/some_type.rb +27 -0
- data/spec/star_spec.rb +107 -0
- data/spec/starbound/encryptor_spec.rb +33 -0
- data/spec/starbound/openssl_encryptor_spec.rb +80 -0
- data/spec/starbound/packet_spec.rb +61 -0
- data/spec/starbound/plaintext_encryptor_spec.rb +27 -0
- data/spec/starbound/protocol_spec.rb +163 -0
- data/spec/starbound/rbnacl_encryptor_spec.rb +70 -0
- 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
|
data/lib/nova/project.rb
ADDED
@@ -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
|