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.
@@ -0,0 +1,93 @@
1
+ # Starbound Control Panel
2
+ [![Gem Version](https://badge.fury.io/rb/sbcp.svg)](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
+
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :spec
@@ -0,0 +1 @@
1
+ SBCP uses this directory to create incremental backups.
@@ -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