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 CHANGED
@@ -13,7 +13,7 @@ group :development do
13
13
  gem "reek", "~> 1.2.8"
14
14
  gem "roodi", "~> 2.1.0"
15
15
  gem "sinatra", ">= 1.2.6"
16
- gem "main", ">= 4.7.3"
16
+ gem "micro-optparse", "~> 1"
17
17
  gem "httpclient", ">= 2.2.1"
18
18
  gem "mongrel", ">= 1.1.5"
19
19
  gem "mongrel", ">= 1.1.5"
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
- main (4.7.7)
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
- main (>= 4.7.3)
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
1
+ 2.0.2
data/bin/minecraftctl CHANGED
@@ -1,54 +1,50 @@
1
1
  #!/usr/bin/ruby
2
2
  require 'rubygems'
3
- require 'main'
3
+ require 'micro-optparse'
4
4
  require 'httpclient'
5
5
  require 'thread'
6
6
  Thread.abort_on_exception = true
7
7
 
8
- Main do
9
- description 'controls minecraft server via minecraftctlserver'
8
+ options = Parser.new do |p|
9
+ p.banner = <<EOF
10
+ Controls minecraft server started via minecraftctlserver
10
11
 
11
- option 'server', 's' do
12
- default 'localhost'
13
- description 'minecraft control server address'
14
- argument_required
15
- end
12
+ Usage: #{$0} [options] command [arguments]
16
13
 
17
- option 'port', 'p' do
18
- default 25560
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
- argument 'command' do
24
- description 'command to send to control server: try "/" for available commands'
25
- validate{|cmd| cmd =~ /^\//}
26
- end
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
- argument 'arguments' do
29
- required false
30
- arity -1
31
- end
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
- run do
34
- c = HTTPClient.new
35
-
36
- begin
37
- command = params['command'].value
38
- args = params['arguments'].values
39
-
40
- if args.empty?
41
- c.get_async("http://#{params['server'].value}:#{params['port'].value}#{command}").pop.content.each do |line|
42
- puts line
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
 
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/ruby
2
2
  require 'rubygems'
3
- require 'main'
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
- Main do
128
- description 'lounches Minecraft server that can be controlled via HTTP'
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
- option 'command', 'c' do
131
- default 'java -Xms256M -Xmx512M -Djava.net.preferIPv4Stack=true -jar minecraft_server.jar nogui'
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
- option 'port', 'p' do
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
- option 'bind', 'b' do
143
- description 'IP address of interface to listen for connections on; use 0.0.0.0 to bind to all interfaces'
144
- default '127.0.0.1'
145
- argument_required
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
- option 'foreground', 'f' do
149
- description 'don\'t daemonize'
150
- end
169
+ minecraft = nil
151
170
 
152
- option 'pid-file', 'P' do
153
- description 'pid file relative to minecraft-dir'
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
- option 'log-file', 'l' do
159
- description 'log file relative to minecraft-dir when in not in foreground'
160
- default 'minecraftctlserver.log'
161
- argument_required
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
- option 'startup-timeout', 's' do
165
- description 'time in seconds after which control server will exit with error while waiting for minecraft to start up'
166
- default 120
167
- cast :float
168
- argument_required
169
- end
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
- option 'command-timeout', 't' do
172
- description 'time in seconds after which control server will exit with error while waiting for minecraft console command to finish'
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
- argument 'minecraft-dir' do
179
- description 'directory path to mincraft server installation directory'
180
- argument_required
203
+ get 'pid', 'minecraft control server PID' do
204
+ Process.pid.to_s + "\n"
181
205
  end
182
206
 
183
- run do
184
- pid_file = Pathname.new(params['pid-file'].value)
185
- log_file = Pathname.new(params['log-file'].value)
207
+ get 'pid_file', 'minecraft control server PID file' do
208
+ pid_file.realpath.to_s + "\n"
209
+ end
186
210
 
187
- Dir.chdir(params['minecraft-dir'].value)
211
+ get 'log_file', 'minecraft control server log file' do
212
+ log_file.realpath.to_s + "\n"
213
+ end
188
214
 
189
- if params['foreground'].given?
190
- Daemon.lock(pid_file)
191
- else
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
- minecraft = Minecraft.new(params['command'].value, :startup_timeout => params['startup-timeout'].value, :command_timeout => params['command-timeout'].value)
219
+ post 'shutdown', 'shutdown minecraft and control server' do
196
220
  TextCollector.for(minecraft) do
197
- start
198
- end.each do |msg|
199
- puts msg
200
- end
221
+ minecraft.stop if minecraft.running?
222
+ log "Shutting down minecraftctlserver"
201
223
 
202
- sinatra = Sinatra.new
203
- sinatra.set :port, params['port'].value
204
- sinatra.set :bind, params['bind'].value
205
- sinatra.set :environment, 'production'
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
- get 'pid_file', 'minecraft control server PID file' do
223
- pid_file.realpath.to_s + "\n"
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
- get 'log_file', 'minecraft control server log file' do
227
- log_file.realpath.to_s + "\n"
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
- get 'out', 'output generated by control and minecraft server' do
231
- minecraft.history.join("\n") + "\n"
246
+ post 'start', 'starts minecraft server' do
247
+ TextCollector.for(minecraft) do
248
+ start
232
249
  end
250
+ end
233
251
 
234
- post 'shutdown', 'shutdown minecraft and control server' do
235
- TextCollector.for(minecraft) do
236
- minecraft.stop if minecraft.running?
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
- path 'server', 'minecraft server API' do
245
- get 'status', 'server status' do
246
- if minecraft.running?
247
- "running\n"
248
- else
249
- "stopped\n"
250
- end
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
- sinatra.not_found do
287
- "Unknown request: #{env['REQUEST_PATH']}\n"
288
- end
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
- sinatra.run!
275
+ sinatra.error do
276
+ "Error in minecraftctlserver while processing request '#{env['REQUEST_PATH']}': #{env['sinatra.error']}\n"
277
+ end
295
278
 
296
- # make sure we stop the server on exit
297
- if minecraft.running?
298
- puts 'stopping minecraft'
299
- minecraft.stop
300
- end
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
@@ -102,7 +102,7 @@ class Minecraft
102
102
  end
103
103
  end
104
104
 
105
- def initialize(cmd, options)
105
+ def initialize(cmd, options = {})
106
106
  @cmd = cmd
107
107
  @in_queue = Queue.new
108
108
  @message_queue = MessageQueue.new
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.1"
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<main>, [">= 4.7.3"])
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<main>, [">= 4.7.3"])
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<main>, [">= 4.7.3"])
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: 13
4
+ hash: 11
5
5
  prerelease:
6
6
  segments:
7
7
  - 2
8
8
  - 0
9
- - 1
10
- version: 2.0.1
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: 37
136
+ hash: 1
137
137
  segments:
138
- - 4
139
- - 7
140
- - 3
141
- version: 4.7.3
138
+ - 1
139
+ version: "1"
142
140
  version_requirements: *id008
143
- name: main
141
+ name: micro-optparse
144
142
  prerelease: false
145
143
  type: :development
146
144
  - !ruby/object:Gem::Dependency