minecraftctl 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +62 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +29 -0
- data/Rakefile +64 -0
- data/VERSION +1 -0
- data/bin/minecraftctl +50 -0
- data/bin/minecraftctlserver +348 -0
- data/lib/minecraftctl.rb +0 -0
- data/minecraftctl.gemspec +81 -0
- data/spec/minecraftctl_spec.rb +7 -0
- data/spec/spec_helper.rb +12 -0
- metadata +237 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
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 "haml", ">= 3.1.3"
|
18
|
+
gem "httpclient", ">= 2.2.1"
|
19
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
arrayfields (4.7.4)
|
5
|
+
chronic (0.6.4)
|
6
|
+
diff-lcs (1.1.3)
|
7
|
+
fattr (2.2.0)
|
8
|
+
git (1.2.5)
|
9
|
+
haml (3.1.3)
|
10
|
+
httpclient (2.2.1)
|
11
|
+
jeweler (1.6.4)
|
12
|
+
bundler (~> 1.0)
|
13
|
+
git (>= 1.2.5)
|
14
|
+
rake
|
15
|
+
main (4.7.3)
|
16
|
+
arrayfields (~> 4.7.4)
|
17
|
+
chronic (~> 0.6.2)
|
18
|
+
fattr (~> 2.2.0)
|
19
|
+
map (~> 4.3.0)
|
20
|
+
map (4.3.0)
|
21
|
+
rack (1.3.2)
|
22
|
+
rake (0.9.2)
|
23
|
+
rcov (0.9.10)
|
24
|
+
reek (1.2.8)
|
25
|
+
ruby2ruby (~> 1.2)
|
26
|
+
ruby_parser (~> 2.0)
|
27
|
+
sexp_processor (~> 3.0)
|
28
|
+
roodi (2.1.0)
|
29
|
+
ruby_parser
|
30
|
+
rspec (2.3.0)
|
31
|
+
rspec-core (~> 2.3.0)
|
32
|
+
rspec-expectations (~> 2.3.0)
|
33
|
+
rspec-mocks (~> 2.3.0)
|
34
|
+
rspec-core (2.3.1)
|
35
|
+
rspec-expectations (2.3.0)
|
36
|
+
diff-lcs (~> 1.1.2)
|
37
|
+
rspec-mocks (2.3.0)
|
38
|
+
ruby2ruby (1.3.0)
|
39
|
+
ruby_parser (~> 2.0)
|
40
|
+
sexp_processor (~> 3.0)
|
41
|
+
ruby_parser (2.3.0)
|
42
|
+
sexp_processor (~> 3.0)
|
43
|
+
sexp_processor (3.0.6)
|
44
|
+
sinatra (1.2.6)
|
45
|
+
rack (~> 1.1)
|
46
|
+
tilt (>= 1.2.2, < 2.0)
|
47
|
+
tilt (1.3.3)
|
48
|
+
|
49
|
+
PLATFORMS
|
50
|
+
ruby
|
51
|
+
|
52
|
+
DEPENDENCIES
|
53
|
+
bundler (~> 1.0.0)
|
54
|
+
haml (>= 3.1.3)
|
55
|
+
httpclient (>= 2.2.1)
|
56
|
+
jeweler (~> 1.6.4)
|
57
|
+
main (>= 4.7.3)
|
58
|
+
rcov
|
59
|
+
reek (~> 1.2.8)
|
60
|
+
roodi (~> 2.1.0)
|
61
|
+
rspec (~> 2.3.0)
|
62
|
+
sinatra (>= 1.2.6)
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Jakub Pastuszek
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
= minecraftctl
|
2
|
+
|
3
|
+
Allows running Minecraft server in background (daemon) and send commands, stop, start etc. with minecraftctl command.
|
4
|
+
|
5
|
+
== Usage
|
6
|
+
|
7
|
+
Lounch Minecraft server with:
|
8
|
+
|
9
|
+
$ minecraftctlserver <path to minecraft server install dir>
|
10
|
+
|
11
|
+
And control it with 'minecraftctl', for help try:
|
12
|
+
|
13
|
+
$ minecraftctl serverhelp
|
14
|
+
|
15
|
+
== Contributing to minecraftctl
|
16
|
+
|
17
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
18
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
19
|
+
* Fork the project
|
20
|
+
* Start a feature/bugfix branch
|
21
|
+
* Commit and push until you are happy with your contribution
|
22
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
23
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
24
|
+
|
25
|
+
== Copyright
|
26
|
+
|
27
|
+
Copyright (c) 2011 Jakub Pastuszek. See LICENSE.txt for
|
28
|
+
further details.
|
29
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "minecraftctl"
|
18
|
+
gem.homepage = "http://github.com/jpastuszek/minecraftctl"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = "Minecraft server control"
|
21
|
+
gem.description = "Allows to send messages, start and stop Minecraft server"
|
22
|
+
gem.email = "jpastuszek@gmail.com"
|
23
|
+
gem.authors = ["Jakub Pastuszek"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
gem.executables << 'minecraftctl'
|
26
|
+
gem.executables << 'minecraftctlserver'
|
27
|
+
end
|
28
|
+
Jeweler::RubygemsDotOrgTasks.new
|
29
|
+
|
30
|
+
require 'rspec/core'
|
31
|
+
require 'rspec/core/rake_task'
|
32
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
33
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
34
|
+
end
|
35
|
+
|
36
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
37
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
38
|
+
spec.rcov = true
|
39
|
+
end
|
40
|
+
|
41
|
+
require 'reek/rake/task'
|
42
|
+
Reek::Rake::Task.new do |t|
|
43
|
+
t.fail_on_error = true
|
44
|
+
t.verbose = false
|
45
|
+
t.source_files = 'lib/**/*.rb'
|
46
|
+
end
|
47
|
+
|
48
|
+
require 'roodi'
|
49
|
+
require 'roodi_task'
|
50
|
+
RoodiTask.new do |t|
|
51
|
+
t.verbose = false
|
52
|
+
end
|
53
|
+
|
54
|
+
task :default => :spec
|
55
|
+
|
56
|
+
require 'rake/rdoctask'
|
57
|
+
Rake::RDocTask.new do |rdoc|
|
58
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
59
|
+
|
60
|
+
rdoc.rdoc_dir = 'rdoc'
|
61
|
+
rdoc.title = "minecraftctl #{version}"
|
62
|
+
rdoc.rdoc_files.include('README*')
|
63
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
64
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
data/bin/minecraftctl
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'main'
|
4
|
+
require 'httpclient'
|
5
|
+
|
6
|
+
Main do
|
7
|
+
description 'controls Minecraft via minecraftctlserver'
|
8
|
+
|
9
|
+
option 'server', 's' do
|
10
|
+
default 'localhost'
|
11
|
+
description 'minecraftctlserver address'
|
12
|
+
end
|
13
|
+
|
14
|
+
option 'port', 'p' do
|
15
|
+
default 25560
|
16
|
+
description 'minecraftctlserver port'
|
17
|
+
end
|
18
|
+
|
19
|
+
argument 'command' do
|
20
|
+
description 'command to send to Minecraft server: try "serverhelp"'
|
21
|
+
end
|
22
|
+
|
23
|
+
argument 'arguments' do
|
24
|
+
required false
|
25
|
+
arity -1
|
26
|
+
end
|
27
|
+
|
28
|
+
run do
|
29
|
+
c = HTTPClient.new
|
30
|
+
|
31
|
+
begin
|
32
|
+
command = case params['command'].value
|
33
|
+
when 'serverhelp'
|
34
|
+
'help'
|
35
|
+
else
|
36
|
+
params['command'].value
|
37
|
+
end
|
38
|
+
|
39
|
+
args = params['arguments'].values
|
40
|
+
|
41
|
+
if ['log', 'inspect', 'list', 'help'].include? command
|
42
|
+
puts c.get_content("http://#{params['server'].value}:#{params['port'].value}/#{command}")
|
43
|
+
else
|
44
|
+
puts c.post_content("http://#{params['server'].value}:#{params['port'].value}/#{command}", args.join("\n"))
|
45
|
+
end
|
46
|
+
rescue Errno::ECONNREFUSED => e
|
47
|
+
puts "Falied to connect to minecraftctlserver; please run minecraftctlserver: #{e}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,348 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'main'
|
4
|
+
require 'open3'
|
5
|
+
require 'thread'
|
6
|
+
require 'pathname'
|
7
|
+
|
8
|
+
class Message
|
9
|
+
def initialize(msg)
|
10
|
+
@msg = msg
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :msg
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
@msg
|
17
|
+
end
|
18
|
+
|
19
|
+
class Internal < Message
|
20
|
+
def initialize(msg)
|
21
|
+
super(' -- ' + msg)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Out < Message
|
26
|
+
end
|
27
|
+
|
28
|
+
class Err < Message
|
29
|
+
def initialize(line)
|
30
|
+
x, @time, @level, @msg = *line.match(/^([^ ]* [^ ]*) \[([^\]]*)\] (.*)/)
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader :time, :level, :msg
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
@msg
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Minecraft
|
42
|
+
def initialize(cmd)
|
43
|
+
@cmd = cmd
|
44
|
+
@in_queue = Queue.new
|
45
|
+
@out_queue = Queue.new
|
46
|
+
|
47
|
+
@running = false
|
48
|
+
|
49
|
+
@history = []
|
50
|
+
@recent = []
|
51
|
+
end
|
52
|
+
|
53
|
+
def running?
|
54
|
+
@running
|
55
|
+
end
|
56
|
+
|
57
|
+
def start
|
58
|
+
collect_msg do
|
59
|
+
if @running
|
60
|
+
internal_msg "Server already running"
|
61
|
+
else
|
62
|
+
time_operation("Server start") do
|
63
|
+
@stdin, stdout, stderr = Open3.popen3(@cmd)
|
64
|
+
@running = true
|
65
|
+
|
66
|
+
@out_reader = Thread.new do
|
67
|
+
stdout.each do |line|
|
68
|
+
puts "OUT: #{line}"
|
69
|
+
@out_queue << Message::Out.new(line)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
@err_reader = Thread.new do
|
74
|
+
stderr.each do |line|
|
75
|
+
puts "ERR: #{line}"
|
76
|
+
@out_queue << Message::Err.new(line)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
wait_msg do |m|
|
81
|
+
m.msg =~ /Done \(([^n]*)ns\)!/
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def stop
|
89
|
+
unless @running
|
90
|
+
return collect_msg do
|
91
|
+
internal_msg "Server already stopped"
|
92
|
+
end
|
93
|
+
else
|
94
|
+
return command('stop') do
|
95
|
+
@running = false
|
96
|
+
time_operation("Server stop") do
|
97
|
+
@out_reader.join
|
98
|
+
@err_reader.join
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def save_all
|
105
|
+
command('save-all') do
|
106
|
+
time_operation("Save") do
|
107
|
+
wait_msg{|m| m.msg =~ /Save complete/}
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def list
|
113
|
+
command('list') do
|
114
|
+
wait_msg{|m| m.msg =~ /Connected players:/}
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def command(cmd)
|
119
|
+
raise RuntimeError, "server not running" unless @running
|
120
|
+
collect_msg do
|
121
|
+
@stdin.write("#{cmd}\n")
|
122
|
+
if block_given?
|
123
|
+
yield
|
124
|
+
else
|
125
|
+
active_wait
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def history
|
131
|
+
archive_msg
|
132
|
+
@history
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def flush_msg
|
138
|
+
until @out_queue.empty?
|
139
|
+
@recent << @out_queue.pop(true)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def archive_msg
|
144
|
+
flush_msg
|
145
|
+
recent = @recent.dup
|
146
|
+
@history += @recent
|
147
|
+
@recent.clear
|
148
|
+
recent
|
149
|
+
end
|
150
|
+
|
151
|
+
def collect_msg
|
152
|
+
archive_msg
|
153
|
+
yield
|
154
|
+
archive_msg
|
155
|
+
end
|
156
|
+
|
157
|
+
def internal_msg(msg)
|
158
|
+
@out_queue << Message::Internal.new(msg)
|
159
|
+
end
|
160
|
+
|
161
|
+
def time_operation(name)
|
162
|
+
start = Time.now
|
163
|
+
yield
|
164
|
+
internal_msg "#{name} finished in #{(Time.now - start).to_f}"
|
165
|
+
end
|
166
|
+
|
167
|
+
def wait_msg(discard = false)
|
168
|
+
loop do
|
169
|
+
msg = @out_queue.pop
|
170
|
+
if yield msg
|
171
|
+
@recent << msg unless discard
|
172
|
+
break
|
173
|
+
end
|
174
|
+
@recent << msg
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def active_wait
|
179
|
+
@stdin.write("list\n")
|
180
|
+
wait_msg(true){|m| m.msg =~ /Connected players:/}
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
class Daemon
|
186
|
+
def self.daemonize(pid_file, log_file = nil)
|
187
|
+
exit if fork
|
188
|
+
Process.setsid # become session leader
|
189
|
+
exit if fork # and exits
|
190
|
+
# now in child
|
191
|
+
|
192
|
+
# try to lock before we kill stdin/out
|
193
|
+
lock(pid_file)
|
194
|
+
|
195
|
+
if log_file
|
196
|
+
log = File.open(log_file, 'a')
|
197
|
+
else
|
198
|
+
log = '/dev/null'
|
199
|
+
end
|
200
|
+
|
201
|
+
# disconnect
|
202
|
+
STDIN.reopen '/dev/null'
|
203
|
+
STDOUT.reopen log
|
204
|
+
STDERR.reopen log
|
205
|
+
end
|
206
|
+
|
207
|
+
def self.lock(pid_file)
|
208
|
+
pf = File.open(pid_file, 'r+')
|
209
|
+
fail "Server already running with pid: #{pf.read}" unless pf.flock(File::LOCK_EX|File::LOCK_NB)
|
210
|
+
pf.truncate(0)
|
211
|
+
pf.write(Process.pid.to_s)
|
212
|
+
pf.flush
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
Main do
|
217
|
+
description 'lounches Minecraft server that can be controlled via HTTP'
|
218
|
+
|
219
|
+
option 'command', 'c' do
|
220
|
+
default 'java -Xms256M -Xmx512M -Djava.net.preferIPv4Stack=true -jar minecraft_server.jar nogui'
|
221
|
+
description 'command to be used to span server'
|
222
|
+
end
|
223
|
+
|
224
|
+
option 'port', 'p' do
|
225
|
+
default 25560
|
226
|
+
description 'port on which the control HTTP server should be running'
|
227
|
+
end
|
228
|
+
|
229
|
+
option 'foreground', 'f' do
|
230
|
+
description 'don\'t daemonize'
|
231
|
+
end
|
232
|
+
|
233
|
+
option 'pid-file', 'P' do
|
234
|
+
description 'pid file relative to minecraft-dir'
|
235
|
+
default 'minecraftctlserver.pid'
|
236
|
+
end
|
237
|
+
|
238
|
+
option 'log-file', 'l' do
|
239
|
+
description 'log file relative to minecraft-dir when in not in foreground'
|
240
|
+
default 'minecraftctlserver.log'
|
241
|
+
end
|
242
|
+
|
243
|
+
argument 'minecraft-dir' do
|
244
|
+
description 'directory path to mincraft server installation directory'
|
245
|
+
end
|
246
|
+
|
247
|
+
run do
|
248
|
+
pid_file = Pathname.new(params['minecraft-dir'].value) + params['pid-file'].value
|
249
|
+
log_file = Pathname.new(params['minecraft-dir'].value) + params['log-file'].value
|
250
|
+
|
251
|
+
if params['foreground'].given?
|
252
|
+
Daemon.lock(pid_file)
|
253
|
+
else
|
254
|
+
Daemon.daemonize(pid_file, log_file)
|
255
|
+
end
|
256
|
+
|
257
|
+
require 'sinatra/base'
|
258
|
+
require 'haml'
|
259
|
+
|
260
|
+
Dir.chdir(params['minecraft-dir'].value)
|
261
|
+
|
262
|
+
minecraft = Minecraft.new(params['command'].value)
|
263
|
+
|
264
|
+
minecraft.start
|
265
|
+
|
266
|
+
s = Sinatra.new
|
267
|
+
s.set :port, params['port'].value
|
268
|
+
|
269
|
+
s.post '/save-all' do
|
270
|
+
@msg = minecraft.save_all
|
271
|
+
haml :messages
|
272
|
+
end
|
273
|
+
|
274
|
+
s.post '/start' do
|
275
|
+
@msg = minecraft.start
|
276
|
+
haml :messages
|
277
|
+
end
|
278
|
+
|
279
|
+
s.post '/stop' do
|
280
|
+
@msg = minecraft.stop
|
281
|
+
haml :messages
|
282
|
+
end
|
283
|
+
|
284
|
+
s.post '/shutdown' do
|
285
|
+
@msg = minecraft.stop
|
286
|
+
|
287
|
+
pid = Process.pid
|
288
|
+
Thread.new{ sleep 1; Process.kill(15, pid)}
|
289
|
+
|
290
|
+
haml :messages
|
291
|
+
end
|
292
|
+
|
293
|
+
s.post %r{/(.+)} do |cmd|
|
294
|
+
args = request.body.read.split("\n")
|
295
|
+
@msg = minecraft.command(cmd + " " + args.join(' '))
|
296
|
+
haml :messages
|
297
|
+
end
|
298
|
+
|
299
|
+
s.get '/help' do
|
300
|
+
start = false
|
301
|
+
@msg = minecraft.command('help').
|
302
|
+
map{|m| m.msg}.
|
303
|
+
select do |m|
|
304
|
+
next true if start
|
305
|
+
if m =~ /Console commands:/
|
306
|
+
start = true
|
307
|
+
next false
|
308
|
+
end
|
309
|
+
end.
|
310
|
+
map{|m| m.sub(/help or \?/, 'serverhelp ')}.
|
311
|
+
map{|m| m.sub(/^( |\t)*/, '')}
|
312
|
+
@msg << "log show recent server messages"
|
313
|
+
@msg << "inspect inspect recent server messages"
|
314
|
+
|
315
|
+
haml :messages
|
316
|
+
end
|
317
|
+
|
318
|
+
s.get '/list' do
|
319
|
+
@msg = minecraft.list
|
320
|
+
haml :messages
|
321
|
+
end
|
322
|
+
|
323
|
+
s.get '/inspect' do
|
324
|
+
@msg = minecraft.history
|
325
|
+
haml :messages_inspect
|
326
|
+
end
|
327
|
+
|
328
|
+
s.get '/log' do
|
329
|
+
@msg = minecraft.history
|
330
|
+
haml :messages
|
331
|
+
end
|
332
|
+
|
333
|
+
s.get %r{/(.+)} do |cmd|
|
334
|
+
@msg = minecraft.command(cmd)
|
335
|
+
haml :messages
|
336
|
+
end
|
337
|
+
|
338
|
+
s.template :messages do
|
339
|
+
'= @msg.join("\n")'
|
340
|
+
end
|
341
|
+
|
342
|
+
s.template :messages_inspect do
|
343
|
+
'= @msg.map{|m| m.inspect}.join("\n")'
|
344
|
+
end
|
345
|
+
|
346
|
+
s.run!
|
347
|
+
end
|
348
|
+
end
|
data/lib/minecraftctl.rb
ADDED
File without changes
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "minecraftctl"
|
8
|
+
s.version = "1.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Jakub Pastuszek"]
|
12
|
+
s.date = "2011-09-10"
|
13
|
+
s.description = "Allows to send messages, start and stop Minecraft server"
|
14
|
+
s.email = "jpastuszek@gmail.com"
|
15
|
+
s.executables = ["minecraftctl", "minecraftctlserver", "minecraftctl", "minecraftctlserver"]
|
16
|
+
s.extra_rdoc_files = [
|
17
|
+
"LICENSE.txt",
|
18
|
+
"README.rdoc"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
".document",
|
22
|
+
".rspec",
|
23
|
+
"Gemfile",
|
24
|
+
"Gemfile.lock",
|
25
|
+
"LICENSE.txt",
|
26
|
+
"README.rdoc",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"bin/minecraftctl",
|
30
|
+
"bin/minecraftctlserver",
|
31
|
+
"lib/minecraftctl.rb",
|
32
|
+
"minecraftctl.gemspec",
|
33
|
+
"spec/minecraftctl_spec.rb",
|
34
|
+
"spec/spec_helper.rb"
|
35
|
+
]
|
36
|
+
s.homepage = "http://github.com/jpastuszek/minecraftctl"
|
37
|
+
s.licenses = ["MIT"]
|
38
|
+
s.require_paths = ["lib"]
|
39
|
+
s.rubygems_version = "1.8.10"
|
40
|
+
s.summary = "Minecraft server control"
|
41
|
+
|
42
|
+
if s.respond_to? :specification_version then
|
43
|
+
s.specification_version = 3
|
44
|
+
|
45
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
46
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
|
47
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
48
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
|
49
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
50
|
+
s.add_development_dependency(%q<reek>, ["~> 1.2.8"])
|
51
|
+
s.add_development_dependency(%q<roodi>, ["~> 2.1.0"])
|
52
|
+
s.add_development_dependency(%q<sinatra>, [">= 1.2.6"])
|
53
|
+
s.add_development_dependency(%q<main>, [">= 4.7.3"])
|
54
|
+
s.add_development_dependency(%q<haml>, [">= 3.1.3"])
|
55
|
+
s.add_development_dependency(%q<httpclient>, [">= 2.2.1"])
|
56
|
+
else
|
57
|
+
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
58
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
59
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
60
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
61
|
+
s.add_dependency(%q<reek>, ["~> 1.2.8"])
|
62
|
+
s.add_dependency(%q<roodi>, ["~> 2.1.0"])
|
63
|
+
s.add_dependency(%q<sinatra>, [">= 1.2.6"])
|
64
|
+
s.add_dependency(%q<main>, [">= 4.7.3"])
|
65
|
+
s.add_dependency(%q<haml>, [">= 3.1.3"])
|
66
|
+
s.add_dependency(%q<httpclient>, [">= 2.2.1"])
|
67
|
+
end
|
68
|
+
else
|
69
|
+
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
70
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
71
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
72
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
73
|
+
s.add_dependency(%q<reek>, ["~> 1.2.8"])
|
74
|
+
s.add_dependency(%q<roodi>, ["~> 2.1.0"])
|
75
|
+
s.add_dependency(%q<sinatra>, [">= 1.2.6"])
|
76
|
+
s.add_dependency(%q<main>, [">= 4.7.3"])
|
77
|
+
s.add_dependency(%q<haml>, [">= 3.1.3"])
|
78
|
+
s.add_dependency(%q<httpclient>, [">= 2.2.1"])
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
require 'minecraftctl'
|
5
|
+
|
6
|
+
# Requires supporting files with custom matchers and macros, etc,
|
7
|
+
# in ./support/ and its subdirectories.
|
8
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
|
12
|
+
end
|
metadata
ADDED
@@ -0,0 +1,237 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: minecraftctl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Jakub Pastuszek
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-09-10 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
22
|
+
none: false
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
hash: 3
|
27
|
+
segments:
|
28
|
+
- 2
|
29
|
+
- 3
|
30
|
+
- 0
|
31
|
+
version: 2.3.0
|
32
|
+
version_requirements: *id001
|
33
|
+
name: rspec
|
34
|
+
prerelease: false
|
35
|
+
type: :development
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ~>
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 23
|
43
|
+
segments:
|
44
|
+
- 1
|
45
|
+
- 0
|
46
|
+
- 0
|
47
|
+
version: 1.0.0
|
48
|
+
version_requirements: *id002
|
49
|
+
name: bundler
|
50
|
+
prerelease: false
|
51
|
+
type: :development
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ~>
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 7
|
59
|
+
segments:
|
60
|
+
- 1
|
61
|
+
- 6
|
62
|
+
- 4
|
63
|
+
version: 1.6.4
|
64
|
+
version_requirements: *id003
|
65
|
+
name: jeweler
|
66
|
+
prerelease: false
|
67
|
+
type: :development
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
hash: 3
|
75
|
+
segments:
|
76
|
+
- 0
|
77
|
+
version: "0"
|
78
|
+
version_requirements: *id004
|
79
|
+
name: rcov
|
80
|
+
prerelease: false
|
81
|
+
type: :development
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ~>
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
hash: 15
|
89
|
+
segments:
|
90
|
+
- 1
|
91
|
+
- 2
|
92
|
+
- 8
|
93
|
+
version: 1.2.8
|
94
|
+
version_requirements: *id005
|
95
|
+
name: reek
|
96
|
+
prerelease: false
|
97
|
+
type: :development
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ~>
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
hash: 11
|
105
|
+
segments:
|
106
|
+
- 2
|
107
|
+
- 1
|
108
|
+
- 0
|
109
|
+
version: 2.1.0
|
110
|
+
version_requirements: *id006
|
111
|
+
name: roodi
|
112
|
+
prerelease: false
|
113
|
+
type: :development
|
114
|
+
- !ruby/object:Gem::Dependency
|
115
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
hash: 19
|
121
|
+
segments:
|
122
|
+
- 1
|
123
|
+
- 2
|
124
|
+
- 6
|
125
|
+
version: 1.2.6
|
126
|
+
version_requirements: *id007
|
127
|
+
name: sinatra
|
128
|
+
prerelease: false
|
129
|
+
type: :development
|
130
|
+
- !ruby/object:Gem::Dependency
|
131
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
132
|
+
none: false
|
133
|
+
requirements:
|
134
|
+
- - ">="
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
hash: 37
|
137
|
+
segments:
|
138
|
+
- 4
|
139
|
+
- 7
|
140
|
+
- 3
|
141
|
+
version: 4.7.3
|
142
|
+
version_requirements: *id008
|
143
|
+
name: main
|
144
|
+
prerelease: false
|
145
|
+
type: :development
|
146
|
+
- !ruby/object:Gem::Dependency
|
147
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
148
|
+
none: false
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
hash: 5
|
153
|
+
segments:
|
154
|
+
- 3
|
155
|
+
- 1
|
156
|
+
- 3
|
157
|
+
version: 3.1.3
|
158
|
+
version_requirements: *id009
|
159
|
+
name: haml
|
160
|
+
prerelease: false
|
161
|
+
type: :development
|
162
|
+
- !ruby/object:Gem::Dependency
|
163
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
164
|
+
none: false
|
165
|
+
requirements:
|
166
|
+
- - ">="
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
hash: 5
|
169
|
+
segments:
|
170
|
+
- 2
|
171
|
+
- 2
|
172
|
+
- 1
|
173
|
+
version: 2.2.1
|
174
|
+
version_requirements: *id010
|
175
|
+
name: httpclient
|
176
|
+
prerelease: false
|
177
|
+
type: :development
|
178
|
+
description: Allows to send messages, start and stop Minecraft server
|
179
|
+
email: jpastuszek@gmail.com
|
180
|
+
executables:
|
181
|
+
- minecraftctl
|
182
|
+
- minecraftctlserver
|
183
|
+
extensions: []
|
184
|
+
|
185
|
+
extra_rdoc_files:
|
186
|
+
- LICENSE.txt
|
187
|
+
- README.rdoc
|
188
|
+
files:
|
189
|
+
- .document
|
190
|
+
- .rspec
|
191
|
+
- Gemfile
|
192
|
+
- Gemfile.lock
|
193
|
+
- LICENSE.txt
|
194
|
+
- README.rdoc
|
195
|
+
- Rakefile
|
196
|
+
- VERSION
|
197
|
+
- bin/minecraftctl
|
198
|
+
- bin/minecraftctlserver
|
199
|
+
- lib/minecraftctl.rb
|
200
|
+
- minecraftctl.gemspec
|
201
|
+
- spec/minecraftctl_spec.rb
|
202
|
+
- spec/spec_helper.rb
|
203
|
+
homepage: http://github.com/jpastuszek/minecraftctl
|
204
|
+
licenses:
|
205
|
+
- MIT
|
206
|
+
post_install_message:
|
207
|
+
rdoc_options: []
|
208
|
+
|
209
|
+
require_paths:
|
210
|
+
- lib
|
211
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
212
|
+
none: false
|
213
|
+
requirements:
|
214
|
+
- - ">="
|
215
|
+
- !ruby/object:Gem::Version
|
216
|
+
hash: 3
|
217
|
+
segments:
|
218
|
+
- 0
|
219
|
+
version: "0"
|
220
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
221
|
+
none: false
|
222
|
+
requirements:
|
223
|
+
- - ">="
|
224
|
+
- !ruby/object:Gem::Version
|
225
|
+
hash: 3
|
226
|
+
segments:
|
227
|
+
- 0
|
228
|
+
version: "0"
|
229
|
+
requirements: []
|
230
|
+
|
231
|
+
rubyforge_project:
|
232
|
+
rubygems_version: 1.8.10
|
233
|
+
signing_key:
|
234
|
+
specification_version: 3
|
235
|
+
summary: Minecraft server control
|
236
|
+
test_files: []
|
237
|
+
|