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