minecraftctl 2.0.1 → 2.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.
- data/Gemfile +1 -1
- data/Gemfile.lock +2 -10
- data/README.rdoc +3 -0
- data/VERSION +1 -1
- data/bin/minecraftctl +35 -39
- data/bin/minecraftctlserver +129 -141
- data/lib/minecraft.rb +1 -1
- data/minecraftctl.gemspec +4 -4
- metadata +8 -10
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,14 +1,11 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
-
arrayfields (4.7.4)
|
5
4
|
cgi_multipart_eof_fix (2.5.0)
|
6
|
-
chronic (0.6.4)
|
7
5
|
daemon (1.1.0)
|
8
6
|
daemons (1.1.4)
|
9
7
|
diff-lcs (1.1.3)
|
10
8
|
fastthread (1.0.7)
|
11
|
-
fattr (2.2.0)
|
12
9
|
gem_plugin (0.2.3)
|
13
10
|
git (1.2.5)
|
14
11
|
httpclient (2.2.1)
|
@@ -16,12 +13,7 @@ GEM
|
|
16
13
|
bundler (~> 1.0)
|
17
14
|
git (>= 1.2.5)
|
18
15
|
rake
|
19
|
-
|
20
|
-
arrayfields (~> 4.7.4)
|
21
|
-
chronic (~> 0.6.2)
|
22
|
-
fattr (~> 2.2.0)
|
23
|
-
map (~> 4.3.0)
|
24
|
-
map (4.3.0)
|
16
|
+
micro-optparse (1.1.5)
|
25
17
|
mongrel (1.1.5)
|
26
18
|
cgi_multipart_eof_fix (>= 2.4)
|
27
19
|
daemons (>= 1.0.3)
|
@@ -63,7 +55,7 @@ DEPENDENCIES
|
|
63
55
|
daemon (~> 1)
|
64
56
|
httpclient (>= 2.2.1)
|
65
57
|
jeweler (~> 1.6.4)
|
66
|
-
|
58
|
+
micro-optparse (~> 1)
|
67
59
|
mongrel (>= 1.1.5)
|
68
60
|
rcov
|
69
61
|
reek (~> 1.2.8)
|
data/README.rdoc
CHANGED
@@ -46,6 +46,9 @@ Some cURL examples:
|
|
46
46
|
|
47
47
|
== Changelog
|
48
48
|
|
49
|
+
=== v2.0.2
|
50
|
+
* better help message and switch related error handling
|
51
|
+
|
49
52
|
=== v2.0.1
|
50
53
|
* increased startup and command timeout
|
51
54
|
* startup and command timeout values are now configurable via -t and -s switches
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.0.
|
1
|
+
2.0.2
|
data/bin/minecraftctl
CHANGED
@@ -1,54 +1,50 @@
|
|
1
1
|
#!/usr/bin/ruby
|
2
2
|
require 'rubygems'
|
3
|
-
require '
|
3
|
+
require 'micro-optparse'
|
4
4
|
require 'httpclient'
|
5
5
|
require 'thread'
|
6
6
|
Thread.abort_on_exception = true
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
options = Parser.new do |p|
|
9
|
+
p.banner = <<EOF
|
10
|
+
Controls minecraft server started via minecraftctlserver
|
10
11
|
|
11
|
-
|
12
|
-
default 'localhost'
|
13
|
-
description 'minecraft control server address'
|
14
|
-
argument_required
|
15
|
-
end
|
12
|
+
Usage: #{$0} [options] command [arguments]
|
16
13
|
|
17
|
-
|
18
|
-
|
19
|
-
description 'minecraft control server port'
|
20
|
-
argument_required
|
21
|
-
end
|
14
|
+
Command has to start with '/'
|
15
|
+
For available server commands type '#{$0} /'
|
22
16
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
17
|
+
Options:
|
18
|
+
EOF
|
19
|
+
p.option :server, 'minecraft control server address', :default => 'localhost'
|
20
|
+
p.option :port, 'minecraft control server port', :default => 25560
|
21
|
+
end.process!
|
27
22
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
23
|
+
command = ARGV.shift
|
24
|
+
unless command
|
25
|
+
puts "command not specified, see '#{$0} -h' for help"
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
unless command =~ /^\//
|
29
|
+
puts "invalid command '#{command}', command has to start with '/'. Type '#{$0} /' to see available server commands"
|
30
|
+
exit 1
|
31
|
+
end
|
32
|
+
|
33
|
+
args = ARGV
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
end
|
44
|
-
else
|
45
|
-
c.post_async("http://#{params['server'].value}:#{params['port'].value}#{command}", args.join("\n")).pop.content.each do |line|
|
46
|
-
puts line
|
47
|
-
end
|
48
|
-
end
|
49
|
-
rescue Errno::ECONNREFUSED => e
|
50
|
-
puts "Falied to connect to minecraftctlserver; please run minecraftctlserver first: #{e}"
|
35
|
+
c = HTTPClient.new
|
36
|
+
|
37
|
+
begin
|
38
|
+
if args.empty?
|
39
|
+
c.get_async("http://#{options[:server]}:#{options[:port]}#{command}").pop.content.each do |line|
|
40
|
+
puts line
|
41
|
+
end
|
42
|
+
else
|
43
|
+
c.post_async("http://#{options[:server]}:#{options[:port]}#{command}", args.join("\n")).pop.content.each do |line|
|
44
|
+
puts line
|
51
45
|
end
|
52
46
|
end
|
47
|
+
rescue SocketError, Errno::ECONNREFUSED => e
|
48
|
+
puts "Falied to connect to minecraft control server (to start it run 'minecraftctlserver .' in your minecraft install directory): #{e}"
|
53
49
|
end
|
54
50
|
|
data/bin/minecraftctlserver
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/ruby
|
2
2
|
require 'rubygems'
|
3
|
-
require '
|
3
|
+
require 'micro-optparse'
|
4
4
|
require 'open3'
|
5
5
|
require 'thread'
|
6
6
|
require 'pathname'
|
@@ -124,180 +124,168 @@ class APIBuilder
|
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
127
|
-
|
128
|
-
|
127
|
+
options = Parser.new do |p|
|
128
|
+
p.banner = <<EOF
|
129
|
+
Lounches minecraft server that can be controlled via HTTP
|
130
|
+
|
131
|
+
Usage: #{$0} [options] directory
|
132
|
+
|
133
|
+
Directory has to be a path to the minecraft server install directory (where you have 'minecraft_server.jar'); use '.' for current directory
|
134
|
+
|
135
|
+
Options:
|
136
|
+
EOF
|
137
|
+
p.option :command, 'command to be used to span server', :default => 'java -Xms256M -Xmx512M -Djava.net.preferIPv4Stack=true -jar minecraft_server.jar nogui'
|
138
|
+
p.option :port, 'TCP port number on which the HTTP control server will be listening', :default => 25560
|
139
|
+
p.option :bind, 'IP address of interface on which the HTTP control server will be listening on; use 0.0.0.0 to bind to all interfaces', :default => '127.0.0.1'
|
140
|
+
p.option :foreground, 'don\'t daemonize, stay in foreground'
|
141
|
+
p.option :pid_file, 'pid file relative to minecraft server direcotry', :default => 'minecraftctlserver.pid', :short => 'P'
|
142
|
+
p.option :log_file, 'log file relative to minecraft server directory where daemon messages will be written', :default => 'minecraftctlserver.log'
|
143
|
+
p.option :startup_timeout, 'time in seconds after which the control server will exit with error while waiting for minecraft to start up', :default => 120
|
144
|
+
p.option :command_timeout, 'time in seconds after which control server will exit with error while waiting for minecraft console command to finish', :default => 40
|
145
|
+
end.process!
|
146
|
+
|
147
|
+
directory = ARGV.shift
|
148
|
+
unless directory
|
149
|
+
puts "directory not specified, see '#{$0} -h' for help"
|
150
|
+
exit 1
|
151
|
+
end
|
129
152
|
|
130
|
-
|
131
|
-
|
132
|
-
description 'command to be used to span server'
|
133
|
-
argument_required
|
134
|
-
end
|
153
|
+
pid_file = Pathname.new(options[:pid_file])
|
154
|
+
log_file = Pathname.new(options[:log_file])
|
135
155
|
|
136
|
-
|
137
|
-
default 25560
|
138
|
-
description 'port on which the control HTTP server should be running'
|
139
|
-
argument_required
|
140
|
-
end
|
156
|
+
Dir.chdir(directory)
|
141
157
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
158
|
+
begin
|
159
|
+
if options[:foreground]
|
160
|
+
Daemon.lock(pid_file)
|
161
|
+
else
|
162
|
+
Daemon.daemonize(pid_file, log_file)
|
146
163
|
end
|
164
|
+
rescue => e
|
165
|
+
puts "Error: failed to start daemon/lock pid: #{e}"
|
166
|
+
exit 2
|
167
|
+
end
|
147
168
|
|
148
|
-
|
149
|
-
description 'don\'t daemonize'
|
150
|
-
end
|
169
|
+
minecraft = nil
|
151
170
|
|
152
|
-
|
153
|
-
|
154
|
-
default 'minecraftctlserver.pid'
|
155
|
-
argument_required
|
156
|
-
end
|
171
|
+
begin
|
172
|
+
minecraft = Minecraft.new(options[:command], :startup_timeout => options[:startup_timeout], :command_timeout => options[:command_timeout])
|
157
173
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
174
|
+
TextCollector.for(minecraft) do
|
175
|
+
start
|
176
|
+
end.each do |msg|
|
177
|
+
puts msg
|
162
178
|
end
|
179
|
+
rescue Minecraft::StartupFailedError => e
|
180
|
+
puts "Error: failed to start minecraft with '#{options[:command]}' in '#{directory}': #{e}"
|
181
|
+
exit 3
|
182
|
+
rescue => e
|
183
|
+
puts "Error: #{e}"
|
184
|
+
exit 4
|
185
|
+
end
|
163
186
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
187
|
+
sinatra = Sinatra.new
|
188
|
+
sinatra.set :port, options[:port]
|
189
|
+
sinatra.set :bind, options[:bind]
|
190
|
+
sinatra.set :environment, 'production'
|
191
|
+
sinatra.set :server, ['mongrel']
|
192
|
+
sinatra.set :lock, true
|
193
|
+
|
194
|
+
APIBuilder.new(sinatra, 'minecraft control server API') do
|
195
|
+
#get 'inspect', 'internal representation of output data' do
|
196
|
+
#minecraft.history.map{|m| m.inspect}.join("\n") + "\n"
|
197
|
+
#end
|
170
198
|
|
171
|
-
|
172
|
-
|
173
|
-
default 40
|
174
|
-
cast :float
|
175
|
-
argument_required
|
199
|
+
get 'dir', 'minecraft directory' do
|
200
|
+
Dir.pwd + "\n"
|
176
201
|
end
|
177
202
|
|
178
|
-
|
179
|
-
|
180
|
-
argument_required
|
203
|
+
get 'pid', 'minecraft control server PID' do
|
204
|
+
Process.pid.to_s + "\n"
|
181
205
|
end
|
182
206
|
|
183
|
-
|
184
|
-
pid_file
|
185
|
-
|
207
|
+
get 'pid_file', 'minecraft control server PID file' do
|
208
|
+
pid_file.realpath.to_s + "\n"
|
209
|
+
end
|
186
210
|
|
187
|
-
|
211
|
+
get 'log_file', 'minecraft control server log file' do
|
212
|
+
log_file.realpath.to_s + "\n"
|
213
|
+
end
|
188
214
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
Daemon.daemonize(pid_file, log_file)
|
193
|
-
end
|
215
|
+
get 'out', 'output generated by control and minecraft server' do
|
216
|
+
minecraft.history.join("\n") + "\n"
|
217
|
+
end
|
194
218
|
|
195
|
-
|
219
|
+
post 'shutdown', 'shutdown minecraft and control server' do
|
196
220
|
TextCollector.for(minecraft) do
|
197
|
-
|
198
|
-
|
199
|
-
puts msg
|
200
|
-
end
|
221
|
+
minecraft.stop if minecraft.running?
|
222
|
+
log "Shutting down minecraftctlserver"
|
201
223
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
sinatra.set :server, ['mongrel']
|
207
|
-
sinatra.set :lock, true
|
208
|
-
|
209
|
-
APIBuilder.new(sinatra, 'minecraft control server API') do
|
210
|
-
#get 'inspect', 'internal representation of output data' do
|
211
|
-
#minecraft.history.map{|m| m.inspect}.join("\n") + "\n"
|
212
|
-
#end
|
213
|
-
|
214
|
-
get 'dir', 'minecraft directory' do
|
215
|
-
Dir.pwd + "\n"
|
216
|
-
end
|
217
|
-
|
218
|
-
get 'pid', 'minecraft control server PID' do
|
219
|
-
Process.pid.to_s + "\n"
|
220
|
-
end
|
224
|
+
pid = Process.pid
|
225
|
+
Thread.new{Process.kill(15, pid)}
|
226
|
+
end
|
227
|
+
end
|
221
228
|
|
222
|
-
|
223
|
-
|
229
|
+
path 'server', 'minecraft server API' do
|
230
|
+
get 'status', 'server status' do
|
231
|
+
if minecraft.running?
|
232
|
+
"running\n"
|
233
|
+
else
|
234
|
+
"stopped\n"
|
224
235
|
end
|
236
|
+
end
|
225
237
|
|
226
|
-
|
227
|
-
|
238
|
+
get 'pid', 'minecraft server PID' do
|
239
|
+
if minecraft.server_pid
|
240
|
+
minecraft.server_pid.to_s + "\n"
|
241
|
+
else
|
242
|
+
"Server not running\n"
|
228
243
|
end
|
244
|
+
end
|
229
245
|
|
230
|
-
|
231
|
-
|
246
|
+
post 'start', 'starts minecraft server' do
|
247
|
+
TextCollector.for(minecraft) do
|
248
|
+
start
|
232
249
|
end
|
250
|
+
end
|
233
251
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
log "Shutting down minecraftctlserver"
|
238
|
-
|
239
|
-
pid = Process.pid
|
240
|
-
Thread.new{Process.kill(15, pid)}
|
241
|
-
end
|
252
|
+
post 'stop', 'stops minecraft server' do
|
253
|
+
TextCollector.for(minecraft) do
|
254
|
+
stop
|
242
255
|
end
|
256
|
+
end
|
243
257
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
end
|
252
|
-
|
253
|
-
get 'pid', 'minecraft server PID' do
|
254
|
-
if minecraft.server_pid
|
255
|
-
minecraft.server_pid.to_s + "\n"
|
256
|
-
else
|
257
|
-
"Server not running\n"
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
|
-
post 'start', 'starts minecraft server' do
|
262
|
-
TextCollector.for(minecraft) do
|
263
|
-
start
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
|
-
post 'stop', 'stops minecraft server' do
|
268
|
-
TextCollector.for(minecraft) do
|
269
|
-
stop
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
post 'console', 'send console command' do |args|
|
274
|
-
next "Console command not specified; try 'console help'\n" if args.empty?
|
275
|
-
TextCollector.for(minecraft) do
|
276
|
-
begin
|
277
|
-
send(args.shift.tr('-', '_').to_sym, *args)
|
278
|
-
rescue Minecraft::ServerNotRunningError
|
279
|
-
log "Server not running"
|
280
|
-
end
|
281
|
-
end
|
258
|
+
post 'console', 'send console command' do |args|
|
259
|
+
next "Console command not specified; try 'console help'\n" if args.empty?
|
260
|
+
TextCollector.for(minecraft) do
|
261
|
+
begin
|
262
|
+
send(args.shift.tr('-', '_').to_sym, *args)
|
263
|
+
rescue Minecraft::ServerNotRunningError
|
264
|
+
log "Server not running"
|
282
265
|
end
|
283
266
|
end
|
284
267
|
end
|
268
|
+
end
|
269
|
+
end
|
285
270
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
sinatra.error do
|
291
|
-
"Error in minecraftctlserver while processing request '#{env['REQUEST_PATH']}': #{env['sinatra.error']}\n"
|
292
|
-
end
|
271
|
+
sinatra.not_found do
|
272
|
+
"Unknown request: #{env['REQUEST_PATH']}\n"
|
273
|
+
end
|
293
274
|
|
294
|
-
|
275
|
+
sinatra.error do
|
276
|
+
"Error in minecraftctlserver while processing request '#{env['REQUEST_PATH']}': #{env['sinatra.error']}\n"
|
277
|
+
end
|
295
278
|
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
279
|
+
begin
|
280
|
+
sinatra.run!
|
281
|
+
rescue Errno::EACCES, Errno::EADDRNOTAVAIL, SocketError => e
|
282
|
+
puts "Error: failed to bind HTTP server socket (#{options[:bind]}): #{e}"
|
283
|
+
exit 5
|
284
|
+
ensure
|
285
|
+
# make sure we stop the server on exit
|
286
|
+
if minecraft.running?
|
287
|
+
puts 'stopping minecraft'
|
288
|
+
minecraft.stop
|
301
289
|
end
|
302
290
|
end
|
303
291
|
|
data/lib/minecraft.rb
CHANGED
data/minecraftctl.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "minecraftctl"
|
8
|
-
s.version = "2.0.
|
8
|
+
s.version = "2.0.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jakub Pastuszek"]
|
@@ -55,7 +55,7 @@ Gem::Specification.new do |s|
|
|
55
55
|
s.add_development_dependency(%q<reek>, ["~> 1.2.8"])
|
56
56
|
s.add_development_dependency(%q<roodi>, ["~> 2.1.0"])
|
57
57
|
s.add_development_dependency(%q<sinatra>, [">= 1.2.6"])
|
58
|
-
s.add_development_dependency(%q<
|
58
|
+
s.add_development_dependency(%q<micro-optparse>, ["~> 1"])
|
59
59
|
s.add_development_dependency(%q<httpclient>, [">= 2.2.1"])
|
60
60
|
s.add_development_dependency(%q<mongrel>, [">= 1.1.5"])
|
61
61
|
s.add_development_dependency(%q<mongrel>, [">= 1.1.5"])
|
@@ -68,7 +68,7 @@ Gem::Specification.new do |s|
|
|
68
68
|
s.add_dependency(%q<reek>, ["~> 1.2.8"])
|
69
69
|
s.add_dependency(%q<roodi>, ["~> 2.1.0"])
|
70
70
|
s.add_dependency(%q<sinatra>, [">= 1.2.6"])
|
71
|
-
s.add_dependency(%q<
|
71
|
+
s.add_dependency(%q<micro-optparse>, ["~> 1"])
|
72
72
|
s.add_dependency(%q<httpclient>, [">= 2.2.1"])
|
73
73
|
s.add_dependency(%q<mongrel>, [">= 1.1.5"])
|
74
74
|
s.add_dependency(%q<mongrel>, [">= 1.1.5"])
|
@@ -82,7 +82,7 @@ Gem::Specification.new do |s|
|
|
82
82
|
s.add_dependency(%q<reek>, ["~> 1.2.8"])
|
83
83
|
s.add_dependency(%q<roodi>, ["~> 2.1.0"])
|
84
84
|
s.add_dependency(%q<sinatra>, [">= 1.2.6"])
|
85
|
-
s.add_dependency(%q<
|
85
|
+
s.add_dependency(%q<micro-optparse>, ["~> 1"])
|
86
86
|
s.add_dependency(%q<httpclient>, [">= 2.2.1"])
|
87
87
|
s.add_dependency(%q<mongrel>, [">= 1.1.5"])
|
88
88
|
s.add_dependency(%q<mongrel>, [">= 1.1.5"])
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: minecraftctl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 11
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 2
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 2.0.
|
9
|
+
- 2
|
10
|
+
version: 2.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jakub Pastuszek
|
@@ -131,16 +131,14 @@ dependencies:
|
|
131
131
|
requirement: &id008 !ruby/object:Gem::Requirement
|
132
132
|
none: false
|
133
133
|
requirements:
|
134
|
-
- -
|
134
|
+
- - ~>
|
135
135
|
- !ruby/object:Gem::Version
|
136
|
-
hash:
|
136
|
+
hash: 1
|
137
137
|
segments:
|
138
|
-
-
|
139
|
-
|
140
|
-
- 3
|
141
|
-
version: 4.7.3
|
138
|
+
- 1
|
139
|
+
version: "1"
|
142
140
|
version_requirements: *id008
|
143
|
-
name:
|
141
|
+
name: micro-optparse
|
144
142
|
prerelease: false
|
145
143
|
type: :development
|
146
144
|
- !ruby/object:Gem::Dependency
|