sbcp 0.1.4 → 0.2.3
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.
- checksums.yaml +4 -4
- data/README.md +43 -18
- data/bin/sbcp +30 -621
- data/config.yml +3 -1
- data/lib/sbcp.rb +265 -33
- data/lib/sbcp/backup.rb +27 -7
- data/lib/sbcp/config.rb +229 -0
- data/lib/sbcp/daemon.rb +37 -73
- data/lib/sbcp/help.rb +27 -0
- data/lib/sbcp/logs.rb +16 -0
- data/lib/sbcp/panel.rb +44 -0
- data/lib/sbcp/parser.rb +110 -2
- data/lib/sbcp/rcon.rb +41 -0
- data/lib/sbcp/setup.rb +193 -0
- data/lib/sbcp/starbound.rb +45 -21
- data/lib/sbcp/version.rb +17 -1
- data/sbcp.gemspec +4 -3
- metadata +43 -4
data/lib/sbcp/daemon.rb
CHANGED
|
@@ -1,66 +1,56 @@
|
|
|
1
|
+
# SBCP - Starbound Server Management Solution for Linux Servers
|
|
2
|
+
# Copyright (C) 2016 Kazyyk
|
|
3
|
+
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
# License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
1
17
|
require 'yaml'
|
|
2
|
-
require 'logger'
|
|
3
18
|
require 'tempfile'
|
|
4
|
-
require 'rufus-scheduler'
|
|
5
19
|
require 'celluloid/current'
|
|
6
20
|
require_relative 'starbound'
|
|
7
21
|
require_relative 'backup'
|
|
8
|
-
require_relative 'parser'
|
|
9
22
|
require_relative 'logs'
|
|
23
|
+
|
|
10
24
|
module SBCP
|
|
11
25
|
class Daemon
|
|
26
|
+
include Celluloid
|
|
27
|
+
|
|
12
28
|
def initialize
|
|
13
|
-
# Loads the config into an instance variable for use in GUI mode
|
|
14
29
|
@config = YAML.load_file(File.expand_path('../../../config.yml', __FILE__))
|
|
15
30
|
end
|
|
16
31
|
|
|
17
|
-
def
|
|
18
|
-
# This method is used when starting SBCP from the sbcp executable.
|
|
19
|
-
# It's primary purpose is to enable running SBCP in CLI mode.
|
|
20
|
-
# The Sinatra web server is completely bypassed in this case.
|
|
21
|
-
|
|
22
|
-
# Check to see if the daemon is already running.
|
|
23
|
-
# This can happen after a server shut down and it's taking a backup or handling log files.
|
|
24
|
-
abort("SBCP is currently running. If you recently shut down Starbound, please allow a few minutes.\nSBCP is likely handling backup or log file operations. Interruption could lead to data loss.") if not Dir.glob('/tmp/sbcp_daemon-pid*').empty?
|
|
25
|
-
|
|
26
|
-
# Create a file containing the pid of this process so it can be aborted if neccesary.
|
|
27
|
-
pid_file = Tempfile.new('sbcp_daemon-pid')
|
|
28
|
-
pid = Process.pid.to_s
|
|
29
|
-
pid_file.write(pid)
|
|
30
|
-
|
|
31
|
-
# Next, we perform a check to ensure that the server isn't already running.
|
|
32
|
-
abort('Starbound is already running.') if not `pidof starbound_server`.empty?
|
|
33
|
-
|
|
34
|
-
# We should load the config values into a local variable.
|
|
35
|
-
# Since CLI mode does not create an instance of the daemon method,
|
|
36
|
-
# we have to set things up separately so they can be used.
|
|
37
|
-
config = YAML.load_file(File.expand_path('../../../config.yml', __FILE__))
|
|
38
|
-
|
|
32
|
+
def start
|
|
39
33
|
# Quick check for invalid config values.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
34
|
+
raise('Please run setup first.') if @config['starbound_directory'].nil?
|
|
35
|
+
raise('Error - Invalid starbound directory') if not Dir.exist?(@config['starbound_directory']) && Dir.exist?(@config['starbound_directory'] + '/giraffe_storage')
|
|
36
|
+
raise('Error - Invalid backup directory') if not Dir.exist?(@config['backup_directory'])
|
|
37
|
+
raise('Error - Invalid backup schedule') if not ['hourly', 2, 3, 4, 6, 8, 12, 'daily', 'restart'].include? @config['backup_schedule']
|
|
38
|
+
raise('Error - Invalid backup history') if not @config['backup_history'] == 'none' || @config['backup_history'] >= 1
|
|
39
|
+
raise('Error - Invalid log directory') if not Dir.exist?(@config['log_directory'])
|
|
40
|
+
raise('Error - Invalid log history') if not @config['log_history'].is_a?(Integer) && @config['log_history'] >= 1
|
|
41
|
+
raise('Error - Invalid log style') if not ['daily', 'restart'].include? @config['log_style']
|
|
42
|
+
raise('Error - Invalid restart schedule') if not ['none', 'hourly', 2, 3, 4, 6, 8, 12, 'daily'].include? @config['restart_schedule']
|
|
49
43
|
|
|
50
44
|
# Require any present plugins
|
|
51
|
-
plugins_directory = "#{config['starbound_directory']}/sbcp/plugins"
|
|
45
|
+
plugins_directory = "#{@config['starbound_directory']}/sbcp/plugins"
|
|
52
46
|
$LOAD_PATH.unshift(plugins_directory)
|
|
53
47
|
Dir[File.join(plugins_directory, '*.rb')].each {|file| require File.basename(file) }
|
|
54
48
|
|
|
55
|
-
# We detach and daemonize this process to prevent a block in the calling executable.
|
|
56
|
-
Process.daemon(nochdir=true)
|
|
57
|
-
|
|
58
49
|
# We create an infinite loop so we can easily restart the server.
|
|
59
50
|
loop do
|
|
60
51
|
# Next we invoke the Starbound class to create an instance of the server.
|
|
61
52
|
# This class will spawn a sub-process containing the server.
|
|
62
|
-
|
|
63
|
-
server.start
|
|
53
|
+
Starbound.new.start
|
|
64
54
|
|
|
65
55
|
# We wait for the server process to conclude before moving on.
|
|
66
56
|
# This normally occurs after a shutdown, crash, or restart.
|
|
@@ -69,47 +59,21 @@ module SBCP
|
|
|
69
59
|
# Once the server has finished running, we'll want to age our logfiles.
|
|
70
60
|
# We'll also take backups here if they've been set to behave that way.
|
|
71
61
|
# There's probably a better way than sending config values as arguements, but...
|
|
72
|
-
|
|
73
|
-
|
|
62
|
+
Logs.age(@config['log_directory'], @config['log_history']) if @config['log_style'] == 'restart'
|
|
63
|
+
Backup.create_backup if @config['backup_schedule'] == 'restart'
|
|
74
64
|
|
|
75
65
|
# Now we must determine if the server was closed intentionally.
|
|
76
66
|
# If the server was shut down on purpose, we don't want to automatically restart it.
|
|
77
67
|
# If the shutdown file exists, it was an intentional shutdown.
|
|
78
68
|
# We break the loop which ends the method and closes the Daemon process.
|
|
79
|
-
|
|
69
|
+
if not Dir.glob('/tmp/sb-shutdown*').empty?
|
|
70
|
+
$daemon = nil
|
|
71
|
+
break
|
|
72
|
+
end
|
|
80
73
|
|
|
81
74
|
# This delay is needed or some commands don't report back correctly
|
|
82
75
|
sleep 5
|
|
83
76
|
end
|
|
84
|
-
ensure
|
|
85
|
-
unless pid_file.nil?
|
|
86
|
-
pid_file.close
|
|
87
|
-
pid_file.unlink
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
private
|
|
92
|
-
|
|
93
|
-
# These methods are used only in GUI mode for managing the server.
|
|
94
|
-
# In CLI mode, server management is handled via CLI options.
|
|
95
|
-
|
|
96
|
-
def start_server
|
|
97
|
-
# TODO: Create code that spawns a sub-process containing the server
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def restart_server
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def force_restart_server
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def stop_server
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def force_stop_server
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def server_status
|
|
113
77
|
end
|
|
114
78
|
end
|
|
115
79
|
end
|
data/lib/sbcp/help.rb
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# SBCP - Starbound Server Management Solution for Linux Servers
|
|
2
|
+
# Copyright (C) 2016 Kazyyk
|
|
3
|
+
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
# License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
require 'highline'
|
|
18
|
+
|
|
19
|
+
module SBCP
|
|
20
|
+
class Help
|
|
21
|
+
def self.menu(type)
|
|
22
|
+
case type
|
|
23
|
+
when :main
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/sbcp/logs.rb
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
# SBCP - Starbound Server Management Solution for Linux Servers
|
|
2
|
+
# Copyright (C) 2016 Kazyyk
|
|
3
|
+
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
# License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
1
17
|
module SBCP
|
|
2
18
|
class Logs
|
|
3
19
|
def self.age(directory, days)
|
data/lib/sbcp/panel.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# SBCP - Starbound Server Management Solution for Linux Servers
|
|
2
|
+
# Copyright (C) 2016 Kazyyk
|
|
3
|
+
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
# License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
require 'sinatra/base'
|
|
18
|
+
require 'sinatra/contrib'
|
|
19
|
+
require 'sinatra/flash'
|
|
20
|
+
require 'securerandom'
|
|
21
|
+
require 'fileutils'
|
|
22
|
+
require 'logger'
|
|
23
|
+
require 'yaml'
|
|
24
|
+
|
|
25
|
+
require_relative 'daemon'
|
|
26
|
+
|
|
27
|
+
module SBCP
|
|
28
|
+
class Panel < Sinatra::Base
|
|
29
|
+
register Sinatra::Contrib
|
|
30
|
+
register Sinatra::Flash
|
|
31
|
+
config = YAML.load_file(File.expand_path('../../config.yml', __FILE__))
|
|
32
|
+
configure do
|
|
33
|
+
set :environment, :development
|
|
34
|
+
set :server, 'thin'
|
|
35
|
+
set :threaded, true
|
|
36
|
+
set :bind, '0.0.0.0'
|
|
37
|
+
use Rack::Session::Cookie,
|
|
38
|
+
:key => 'rack.session',
|
|
39
|
+
:path => '/',
|
|
40
|
+
:expire_after => 3600 # In seconds
|
|
41
|
+
end
|
|
42
|
+
run! if app_file == $0
|
|
43
|
+
end
|
|
44
|
+
end
|
data/lib/sbcp/parser.rb
CHANGED
|
@@ -1,10 +1,118 @@
|
|
|
1
|
+
# SBCP - Starbound Server Management Solution for Linux Servers
|
|
2
|
+
# Copyright (C) 2016 Kazyyk
|
|
3
|
+
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
# License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
require 'celluloid/current'
|
|
18
|
+
require 'tempfile'
|
|
19
|
+
require 'yaml'
|
|
20
|
+
|
|
21
|
+
require_relative 'rcon'
|
|
22
|
+
|
|
1
23
|
module SBCP
|
|
2
24
|
class Parser
|
|
3
25
|
include Celluloid
|
|
4
26
|
|
|
27
|
+
def initialize
|
|
28
|
+
Starbound::SESSION[:players] = {} if not Starbound::SESSION[:players].empty?
|
|
29
|
+
@config = YAML.load_file(File.expand_path('../../../config.yml', __FILE__))
|
|
30
|
+
sb_config_raw = File.read("#{@config['starbound_directory']}/giraffe_storage/starbound.config")
|
|
31
|
+
@sb_config_parsed = JSON.parse(sb_config_raw)
|
|
32
|
+
@tmp = {}
|
|
33
|
+
if @config['log_style'] == 'daily' then
|
|
34
|
+
@log = Logger.new("#{@config['log_directory']}/starbound.log", 'daily', @config['log_history'])
|
|
35
|
+
elsif @config['log_style'] == 'restart' then
|
|
36
|
+
stamp = "#{Time.now.strftime("%m-%d-%Y-%H-%M-%S")}-starbound"
|
|
37
|
+
@log = Logger.new("#{@config['log_directory']}/#{stamp}.log")
|
|
38
|
+
end
|
|
39
|
+
@log.formatter = proc { |severity, datetime, progname, msg| date_format = datetime.strftime("%H:%M:%S.%N")[0...-6]; "[#{date_format}] #{msg}" }
|
|
40
|
+
@log.level = Logger::INFO
|
|
41
|
+
@log.info("---------- SBCP is starting a new Starbound instance ----------\n")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def log(string)
|
|
45
|
+
@log.info(string)
|
|
46
|
+
end
|
|
47
|
+
|
|
5
48
|
def parse(line)
|
|
6
|
-
|
|
7
|
-
|
|
49
|
+
if line.include? "Chat:"
|
|
50
|
+
parse_chat(line)
|
|
51
|
+
else
|
|
52
|
+
case line
|
|
53
|
+
when /Starting UniverseServer with UUID:/
|
|
54
|
+
if @sb_config_parsed["runRconServer"] == true
|
|
55
|
+
$rcon = RCON.new(@sb_config_parsed["rconServerPort"], @sb_config_parsed["rconServerPassword"])
|
|
56
|
+
else
|
|
57
|
+
puts "RCON is not enabled. Please check your starbound.config file."
|
|
58
|
+
puts "Some of SBCP's features may not work correctly without RCON."
|
|
59
|
+
end
|
|
60
|
+
when /Logged in account '(.+)' as player '(.+)' from address (.+)/
|
|
61
|
+
id = Starbound::SESSION[:players].count + 1
|
|
62
|
+
@tmp[id] = {
|
|
63
|
+
:account => $1,
|
|
64
|
+
:name => $2,
|
|
65
|
+
:ip => $3,
|
|
66
|
+
:nick => nil
|
|
67
|
+
}
|
|
68
|
+
when /Client '(.+)' <(\d+)> \((.+)\) connected/
|
|
69
|
+
if get_id_from_name($1)
|
|
70
|
+
unless $rcon.nil?
|
|
71
|
+
$rcon.execute("kick $#{$2} \"#{@config['duplicate_kick_msg']}\"")
|
|
72
|
+
id = get_tempid_from_name($1)
|
|
73
|
+
@tmp.delete(id)
|
|
74
|
+
else
|
|
75
|
+
log('DUPLICATE NAME DETECTED BUT RCON DISABLED - CANNOT HANDLE')
|
|
76
|
+
end
|
|
77
|
+
elsif id = get_tempid_from_name($1)
|
|
78
|
+
Starbound::SESSION[:players][$2] = @tmp[id]
|
|
79
|
+
@tmp.delete(id)
|
|
80
|
+
end
|
|
81
|
+
when /Client '(.+)' <(\d+)> \((.+)\) disconnected/
|
|
82
|
+
Starbound::SESSION[:players].delete($2) unless Starbound::SESSION[:players][$2].nil?
|
|
83
|
+
end
|
|
84
|
+
log(line)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def close
|
|
89
|
+
@log.close
|
|
8
90
|
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def parse_chat(line)
|
|
95
|
+
case line
|
|
96
|
+
when /<(.+)> \/nick (.+)/
|
|
97
|
+
id = get_id_from_name($1)
|
|
98
|
+
Starbound::SESSION[:players][id][:nick] = $2
|
|
99
|
+
end
|
|
100
|
+
log(line)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def get_tempid_from_name(name)
|
|
104
|
+
@tmp.each_pair { |k,v|
|
|
105
|
+
return k if v[:name] == name
|
|
106
|
+
}
|
|
107
|
+
return nil
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def get_id_from_name(name)
|
|
111
|
+
Starbound::SESSION[:players].each_pair { |k,v|
|
|
112
|
+
return k if v[:name] == name
|
|
113
|
+
}
|
|
114
|
+
return nil
|
|
115
|
+
end
|
|
116
|
+
|
|
9
117
|
end
|
|
10
118
|
end
|
data/lib/sbcp/rcon.rb
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# SBCP - Starbound Server Management Solution for Linux Servers
|
|
2
|
+
# Copyright (C) 2016 Kazyyk
|
|
3
|
+
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
# License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
require 'steam-condenser'
|
|
18
|
+
require 'json'
|
|
19
|
+
require 'yaml'
|
|
20
|
+
|
|
21
|
+
module SBCP
|
|
22
|
+
class RCON
|
|
23
|
+
def initialize(port, pass)
|
|
24
|
+
original_verbosity = $VERBOSE
|
|
25
|
+
$VERBOSE = nil
|
|
26
|
+
SteamSocket.timeout = 100
|
|
27
|
+
@rcon = SourceServer.new("127.0.0.1:#{port}")
|
|
28
|
+
@rcon.rcon_auth(pass)
|
|
29
|
+
$VERBOSE = original_verbosity
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def execute(command)
|
|
33
|
+
# We swallow the time out exception here because Steam Condenser expects a reply
|
|
34
|
+
# Starbound doesn't seem to always give a reply, even though the commands work
|
|
35
|
+
begin
|
|
36
|
+
@rcon.rcon_exec(command)
|
|
37
|
+
rescue Exception
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
data/lib/sbcp/setup.rb
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# SBCP - Starbound Server Management Solution for Linux Servers
|
|
2
|
+
# Copyright (C) 2016 Kazyyk
|
|
3
|
+
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU Affero General Public License as
|
|
6
|
+
# published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
# License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
require 'yaml'
|
|
18
|
+
require 'fileutils'
|
|
19
|
+
require 'highline'
|
|
20
|
+
|
|
21
|
+
module SBCP
|
|
22
|
+
class Setup
|
|
23
|
+
def initialize
|
|
24
|
+
@cli = HighLine.new
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def run
|
|
28
|
+
config_file = File.expand_path('../../../config.yml', __FILE__)
|
|
29
|
+
config = YAML.load_file(config_file)
|
|
30
|
+
response = @cli.agree('Are you sure you want to run the first-time setup? (y/n)')
|
|
31
|
+
if response # If response is true, continue
|
|
32
|
+
# First, we must attempt to locate where Starbound is installed.
|
|
33
|
+
# This performs a recursive search on the OS for a folder named 'giraffe_storage'
|
|
34
|
+
@cli.newline
|
|
35
|
+
@cli.say('SBCP is starting up...')
|
|
36
|
+
@cli.say('SBCP is attempting to automatically locate Starbound...')
|
|
37
|
+
result = Dir.glob('/**/*/giraffe_storage')
|
|
38
|
+
if result.empty?
|
|
39
|
+
@cli.say('Unable to locate the Starbound installation directory.')
|
|
40
|
+
a = ''
|
|
41
|
+
until Dir.exist?(a) && Dir.exist?(a + '/giraffe_storage') && File.writable?(a)
|
|
42
|
+
a = @cli.ask("Please locate the directory manually and enter it below.\n> ")
|
|
43
|
+
if not Dir.exist?(a) && Dir.exist?(a + '/giraffe_storage')
|
|
44
|
+
@cli.say('Error - This dirctory does not exist or is not a Starbound installation. Try again.')
|
|
45
|
+
elsif not File.writable?(a)
|
|
46
|
+
@cli.say('Error - This dirctory cannot be written to. Check permissions and try again.')
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
config['starbound_directory'] = a
|
|
50
|
+
else
|
|
51
|
+
if result.count > 1
|
|
52
|
+
@cli.say('SBCP encountered multiple possible directories.')
|
|
53
|
+
answer = @cli.choose do |menu|
|
|
54
|
+
menu.prompt = "Please select a directory\n> "
|
|
55
|
+
result.each do |dir|
|
|
56
|
+
dir = dir.split("/")[0..3].join("/")
|
|
57
|
+
menu.choice(dir) { abort('Error - This directory cannot be written to. Check permissions and try again.') if not File.writable?(dir); config['starbound_directory'] = dir }
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
@cli.say("Starbound installation directory set to \"#{config['starbound_directory']}\"")
|
|
61
|
+
else
|
|
62
|
+
r = result.first.split("/giraffe_storage").first
|
|
63
|
+
@cli.say('SBCP successfully located the Starbound installation directory at:')
|
|
64
|
+
@cli.say("\"#{r}\"")
|
|
65
|
+
abort('Error - This directory cannot be written to. Check permissions and try again.') if not File.writable?(r)
|
|
66
|
+
config['starbound_directory'] = r
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
root = config['starbound_directory']
|
|
70
|
+
|
|
71
|
+
@cli.newline
|
|
72
|
+
@cli.say('Welcome to SBCP.')
|
|
73
|
+
@cli.say('You can change any options later by running the config command. (config)')
|
|
74
|
+
if @cli.agree("Would you like to skip setup and just use SBCP's default settings? (See README) (y/n)")
|
|
75
|
+
# So we're running with the defaults. Let's get 'em setup!
|
|
76
|
+
FileUtils.mkdir "#{root}/sbcp" if not Dir.exist?("#{root}/sbcp")
|
|
77
|
+
FileUtils.mkdir "#{root}/sbcp/backups" if not Dir.exist?("#{root}/sbcp/backups")
|
|
78
|
+
FileUtils.mkdir "#{root}/sbcp/logs" if not Dir.exist?("#{root}/sbcp/logs")
|
|
79
|
+
config['backup_directory'] = "#{root}/sbcp/backups"
|
|
80
|
+
config['backup_history'] = 90
|
|
81
|
+
config['backup_schedule'] = "hourly"
|
|
82
|
+
config['log_directory'] = "#{root}/sbcp/logs"
|
|
83
|
+
config['log_history'] = 90
|
|
84
|
+
config['log_style'] = "daily"
|
|
85
|
+
config['duplicate_names'] = false
|
|
86
|
+
config['duplicate_kick_msg'] = "Another player is currently online with your character's name."
|
|
87
|
+
config['restart_schedule'] = 4
|
|
88
|
+
else
|
|
89
|
+
# Backup Settings
|
|
90
|
+
@cli.newline
|
|
91
|
+
@cli.say('--- Automatic Backups ---')
|
|
92
|
+
if @cli.agree('Would you like to enable automatic backups?')
|
|
93
|
+
@cli.newline
|
|
94
|
+
@cli.say('--- Backup Directory Location ---')
|
|
95
|
+
answer = ''
|
|
96
|
+
until Dir.exist?(answer) && File.writable?(answer) || answer == 'default'
|
|
97
|
+
answer = @cli.ask('Where would you like backups to be stored? Type "default" to use default.')
|
|
98
|
+
if not Dir.exist?(answer)
|
|
99
|
+
@cli.say('Error - This dirctory does not exist. Try again.') unless answer == 'default'
|
|
100
|
+
elsif not File.writable?(answer)
|
|
101
|
+
@cli.say('Error - This dirctory cannot be written to. Check permissions and try again.')
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
if answer == 'default'
|
|
105
|
+
config['backup_directory'] = "#{root}/sbcp/backups"
|
|
106
|
+
FileUtils.mkdir_p "#{root}/sbcp/backups" if not Dir.exist?("#{root}/sbcp/backups")
|
|
107
|
+
else
|
|
108
|
+
config['backup_directory'] = answer
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
@cli.newline
|
|
112
|
+
@cli.say('--- Backup Schedule ---')
|
|
113
|
+
answer = @cli.ask('How frequently would you like to take backups (in hours)? Type 0 for on restart.', Integer) { |q| q.in = [0, 1, 2, 3, 4, 6, 8, 12, 24] }
|
|
114
|
+
answer = 'restart' if answer == 0
|
|
115
|
+
answer = 'hourly' if answer == 1
|
|
116
|
+
answer = 'daily' if answer == 24
|
|
117
|
+
config['backup_schedule'] = answer
|
|
118
|
+
|
|
119
|
+
@cli.newline
|
|
120
|
+
@cli.say('--- Backup History ---')
|
|
121
|
+
answer = 0
|
|
122
|
+
until answer > 0
|
|
123
|
+
answer = @cli.ask('How long would like to keep the backups (in # of days)?', Integer)
|
|
124
|
+
@cli.say('Value must be greater than zero.') if not answer > 0
|
|
125
|
+
end
|
|
126
|
+
config['backup_history'] = answer
|
|
127
|
+
else
|
|
128
|
+
config['backup_history'] = 'none'
|
|
129
|
+
end
|
|
130
|
+
File.write(config_file, config.to_yaml) # Periodic save
|
|
131
|
+
|
|
132
|
+
# Log Settings
|
|
133
|
+
@cli.newline
|
|
134
|
+
@cli.say('--- Log Directory Location ---')
|
|
135
|
+
answer = ''
|
|
136
|
+
until Dir.exist?(answer) && File.writable?(answer) || answer == 'default'
|
|
137
|
+
answer = @cli.ask('Where would you like log files to be stored? Type "default" to use default.')
|
|
138
|
+
if not Dir.exist?(answer)
|
|
139
|
+
@cli.say('Error - This dirctory does not exist. Try again.') unless answer == 'default'
|
|
140
|
+
elsif not File.writable?(answer)
|
|
141
|
+
@cli.say('Error - This dirctory cannot be written to. Check permissions and try again.')
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
if answer == 'default'
|
|
145
|
+
config['log_directory'] = "#{root}/sbcp/logs"
|
|
146
|
+
FileUtils.mkdir_p "#{root}/sbcp/logs" if not Dir.exist?("#{root}/sbcp/logs")
|
|
147
|
+
else
|
|
148
|
+
config['log_directory'] = answer
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
@cli.newline
|
|
152
|
+
@cli.say('--- Log History ---')
|
|
153
|
+
answer = 0
|
|
154
|
+
until answer > 0
|
|
155
|
+
answer = @cli.ask('How long would you like log files to be kept (in days)?', Integer)
|
|
156
|
+
@cli.say('Value must be greater than zero.') if not answer > 0
|
|
157
|
+
end
|
|
158
|
+
config['log_history'] = answer
|
|
159
|
+
|
|
160
|
+
@cli.newline
|
|
161
|
+
@cli.say('--- Log Style ---')
|
|
162
|
+
@cli.say('There are two types of log styles available.')
|
|
163
|
+
@cli.say('Daily: One log file per day. Bigger files, but less of them.')
|
|
164
|
+
@cli.say('Restart: One log file per restart. Smaller files, but more of them.')
|
|
165
|
+
answer = @cli.ask("What kind of log style do you prefer?\n> ") { |q| q.in = ['daily', 'restart'] }
|
|
166
|
+
config['log_style'] = answer
|
|
167
|
+
File.write(config_file, config.to_yaml)
|
|
168
|
+
|
|
169
|
+
# Restart Settings
|
|
170
|
+
@cli.newline
|
|
171
|
+
@cli.say('--- Restart Schedule ---')
|
|
172
|
+
answer = @cli.ask('How frequently would you like the Starbound server to restart (in hours)? Type 0 to disable.', Integer) { |q| q.in = [0, 1, 2, 3, 4, 6, 8, 12, 24] }
|
|
173
|
+
answer = 'none' if response == 0
|
|
174
|
+
answer = 'hourly' if response == 1
|
|
175
|
+
answer = 'daily' if response == 24
|
|
176
|
+
config['restart_schedule'] = answer
|
|
177
|
+
File.write(config_file, config.to_yaml)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Create the plugins directory and readme
|
|
181
|
+
FileUtils.mkdir_p "#{root}/sbcp/plugins" if not Dir.exist?("#{root}/sbcp/plugins")
|
|
182
|
+
File.write("#{root}/sbcp/plugins/README.txt", "You can override SBCP's behavior by writing your own Ruby plugins and placing them here.\nCheck the README on GitHub for more information.")
|
|
183
|
+
|
|
184
|
+
# We save everything back to the config file at the end.
|
|
185
|
+
File.write(config_file, config.to_yaml)
|
|
186
|
+
|
|
187
|
+
@cli.newline
|
|
188
|
+
@cli.say('SBCP has been configured successfully.')
|
|
189
|
+
@cli.say('Type help for a list of commands.')
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|