mclaunch 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ lib/tags
19
+ tags
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ #Required Gems
4
+ gem "progressbar"
5
+ gem "logrotate"
6
+
7
+ # Specify your gem's dependencies in mclaunch.gemspec
8
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 odie
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # Mclaunch
2
+
3
+ mclaunch is a launcher for a craftbukkit server, that runs the
4
+ craftbukkit server in either a tmux or a GNU screen session.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'mclaunch'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install mclaunch
19
+
20
+ ## Usage
21
+
22
+ type "mclaunch --help" in a terminal for help
23
+
24
+ ## Contributing
25
+
26
+ 1. Fork it
27
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
28
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
29
+ 4. Push to the branch (`git push origin my-new-feature`)
30
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/mclaunch ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mclaunch'
@@ -0,0 +1,155 @@
1
+ module Mclaunch
2
+ # Commands to issue on minecraft server
3
+
4
+ class Commands
5
+ def initialize(runtime=nil, options=nil, tools=nil)
6
+ @runtime = runtime
7
+ @options = options
8
+ @tools = tools
9
+ @quiet = @options[:quiet]
10
+ @debug = @options[:debug]
11
+ end #end initialize
12
+
13
+ #setter for @runtime
14
+ def set_runtime(runtime)
15
+ @runtime = runtime
16
+ end #end set_runtime(runtime)
17
+
18
+ #setter for @options
19
+ def set_options(options)
20
+ @options = options
21
+ end #end set_options(options)
22
+
23
+ #Reload command
24
+ def reload
25
+ puts "sending reload command to server" unless @quiet
26
+ @runtime.send_command("reload")
27
+ end #end reload
28
+
29
+ #save-on command
30
+ def save_on
31
+ puts "sending save-on command to server" unless @quiet
32
+ @runtime.send_command("save-on")
33
+ end #end save_on
34
+
35
+ #save-off command
36
+ def save_off
37
+ puts "sending save-off command to server" unless @quiet
38
+ @runtime.send_command("save-off")
39
+ end #end save_off
40
+
41
+ #save-all command
42
+ def save_all
43
+ puts "sending save-all command to server" unless @quiet
44
+ @runtime.send_command("save-all")
45
+ end #end save_all
46
+
47
+ #defaultgamemode command
48
+ def change_gamemode(mode)
49
+ raise "\n False command: #{mode}\n\n Use:\n 0 or survival\n 1 or creative\n 2 or adventure" unless mode =~ /^([0-2]|(survival|creative|adventure))$/
50
+ puts "changing gamemode to \"#{mode}\"" unless @quiet
51
+ @runtime.send_command("defaultgamemode #{mode.to_i}") if mode =~ /^[0-2]$/
52
+ @runtime.send_command("defaultgamemode #{mode.to_s}") if mode =~ /^(survival|creative|adventure)$/
53
+ end #end change_gamemode(mode)
54
+
55
+ #difficulty command
56
+ def change_difficulty(difficulty)
57
+ raise "\n Command only available with minecraft-server.jar" unless @options[:server_executable].eql? "minecraft-server.jar"
58
+ raise "\n False command: #{difficulty}\n\n Use:\n 0 or peaceful\n 1 or easy\n 2 or normal\n 3 or hard" unless difficulty =~ /^([0-3]|(peaceful|easy|normal|hard))$/
59
+ puts "changing difficulty to \"#{difficulty}\"" unless @quiet
60
+ @runtime.send_command("difficulty #{difficulty.to_i}") if difficulty =~ /^[0-3]$/
61
+ @runtime.send_command("difficulty #{difficulty.to_s}") if difficulty =~ /^(peaceful|easy|normal|hard)i$/
62
+ end #end change_difficulty(difficulty)
63
+
64
+ #op command
65
+ def op(player)
66
+ cmd = "op #{player}"
67
+ online_mode = @tools.to_boolean(@runtime.get_server_properties['online-mode'])
68
+ is_player = @tools.is_minecraft_player?(player)
69
+ puts "adding \"#{player}\" to #{@options[:server_runtime_directory]}opts.txt" unless @quiet
70
+ if online_mode
71
+ @runtime.send_command(cmd) if is_player && @tools.is_op?(player)
72
+ else
73
+ @runtime.send_command(cmd)
74
+ end
75
+ end #end op(player)
76
+
77
+ #deop command
78
+ def deop(player)
79
+ puts "removing #{player} from #{@options[:server_runtime_directory]}opts.txt" unless @quiet
80
+ @runtime.send_command("deop #{player}") if @tools.is_op?(player)
81
+ end #end deop(player)
82
+
83
+ #kick player command
84
+ def kick_player(player)
85
+ puts "kicking #{player} from server" unless @quiet
86
+ @runtime.send_command("kick #{player}")
87
+ end #end kick_player(player, reason=nil)
88
+
89
+ #ban player command
90
+ def ban_player(player, reason=nil)
91
+ puts "banning #{player} from server" unless @quiet
92
+ reason_string = reason if reason.is_a?(String)
93
+ reason_string = @tools.array_to_string(reason) if reason.is_a?(Array)
94
+ @runtime.send_command("ban #{player} #{reason_string}")
95
+ end #end ban_player(player, reason=nil)
96
+
97
+ #ban ip command
98
+ def ban_ip(ip, reason=nil)
99
+ raise "This is not an IP address!" unless ip =~/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/
100
+ puts "banning \"#{ip}\ from server" unless @quiet
101
+ reason_string = reason if reason.is_a?(String)
102
+ reason_string = @tools.array_to_string(reason) if reason.is_a?(Array)
103
+ @runtime.send_command("ban-ip #{ip} #{reason_string}")
104
+ end #end ban_ip(ip, reason=nil)
105
+
106
+ #pardon player command
107
+ def pardon_player(player)
108
+ puts "removing ban for \"#{player}\"." unless @quiet
109
+ @runtime.send_command("pardon #{player}")
110
+ end #end pardon_player(player, reason=nil)
111
+
112
+ #pardon ip command
113
+ def pardon_ip(ip)
114
+ raise "This is not an IP address!" unless ip =~/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/
115
+ puts "removing ban for \"#{ip}\"." unless @quiet
116
+ @runtime.send_command("pardon-ip #{ip}")
117
+ end #end pardon_ip(ip, reason=nil)
118
+
119
+ #whitelist <on|off|list> command
120
+ def whitelist(cmd)
121
+ raise "Available commands are: on, off, list" unless cmd =~ /^(on|off|list)$/
122
+ unless @quiet
123
+ puts "turning whitelist on." if cmd.eql?("on")
124
+ puts "turning whitelist off." if cmd.eql?("off")
125
+ end
126
+ @runtime.send_command("whitelist #{cmd}")
127
+ end #end whitelist(cmd)
128
+
129
+ #whitelist add command
130
+ def whitelist_add(player)
131
+ cmd = "whitelist add #{player}"
132
+ online_mode = @tools.to_boolean(@runtime.get_server_properties['online-mode'])
133
+ is_player = @tools.is_minecraft_player?(player)
134
+ puts "adding \"#{player}\" to whitelist" unless @quiet
135
+ if online_mode
136
+ @runtime.send_command(cmd) if is_player
137
+ else
138
+ @runtime.send_command(cmd)
139
+ end
140
+ end #end whitelist_add(player)
141
+
142
+ #whitelist remove command
143
+ def whitelist_remove(player)
144
+ cmd = "whitelist remove #{player}"
145
+ online_mode = @tools.to_boolean(@runtime.get_server_properties['online-mode'])
146
+ is_player = @tools.is_minecraft_player?(player)
147
+ puts "removing \"#{player}\" to whitelist" unless @quiet
148
+ if online_mode
149
+ @runtime.send_command(cmd) if is_player && @tools.is_op?(player)
150
+ else
151
+ @runtime.send_command(cmd)
152
+ end
153
+ end #end whitelist_remove(player)
154
+ end #end Commands
155
+ end
@@ -0,0 +1,143 @@
1
+ module Mclaunch
2
+ # Runtime Class for Minecraft server
3
+
4
+ extend self
5
+ require 'logrotate'
6
+ require 'mclaunch'
7
+
8
+ class Runtime
9
+ def initialize(options=nil)
10
+ @options = options
11
+ @start_cmd = "java -Xms#{@options[:server_min_heap_memory]} -Xmx#{@options[:server_max_heap_memory]} #{@options[:server_additional_options]} -jar #{@options[:server_executable]}"
12
+ @path = options[:server_runtime_directory]
13
+ @quiet = @options[:quiet]
14
+ @debug = @options[:debug]
15
+ @multiplexer = @options[:server_terminal_multiplexer]
16
+ @multiplexer_session_name = @options[:server_terminal_multiplexer_name]
17
+ @multiplexer_session = @options[:server_terminal_multiplexer_session]
18
+ end #end initialize
19
+
20
+ #setter for @options
21
+ def set_options(options)
22
+ @options = options
23
+ end #end set_options(options)
24
+
25
+ #Run server
26
+ def run
27
+ puts "starting server now." unless @quiet
28
+ if @debug
29
+ puts "Command: #{@start_cmd}"
30
+ puts "Multiplexer: #{@multiplexer}"
31
+ end
32
+ Dir.chdir(@path)
33
+ create_tmux_session(@multiplexer_session_name)
34
+ start
35
+ sleep 1
36
+ if is_running?
37
+ puts "server is running now." unless @quiet
38
+ else
39
+ run
40
+ end
41
+ end #end run
42
+
43
+ #start server
44
+ def start
45
+ send_command(@start_cmd)
46
+ end #end start
47
+
48
+ #stop server
49
+ def stop
50
+ send_command("stop")
51
+ sleep 5
52
+ end #end stop
53
+
54
+ #halt
55
+ def halt
56
+ puts "halting server now." unless @quiet
57
+ stop
58
+ log_rotate
59
+ kill_tmux_session(@multiplexer_session_name)
60
+ puts "server haltet." unless @quiet
61
+ end #end halt
62
+
63
+ def restart
64
+ puts "restarting server now." unless @quiet
65
+ stop
66
+ start
67
+ if is_running?
68
+ puts "server restart complete" unless @quiet
69
+ else
70
+ run
71
+ end
72
+ end
73
+
74
+ #check is server is running
75
+ def is_running?
76
+ puts "check if server is running" if @debug
77
+ return true if `ps ax | grep -v grep | egrep "(minecraft|craftbukkit).jar" | wc -l`.to_i > 0
78
+ end #end is_running?
79
+
80
+ #Send a command to a running server
81
+ def send_command(cmd)
82
+ puts "sending \"#{cmd}\" to #{@multiplexer} session \"#{@multiplexer_session_name}\"" if @debug
83
+ `tmux -S #{@multiplexer_session} send -t #{@multiplexer_session_name} "#{cmd}" ENTER` if @multiplexer.eql?("tmux")
84
+ `screen -p 0 -S #{@multiplexer_session_name} -X eval 'stuff \"#{cmd}\"'\15` if @multiplexer.eql?("screen")
85
+ end #end send_command(cmd)
86
+
87
+ #Send a chat message as a server say command
88
+ def send_message(msg)
89
+ msg = "say #{msg}"
90
+ puts "sending \"#{msg}\" as server chat message" if @debug
91
+ send_command(msg)
92
+ end #end send_message(msg)
93
+
94
+ #Create a tmux session for the server to run in
95
+ def create_tmux_session(name)
96
+ puts "connecting to or creating a new #{@multiplexer} session now" if @debug
97
+ `tmux -S #{@multiplexer_session} has-session -t #{name} > /dev/null 2>&1 || tmux -S #{@multiplexer_session} new-session -s #{name} -d` if @multiplexer.eql?("tmux")
98
+ `ps ax | grep -v grep | grep SCREEN | grep craftbukkit 2>&1 || screen -dmS #{name}` if @multiplexer.eql?("screen")
99
+ puts "multiplexer session should be started now" if @debug
100
+ sleep 0.1
101
+ File.chmod(01000, @multiplexer_session) if @Multiplexer.eql?("tmux")
102
+ end #end create_tmux_session(name)
103
+
104
+ #Kill a tmux session
105
+ def kill_tmux_session(name)
106
+ puts "killing #{@multiplexer} sessinon now" if @debug
107
+ case @multiplexer
108
+ when "screen"
109
+ send_command("exit") unless is_running?
110
+ when "tmux"
111
+ `tmux -S #{@multiplexer_session} kill-session -t #{@multiplexer_session_name}`
112
+ end
113
+ halt if is_running?
114
+ end #end kill_tmux_session(name)
115
+
116
+ #Rotate the server log file
117
+ def log_rotate
118
+ puts "Rotating logfile now" if @debug
119
+ options = {
120
+ :gzip => true,
121
+ :count => 5,
122
+ }
123
+ LogRotate.rotate_file("/home/odie/bukkit/server/server.log", options)
124
+ end #end log_rotate
125
+
126
+ #Get server.properties file from server runtime directory
127
+ def get_server_properties
128
+ props = Hash[File.read("#{@options[:server_runtime_directory]}server.properties").split("\n").map{|i|i.split('=') unless i =~ /^#.*$/}]
129
+ if @debug
130
+ puts "---"
131
+ puts "Server properties: "
132
+ puts
133
+ props.each do |k,v|
134
+ puts "\t#{k}=#{v}"
135
+ end
136
+ puts "---"
137
+ puts
138
+ end
139
+ props
140
+ end #end get_server_properties
141
+
142
+ end #end Runtime
143
+ end
@@ -0,0 +1,323 @@
1
+ module Mclaunch
2
+ require 'net/http'
3
+ require 'net/https'
4
+ require 'rexml/document'
5
+ require 'open-uri'
6
+ require 'progressbar'
7
+ require 'date'
8
+
9
+ class Tools
10
+ def initialize(runtime, options)
11
+ @runtime = runtime
12
+ @options = options
13
+ @server_properties = @runtime.get_server_properties
14
+ @versions = {}
15
+ @debug = @options[:debug]
16
+ @quiet = @options[:quiet]
17
+ @xml_document = nil
18
+ @craftbukkit_version_regex = /^[1-9]\.[0-9]\.[0-9]-R[0-9]\.[0-9]$/
19
+ @commands = nil
20
+ end #end initialize
21
+
22
+ #Method desctiption
23
+ def commands(commands=nil)
24
+ @commands = commands
25
+ @commands unless @commands
26
+ end #end commands(commands=nil)
27
+
28
+ #Check online if Player name is a valid minecraft username if server is in online mode
29
+ def is_minecraft_player?(player)
30
+ if to_boolean(@server_properties['online-mode']) == true
31
+ uri = URI.parse("https://minecraft.net/haspaid.jsp?user=#{player}")
32
+ http = Net::HTTP.new(uri.host, uri.port)
33
+ http.use_ssl = true
34
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
35
+ request = Net::HTTP::Get.new(uri.request_uri)
36
+ response = http.request(request)
37
+ to_boolean response.body
38
+ end
39
+ end #end is_minecraft_player?(player, cmd)
40
+
41
+ #check if player is in ops.txt
42
+ def is_op?(player)
43
+ puts "checking if \"#{player}\" is op." if @debug
44
+ ops = File.new("#{@options[:server_runtime_directory]}ops.txt", "r")
45
+ op = false
46
+ ops.each_line do |l|
47
+ op = true if l.gsub("\n", "").eql?(player)
48
+ end
49
+ op
50
+ end #end is_op?
51
+
52
+ def is_symlink_or_file(path)
53
+ File.exist?(path) || File.symlink?(path)
54
+ end #end is_symlink_or_file(path)
55
+
56
+ #Convert String to Boolean
57
+ def to_boolean(s)
58
+ s.eql?"true"
59
+ end #end to_boolean(s)
60
+
61
+ #Convert a array into a String.
62
+ def array_to_string(array, delimiter=" ")
63
+ tmp = ""
64
+ array.each do |s|
65
+ tmp += s+delimiter
66
+ end
67
+ tmp
68
+ end #end array_to_string(array, delimiter=" ")
69
+
70
+ def get_worlds
71
+ worlds = {}
72
+ dir = Dir.new(@options[:server_world_directory])
73
+ dir.each do |world|
74
+ unless world =~ /^(\.|\.\.)$/
75
+ ramdisk = false
76
+ ramdisk = true if File.exists?("#{@options[:server_world_directory]}#{world}/ramdisk")
77
+ worlds[world] = ramdisk
78
+ if @debug
79
+ puts " world: #{world} runs from ramdisk" if ramdisk
80
+ puts " world: #{world} runs from disk" unless ramdisk
81
+ end
82
+ end
83
+ end #end dir.each
84
+ return worlds
85
+ end #end get_worlds
86
+
87
+ #Create world Symlinks
88
+ def worlds_create_symlinks
89
+ worlds = get_worlds
90
+ worlds.each do |world,ramdisk|
91
+ src = "#{@options[:server_world_directory]}#{world}"
92
+ src = "#{@options[:server_ramdisk_directory]}#{world}" if ramdisk
93
+ dst = "#{@options[:server_runtime_directory]}#{world}"
94
+ File.unlink(dst) if File.symlink?(dst)
95
+ File.symlink(src,dst)
96
+ puts "Symlink created for: #{world}" unless @quiet
97
+ puts "Source: #{src}\nDestination: #{dst}" if @debug
98
+ end
99
+ end #end worlds_create_symlinks
100
+
101
+ def world_ramdisk_state(world_name)
102
+ worlds = get_worlds
103
+ world_exists = false
104
+ world_already_on_ramdisk = false
105
+ worlds.each do |world,ramdisk|
106
+ if world.eql? world_name
107
+ world_exists = true
108
+ world_already_on_ramdisk = ramdisk
109
+ end
110
+ end
111
+ if world_name
112
+ if world_exists
113
+ if world_already_on_ramdisk
114
+ puts "\"#{world_name}\" will run from harddisk on next server start" unless @quiet
115
+ File.delete("#{@options[:server_world_directory]}#{world_name}/ramdisk")
116
+ else
117
+ puts "\"#{world_name}\" will run from ramdisk on next server start" unless @quiet
118
+ File.open("#{@options[:server_world_directory]}#{world_name}/ramdisk", "w")
119
+ end #end if world_already_on_ramdisk
120
+ else
121
+ puts "\"#{world_name}\" does not exist in world folder!"
122
+ end #end if world_exists
123
+ end #end if world_name
124
+ end #end world_ramdisk_state(world_name)
125
+
126
+ def worlds_to_ramdisk
127
+ worlds = get_worlds
128
+ worlds.each do |world,ramdisk|
129
+ if ramdisk
130
+ print "copy #{world} to ramdisk... " unless @quiet
131
+ `rsync -rt --exclude 'ramdisk' #{@options[:server_world_directory]}#{world}/ #{@options[:server_ramdisk_directory]}#{world}`
132
+ puts "ok" unless @quiet
133
+ end #end if ramdisk
134
+ end #worlds.each
135
+ end #end to_ramdisk
136
+
137
+ def worlds_to_disk
138
+ worlds = get_worlds()
139
+ ramdisk_worlds = Dir.open("#{@options[:server_ramdisk_directory]}")
140
+ ramdisk_worlds.each do |world|
141
+ if worlds.key?(world)
142
+ if worlds[world]
143
+ print "copy #{world} to harddisk... " unless @quiet
144
+ `rsync -rt --exclude 'ramdisk' #{@options[:server_ramdisk_directory]}#{world}/ #{@options[:server_world_directory]}#{world}`
145
+ puts "ok" unless @quiet
146
+ end
147
+ end #end if ramdisk
148
+ end #worlds.each
149
+ end #end to_ramdisk
150
+
151
+ #Get a hash of the locally available server versions
152
+ def get_local_server_versions
153
+ dir = Dir.new(@options[:server_jar_directory])
154
+ dir.sort.each do |f|
155
+ @versions[f.gsub(/^craftbukkit-|\.jar$/, "")] = "#{@options[:server_jar_directory]}#{f}" unless f =~ /^(\.\.|\.)$/
156
+ end
157
+ @versions
158
+ end #end get_local_server_versions
159
+
160
+ #Print locally available server versions to stdout
161
+ def print_local_server_versions
162
+ get_local_server_versions.each do |k,v|
163
+ puts "#{k}, #{v}"
164
+ end
165
+ end #end print_local_server_versions
166
+
167
+ #Check if given version is available locally
168
+ def local_version_available?(channel, version, build_number)
169
+ true if get_local_server_versions.has_key?("#{channel}-#{version}-#{build_number}")
170
+ end #end local_version_available?(version)
171
+
172
+ #Get an xml Document from the given url
173
+ def get_xml_document(url)
174
+ xml_data = Net::HTTP.get_response(URI.parse(url))
175
+ raise "Search for xml document data returned HTTP Error 404\n\nMaybe the version you entered does not exist." if xml_data.is_a?(Net::HTTPNotFound)
176
+ @xml_document = REXML::Document.new(xml_data.body)
177
+ raise "xml document empty" unless @xml_document
178
+ end #end get_xml_document(url)
179
+
180
+ #Get xml data from craftbukkit site as hash
181
+ def get_xml_first_path(url, path)
182
+ get_xml_document(url)
183
+ REXML::XPath.first(@xml_document, path).text
184
+ end #end get_xml_data(url)
185
+
186
+ #Get the latest build number for given version that was not broken
187
+ def get_latest_build_number(version, page=1)
188
+ url = "http://dl.bukkit.org/api/1.0/downloads/projects/craftbukkit/artifacts/?_accept=application%2Fxml&amp;limit=20&amp;page=#{page}"
189
+ build_number = nil
190
+ get_xml_document(url)
191
+ max_page = REXML::XPath.first(@xml_document, "//pages").text
192
+ REXML::XPath.each(@xml_document, "/root/results/list-item") do |element|
193
+ vers = element.text "version"
194
+ build_nr = element.text "build_number"
195
+ next if element.text("is_broken") =~ /^[Tt][Rr][Uu][Ee]$/
196
+ build_number = build_nr if version.eql? vers
197
+ end
198
+ if build_number.to_i > 0
199
+ return build_number
200
+ else
201
+ get_latest_build_number(version, page + 1) if page <= max_page.to_i
202
+ end
203
+ end #end get_latest_build_number(version)
204
+
205
+ #Return the link for the latest version of craftbukkit
206
+ def get_download_link(version)
207
+ prefix = "http://dl.bukkit.org"
208
+ url = "#{prefix}/api/1.0/downloads/projects/craftbukkit/artifacts/#{version}/?_accept=application%2Fxml" if version =~ /^(rb|beta|dev)$/
209
+ url = "#{prefix}/api/1.0/downloads/projects/craftbukkit/view/build-#{version}/?_accept=application%2Fxml" if version =~ /^[0-9][0-9][0-9][0-9]$/
210
+ url = "#{prefix}/api/1.0/downloads/projects/craftbukkit/view/build-#{get_latest_build_number(version)}/?_accept=application%2Fxml" if version =~ @craftbukkit_version_regex
211
+ raise "Thist is no Craftbukkit Version." unless url
212
+ {
213
+ :link => "#{prefix}#{get_xml_first_path(url, '//file/url')}",
214
+ :checksum => get_xml_first_path(url, "//file/checksum_md5"),
215
+ :version => get_xml_first_path(url, "//version"),
216
+ :build_number => get_xml_first_path(url, "//build_number"),
217
+ :channel => get_xml_first_path(url, "//channel/slug"),
218
+ }
219
+ end #end get_latest_download_link
220
+
221
+ #Download the latest server executable
222
+ def download_server_executable(version)
223
+ link = get_download_link(version)
224
+ url = link[:link]
225
+ md5 = link[:checksum]
226
+ version = link[:version]
227
+ build_number = link[:build_number]
228
+ channel = link[:channel]
229
+ target = "#{@options[:server_jar_directory]}craftbukkit-#{channel}-#{version}-#{build_number}.jar"
230
+
231
+ #Debug output
232
+ if @debug
233
+ puts "[#{version}]"
234
+ puts " link:\t\t#{url}"
235
+ puts " md5:\t\t#{md5}"
236
+ puts " taret:\t#{target}"
237
+ puts " build_nr:\t#{build_number}"
238
+ puts " channel:\t#{channel}"
239
+ end
240
+
241
+ if local_version_available? channel, version, build_number
242
+ puts "local version available. Will symlink local version to server runtime directory." if @debug
243
+ else
244
+ puts "local version not available. Will download new version and put symlink to it in server runtime directory." if @debug
245
+ download_file(url, target)
246
+ end
247
+ set_server_exe_symlink(target)
248
+ end #end download_latest_server_executable
249
+
250
+ #Change server version manually
251
+ def server_change_version(version)
252
+ link = get_download_link(version)
253
+ raise "This is no Craftbukkit Version!" unless version =~ /^(#{@craftbukkit_version_regex}|[0-9]{4})$/
254
+ if local_version_available?(link[:channel], link[:version], link[:build_number])
255
+ filename = "craftbukkit-#{version}.jar"
256
+ set_server_exe_symlink filename
257
+ else
258
+ download_server_executable(version)
259
+ end
260
+ end #end server_change_version(version)
261
+
262
+ #Download url to path
263
+ def download_file(url, path)
264
+ puts "downloading file from: \"#{url}\"" unless @quiet
265
+ url = URI(url)
266
+ location = URI(Net::HTTP.get_response(url)['location'])
267
+ Net::HTTP.start(location.host, location.port) do |http|
268
+ unless File.exist?(path)
269
+ f = open(path, 'wb')
270
+ begin
271
+ downloadedSize = 0
272
+ http.request_get(location.request_uri) do |resp|
273
+ progressBar = ProgressBar.new("Downloading", 100)
274
+ size = resp.content_length
275
+ resp.read_body do |segment|
276
+ downloadedSize += segment.length
277
+ if(downloadedSize != 0)
278
+ percent = (downloadedSize * 100 / size)
279
+ progressBar.set(percent)
280
+ end
281
+ f.write(segment)
282
+ end #end resp.read_body
283
+ progressBar.finish
284
+ end #end http.request_get
285
+ ensure
286
+ f.close()
287
+ end #end begin
288
+ end #end Net::HTTP.start
289
+ end
290
+ end #end download_file(url, path)
291
+
292
+ def set_server_exe_symlink(file)
293
+ current_file = "#{@options[:server_runtime_directory]}#{@options[:server_executable]}"
294
+ was_running = false
295
+ if @runtime.is_running?
296
+ was_running = true
297
+ @runtime.stop
298
+ end
299
+ puts "symlinking #{file} to #{current_file}"
300
+ File.unlink(current_file) if is_symlink_or_file(current_file)
301
+ File.symlink(file,current_file)
302
+ @runtime.start if was_running
303
+ end #end set_server_exe_symlink(file)
304
+
305
+ #Create a world backup with rsync
306
+ def world_backup_create
307
+ puts "Creating world folder backup now." unless @quiet
308
+ @commands.save_off
309
+ @commands.save_all
310
+ sleep 1
311
+ `rsync -a --delete-after #{@options[:server_world_directory]} #{@options[:server_backup_directory]}worlds/latest > #{@options[:server_backup_directory]}worlds/latest/rsync.log`
312
+ @commands.save_on
313
+ now = DateTime.now.strftime("%Y-%m-%d-%H:%M:%S")
314
+ `cp -al #{@options[:server_backup_directory]}worlds/latest #{@options[:server_backup_directory]}worlds/#{now}`
315
+ end #end world_backup create
316
+
317
+ #Delete world backups which are older than a month
318
+ def world_backup_delete
319
+ puts "Deleting old backups" unless @quiet
320
+ `find #{@options[:server_backup_directory]} -mindepth 1 -maxdepth 1 -not -newermt '1 month ago' -exec rm -rf {} \\;`
321
+ end #end world_backup_delete
322
+ end #end class Tools
323
+ end #end module Mclaunch
@@ -0,0 +1,3 @@
1
+ module Mclaunch
2
+ VERSION = "0.0.1"
3
+ end
data/lib/mclaunch.rb ADDED
@@ -0,0 +1,347 @@
1
+ module Mclaunch
2
+ require "mclaunch/version"
3
+ require "mclaunch/runtime"
4
+ require "mclaunch/commands"
5
+ require "mclaunch/tools"
6
+ require 'optparse'
7
+ require 'yaml'
8
+
9
+ default_options = {
10
+ :server_executable => "craftbukkit.jar",
11
+ :server_runtime_directory => "#{ENV["HOME"]}/bukkit/server/",
12
+ :server_world_directory => "#{ENV["HOME"]}/bukkit/worlds/",
13
+ :server_jar_directory => "#{ENV["HOME"]}/bukkit/jars/",
14
+ :server_backup_directory => "#{ENV["HOME"]}/bukkit/backup/",
15
+ :server_ramdisk_directory => "#{ENV["HOME"]}/bukkit/ramdisk/",
16
+ :server_min_heap_memory => "512M",
17
+ :server_max_heap_memory => "1024M",
18
+ :server_additional_options => nil,
19
+ :server_terminal_multiplexer => "tmux",
20
+ :server_terminal_multiplexer_name => "craftbukkit",
21
+ :server_terminal_multiplexer_session => "/tmp/craftbukkit",
22
+ }
23
+ @options = {
24
+ :debug => false,
25
+ :quiet => false,
26
+ :config_file => nil,
27
+ :server_management => {
28
+ :list_versions => false,
29
+ :update_to_latest => nil,
30
+ :server_change_version => nil,
31
+ :world_to_ramdisk => nil,
32
+ :world_to_disk => nil,
33
+ :worlds_create_symlinks => nil,
34
+ },
35
+ :server_commands => {
36
+ :reload => false,
37
+ :save_on => false,
38
+ :save_off => false,
39
+ :save_all => false,
40
+ :gamemode => nil,
41
+ :difficulty => nil,
42
+ :op => nil,
43
+ :deop => nil,
44
+ :kick => nil,
45
+ :kick_player => nil,
46
+ :kick_ip => nil,
47
+ :pardon_player => nil,
48
+ :pardon_ip => nil,
49
+ :whitelist_on => false,
50
+ :whitelist_off => false,
51
+ :whitelist_add => nil,
52
+ :whitelist_remove => nil,
53
+ }
54
+ }
55
+ @options.merge! default_options
56
+
57
+
58
+ opt_parser = OptionParser.new do |opts|
59
+
60
+ #Write Standard config file if it does't exist
61
+
62
+ @config_file = "#{@options[:server_runtime_directory]}mclaunch.properties" unless @options[:config_file]
63
+ @config_file = @options[:config_file] if @options[:config_file]
64
+ if File.exists?(@config_file) == false
65
+ File.open(@config_file, "w") {|f| f.write(default_options.to_yaml)}
66
+ end
67
+
68
+
69
+ opts.banner = " Usage:\t#{__FILE__.gsub(/(^\/.*\/|\.rb)/, "")} <options> start/stop/restart\n"
70
+ opts.separator ""
71
+ opts.separator " Avalable options are:\n"
72
+ opts.separator ""
73
+
74
+ opts.separator " Game management:"
75
+
76
+ opts.on('--reload', "reload the minecraft server") do
77
+ @options[:server_commands][:reload] = true
78
+ end #end opts.on
79
+
80
+ opts.on('--save-on', "turn the save mode on") do
81
+ @options[:server_commands][:save_on] = true
82
+ end #end opts.on
83
+
84
+ opts.on('--save-off', "turn the save mode off") do
85
+ @options[:server_commands][:save_off] = true
86
+ end #end opts.on
87
+
88
+ opts.on('--save-all', "save the current world state") do
89
+ @options[:server_commands][:save_all] = true
90
+ end #end opts.on
91
+
92
+ opts.on('--gamemode GAMEMODE', String, "change the current gamemode to GAMEMODE") do |arg|
93
+ @options[:server_commands][:gamemode] = arg
94
+ end #end opts.on
95
+
96
+ opts.on('--difficulty DIFFICULTY', String, "change the current difficulty to DIFFICULTY") do |arg|
97
+ @options[:server_commands][:difficulty] = arg
98
+ end #end opts.on
99
+
100
+ opts.on('--op-player PLAYER', String, "grant op status on PLAYER") do |arg|
101
+ @options[:server_commands][:op] = arg
102
+ end #end opts.on
103
+
104
+ opts.on('--deop-player PLAYER', String, "revoke op status on Player") do |arg|
105
+ @options[:server_commands][:deop] = arg
106
+ end #end opts.on
107
+
108
+ opts.on('--ban-player PLAYER [REASON]', String, "ban PLAYER") do |arg|
109
+ @options[:server_commands][:ban_player] = arg
110
+ end #end opts.on
111
+
112
+ opts.on('--ban-ip 11.22.33.44 [REASON]', String, "ban IP") do |arg|
113
+ @options[:server_commands][:ban_ip] = arg
114
+ end #end opts.on
115
+
116
+ opts.on('--pardon-player PLAYER', String, "pardon PLAYER") do |arg|
117
+ @options[:server_commands][:pardon_player] = arg
118
+ end #end opts.on
119
+
120
+ opts.on('--pardon-ip 11.22.33.44', String, "pardon IP") do |arg|
121
+ @options[:server_commands][:pardon_ip] = arg
122
+ end #end opts.on
123
+
124
+ opts.on('--whitelist-add PLAYER', String, "add PLAYER to whitelist") do |arg|
125
+ @options[:server_commands][:whitelist_add] = arg
126
+ end #end opts.on
127
+
128
+ opts.on('--whitelist-remove PLAYER', String, "remove PLAYER from whitelist") do |arg|
129
+ @options[:server_commands][:whitelist_remove] = arg
130
+ end #end opts.on
131
+
132
+ opts.on('--whitelist-on', "turn the whitelist on") do
133
+ @options[:server_commands][:whitelist_on] = true
134
+ end #end opts.on
135
+
136
+ opts.on('--whitelist-off', "turn the whitelist off") do
137
+ @options[:server_commands][:whitelist_off] = true
138
+ end #end opts.on
139
+
140
+ opts.separator ""
141
+ opts.separator " Server Settings:"
142
+
143
+ opts.on('-m', '--minimal-mem 512M', "set the minimal memory to use in format \"512M\"") do |arg|
144
+ @options[:server_min_heap_memory] = arg
145
+ end
146
+
147
+ opts.on('-M', '--maximal-mem 1G', "set the maximal memory to use in format \"1024M\"") do |arg|
148
+ @options[:server_max_heap_memory] = arg
149
+ end
150
+
151
+ opts.on('--server-executable JAR', String, "set the JAR to use for current session") do |arg|
152
+ @options[:server_executable] = arg
153
+ end
154
+
155
+ opts.on('--server-directory DIR', String, "set the directory to user to DIR") do |arg|
156
+ @options[:server_runtime_directory] = arg
157
+ end
158
+
159
+ opts.on('--jar-directory DIR', String, "set the jar directory to use to DIR") do |arg|
160
+ @options[:server_jar_directory] = arg
161
+ end
162
+
163
+ opts.on('--world-directory DIR', String, "set the world directory to use to DIR") do |arg|
164
+ @options[:server_world_directory] = arg
165
+ end
166
+
167
+ opts.on('--backup-directory DIR', String, "set the backup directory to use to DIR") do |arg|
168
+ @options[:server_backup_directory] = arg
169
+ end
170
+
171
+ opts.separator ""
172
+ opts.separator " Server Magagement:"
173
+
174
+ opts.on('-l', '--list-versions', "list locally available Server versions") do
175
+ @options[:server_management][:list_versions] = true
176
+ end
177
+
178
+ opts.on('--update VERSION', "update to latest craftbukkit version, where version may be \"rb, beta or dev\"") do |arg|
179
+ @options[:server_management][:update_to_latest] = arg
180
+ end
181
+
182
+ opts.on('--server-version VERSION', "Set server version to Version") do |arg|
183
+ @options[:server_management][:server_change_version] = arg
184
+ end
185
+
186
+ opts.separator ""
187
+ opts.separator " World Management:"
188
+
189
+ opts.on('--world-to-ramdisk WORLD', "Set ramdisk flag for WORLD") do |arg|
190
+ @options[:server_management][:world_to_disk] = arg
191
+ end
192
+
193
+ opts.on('--world-to-disk WORLD', "Remove ramdisk flag from WORLD") do |arg|
194
+ @options[:server_management][:world_to_ramdisk] = arg
195
+ end
196
+
197
+ opts.on('--worlds-symlink', "Symlink all worlds in the worlds directory to runtime directory")do |arg|
198
+ @options[:server_management][:worlds_create_symlinks] = arg
199
+ end
200
+
201
+ opts.on('--world-backup-create', "Create a Backup from world directory to backup directory") do
202
+ @options[:server_management][:world_backup_create] = true
203
+ end
204
+
205
+ opts.on('--world-backup-delete', "Delete 1 month old backupa from backup directory") do
206
+ @options[:server_management][:world_backup_delete] = true
207
+ end
208
+
209
+ opts.separator ""
210
+ opts.separator " Misc Options:"
211
+
212
+ opts.on('-q', '--quiet', "turn off all output") do
213
+ @options[:quiet] = true
214
+ end #end opts.on
215
+
216
+ opts.on('-d', '--debug', "turn debug output on") do
217
+ @options[:debug] = true
218
+ end #end opts.on
219
+
220
+ opts.on("-h", "--help", "Show this message") do
221
+ puts opts
222
+ end # end opts.on_tail
223
+
224
+ opts.separator ""
225
+ opts.separator ""
226
+ opts.separator " Usage Examples:"
227
+ opts.separator ""
228
+ opts.separator " Start, Stop, Restart"
229
+ opts.separator " To start the craftbukkit server use:"
230
+ opts.separator " #{__FILE__.gsub(/(^\/.*\/|\.rb)/, "")} <options> start"
231
+ opts.separator " To stop the craftbukkit server use:"
232
+ opts.separator " #{__FILE__.gsub(/(^\/.*\/|\.rb)/, "")} stop"
233
+ opts.separator " To restart the craftbukkit server use:"
234
+ opts.separator " #{__FILE__.gsub(/(^\/.*\/|\.rb)/, "")} <options> restart"
235
+ opts.separator ""
236
+ opts.separator " Server Management:"
237
+ opts.separator " kick player:"
238
+ opts.separator " #{__FILE__.gsub(/(^\/.*\/|\.rb)/, "")} --kick-player notch"
239
+ opts.separator " change gamemode:"
240
+ opts.separator " #{__FILE__.gsub(/(^\/.*\/|\.rb)/, "")} --gamemode creative"
241
+ opts.separator ""
242
+
243
+
244
+ end
245
+
246
+ begin
247
+ @options.merge!(Hash[YAML::load(File.new(@config_file)).map { |k, v| @options[k] = v}])
248
+
249
+ opt_parser.parse!
250
+ rescue => exc
251
+ STDERR.puts "an error with the command line options occured:\n\t#{exc}"
252
+ STDERR.puts
253
+ STDERR.puts "For usage options use #{__FILE__.gsub(/^\/.*\//, "")} --help"
254
+ exit 1
255
+ end
256
+
257
+ begin
258
+ @runtime = Runtime.new(@options)
259
+ @tools = Tools.new(@runtime, @options)
260
+ @commands = Commands.new(@runtime, @options, @tools)
261
+ @tools.commands(@commands)
262
+ @craftbukkit_version_regex = /^[1-9]\.[0-9]\.[0-9]-R[0-9]\.[0-9]$/
263
+
264
+ @options[:server_management].each do |k,v|
265
+ case k
266
+ when :list_versions
267
+ @tools.print_local_server_versions if v
268
+ when :update_to_latest
269
+ @tools.download_server_executable(v) if v =~ /^(rb|beta|dev)$/
270
+ when :server_change_version
271
+ @tools.server_change_version(v) if v =~ /^(#{@craftbukkit_version_regex}|[0-9]{4})$/
272
+ when :world_to_ramdisk
273
+ @tools.world_ramdisk_state(v) if v
274
+ when :world_to_disk
275
+ @tools.world_ramdisk_state(v) if v
276
+ when :worlds_create_symlinks
277
+ @tools.worlds_create_symlinks if v
278
+ when :world_backup_create
279
+ @tools.world_backup_create if v
280
+ when :world_backup_delete
281
+ @tools.world_backup_delete if v
282
+ end
283
+ end
284
+ @options[:server_commands].each do |k,v|
285
+ case k
286
+ when :reload
287
+ @commands.reload if v
288
+ when :save_on
289
+ @commands.save_on if v
290
+ when :save_off
291
+ @commands.save_off if v
292
+ when :save_all
293
+ @commands.save_all if v
294
+ when :gamemode
295
+ @commands.change_gamemode(v) if v
296
+ when :difficulty
297
+ @commands.change_difficulty(v) if v
298
+ when :op
299
+ @commands.op(v) if v
300
+ when :deop
301
+ @commands.deop(v) if v
302
+ when :kick_player
303
+ @commands.kick_player(v) if v
304
+ when :kick_ip
305
+ @commands.kick_ip(v) if v
306
+ when :ban_player
307
+ @commands.ban_player(v, ARGV) if v
308
+ when :ban_ip
309
+ @commands.ban_ip(v, ARGV) if v
310
+ when :pardon_player
311
+ @commands.pardon_player(v) if v
312
+ when :pardon_ip
313
+ @commands.pardon_ip(v) if v
314
+ when :whitelist_on
315
+ @commands.whitelist("on") if v
316
+ when :whitelist_off
317
+ @commands.whitelist("off") if v
318
+ when :whitelist_add
319
+ @commands.whitelist_add(v) if v
320
+ when :whitelist_remove
321
+ @commands.whitelist_remove(v) if v
322
+ end
323
+ end
324
+ rescue => exc
325
+ STDERR.puts "An runtime error occured:\n\t#{exc.message}"
326
+ STDERR.puts
327
+ STDERR.puts "For usage options use #{__FILE__.gsub(/^\/.*\//, "")} --help"
328
+ end
329
+
330
+ begin
331
+ case ARGV[0]
332
+ when "start"
333
+ @tools.worlds_to_ramdisk
334
+ @runtime.run
335
+ when "stop"
336
+ @runtime.halt
337
+ @tools.worlds_to_disk
338
+ when "restart"
339
+ @tools.worlds_to_disk
340
+ @tools.worlds_to_ramdisk
341
+ @runtime.restart
342
+ end
343
+ rescue => exc
344
+ STDERR.puts exc.message
345
+ end
346
+ end
347
+
data/mclaunch.gemspec ADDED
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mclaunch/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "mclaunch"
8
+ gem.version = Mclaunch::VERSION
9
+ gem.authors = ["odie"]
10
+ gem.email = ["masterodie@gmail.com"]
11
+ gem.description = "A craftbukkit server launcher"
12
+ gem.summary = "A craftbukkit server launcher"
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ end
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mclaunch
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - odie
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-01 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A craftbukkit server launcher
15
+ email:
16
+ - masterodie@gmail.com
17
+ executables:
18
+ - mclaunch
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .gitignore
23
+ - Gemfile
24
+ - LICENSE.txt
25
+ - README.md
26
+ - Rakefile
27
+ - bin/mclaunch
28
+ - lib/mclaunch.rb
29
+ - lib/mclaunch/commands.rb
30
+ - lib/mclaunch/runtime.rb
31
+ - lib/mclaunch/tools.rb
32
+ - lib/mclaunch/version.rb
33
+ - mclaunch.gemspec
34
+ homepage: ''
35
+ licenses: []
36
+ post_install_message:
37
+ rdoc_options: []
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ requirements: []
53
+ rubyforge_project:
54
+ rubygems_version: 1.8.24
55
+ signing_key:
56
+ specification_version: 3
57
+ summary: A craftbukkit server launcher
58
+ test_files: []