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