minecraftctl 1.1.0 → 2.0.0
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 +12 -12
- data/Gemfile.lock +2 -4
- data/README.rdoc +39 -2
- data/VERSION +1 -1
- data/bin/minecraftctl +8 -8
- data/bin/minecraftctlserver +158 -115
- data/lib/minecraft.rb +10 -2
- data/minecraftctl.gemspec +8 -8
- data/spec/minecraftctlserver_spec.rb +109 -55
- metadata +22 -24
data/Gemfile
CHANGED
@@ -6,17 +6,17 @@ source "http://rubygems.org"
|
|
6
6
|
# Add dependencies to develop your gem here.
|
7
7
|
# Include everything needed to run rake, tests, features, etc.
|
8
8
|
group :development do
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
9
|
+
gem "rspec", "~> 2.3.0"
|
10
|
+
gem "bundler", "~> 1.0.0"
|
11
|
+
gem "jeweler", "~> 1.6.4"
|
12
|
+
gem "rcov", ">= 0"
|
13
|
+
gem "reek", "~> 1.2.8"
|
14
|
+
gem "roodi", "~> 2.1.0"
|
15
|
+
gem "sinatra", ">= 1.2.6"
|
16
|
+
gem "main", ">= 4.7.3"
|
17
|
+
gem "httpclient", ">= 2.2.1"
|
18
|
+
gem "mongrel", ">= 1.1.5"
|
19
|
+
gem "mongrel", ">= 1.1.5"
|
20
|
+
gem "daemon", "~> 1"
|
21
21
|
end
|
22
22
|
|
data/Gemfile.lock
CHANGED
@@ -4,13 +4,13 @@ GEM
|
|
4
4
|
arrayfields (4.7.4)
|
5
5
|
cgi_multipart_eof_fix (2.5.0)
|
6
6
|
chronic (0.6.4)
|
7
|
+
daemon (1.0.0)
|
7
8
|
daemons (1.1.4)
|
8
9
|
diff-lcs (1.1.3)
|
9
10
|
fastthread (1.0.1)
|
10
11
|
fattr (2.2.0)
|
11
12
|
gem_plugin (0.2.3)
|
12
13
|
git (1.2.5)
|
13
|
-
haml (3.1.3)
|
14
14
|
httpclient (2.2.1)
|
15
15
|
jeweler (1.6.4)
|
16
16
|
bundler (~> 1.0)
|
@@ -27,7 +27,6 @@ GEM
|
|
27
27
|
daemons (>= 1.0.3)
|
28
28
|
fastthread (>= 1.0.1)
|
29
29
|
gem_plugin (>= 0.2.3)
|
30
|
-
open4 (1.1.0)
|
31
30
|
rack (1.3.2)
|
32
31
|
rake (0.9.2)
|
33
32
|
rcov (0.9.10)
|
@@ -61,12 +60,11 @@ PLATFORMS
|
|
61
60
|
|
62
61
|
DEPENDENCIES
|
63
62
|
bundler (~> 1.0.0)
|
64
|
-
|
63
|
+
daemon (~> 1)
|
65
64
|
httpclient (>= 2.2.1)
|
66
65
|
jeweler (~> 1.6.4)
|
67
66
|
main (>= 4.7.3)
|
68
67
|
mongrel (>= 1.1.5)
|
69
|
-
open4 (>= 1.1.0)
|
70
68
|
rcov
|
71
69
|
reek (~> 1.2.8)
|
72
70
|
roodi (~> 2.1.0)
|
data/README.rdoc
CHANGED
@@ -4,16 +4,53 @@ Allows running Minecraft server in background (daemon) and send commands, stop,
|
|
4
4
|
|
5
5
|
== Usage
|
6
6
|
|
7
|
-
|
7
|
+
Launch Minecraft server with:
|
8
8
|
|
9
9
|
$ minecraftctlserver <path to minecraft server install dir>
|
10
10
|
|
11
11
|
And control it with 'minecraftctl', for help try:
|
12
12
|
|
13
|
-
$ minecraftctl
|
13
|
+
$ minecraftctl /
|
14
|
+
|
15
|
+
Executing console commands:
|
16
|
+
|
17
|
+
$ minecraftctl /server console help
|
18
|
+
$ minecraftctl /server console say hello world
|
19
|
+
$ minecraftctl /server console list
|
20
|
+
$ minecraftctl /server console kick kazuya
|
21
|
+
|
22
|
+
Stopping and starting minecraft server:s
|
23
|
+
|
24
|
+
$ minecraftctl /server stop
|
25
|
+
$ minecraftctl /server start
|
26
|
+
|
27
|
+
Shutting down minecraftctlserver and minecraft server within:
|
28
|
+
|
29
|
+
$ minecraftctl / shutdown
|
30
|
+
|
31
|
+
== API
|
32
|
+
|
33
|
+
The minecraftctlserver exposes HTTP API on port 25560 (by default) and on localhost (by default).
|
34
|
+
GET call will return a value for given URI or available API commands for GET / and /server.
|
35
|
+
Use space delimited list of arguments as POST data. First argument will be threated as API command.
|
36
|
+
|
37
|
+
Some cURL examples:
|
38
|
+
|
39
|
+
$ curl localhost:25560/ # GET / give list of all API calls
|
40
|
+
$ curl localhost:25560/pid_file # get PID file location
|
41
|
+
$ curl localhost:25560/ -d shutdown # POST / with shutdown POST data will stop the control server
|
42
|
+
$ curl localhost:25560/status # get minecraft server status
|
43
|
+
$ curl localhost:25560/server -d 'stop' # stop minecraft server
|
44
|
+
$ curl localhost:25560/server -d 'start' # stop minecraft server
|
45
|
+
$ curl localhost:25560/server -d 'console list' # list all connected users
|
14
46
|
|
15
47
|
== Changelog
|
16
48
|
|
49
|
+
=== v2.0.0
|
50
|
+
* New cleaner API - more REST like
|
51
|
+
* New API commands: pid, pid_file, dir, out...
|
52
|
+
* Cleanups and fixes
|
53
|
+
|
17
54
|
=== v1.1.0
|
18
55
|
* Output from server is streamed in real time
|
19
56
|
* Fixed problem with initial pid file creation
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.0.0
|
data/bin/minecraftctl
CHANGED
@@ -6,22 +6,22 @@ require 'thread'
|
|
6
6
|
Thread.abort_on_exception = true
|
7
7
|
|
8
8
|
Main do
|
9
|
-
description 'controls
|
9
|
+
description 'controls minecraft server via minecraftctlserver'
|
10
10
|
|
11
11
|
option 'server', 's' do
|
12
12
|
default 'localhost'
|
13
|
-
description '
|
13
|
+
description 'minecraft control server address'
|
14
14
|
argument_required
|
15
15
|
end
|
16
16
|
|
17
17
|
option 'port', 'p' do
|
18
18
|
default 25560
|
19
|
-
description '
|
19
|
+
description 'minecraft control server port'
|
20
20
|
argument_required
|
21
21
|
end
|
22
22
|
|
23
23
|
argument 'command' do
|
24
|
-
description 'command to send to
|
24
|
+
description 'command to send to control server: try "/" for available commands'
|
25
25
|
end
|
26
26
|
|
27
27
|
argument 'arguments' do
|
@@ -42,17 +42,17 @@ Main do
|
|
42
42
|
|
43
43
|
args = params['arguments'].values
|
44
44
|
|
45
|
-
if
|
46
|
-
c.get_async("http://#{params['server'].value}:#{params['port'].value}
|
45
|
+
if args.empty?
|
46
|
+
c.get_async("http://#{params['server'].value}:#{params['port'].value}#{command}").pop.content.each do |line|
|
47
47
|
puts line
|
48
48
|
end
|
49
49
|
else
|
50
|
-
c.post_async("http://#{params['server'].value}:#{params['port'].value}
|
50
|
+
c.post_async("http://#{params['server'].value}:#{params['port'].value}#{command}", args.join("\n")).pop.content.each do |line|
|
51
51
|
puts line
|
52
52
|
end
|
53
53
|
end
|
54
54
|
rescue Errno::ECONNREFUSED => e
|
55
|
-
puts "Falied to connect to minecraftctlserver; please run minecraftctlserver: #{e}"
|
55
|
+
puts "Falied to connect to minecraftctlserver; please run minecraftctlserver first: #{e}"
|
56
56
|
end
|
57
57
|
end
|
58
58
|
end
|
data/bin/minecraftctlserver
CHANGED
@@ -4,6 +4,8 @@ require 'main'
|
|
4
4
|
require 'open3'
|
5
5
|
require 'thread'
|
6
6
|
require 'pathname'
|
7
|
+
require 'daemon'
|
8
|
+
require 'sinatra/base'
|
7
9
|
|
8
10
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
9
11
|
|
@@ -38,34 +40,87 @@ class TextCollector < MessageCollectorProcessed
|
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
41
|
-
class
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
exit if fork # and exits
|
46
|
-
# now in child
|
43
|
+
class APIBuilder
|
44
|
+
def initialize(sinatra, description, path = '', &block)
|
45
|
+
@sinatra = sinatra
|
46
|
+
@description = description
|
47
47
|
|
48
|
-
|
49
|
-
|
48
|
+
@dsl = DSL.new(sinatra, path, &block).data
|
49
|
+
@path = path
|
50
|
+
root = self
|
50
51
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
@sinatra.get(root_path) do
|
53
|
+
root.help.join("\n") + "\n"
|
54
|
+
end
|
55
|
+
|
56
|
+
@dsl.gets.each do |op|
|
57
|
+
@sinatra.get(path + '/' + op.name, &op.block)
|
55
58
|
end
|
56
59
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
60
|
+
post_map = {}
|
61
|
+
|
62
|
+
@dsl.posts.each do |op|
|
63
|
+
post_map[op.name] = op
|
64
|
+
end
|
65
|
+
|
66
|
+
@sinatra.post(root_path) do
|
67
|
+
cmd, *args = request.body.read.split(' ')
|
68
|
+
op = post_map[cmd] or return [400, "Unknown argument: #{cmd} for request: #{request.path_info}\n"]
|
69
|
+
op.block.call(args)
|
70
|
+
end
|
61
71
|
end
|
62
72
|
|
63
|
-
def
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
73
|
+
def root_path
|
74
|
+
@path.empty? ? '/' : @path
|
75
|
+
end
|
76
|
+
|
77
|
+
def help
|
78
|
+
out = []
|
79
|
+
out << "#{root_path} - #{@description}"
|
80
|
+
|
81
|
+
@dsl.posts.each do |op|
|
82
|
+
out << "#{root_path} #{op.name} - #{op.description}"
|
83
|
+
end
|
84
|
+
|
85
|
+
@dsl.gets.each do |op|
|
86
|
+
out << "#{@path}/#{op.name} - #{op.description}"
|
87
|
+
end
|
88
|
+
|
89
|
+
@dsl.paths.each do |path|
|
90
|
+
out += path.help
|
91
|
+
end
|
92
|
+
|
93
|
+
out
|
94
|
+
end
|
95
|
+
|
96
|
+
class DSL
|
97
|
+
OP = Struct.new(:name, :description, :block)
|
98
|
+
def initialize(sinatra, path, &block)
|
99
|
+
@sinatra = sinatra
|
100
|
+
@path = path
|
101
|
+
|
102
|
+
@gets = []
|
103
|
+
@posts = []
|
104
|
+
@paths = []
|
105
|
+
|
106
|
+
instance_eval(&block)
|
107
|
+
end
|
108
|
+
|
109
|
+
def data
|
110
|
+
Struct.new(:gets, :posts, :paths).new(@gets, @posts, @paths)
|
111
|
+
end
|
112
|
+
|
113
|
+
def get(name, description, &block)
|
114
|
+
@gets << OP.new(name, description, block)
|
115
|
+
end
|
116
|
+
|
117
|
+
def post(name, description, &block)
|
118
|
+
@posts << OP.new(name, description, block)
|
119
|
+
end
|
120
|
+
|
121
|
+
def path(name, description, &block)
|
122
|
+
@paths << APIBuilder.new(@sinatra, description, @path + '/' + name, &block)
|
123
|
+
end
|
69
124
|
end
|
70
125
|
end
|
71
126
|
|
@@ -84,6 +139,12 @@ Main do
|
|
84
139
|
argument_required
|
85
140
|
end
|
86
141
|
|
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
|
146
|
+
end
|
147
|
+
|
87
148
|
option 'foreground', 'f' do
|
88
149
|
description 'don\'t daemonize'
|
89
150
|
end
|
@@ -106,8 +167,10 @@ Main do
|
|
106
167
|
end
|
107
168
|
|
108
169
|
run do
|
109
|
-
pid_file = Pathname.new(params['
|
110
|
-
log_file = Pathname.new(params['
|
170
|
+
pid_file = Pathname.new(params['pid-file'].value)
|
171
|
+
log_file = Pathname.new(params['log-file'].value)
|
172
|
+
|
173
|
+
Dir.chdir(params['minecraft-dir'].value)
|
111
174
|
|
112
175
|
if params['foreground'].given?
|
113
176
|
Daemon.lock(pid_file)
|
@@ -115,128 +178,108 @@ Main do
|
|
115
178
|
Daemon.daemonize(pid_file, log_file)
|
116
179
|
end
|
117
180
|
|
118
|
-
require 'sinatra/base'
|
119
|
-
require 'haml'
|
120
|
-
|
121
|
-
Dir.chdir(params['minecraft-dir'].value)
|
122
|
-
|
123
181
|
minecraft = Minecraft.new(params['command'].value)
|
124
|
-
|
125
182
|
minecraft.start
|
126
183
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
184
|
+
sinatra = Sinatra.new
|
185
|
+
sinatra.set :port, params['port'].value
|
186
|
+
sinatra.set :bind, params['bind'].value
|
187
|
+
sinatra.set :environment, 'production'
|
188
|
+
sinatra.set :server, ['mongrel']
|
189
|
+
sinatra.set :lock, true
|
132
190
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
end
|
137
|
-
end
|
191
|
+
APIBuilder.new(sinatra, 'minecraft control server API') do
|
192
|
+
#get 'inspect', 'internal representation of output data' do
|
193
|
+
#minecraft.history.map{|m| m.inspect}.join("\n") + "\n"
|
194
|
+
#end
|
138
195
|
|
139
|
-
|
140
|
-
|
141
|
-
start
|
196
|
+
get 'dir', 'minecraft directory' do
|
197
|
+
Dir.pwd + "\n"
|
142
198
|
end
|
143
|
-
end
|
144
199
|
|
145
|
-
|
146
|
-
|
147
|
-
stop
|
200
|
+
get 'pid', 'minecraft control server PID' do
|
201
|
+
Process.pid.to_s + "\n"
|
148
202
|
end
|
149
|
-
end
|
150
203
|
|
151
|
-
|
152
|
-
|
153
|
-
stop
|
154
|
-
|
155
|
-
pid = Process.pid
|
156
|
-
Thread.new{ sleep 1; Process.kill(15, pid)}
|
204
|
+
get 'pid_file', 'minecraft control server PID file' do
|
205
|
+
pid_file.realpath.to_s + "\n"
|
157
206
|
end
|
158
|
-
end
|
159
207
|
|
160
|
-
|
161
|
-
|
162
|
-
TextCollector.for(minecraft) do
|
163
|
-
send(cmd.tr('-', '_').to_sym, *args)
|
208
|
+
get 'log_file', 'minecraft control server log file' do
|
209
|
+
log_file.realpath.to_s + "\n"
|
164
210
|
end
|
165
|
-
end
|
166
|
-
|
167
|
-
s.get '/help' do
|
168
|
-
start = false
|
169
|
-
TextCollector.for(minecraft) do
|
170
|
-
help
|
171
|
-
log "status show server status"
|
172
|
-
log "log show recent server messages"
|
173
|
-
log "inspect inspect recent server messages"
|
174
|
-
end.process do |msg|
|
175
|
-
msg = msg.to_s
|
176
211
|
|
177
|
-
|
178
|
-
|
179
|
-
next
|
180
|
-
end
|
181
|
-
|
182
|
-
next unless start
|
183
|
-
msg.sub(/help or \?/, 'serverhelp ').sub(/^( |\t)*/, '')
|
212
|
+
get 'out', 'output generated by control and minecraft server' do
|
213
|
+
minecraft.history.join("\n") + "\n"
|
184
214
|
end
|
185
|
-
end
|
186
215
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
end
|
216
|
+
post 'shutdown', 'shutdown minecraft and control server' do
|
217
|
+
TextCollector.for(minecraft) do
|
218
|
+
minecraft.stop if minecraft.running?
|
219
|
+
log "Shutting down minecraftctlserver"
|
192
220
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
haml :status_running
|
197
|
-
else
|
198
|
-
haml :status_stopped
|
221
|
+
pid = Process.pid
|
222
|
+
Thread.new{Process.kill(15, pid)}
|
223
|
+
end
|
199
224
|
end
|
200
|
-
end
|
201
|
-
|
202
|
-
s.get '/inspect' do
|
203
|
-
@msg = minecraft.history
|
204
|
-
haml :messages_inspect
|
205
|
-
end
|
206
225
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
226
|
+
path 'server', 'minecraft server API' do
|
227
|
+
get 'status', 'server status' do
|
228
|
+
if minecraft.running?
|
229
|
+
"running\n"
|
230
|
+
else
|
231
|
+
"stopped\n"
|
232
|
+
end
|
233
|
+
end
|
211
234
|
|
212
|
-
|
213
|
-
|
214
|
-
|
235
|
+
get 'pid', 'minecraft server PID' do
|
236
|
+
if minecraft.server_pid
|
237
|
+
minecraft.server_pid.to_s + "\n"
|
238
|
+
else
|
239
|
+
"Server not running\n"
|
240
|
+
end
|
241
|
+
end
|
215
242
|
|
216
|
-
|
217
|
-
|
218
|
-
|
243
|
+
post 'start', 'starts minecraft server' do
|
244
|
+
TextCollector.for(minecraft) do
|
245
|
+
start
|
246
|
+
end
|
247
|
+
end
|
219
248
|
|
220
|
-
|
221
|
-
|
222
|
-
|
249
|
+
post 'stop', 'stops minecraft server' do
|
250
|
+
TextCollector.for(minecraft) do
|
251
|
+
stop
|
252
|
+
end
|
253
|
+
end
|
223
254
|
|
224
|
-
|
225
|
-
|
255
|
+
post 'console', 'send console command' do |args|
|
256
|
+
next "Console command not specified; try 'console help'\n" if args.empty?
|
257
|
+
TextCollector.for(minecraft) do
|
258
|
+
begin
|
259
|
+
send(args.shift.tr('-', '_').to_sym, *args)
|
260
|
+
rescue Minecraft::ServerNotRunningError
|
261
|
+
log "Server not running"
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
226
266
|
end
|
227
267
|
|
228
|
-
|
229
|
-
"
|
268
|
+
sinatra.not_found do
|
269
|
+
"Unknown request: #{env['REQUEST_PATH']}\n"
|
230
270
|
end
|
231
271
|
|
232
|
-
|
272
|
+
sinatra.error do
|
233
273
|
"Error in minecraftctlserver while processing request '#{env['REQUEST_PATH']}': #{env['sinatra.error']}\n"
|
234
274
|
end
|
235
275
|
|
236
|
-
|
276
|
+
sinatra.run!
|
237
277
|
|
238
278
|
# make sure we stop the server on exit
|
239
|
-
|
279
|
+
if minecraft.running?
|
280
|
+
puts 'stopping minecraft'
|
281
|
+
minecraft.stop
|
282
|
+
end
|
240
283
|
end
|
241
284
|
end
|
242
285
|
|
data/lib/minecraft.rb
CHANGED
@@ -96,6 +96,12 @@ class Minecraft
|
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
|
+
class ServerNotRunningError < RuntimeError
|
100
|
+
def initialize
|
101
|
+
super 'server not running'
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
99
105
|
def initialize(cmd)
|
100
106
|
@cmd = cmd
|
101
107
|
@in_queue = Queue.new
|
@@ -191,6 +197,7 @@ class Minecraft
|
|
191
197
|
|
192
198
|
unless running?
|
193
199
|
Process.wait(@server_pid)
|
200
|
+
@server_pid = nil
|
194
201
|
raise StartupFailedError, @cmd
|
195
202
|
end
|
196
203
|
rescue Errno::ENOENT
|
@@ -207,10 +214,11 @@ class Minecraft
|
|
207
214
|
command('stop') do
|
208
215
|
time_operation("Server stop") do
|
209
216
|
Process.wait(@server_pid)
|
217
|
+
@server_pid = nil
|
210
218
|
log "Server stopped"
|
211
219
|
end
|
212
220
|
|
213
|
-
wait_msg{|m| m.msg == "
|
221
|
+
wait_msg{|m| m.msg == "Minecraft exits"}
|
214
222
|
end
|
215
223
|
end
|
216
224
|
end
|
@@ -234,7 +242,7 @@ class Minecraft
|
|
234
242
|
end
|
235
243
|
|
236
244
|
def command(cmd)
|
237
|
-
raise
|
245
|
+
raise ServerNotRunningError unless running?
|
238
246
|
@in_queue << "#{cmd}\n"
|
239
247
|
if block_given?
|
240
248
|
yield
|
data/minecraftctl.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "minecraftctl"
|
8
|
-
s.version = "
|
8
|
+
s.version = "2.0.0"
|
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"]
|
12
|
-
s.date = "2011-09-
|
12
|
+
s.date = "2011-09-26"
|
13
13
|
s.description = "Allows to send messages, start and stop Minecraft server"
|
14
14
|
s.email = "jpastuszek@gmail.com"
|
15
15
|
s.executables = ["minecraftctl", "minecraftctlserver", "minecraftctl", "minecraftctlserver"]
|
@@ -56,10 +56,10 @@ Gem::Specification.new do |s|
|
|
56
56
|
s.add_development_dependency(%q<roodi>, ["~> 2.1.0"])
|
57
57
|
s.add_development_dependency(%q<sinatra>, [">= 1.2.6"])
|
58
58
|
s.add_development_dependency(%q<main>, [">= 4.7.3"])
|
59
|
-
s.add_development_dependency(%q<haml>, [">= 3.1.3"])
|
60
59
|
s.add_development_dependency(%q<httpclient>, [">= 2.2.1"])
|
61
|
-
s.add_development_dependency(%q<open4>, [">= 1.1.0"])
|
62
60
|
s.add_development_dependency(%q<mongrel>, [">= 1.1.5"])
|
61
|
+
s.add_development_dependency(%q<mongrel>, [">= 1.1.5"])
|
62
|
+
s.add_development_dependency(%q<daemon>, ["~> 1"])
|
63
63
|
else
|
64
64
|
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
65
65
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
@@ -69,10 +69,10 @@ Gem::Specification.new do |s|
|
|
69
69
|
s.add_dependency(%q<roodi>, ["~> 2.1.0"])
|
70
70
|
s.add_dependency(%q<sinatra>, [">= 1.2.6"])
|
71
71
|
s.add_dependency(%q<main>, [">= 4.7.3"])
|
72
|
-
s.add_dependency(%q<haml>, [">= 3.1.3"])
|
73
72
|
s.add_dependency(%q<httpclient>, [">= 2.2.1"])
|
74
|
-
s.add_dependency(%q<open4>, [">= 1.1.0"])
|
75
73
|
s.add_dependency(%q<mongrel>, [">= 1.1.5"])
|
74
|
+
s.add_dependency(%q<mongrel>, [">= 1.1.5"])
|
75
|
+
s.add_dependency(%q<daemon>, ["~> 1"])
|
76
76
|
end
|
77
77
|
else
|
78
78
|
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
@@ -83,10 +83,10 @@ Gem::Specification.new do |s|
|
|
83
83
|
s.add_dependency(%q<roodi>, ["~> 2.1.0"])
|
84
84
|
s.add_dependency(%q<sinatra>, [">= 1.2.6"])
|
85
85
|
s.add_dependency(%q<main>, [">= 4.7.3"])
|
86
|
-
s.add_dependency(%q<haml>, [">= 3.1.3"])
|
87
86
|
s.add_dependency(%q<httpclient>, [">= 2.2.1"])
|
88
|
-
s.add_dependency(%q<open4>, [">= 1.1.0"])
|
89
87
|
s.add_dependency(%q<mongrel>, [">= 1.1.5"])
|
88
|
+
s.add_dependency(%q<mongrel>, [">= 1.1.5"])
|
89
|
+
s.add_dependency(%q<daemon>, ["~> 1"])
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
@@ -1,92 +1,146 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
require 'httpclient'
|
3
|
-
require 'open4'
|
4
3
|
require 'timeout'
|
4
|
+
require 'spawn'
|
5
5
|
|
6
|
+
$url = 'http://localhost:25560'
|
6
7
|
|
7
|
-
|
8
|
+
def get(uri)
|
9
|
+
HTTPClient.new.get_content($url + uri)
|
10
|
+
end
|
8
11
|
|
9
|
-
def
|
10
|
-
|
12
|
+
def get_with_status(uri)
|
13
|
+
res = HTTPClient.new.get($url + uri)
|
14
|
+
return res.status, res.body
|
15
|
+
end
|
11
16
|
|
12
|
-
|
13
|
-
|
14
|
-
Timeout.timeout(10) do
|
15
|
-
begin
|
16
|
-
c.get_content($url + "status")
|
17
|
-
rescue Errno::ECONNREFUSED
|
18
|
-
sleep 0.4
|
19
|
-
retry
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
17
|
+
def post(uri, data)
|
18
|
+
HTTPClient.new.post_content($url + uri, data)
|
23
19
|
end
|
24
20
|
|
25
|
-
def
|
26
|
-
HTTPClient.new.
|
21
|
+
def post_with_status(uri, data)
|
22
|
+
res = HTTPClient.new.post($url + uri, data)
|
23
|
+
return res.status, res.body
|
24
|
+
end
|
25
|
+
|
26
|
+
def start_stub
|
27
|
+
pid, stdin, stdout, stderr = Spawn::spawn(File.dirname(__FILE__) + '/../bin/minecraftctlserver -c ./minecraft ' + File.dirname(__FILE__) + '/stub_server')
|
27
28
|
|
28
29
|
Timeout.timeout(10) do
|
29
30
|
begin
|
30
|
-
|
31
|
-
HTTPClient.new.get_content($url + "status")
|
32
|
-
sleep 0.4
|
33
|
-
end
|
31
|
+
@pid_file = get('/pid_file').strip
|
34
32
|
rescue Errno::ECONNREFUSED
|
35
|
-
|
36
|
-
|
33
|
+
sleep 0.1
|
34
|
+
retry
|
37
35
|
end
|
38
36
|
end
|
39
|
-
|
37
|
+
end
|
38
|
+
|
39
|
+
def stop_stub
|
40
|
+
post('/', 'shutdown')
|
41
|
+
|
42
|
+
# wait pid lock release
|
43
|
+
File.open(@pid_file) do |pf|
|
44
|
+
pf.flock(File::LOCK_EX)
|
45
|
+
end
|
40
46
|
end
|
41
47
|
|
42
48
|
describe 'minecraftctlserver' do
|
43
|
-
describe '
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
49
|
+
describe 'while server ready it should respond to' do
|
50
|
+
before :all do
|
51
|
+
start_stub
|
52
|
+
end
|
48
53
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
begin
|
53
|
-
out = HTTPClient.new.get_content($url + "status")
|
54
|
-
rescue Errno::ECONNREFUSED
|
55
|
-
sleep 0.4
|
56
|
-
retry
|
57
|
-
end
|
58
|
-
|
59
|
-
out.should =~ /Minecraft server is running with pid:/
|
60
|
-
end
|
61
|
-
end
|
54
|
+
it 'GET / with API command list' do
|
55
|
+
get('/').should include 'minecraft control server API'
|
56
|
+
end
|
62
57
|
|
63
|
-
|
64
|
-
|
65
|
-
|
58
|
+
it 'GET /pid_file with absolute PID file path' do
|
59
|
+
get('/pid_file').should match(%r{/.*spec/stub_server/minecraftctlserver.pid\n$})
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'GET /log_file with absolute log file path' do
|
63
|
+
get('/log_file').should match(%r{/.*spec/stub_server/minecraftctlserver.log\n$})
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'GET /pid with PID number of control server process' do
|
67
|
+
get('/pid').to_i.should > 0
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'GET /dir with absolute directory path where minecraft server is running from' do
|
71
|
+
get('/dir').should match(%r{/.*spec/stub_server\n$})
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'GET /out with content of minecraft server output' do
|
75
|
+
get('/out').should include "Loading properties\n"
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'stop and start with POST /server stop and POST /server start' do
|
79
|
+
post('/server', 'stop').should include "Server stopped\n"
|
80
|
+
post('/server', 'start').should include "Done (5887241893ns)! For help, type \"help\" or \"?\"\n"
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'POST /server start with server aleady running' do
|
84
|
+
post('/server', 'start').should include "Server already running\n"
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'GET /server/status with running' do
|
88
|
+
get('/server/status').should == "running\n"
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'GET /server/pid with PID number of minecraft server process' do
|
92
|
+
get('/server/pid').to_i.should > 0
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'POST /server/console list with list of connected players' do
|
96
|
+
post('/server', 'console list').should == "Connected players: kazuya\n"
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'POST /server/console with error' do
|
100
|
+
post('/server', 'console').should == "Console command not specified; try 'console help'\n"
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'POST / blah with error' do
|
104
|
+
status, body = post_with_status('/', 'blah')
|
105
|
+
status.should == 400
|
106
|
+
body.should == "Unknown argument: blah for request: /\n"
|
66
107
|
end
|
67
108
|
|
68
|
-
|
109
|
+
it 'GET /blah with error' do
|
110
|
+
status, body = get_with_status('/blah')
|
111
|
+
status.should == 404
|
112
|
+
body.should == "Unknown request: /blah\n"
|
113
|
+
end
|
114
|
+
|
115
|
+
describe '(having minecraft server stopped)' do
|
69
116
|
before :all do
|
70
|
-
|
117
|
+
post('/server', 'stop')
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'POST /server stop with server aleady stopped' do
|
121
|
+
post('/server', 'stop').should include "Server already stopped\n"
|
71
122
|
end
|
72
123
|
|
73
|
-
it '
|
74
|
-
|
124
|
+
it 'GET /server/status with stopped' do
|
125
|
+
get('/server/status').should == "stopped\n"
|
75
126
|
end
|
76
127
|
|
77
|
-
it '
|
78
|
-
|
79
|
-
HTTPClient.new.post_content($url + "start", '').should include 'Done (5887241893ns)! For help, type "help" or "?"'
|
128
|
+
it 'GET /server/pid with error' do
|
129
|
+
get('/server/pid').should == "Server not running\n"
|
80
130
|
end
|
81
131
|
|
82
|
-
it '
|
83
|
-
|
132
|
+
it 'POST /server/console list with error' do
|
133
|
+
post('/server', 'console list').should == "Server not running\n"
|
84
134
|
end
|
85
135
|
|
86
136
|
after :all do
|
87
|
-
|
137
|
+
post('/server', 'start')
|
88
138
|
end
|
89
139
|
end
|
140
|
+
|
141
|
+
after :all do
|
142
|
+
stop_stub
|
143
|
+
end
|
90
144
|
end
|
91
145
|
end
|
92
146
|
|
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: 15
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
|
-
-
|
8
|
-
- 1
|
7
|
+
- 2
|
9
8
|
- 0
|
10
|
-
|
9
|
+
- 0
|
10
|
+
version: 2.0.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jakub Pastuszek
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-09-
|
18
|
+
date: 2011-09-26 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
requirement: &id001 !ruby/object:Gem::Requirement
|
@@ -151,12 +151,12 @@ dependencies:
|
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
hash: 5
|
153
153
|
segments:
|
154
|
-
-
|
154
|
+
- 2
|
155
|
+
- 2
|
155
156
|
- 1
|
156
|
-
|
157
|
-
version: 3.1.3
|
157
|
+
version: 2.2.1
|
158
158
|
version_requirements: *id009
|
159
|
-
name:
|
159
|
+
name: httpclient
|
160
160
|
prerelease: false
|
161
161
|
type: :development
|
162
162
|
- !ruby/object:Gem::Dependency
|
@@ -165,14 +165,14 @@ dependencies:
|
|
165
165
|
requirements:
|
166
166
|
- - ">="
|
167
167
|
- !ruby/object:Gem::Version
|
168
|
-
hash:
|
168
|
+
hash: 25
|
169
169
|
segments:
|
170
|
-
- 2
|
171
|
-
- 2
|
172
170
|
- 1
|
173
|
-
|
171
|
+
- 1
|
172
|
+
- 5
|
173
|
+
version: 1.1.5
|
174
174
|
version_requirements: *id010
|
175
|
-
name:
|
175
|
+
name: mongrel
|
176
176
|
prerelease: false
|
177
177
|
type: :development
|
178
178
|
- !ruby/object:Gem::Dependency
|
@@ -181,30 +181,28 @@ dependencies:
|
|
181
181
|
requirements:
|
182
182
|
- - ">="
|
183
183
|
- !ruby/object:Gem::Version
|
184
|
-
hash:
|
184
|
+
hash: 25
|
185
185
|
segments:
|
186
186
|
- 1
|
187
187
|
- 1
|
188
|
-
-
|
189
|
-
version: 1.1.
|
188
|
+
- 5
|
189
|
+
version: 1.1.5
|
190
190
|
version_requirements: *id011
|
191
|
-
name:
|
191
|
+
name: mongrel
|
192
192
|
prerelease: false
|
193
193
|
type: :development
|
194
194
|
- !ruby/object:Gem::Dependency
|
195
195
|
requirement: &id012 !ruby/object:Gem::Requirement
|
196
196
|
none: false
|
197
197
|
requirements:
|
198
|
-
- -
|
198
|
+
- - ~>
|
199
199
|
- !ruby/object:Gem::Version
|
200
|
-
hash:
|
200
|
+
hash: 1
|
201
201
|
segments:
|
202
202
|
- 1
|
203
|
-
|
204
|
-
- 5
|
205
|
-
version: 1.1.5
|
203
|
+
version: "1"
|
206
204
|
version_requirements: *id012
|
207
|
-
name:
|
205
|
+
name: daemon
|
208
206
|
prerelease: false
|
209
207
|
type: :development
|
210
208
|
description: Allows to send messages, start and stop Minecraft server
|