sbcp 0.1.4
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 +7 -0
- data/.gitattributes +22 -0
- data/.gitignore +11 -0
- data/.travis.yml +4 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +661 -0
- data/README.md +93 -0
- data/Rakefile +10 -0
- data/backup/README.md +1 -0
- data/bin/sbcp +653 -0
- data/config.yml +9 -0
- data/lib/sbcp.rb +38 -0
- data/lib/sbcp/backup.rb +59 -0
- data/lib/sbcp/daemon.rb +115 -0
- data/lib/sbcp/logs.rb +11 -0
- data/lib/sbcp/parser.rb +10 -0
- data/lib/sbcp/starbound.rb +71 -0
- data/lib/sbcp/version.rb +3 -0
- data/sbcp.gemspec +41 -0
- metadata +201 -0
data/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Starbound Control Panel
|
|
2
|
+
[](https://badge.fury.io/rb/sbcp)
|
|
3
|
+
|
|
4
|
+
Starbound Control Panel, or SBCP for short, is a Ruby gem that allows server owners to easily manage their servers. It behaves similarly to a wrapper without intercepting connections, relying solely on output. It is my first released project on GitHub, as well as my first Ruby gem.
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
* Relatively easy to install and setup
|
|
9
|
+
* Fully automated backups
|
|
10
|
+
* Fully automated restarts (including recovery from crashes)
|
|
11
|
+
* Easy server managment commands (start, restart, stop, etc.)
|
|
12
|
+
* Intuitive configuration menu for adjusting internal settings
|
|
13
|
+
|
|
14
|
+
## Requirements
|
|
15
|
+
|
|
16
|
+
SBCP was designed for Linux and developed on Ubuntu. It has been tested on Ubuntu Server 16.04.
|
|
17
|
+
|
|
18
|
+
SBCP was developed on Ruby 2.3.0.
|
|
19
|
+
|
|
20
|
+
Your mileage may vary.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
If you don't have Ruby installed, you'll need it.
|
|
25
|
+
I reccommend using [RVM](https://rvm.io/rvm/install):
|
|
26
|
+
|
|
27
|
+
$ gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
|
|
28
|
+
$ \curl -sSL https://get.rvm.io | bash -s stable --ruby=2.3.0
|
|
29
|
+
|
|
30
|
+
If you already have RVM:
|
|
31
|
+
|
|
32
|
+
$ rvm install ruby-2.3.0
|
|
33
|
+
$ rvm use ruby-2.3.0
|
|
34
|
+
|
|
35
|
+
Now just install the SBCP gem:
|
|
36
|
+
|
|
37
|
+
$ gem install sbcp
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
You'll find that SBCP won't work properly without some additional configuration.
|
|
42
|
+
|
|
43
|
+
Go ahead and start this process with the setup command:
|
|
44
|
+
|
|
45
|
+
$ sbcp --setup
|
|
46
|
+
|
|
47
|
+
It will attempt to ascertain the location of your Starbound server's installation directory.
|
|
48
|
+
|
|
49
|
+
Afterwards, it will ask if you want to use the default values. All default directories are based out of the Starbound installation directory. These values are:
|
|
50
|
+
* Backup Directory: ../sbcp/backups
|
|
51
|
+
* Backup History: 90 days
|
|
52
|
+
* Backup Schedule: Hourly
|
|
53
|
+
* Log Directory: ../sbcp/logs
|
|
54
|
+
* Log History: 90 days
|
|
55
|
+
* Log Style: Daily
|
|
56
|
+
* Restart Schedule: Every 4 Hours
|
|
57
|
+
|
|
58
|
+
Once this is finished, you can just do this for commands:
|
|
59
|
+
|
|
60
|
+
$ sbcp --help
|
|
61
|
+
|
|
62
|
+
Note that currently not all commands are implemented.
|
|
63
|
+
|
|
64
|
+
## Plugins
|
|
65
|
+
|
|
66
|
+
SBCP has rudimentary plugin support. You can override SBCP's behavior by adding your own Ruby files to the plugins folder that's created during initial setup. You'll need to examine the source material as plugins will entirely override methods, so if you're looking to make changes to existing methods you will need to copy/paste the source into your plugin before making changes. The filename of your plugin doesn't matter as all Ruby files inside the plugin folder are loaded shortly after the daemon starts.
|
|
67
|
+
|
|
68
|
+
You can find the plugins folder in /sbcp/plugins, in the installation directory of your Starbound folder.
|
|
69
|
+
|
|
70
|
+
## TODO
|
|
71
|
+
|
|
72
|
+
SBCP isn't anywhere near complete. I have some additional features planned:
|
|
73
|
+
|
|
74
|
+
* GUI mode
|
|
75
|
+
* Permissions System to Allow Multiple Users of GUI mode
|
|
76
|
+
* Output Parser (useful for emulating in-game commands, amongst other things)
|
|
77
|
+
* RCON support
|
|
78
|
+
* Better Plugin Support
|
|
79
|
+
* Ban/Kick/Unban commands
|
|
80
|
+
* Server announcements (including restart announcements)
|
|
81
|
+
* More that I can't think of right now, I'm sure
|
|
82
|
+
|
|
83
|
+
## Contributing
|
|
84
|
+
|
|
85
|
+
Bug reports and pull requests are welcome.
|
|
86
|
+
|
|
87
|
+
Although bear with me, I haven't used GitHub much before so I'll need to read up on pull requests.
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
## License
|
|
91
|
+
|
|
92
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
|
93
|
+
|
data/Rakefile
ADDED
data/backup/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
SBCP uses this directory to create incremental backups.
|
data/bin/sbcp
ADDED
|
@@ -0,0 +1,653 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'optparse'
|
|
4
|
+
require 'highline'
|
|
5
|
+
require_relative '../lib/sbcp/version'
|
|
6
|
+
|
|
7
|
+
o = OptionParser.new do |opts|
|
|
8
|
+
opts.banner = 'Usage: sbcp [options]'
|
|
9
|
+
|
|
10
|
+
# This starts SBCP and creates the underlying daemon process.
|
|
11
|
+
# The daemon process is responsible for maintaining the server.
|
|
12
|
+
# There are two modes, Command Line Interface and Graphical User Interface.
|
|
13
|
+
# CLI mode disables the web server to improve performance.
|
|
14
|
+
|
|
15
|
+
opts.on('-s', '--start [MODE]', 'Starts SBCP in either CLI or GUI mode (Default: CLI)') do |mode|
|
|
16
|
+
mode = 'CLI' if mode == nil
|
|
17
|
+
case mode.upcase
|
|
18
|
+
when 'CLI'
|
|
19
|
+
@cli.say('The control panel has been started in CLI mode.')
|
|
20
|
+
require_relative '../lib/sbcp/daemon'
|
|
21
|
+
SBCP::Daemon.run
|
|
22
|
+
when 'GUI'
|
|
23
|
+
abort('Currently unsupported.')
|
|
24
|
+
#require '../lib/sbcp'
|
|
25
|
+
#SBCP::Panel.run!
|
|
26
|
+
#puts "The control panel has been started in GUI mode."
|
|
27
|
+
#puts "Access the GUI at <ipaddress>:4567 in your web browser."
|
|
28
|
+
else
|
|
29
|
+
@cli.say('Please provide either CLI or GUI as an arguement.')
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Attempts to gracefully stop the server without fully shutting it down.
|
|
34
|
+
# This may not always be successful, as Starbound is sometimes unreceptive to kill signals.
|
|
35
|
+
|
|
36
|
+
opts.on('-r', '--restart', 'Gracefully restarts the Starbound server') do
|
|
37
|
+
if @cli.agree('This will attempt to gracefully restart the server. Are you sure? (y/n)') then
|
|
38
|
+
@cli.say('Attempting to gracefully restart the server...')
|
|
39
|
+
pid = `pidof starbound_server`
|
|
40
|
+
if not pid.empty?
|
|
41
|
+
system("kill -15 #{pid.to_i}")
|
|
42
|
+
time = Time.now
|
|
43
|
+
diff = 0
|
|
44
|
+
until `pidof starbound_server`.empty? || diff >= 5
|
|
45
|
+
sleep 1
|
|
46
|
+
diff = Time.now - time
|
|
47
|
+
end
|
|
48
|
+
abort('Unable to stop the server for restart. Reboot command may be required.') if not `pidof starbound_server`.empty?
|
|
49
|
+
@cli.say('The Starbound server has been successfully stopped and will restart automatically.')
|
|
50
|
+
else
|
|
51
|
+
abort('Unable to locate the Starbound server process ID. Is it running?')
|
|
52
|
+
end
|
|
53
|
+
else
|
|
54
|
+
@cli.say('Graceful restart aborted.')
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# This kills the server process almost immediately.
|
|
59
|
+
# This just stops it cold in it's tracks, so it's possible to lose information stored in memory.
|
|
60
|
+
|
|
61
|
+
opts.on('-R', '--reboot', 'Forcibly restarts the Starbound server') do
|
|
62
|
+
if @cli.agree('This will forcibly restart the server. Some data may be lost as a result. Are you sure? (y/n)') then
|
|
63
|
+
@cli.say('Attempting to forcefully reboot the server...')
|
|
64
|
+
pid = `pidof starbound_server`
|
|
65
|
+
if not pid.empty?
|
|
66
|
+
system("kill -9 #{pid.to_i}")
|
|
67
|
+
time = Time.now
|
|
68
|
+
diff = 0
|
|
69
|
+
until `pidof starbound_server`.empty? || diff >= 5
|
|
70
|
+
sleep 1
|
|
71
|
+
diff = Time.now - time
|
|
72
|
+
end
|
|
73
|
+
abort('Unable to forcefully reboot the server. Try again?') if not `pidof starbound_server`.empty?
|
|
74
|
+
@cli.say('The Starbound server has been successfully stopped and will restart automatically.')
|
|
75
|
+
else
|
|
76
|
+
abort('Unable to locate the Starbound server process ID. Is it running?')
|
|
77
|
+
end
|
|
78
|
+
else
|
|
79
|
+
@cli.say('Force restart aborted.')
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Same as the graceful restart option, only the server doesn't come back automatically.
|
|
84
|
+
# We create a temporary file to indicate that we don't want the server to restart.
|
|
85
|
+
# The temporary file is removed when we call file.unlink
|
|
86
|
+
|
|
87
|
+
opts.on('-g', '--grace', 'Gracefully stops the Starbound server') do
|
|
88
|
+
if @cli.agree('This will attempt to gracefully stop the server. Are you sure? (y/n)') then
|
|
89
|
+
require 'tempfile'
|
|
90
|
+
@cli.say('Attempting to gracefully stop the Starbound server...')
|
|
91
|
+
begin
|
|
92
|
+
file = Tempfile.new('sb-shutdown')
|
|
93
|
+
pid = `pidof starbound_server`
|
|
94
|
+
if not pid.empty?
|
|
95
|
+
system("kill -15 #{pid.to_i}")
|
|
96
|
+
time = Time.now
|
|
97
|
+
diff = 0
|
|
98
|
+
until `pidof starbound_server`.empty? || diff >= 5
|
|
99
|
+
sleep 1
|
|
100
|
+
diff = Time.now - time
|
|
101
|
+
end
|
|
102
|
+
abort('Unable to gracefully stop the server. Force may be neccesary.') if not `pidof starbound_server`.empty?
|
|
103
|
+
@cli.say('The Starbound server has been successfully stopped.')
|
|
104
|
+
else
|
|
105
|
+
abort('Unable to locate the Starbound server process ID. Is it running?')
|
|
106
|
+
end
|
|
107
|
+
ensure
|
|
108
|
+
file.close
|
|
109
|
+
file.unlink
|
|
110
|
+
end
|
|
111
|
+
else
|
|
112
|
+
@cli.say('Server shutdown aborted.')
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Same as the force restart option, without the server coming back automatically.
|
|
117
|
+
|
|
118
|
+
opts.on('-K', '--kill', 'Forcibly stops the Starbound server') do
|
|
119
|
+
if @cli.agree('This will forcibly stop the server. Some data may be lost as a result. Are you sure? (y/n)') then
|
|
120
|
+
require 'tempfile'
|
|
121
|
+
@cli.say('Attempting to forcefully stop the Starbound server...')
|
|
122
|
+
begin
|
|
123
|
+
file = Tempfile.new('sb-shutdown')
|
|
124
|
+
pid = `pidof starbound_server`
|
|
125
|
+
if not pid.empty?
|
|
126
|
+
system("kill -9 #{pid.to_i}")
|
|
127
|
+
time = Time.now
|
|
128
|
+
diff = 0
|
|
129
|
+
until `pidof starbound_server`.empty? || diff >= 5
|
|
130
|
+
sleep 1
|
|
131
|
+
diff = Time.now - time
|
|
132
|
+
end
|
|
133
|
+
abort('Unable to forcefully stop the server. Try again?') if not `pidof starbound_server`.empty?
|
|
134
|
+
@cli.say('The Starbound server has been successfully stopped.')
|
|
135
|
+
else
|
|
136
|
+
abort('Unable to locate the Starbound server process ID. Is it running?')
|
|
137
|
+
end
|
|
138
|
+
ensure
|
|
139
|
+
file.close
|
|
140
|
+
file.unlink
|
|
141
|
+
end
|
|
142
|
+
else
|
|
143
|
+
@cli.say('Force stop aborted.')
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Allows an admin to kick a player.
|
|
148
|
+
# UUIDs can be spoofed and names can be changed, so IP is the most reliable. (Although, proxies can bypass this.)
|
|
149
|
+
# There will be support for Steam IDs if/when Starbound supports them.
|
|
150
|
+
|
|
151
|
+
opts.on('-k', '--kick TYPE', [:uuid, :name, :ip], 'Kicks a specified player by either UUID, Name, or IP') do |type|
|
|
152
|
+
@cli.say('This feature will be added later.')
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Same as the kick command, except for a specified time period or permanently.
|
|
156
|
+
# Can be reverse with the unban command.
|
|
157
|
+
|
|
158
|
+
opts.on('-b', '--ban TYPE', [:uuid, :name, :ip], 'Bans a specified player by either UUID, Name, or IP') do |type|
|
|
159
|
+
@cli.say('This feature will be added later.')
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Removes a previously assigned ban on a player based on criteria.
|
|
163
|
+
# It will return an error if the specified critera doesn't exist.
|
|
164
|
+
|
|
165
|
+
opts.on('-u', '--unban TYPE', [:uuid, :name, :ip], 'Unbans a specified player by either UUID, Name, or IP') do |type|
|
|
166
|
+
@cli.say('This feature will be added later.')
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Allows an admin to easily grab the most recent information.
|
|
170
|
+
# Supports up to the last 100 lines.
|
|
171
|
+
|
|
172
|
+
opts.on('-l', '--list TYPE', [:bans, :connections, :logs], 'Lists the last X lines of the specified data type. (bans, connections, or logs)') do |type|
|
|
173
|
+
@cli.say('This feature will be added later.')
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# This command creates a full backup of all Starbound and SBCP data.
|
|
177
|
+
# This includes: Starbound world files, logs files, and the SBCP database.
|
|
178
|
+
|
|
179
|
+
opts.on('-B', '--backup TYPE', [:starbound, :sbcp, :full],'Creates a backup of the specified data. (starbound, sbcp, or full)') do |type|
|
|
180
|
+
if @cli.agree("Are you sure? This will start the backup process.\nIf the Starbound server is running, it may experience brief sluggishness.") then
|
|
181
|
+
require_relative '../lib/sbcp/backup'
|
|
182
|
+
SBCP::Backup.create_backup(type)
|
|
183
|
+
@cli.say('Backup has completed successfully.')
|
|
184
|
+
else
|
|
185
|
+
@cli.say('Backup aborted.')
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Stops the SBCP process as gently as possible.
|
|
190
|
+
# It won't work if Starbound is running, so stop the Starbound server first.
|
|
191
|
+
|
|
192
|
+
opts.on('-e', '--exit', 'Gracefully stops SBCP') do
|
|
193
|
+
@cli.say("This feature is only used in GUI mode. GUI mode is not yet implemented.")
|
|
194
|
+
@cli.say("In CLI mode, stopping Starbound will automatically stop SBCP.")
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Kills both SBCP and the Starbound server, if running.
|
|
198
|
+
# This command needs work. It doesn't always work properly.
|
|
199
|
+
# Usually, the starbound process has to be killed first.
|
|
200
|
+
# After that, SBCP usually closes on it's own... making this command moot.
|
|
201
|
+
|
|
202
|
+
opts.on('-a', '--abort', 'Forcibly stops SBCP') do
|
|
203
|
+
if @cli.agree('This will attempt to forcibly stop the control panel. Some data may be lost as a result. Are you sure? (y/n)') then
|
|
204
|
+
pid = `pidof starbound_server`
|
|
205
|
+
if not pid.empty?
|
|
206
|
+
system("kill -9 #{pid.to_i}")
|
|
207
|
+
time = Time.now
|
|
208
|
+
diff = 0
|
|
209
|
+
until `pidof starbound_server`.empty? || diff >= 5
|
|
210
|
+
sleep 1
|
|
211
|
+
diff = Time.now - time
|
|
212
|
+
end
|
|
213
|
+
abort('Unable to forcfully close Starbound. Try closing it separately?') if not `pidof starbound_server`.empty?
|
|
214
|
+
end
|
|
215
|
+
if not Dir.glob('/tmp/sbcp_daemon-pid*').empty?
|
|
216
|
+
pid_file = Dir.glob('/tmp/sbcp_daemon-pid*').first
|
|
217
|
+
pid = File.read(pid_file)
|
|
218
|
+
system("kill -9 #{pid.to_i}")
|
|
219
|
+
time = Time.now
|
|
220
|
+
diff = 0
|
|
221
|
+
until `ps -p #{pid.to_i} -o comm=`.empty? || diff >= 5
|
|
222
|
+
sleep 1
|
|
223
|
+
diff = Time.now - time
|
|
224
|
+
end
|
|
225
|
+
abort('Unable to forcefully stop the control panel. Try again?') if not `ps -p #{pid.to_i} -o comm=`.empty?
|
|
226
|
+
@cli.say('The control panel has been successfully stopped.')
|
|
227
|
+
else
|
|
228
|
+
@cli.say('Unable to locate the control panel process ID. Is it running?')
|
|
229
|
+
end
|
|
230
|
+
else
|
|
231
|
+
puts 'The control panel was not aborted.'
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Opens the config menu.
|
|
236
|
+
# What else is there to say?
|
|
237
|
+
|
|
238
|
+
opts.on_tail('-c', '--config', 'Opens the config menu') do
|
|
239
|
+
require 'yaml'
|
|
240
|
+
#@cli.say('NOTICE: SBCP must be restarted for any changes to take effect. (GUI mode only)')
|
|
241
|
+
@cli.say('NOTICE: Starbound must be restarted for any changes to take effect.')
|
|
242
|
+
config_menu(:main)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# This sets SBCP up for proper usage.
|
|
246
|
+
# Ideally, only run once.
|
|
247
|
+
|
|
248
|
+
opts.on_tail('-S', '--setup', 'Performs first time setup') do
|
|
249
|
+
require 'yaml'
|
|
250
|
+
require 'fileutils'
|
|
251
|
+
config_file = File.expand_path('../../config.yml', __FILE__)
|
|
252
|
+
config = YAML.load_file(config_file)
|
|
253
|
+
response = @cli.agree('Are you sure you want to run the first-time setup? (y/n)')
|
|
254
|
+
if response # If response is true, continue
|
|
255
|
+
# First, we must attempt to locate where Starbound is installed.
|
|
256
|
+
# This performs a recursive search on the OS for a folder named 'giraffe_storage'
|
|
257
|
+
@cli.newline
|
|
258
|
+
@cli.say('SBCP is starting up...')
|
|
259
|
+
@cli.say('SBCP is attempting to automatically locate Starbound...')
|
|
260
|
+
result = Dir.glob('/**/*/giraffe_storage')
|
|
261
|
+
if result.empty?
|
|
262
|
+
@cli.say('Unable to locate the Starbound installation directory.')
|
|
263
|
+
a = ''
|
|
264
|
+
until Dir.exist?(a) && Dir.exist?(a + '/giraffe_storage') && File.writable?(a)
|
|
265
|
+
a = @cli.ask("Please locate the directory manually and enter it below.\n> ")
|
|
266
|
+
if not Dir.exist?(a) && Dir.exist?(a + '/giraffe_storage')
|
|
267
|
+
@cli.say('Error - This dirctory does not exist or is not a Starbound installation. Try again.')
|
|
268
|
+
elsif not File.writable?(a)
|
|
269
|
+
@cli.say('Error - This dirctory cannot be written to. Check permissions and try again.')
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
config['starbound_directory'] = a
|
|
273
|
+
else
|
|
274
|
+
if result.count > 1
|
|
275
|
+
@cli.say('SBCP encountered multiple possible directories.')
|
|
276
|
+
answer = @cli.choose do |menu|
|
|
277
|
+
menu.prompt = "Please select a directory\n> "
|
|
278
|
+
result.each do |dir|
|
|
279
|
+
dir = dir.split("/")[0..3].join("/")
|
|
280
|
+
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 }
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
@cli.say("Starbound installation directory set to \"#{config['starbound_directory']}\"")
|
|
284
|
+
else
|
|
285
|
+
r = result.first.split("/giraffe_storage").first
|
|
286
|
+
@cli.say('SBCP successfully located the Starbound installation directory at:')
|
|
287
|
+
@cli.say("\"#{r}\"")
|
|
288
|
+
abort('Error - This directory cannot be written to. Check permissions and try again.') if not File.writable?(r)
|
|
289
|
+
config['starbound_directory'] = r
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
root = config['starbound_directory']
|
|
293
|
+
|
|
294
|
+
@cli.newline
|
|
295
|
+
@cli.say('Welcome to SBCP.')
|
|
296
|
+
@cli.say('You can change any options later by running the config command. (sbcp -c)')
|
|
297
|
+
if @cli.agree("Would you like to skip setup and just use SBCP's default settings? (See README) (y/n)")
|
|
298
|
+
# So we're running with the defaults. Let's get 'em setup!
|
|
299
|
+
FileUtils.mkdir "#{root}/sbcp" if not Dir.exist?("#{root}/sbcp")
|
|
300
|
+
FileUtils.mkdir "#{root}/sbcp/backups" if not Dir.exist?("#{root}/sbcp/backups")
|
|
301
|
+
FileUtils.mkdir "#{root}/sbcp/logs" if not Dir.exist?("#{root}/sbcp/logs")
|
|
302
|
+
config['backup_directory'] = "#{root}/sbcp/backups"
|
|
303
|
+
config['log_directory'] = "#{root}/sbcp/logs"
|
|
304
|
+
else
|
|
305
|
+
# Backup Settings
|
|
306
|
+
@cli.newline
|
|
307
|
+
@cli.say('--- Automatic Backups ---')
|
|
308
|
+
if @cli.agree('Would you like to enable automatic backups?')
|
|
309
|
+
@cli.newline
|
|
310
|
+
@cli.say('--- Backup Directory Location ---')
|
|
311
|
+
answer = ''
|
|
312
|
+
until Dir.exist?(answer) && File.writable?(answer) || answer == 'default'
|
|
313
|
+
answer = @cli.ask('Where would you like backups to be stored? Type "default" to use default.')
|
|
314
|
+
if not Dir.exist?(answer)
|
|
315
|
+
@cli.say('Error - This dirctory does not exist. Try again.') unless answer == 'default'
|
|
316
|
+
elsif not File.writable?(answer)
|
|
317
|
+
@cli.say('Error - This dirctory cannot be written to. Check permissions and try again.')
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
if answer == 'default'
|
|
321
|
+
config['backup_directory'] = "#{root}/sbcp/backups"
|
|
322
|
+
FileUtils.mkdir_p "#{root}/sbcp/backups" if not Dir.exist?("#{root}/sbcp/backups")
|
|
323
|
+
else
|
|
324
|
+
config['backup_directory'] = answer
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
@cli.newline
|
|
328
|
+
@cli.say('--- Backup Schedule ---')
|
|
329
|
+
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] }
|
|
330
|
+
answer = 'restart' if answer == 0
|
|
331
|
+
answer = 'hourly' if answer == 1
|
|
332
|
+
answer = 'daily' if answer == 24
|
|
333
|
+
config['backup_schedule'] = answer
|
|
334
|
+
|
|
335
|
+
@cli.newline
|
|
336
|
+
@cli.say('--- Backup History ---')
|
|
337
|
+
answer = 0
|
|
338
|
+
until answer > 0
|
|
339
|
+
answer = @cli.ask('How long would like to keep the backups (in # of days)?', Integer)
|
|
340
|
+
@cli.say('Value must be greater than zero.') if not answer > 0
|
|
341
|
+
end
|
|
342
|
+
config['backup_history'] = answer
|
|
343
|
+
else
|
|
344
|
+
config['backup_history'] = 'none'
|
|
345
|
+
end
|
|
346
|
+
File.write(config_file, config.to_yaml) # Periodic save
|
|
347
|
+
|
|
348
|
+
# Log Settings
|
|
349
|
+
@cli.newline
|
|
350
|
+
@cli.say('--- Log Directory Location ---')
|
|
351
|
+
answer = ''
|
|
352
|
+
until Dir.exist?(answer) && File.writable?(answer) || answer == 'default'
|
|
353
|
+
answer = @cli.ask('Where would you like log files to be stored? Type "default" to use default.')
|
|
354
|
+
if not Dir.exist?(answer)
|
|
355
|
+
@cli.say('Error - This dirctory does not exist. Try again.') unless answer == 'default'
|
|
356
|
+
elsif not File.writable?(answer)
|
|
357
|
+
@cli.say('Error - This dirctory cannot be written to. Check permissions and try again.')
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
if answer == 'default'
|
|
361
|
+
config['log_directory'] = "#{root}/sbcp/logs"
|
|
362
|
+
FileUtils.mkdir_p "#{root}/sbcp/logs" if not Dir.exist?("#{root}/sbcp/logs")
|
|
363
|
+
else
|
|
364
|
+
config['log_directory'] = answer
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
@cli.newline
|
|
368
|
+
@cli.say('--- Log History ---')
|
|
369
|
+
answer = 0
|
|
370
|
+
until answer > 0
|
|
371
|
+
answer = @cli.ask('How long would you like log files to be kept (in days)?', Integer)
|
|
372
|
+
@cli.say('Value must be greater than zero.') if not answer > 0
|
|
373
|
+
end
|
|
374
|
+
config['log_history'] = answer
|
|
375
|
+
|
|
376
|
+
@cli.newline
|
|
377
|
+
@cli.say('--- Log Style ---')
|
|
378
|
+
@cli.say('There are two types of log styles available.')
|
|
379
|
+
@cli.say('Daily: One log file per day. Bigger files, but less of them.')
|
|
380
|
+
@cli.say('Restart: One log file per restart. Smaller files, but more of them.')
|
|
381
|
+
answer = @cli.ask("What kind of log style do you prefer?\n> ") { |q| q.in = ['daily', 'restart'] }
|
|
382
|
+
config['log_style'] = answer
|
|
383
|
+
File.write(config_file, config.to_yaml)
|
|
384
|
+
|
|
385
|
+
# Restart Settings
|
|
386
|
+
@cli.newline
|
|
387
|
+
@cli.say('--- Restart Schedule ---')
|
|
388
|
+
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] }
|
|
389
|
+
answer = 'none' if response == 0
|
|
390
|
+
answer = 'hourly' if response == 1
|
|
391
|
+
answer = 'daily' if response == 24
|
|
392
|
+
config['restart_schedule'] = answer
|
|
393
|
+
File.write(config_file, config.to_yaml)
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
# Create the plugins directory and readme
|
|
397
|
+
FileUtils.mkdir_p "#{root}/sbcp/plugins" if not Dir.exist?("#{root}/sbcp/plugins")
|
|
398
|
+
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.")
|
|
399
|
+
|
|
400
|
+
# We save everything back to the config file at the end.
|
|
401
|
+
File.write(File.expand_path('../../config.yml', __FILE__), config.to_yaml)
|
|
402
|
+
|
|
403
|
+
@cli.newline
|
|
404
|
+
@cli.say('SBCP has been configured successfully.')
|
|
405
|
+
@cli.say('Type sbcp -h for a list of commands.')
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
# Displays help.
|
|
410
|
+
|
|
411
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
|
412
|
+
puts opts
|
|
413
|
+
exit
|
|
414
|
+
end
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
def config_menu(menu)
|
|
418
|
+
config_file = File.expand_path('../../config.yml', __FILE__)
|
|
419
|
+
config = YAML.load_file(config_file)
|
|
420
|
+
case menu
|
|
421
|
+
when :main
|
|
422
|
+
answer = @cli.choose do |menu|
|
|
423
|
+
menu.prompt = "Please select a menu option\n> "
|
|
424
|
+
@cli.say("=== SBCP Configuration Menu ===")
|
|
425
|
+
menu.choice(:General) { config_menu(:general) }
|
|
426
|
+
menu.choice(:Backups) { config_menu(:backups) }
|
|
427
|
+
menu.choice(:Logs) { config_menu(:logs) }
|
|
428
|
+
menu.choice(:Restarts) { config_menu(:restarts) }
|
|
429
|
+
menu.choice(:Exit) { exit }
|
|
430
|
+
end
|
|
431
|
+
when :general
|
|
432
|
+
answer = @cli.choose do |menu|
|
|
433
|
+
menu.prompt = "Please select a menu option\n> "
|
|
434
|
+
@cli.say("=== SBCP General Settings ===")
|
|
435
|
+
menu.choice('Starbound Directory') do
|
|
436
|
+
@cli.choose do |sub_menu|
|
|
437
|
+
sub_menu.prompt = "Please select a menu option\n> "
|
|
438
|
+
@cli.say("=== SBCP Starbound Directory Setting ===")
|
|
439
|
+
@cli.say('Your current starbound directory is:')
|
|
440
|
+
@cli.say("\"#{config['starbound_directory']}\"")
|
|
441
|
+
sub_menu.choice('Keep this directory') { @cli.say('Directory kept.'); config_menu(:general) }
|
|
442
|
+
sub_menu.choice('Change this directory') do
|
|
443
|
+
response = ''
|
|
444
|
+
until Dir.exist?(response) && Dir.exist?(response + '/giraffe_storage') && File.writable?(response)
|
|
445
|
+
response = @cli.ask("Please enter a new directory.\n> ")
|
|
446
|
+
if not Dir.exist?(response) && Dir.exist?(response + '/giraffe_storage')
|
|
447
|
+
@cli.say('Error - This dirctory does not exist or is not a valid starbound installation. Try again.')
|
|
448
|
+
elsif not File.writable?(response)
|
|
449
|
+
@cli.say('Error - This dirctory cannot be written to. Check permissions and try again.')
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
config['starbound_directory'] = response
|
|
453
|
+
File.write(config_file, config.to_yaml)
|
|
454
|
+
@cli.say('Changes saved successfully.')
|
|
455
|
+
config_menu(:general)
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
menu.choice('Back to Main Menu') { config_menu(:main) }
|
|
460
|
+
end
|
|
461
|
+
when :backups
|
|
462
|
+
@cli.choose do |menu|
|
|
463
|
+
menu.prompt = "Please select a menu option\n> "
|
|
464
|
+
@cli.say("=== SBCP Backup Settings ===")
|
|
465
|
+
menu.choice('Backup Directory') do
|
|
466
|
+
@cli.choose do |sub_menu|
|
|
467
|
+
sub_menu.prompt = "Please select a menu option\n> "
|
|
468
|
+
@cli.say("=== SBCP Backup Directory Setting ===")
|
|
469
|
+
@cli.say('Your current backup directory is:')
|
|
470
|
+
@cli.say("\"#{config['backup_directory']}\"")
|
|
471
|
+
sub_menu.choice('Keep this directory') { @cli.say('Directory kept.'); config_menu(:backups) }
|
|
472
|
+
sub_menu.choice('Change this directory') do
|
|
473
|
+
response = ''
|
|
474
|
+
until Dir.exist?(response) && File.writable?(response)
|
|
475
|
+
response = @cli.ask("Please enter a new directory.\n> ")
|
|
476
|
+
if not Dir.exist?(response)
|
|
477
|
+
@cli.say('Error - This dirctory does not exist. Try again.')
|
|
478
|
+
elsif not File.writable?(response)
|
|
479
|
+
@cli.say('Error - This dirctory cannot be written to. Check permissions and try again.')
|
|
480
|
+
end
|
|
481
|
+
end
|
|
482
|
+
config['backup_directory'] = response
|
|
483
|
+
File.write(config_file, config.to_yaml)
|
|
484
|
+
@cli.say('Changes saved successfully.')
|
|
485
|
+
config_menu(:backups)
|
|
486
|
+
end
|
|
487
|
+
end
|
|
488
|
+
end
|
|
489
|
+
menu.choice('Backup History') do
|
|
490
|
+
@cli.choose do |sub_menu|
|
|
491
|
+
sub_menu.prompt = "Please select a menu option\n> "
|
|
492
|
+
@cli.say("=== SBCP Backup History Setting ===")
|
|
493
|
+
@cli.say('Backups are currently set to remain archived for:')
|
|
494
|
+
@cli.say(config['backup_history'].to_s + ' days')
|
|
495
|
+
sub_menu.choice('Keep this setting') { @cli.say('Setting kept.'); config_menu(:backups) }
|
|
496
|
+
sub_menu.choice('Change this setting') do
|
|
497
|
+
until response > 0
|
|
498
|
+
response = @cli.ask("Enter a new value in days (enter 0 to disable backups)\n> ", Integer)
|
|
499
|
+
@cli.say('Value must be greater than zero.') if not response > 0
|
|
500
|
+
end
|
|
501
|
+
config['backup_history'] = response
|
|
502
|
+
File.write(config_file, config.to_yaml)
|
|
503
|
+
@cli.say('Changes saved successfully.')
|
|
504
|
+
config_menu(:backups)
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
end
|
|
508
|
+
menu.choice('Backup Schedule') do
|
|
509
|
+
@cli.choose do |sub_menu|
|
|
510
|
+
sub_menu.prompt = "Please select a menu option\n> "
|
|
511
|
+
@cli.say("=== SBCP Backup Schedule Setting ===")
|
|
512
|
+
@cli.say('The backup schedule is currently set to:')
|
|
513
|
+
config['backup_schedule'].is_a?(Integer) ? @cli.say('Every ' + config['backup_schedule'].to_s + ' hours') : @cli.say(config['backup_schedule'].to_s)
|
|
514
|
+
sub_menu.choice('Keep this setting') { @cli.say('Setting kept.'); config_menu(:backups) }
|
|
515
|
+
sub_menu.choice('Change this setting') do
|
|
516
|
+
response = @cli.ask("Enter a new value in hours (enter 0 for on restart)\n> ", Integer) { |q| q.in = [0, 1, 2, 3, 4, 6, 8, 12, 24] }
|
|
517
|
+
response = 'restart' if response == 0
|
|
518
|
+
response = 'hourly' if response == 1
|
|
519
|
+
response = 'daily' if response == 24
|
|
520
|
+
config['backup_schedule'] = response
|
|
521
|
+
File.write(config_file, config.to_yaml)
|
|
522
|
+
@cli.say('Changes saved successfully.')
|
|
523
|
+
config_menu(:backups)
|
|
524
|
+
end
|
|
525
|
+
end
|
|
526
|
+
end
|
|
527
|
+
menu.choice('Back to Main Menu') { config_menu(:main) }
|
|
528
|
+
end
|
|
529
|
+
when :logs
|
|
530
|
+
@cli.choose do |menu|
|
|
531
|
+
menu.prompt = "Please select a menu option\n> "
|
|
532
|
+
@cli.say("=== SBCP Log Settings ===")
|
|
533
|
+
menu.choice('Log Directory') do
|
|
534
|
+
@cli.choose do |sub_menu|
|
|
535
|
+
sub_menu.prompt = "Please select a menu option\n> "
|
|
536
|
+
@cli.say("=== SBCP Log Directory Setting ===")
|
|
537
|
+
@cli.say('Your current logs directory is:')
|
|
538
|
+
@cli.say("\"#{config['log_directory']}\"")
|
|
539
|
+
sub_menu.choice('Keep this directory') { @cli.say('Directory kept.'); config_menu(:logs) }
|
|
540
|
+
sub_menu.choice('Change this directory') do
|
|
541
|
+
response = ''
|
|
542
|
+
until Dir.exist?(response) && File.writable?(response)
|
|
543
|
+
response = @cli.ask("Please enter a new directory.\n> ")
|
|
544
|
+
if not Dir.exist?(response)
|
|
545
|
+
@cli.say('Error - This dirctory does not exist. Try again.')
|
|
546
|
+
elsif not File.writable?(response)
|
|
547
|
+
@cli.say('Error - This dirctory cannot be written to. Check permissions and try again.')
|
|
548
|
+
end
|
|
549
|
+
end
|
|
550
|
+
config['log_directory'] = response
|
|
551
|
+
File.write(config_file, config.to_yaml)
|
|
552
|
+
@cli.say('Changes saved successfully.')
|
|
553
|
+
config_menu(:logs)
|
|
554
|
+
end
|
|
555
|
+
end
|
|
556
|
+
end
|
|
557
|
+
menu.choice('Log History') do
|
|
558
|
+
@cli.choose do |sub_menu|
|
|
559
|
+
sub_menu.prompt = "Please select a menu option\n> "
|
|
560
|
+
@cli.say("=== SBCP Log History Setting ===")
|
|
561
|
+
@cli.say('Logs are currently set to remain archived for:')
|
|
562
|
+
@cli.say(config['log_history'].to_s + ' days')
|
|
563
|
+
sub_menu.choice('Keep this setting') { @cli.say('Setting kept.'); config_menu(:logs) }
|
|
564
|
+
sub_menu.choice('Change this setting') do
|
|
565
|
+
until response >= 1
|
|
566
|
+
response = @cli.ask("Enter a new value in days\n> ", Integer)
|
|
567
|
+
@cli.say('Value must be greater than or equal to one.') if not response >= 1
|
|
568
|
+
end
|
|
569
|
+
config['log_history'] = response
|
|
570
|
+
File.write(config_file, config.to_yaml)
|
|
571
|
+
@cli.say('Changes saved successfully.')
|
|
572
|
+
config_menu(:logs)
|
|
573
|
+
end
|
|
574
|
+
end
|
|
575
|
+
end
|
|
576
|
+
menu.choice('Log Style') do
|
|
577
|
+
@cli.choose do |sub_menu|
|
|
578
|
+
sub_menu.prompt = "Please select a menu option\n> "
|
|
579
|
+
@cli.say("=== SBCP Log Style Setting ===")
|
|
580
|
+
@cli.say('The log style is currently set to:')
|
|
581
|
+
@cli.say(config['log_style'])
|
|
582
|
+
sub_menu.choice('Keep this setting') { @cli.say('Setting kept.'); config_menu(:logs) }
|
|
583
|
+
sub_menu.choice('Change this setting') do
|
|
584
|
+
response = @cli.ask("Enter a style name (daily, restart))\n> ") { |q| q.in = ['daily', 'restart'] }
|
|
585
|
+
config['log_style'] = response
|
|
586
|
+
File.write(config_file, config.to_yaml)
|
|
587
|
+
@cli.say('Changes saved successfully.')
|
|
588
|
+
config_menu(:logs)
|
|
589
|
+
end
|
|
590
|
+
end
|
|
591
|
+
end
|
|
592
|
+
menu.choice('Back to Main Menu') { config_menu(:main) }
|
|
593
|
+
end
|
|
594
|
+
when :restarts
|
|
595
|
+
@cli.choose do |menu|
|
|
596
|
+
menu.prompt = "Please select a menu option\n> "
|
|
597
|
+
@cli.say("=== SBCP Restart Settings ===")
|
|
598
|
+
menu.choice('Restart Schedule') do
|
|
599
|
+
@cli.choose do |sub_menu|
|
|
600
|
+
sub_menu.prompt = "Please select a menu option\n> "
|
|
601
|
+
@cli.say("=== SBCP Restart Schedule Setting ===")
|
|
602
|
+
@cli.say('The restart schedule is currently set to:')
|
|
603
|
+
config['restart_schedule'].is_a?(Integer) ? @cli.say('Every ' + config['restart_schedule'].to_s + ' hours') : @cli.say(config['restart_schedule'].to_s)
|
|
604
|
+
sub_menu.choice('Keep this setting') { @cli.say('Setting kept.'); config_menu(:restarts) }
|
|
605
|
+
sub_menu.choice('Change this setting') do
|
|
606
|
+
response = @cli.ask("Enter a new value in hours\n> ", Integer) { |q| q.in = [0, 1, 2, 3, 4, 6, 8, 12, 24] }
|
|
607
|
+
response = 'none' if response == 0
|
|
608
|
+
response = 'hourly' if response == 1
|
|
609
|
+
response = 'daily' if response == 24
|
|
610
|
+
config['restart_schedule'] = response
|
|
611
|
+
File.write(config_file, config.to_yaml)
|
|
612
|
+
@cli.say('Changes saved successfully.')
|
|
613
|
+
config_menu(:restarts)
|
|
614
|
+
end
|
|
615
|
+
end
|
|
616
|
+
end
|
|
617
|
+
menu.choice('Back to Main Menu') { config_menu(:main) }
|
|
618
|
+
end
|
|
619
|
+
end
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
ARGV << '-h' if ARGV.empty? # Displays help if no arguements given.
|
|
623
|
+
@cli = HighLine.new # Initialize highline object
|
|
624
|
+
begin o.parse!
|
|
625
|
+
rescue OptionParser::MissingArgument => e
|
|
626
|
+
puts e
|
|
627
|
+
puts 'Please provide an arguement.'
|
|
628
|
+
puts "Example: sbcp #{e.to_s.split(' ').last} <arg>"
|
|
629
|
+
rescue OptionParser::InvalidArgument => e
|
|
630
|
+
puts e
|
|
631
|
+
flag = e.to_s.split(' ')[2]
|
|
632
|
+
case flag
|
|
633
|
+
when '-k'
|
|
634
|
+
puts 'Please provide uuid, name, or ip as an arguement.'
|
|
635
|
+
puts "Example: sbcp #{flag} uuid"
|
|
636
|
+
when '-b'
|
|
637
|
+
puts 'Please provide uuid, name, or ip as an arguement.'
|
|
638
|
+
puts "Example: sbcp #{flag} name"
|
|
639
|
+
when '-u'
|
|
640
|
+
puts 'Please provide uuid, name, or ip as an arguement.'
|
|
641
|
+
puts "Example: sbcp #{flag} ip"
|
|
642
|
+
when '-l'
|
|
643
|
+
puts 'Please provide bans, connections, or logs as an arguement.'
|
|
644
|
+
puts "Example: sbcp #{flag} bans"
|
|
645
|
+
when '-B'
|
|
646
|
+
puts 'Please provide starbound, sbcp, or full as an arguement.'
|
|
647
|
+
puts "Example: sbcp #{flag} starbound"
|
|
648
|
+
end
|
|
649
|
+
rescue OptionParser::InvalidOption => e
|
|
650
|
+
puts e
|
|
651
|
+
puts o
|
|
652
|
+
exit 1
|
|
653
|
+
end
|