rubycon 0.1 → 0.2
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.
- data/Gemfile +0 -2
- data/README.md +75 -15
- data/Rakefile +44 -1
- data/bin/rubycon +171 -2
- data/features/rubycon.feature +8 -0
- data/features/step_definitions/rubycon_steps.rb +6 -0
- data/features/support/env.rb +15 -0
- data/lib/rubycon.rb +12 -2
- data/lib/rubycon/config.rb +51 -0
- data/lib/rubycon/rcon_executor.rb +27 -0
- data/lib/rubycon/{console.rb → rcon_session.rb} +32 -63
- data/lib/rubycon/server.rb +16 -0
- data/lib/rubycon/server_info.rb +23 -0
- data/lib/rubycon/version.rb +1 -1
- data/rubycon.gemspec +23 -19
- data/rubycon.rdoc +5 -0
- data/test/default_test.rb +14 -0
- data/test/test_helper.rb +9 -0
- metadata +143 -16
- data/LICENSE.txt +0 -22
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,24 +1,84 @@
|
|
1
|
-
|
1
|
+
Rubycon is a CLI for managing Source dedicated game servers (TF2, CS:S...). Think of it as a [HSLW](http://www.hlsw.org) clone, but terminal-based.
|
2
2
|
|
3
|
-
|
4
|
-
This program is not stable. Use at your own risk.
|
3
|
+

|
5
4
|
|
6
5
|
Features:
|
7
|
-
* Auto completion for server cvars
|
8
|
-
* Auto completion for map names when using `changelevel`
|
9
6
|
|
10
|
-
|
7
|
+
* RCON session with auto completion
|
8
|
+
* Overview of all your servers
|
9
|
+
* Bulk execution of rcon commands
|
10
|
+
* Start game client and join servers from the command line
|
11
11
|
|
12
|
-
|
12
|
+
# Installation
|
13
13
|
|
14
|
-
|
14
|
+
Rubycon was written in Ruby, Version 1.9.3 is minimum to run rubycon. (`ruby -v`).
|
15
|
+
Make sure to have the following libraries installed:
|
15
16
|
|
16
|
-
|
17
|
+
* RHEL based: `yum install readline-devel bzip2-devel`
|
18
|
+
* Debian based: `apt-get install libreadline-dev libbz2-dev`
|
17
19
|
|
18
|
-
|
20
|
+
Install rubycon with the following command:
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
`$ gem install rubycon`
|
23
|
+
|
24
|
+
# Usage
|
25
|
+
|
26
|
+
First of all, add a game server to rubycon:
|
27
|
+
|
28
|
+
```
|
29
|
+
$ rubycon add my_server \
|
30
|
+
--address=192.168.0.1 \
|
31
|
+
--rcon=foobar
|
32
|
+
```
|
33
|
+
|
34
|
+
Time to check out how your server is doing:
|
35
|
+
|
36
|
+
```
|
37
|
+
$ rubycon list
|
38
|
+
Server Map Players Ping
|
39
|
+
my_server ctf_2fort 4/25 42
|
40
|
+
```
|
41
|
+
|
42
|
+
Hop into a rcon session:
|
43
|
+
|
44
|
+
```
|
45
|
+
$ rubycon console my_server
|
46
|
+
Use CTRL+D to exit.
|
47
|
+
> sta
|
48
|
+
star_memory startdemos startmovie startupmenu stats status
|
49
|
+
> status
|
50
|
+
hostname: MyServer
|
51
|
+
version : 1797820/24 5331 secure
|
52
|
+
udp/ip : 192.168.0.1:27015 (public ip: 192.168.0.1)
|
53
|
+
account : not logged in (No account specified)
|
54
|
+
map : ctf_2fort at: 0 x, 0 y, 0 z
|
55
|
+
sourcetv: port 27020, delay 90.0s
|
56
|
+
players : 0 (25 max)
|
57
|
+
|
58
|
+
# userid name uniqueid connected ping loss state adr
|
59
|
+
>
|
60
|
+
```
|
61
|
+
|
62
|
+
Need stats from all your servers? Yes sir:
|
63
|
+
|
64
|
+
```
|
65
|
+
$ rubycon execute --command=stats --all
|
66
|
+
my_server:
|
67
|
+
CPU In (KB/s) Out (KB/s) Uptime Map changes FPS Players Connects
|
68
|
+
0.00 0.00 0.00 5093 7 62.44 0 1
|
69
|
+
---------------------------------
|
70
|
+
```
|
71
|
+
|
72
|
+
Need further help?
|
73
|
+
`$ rubycon help`
|
74
|
+
`$ rubycon execute help`
|
75
|
+
`$ rubycon rm help`
|
76
|
+
...
|
77
|
+
|
78
|
+
# Contributing
|
79
|
+
|
80
|
+
* Fork it
|
81
|
+
* Create your feature branch (`git checkout -b my-new-feature`)
|
82
|
+
* Commit your changes (`git commit -am 'Add some feature'`)
|
83
|
+
* Push to the branch (`git push origin my-new-feature`)
|
84
|
+
* Create new Pull Request
|
data/Rakefile
CHANGED
@@ -1 +1,44 @@
|
|
1
|
-
require
|
1
|
+
require 'rake/clean'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rubygems/package_task'
|
4
|
+
require 'rdoc/task'
|
5
|
+
require 'cucumber'
|
6
|
+
require 'cucumber/rake/task'
|
7
|
+
Rake::RDocTask.new do |rd|
|
8
|
+
rd.main = "README.rdoc"
|
9
|
+
rd.rdoc_files.include("README.rdoc","lib/**/*.rb","bin/**/*")
|
10
|
+
rd.title = 'Your application title'
|
11
|
+
end
|
12
|
+
|
13
|
+
spec = eval(File.read('rubycon.gemspec'))
|
14
|
+
|
15
|
+
Gem::PackageTask.new(spec) do |pkg|
|
16
|
+
end
|
17
|
+
CUKE_RESULTS = 'results.html'
|
18
|
+
CLEAN << CUKE_RESULTS
|
19
|
+
desc 'Run features'
|
20
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
21
|
+
opts = "features --format html -o #{CUKE_RESULTS} --format progress -x"
|
22
|
+
opts += " --tags #{ENV['TAGS']}" if ENV['TAGS']
|
23
|
+
t.cucumber_opts = opts
|
24
|
+
t.fork = false
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Run features tagged as work-in-progress (@wip)'
|
28
|
+
Cucumber::Rake::Task.new('features:wip') do |t|
|
29
|
+
tag_opts = ' --tags ~@pending'
|
30
|
+
tag_opts = ' --tags @wip'
|
31
|
+
t.cucumber_opts = "features --format html -o #{CUKE_RESULTS} --format pretty -x -s#{tag_opts}"
|
32
|
+
t.fork = false
|
33
|
+
end
|
34
|
+
|
35
|
+
task :cucumber => :features
|
36
|
+
task 'cucumber:wip' => 'features:wip'
|
37
|
+
task :wip => 'features:wip'
|
38
|
+
require 'rake/testtask'
|
39
|
+
Rake::TestTask.new do |t|
|
40
|
+
t.libs << "test"
|
41
|
+
t.test_files = FileList['test/*_test.rb']
|
42
|
+
end
|
43
|
+
|
44
|
+
task :default => [:test,:features]
|
data/bin/rubycon
CHANGED
@@ -1,5 +1,174 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
2
|
+
require 'gli'
|
3
|
+
begin
|
3
4
|
require 'rubycon'
|
5
|
+
rescue LoadError => e
|
6
|
+
puts e.inspect
|
7
|
+
puts e.backtrace
|
8
|
+
exit 64
|
9
|
+
end
|
10
|
+
include GLI::App
|
11
|
+
|
12
|
+
program_desc 'CLI to manage your Source dedicated game servers.'
|
13
|
+
version Rubycon::VERSION
|
14
|
+
|
15
|
+
flag [:c, :config], :default_value => File.join(ENV['HOME'], '.config', 'rubycon', 'rubycon.yml'),
|
16
|
+
:desc => 'Path to configuration file'
|
17
|
+
|
18
|
+
desc 'adds a new server'
|
19
|
+
arg_name 'ALIAS'
|
20
|
+
command :add do |c|
|
21
|
+
c.flag [:a, :address], :arg_name => 'HOSTNAME',
|
22
|
+
:desc => 'hostname or IP'
|
23
|
+
|
24
|
+
c.flag [:p, :port], :default_value => 27015,
|
25
|
+
:arg_name => 'PORT',
|
26
|
+
:desc => 'Port',
|
27
|
+
:type => Integer
|
28
|
+
|
29
|
+
c.flag [:r, :rcon], :arg_name => 'RCON',
|
30
|
+
:desc => 'Rcon password'
|
31
|
+
|
32
|
+
c.action do |g, o, args|
|
33
|
+
exit_now!('ALIAS is required') if args.empty?
|
34
|
+
exit_now!('HOSTNAME is required') unless o[:address]
|
35
|
+
exit_now!('RCON is required') unless o[:rcon]
|
36
|
+
exit_now!("ALIAS #{args.first}` already used") if $config.find_by_name args.first
|
37
|
+
s = Rubycon::Server.new(args.first, o[:a], o[:p], o[:r])
|
38
|
+
$config.add_server s
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
desc 'deletes the specified server'
|
43
|
+
arg_name 'ALIAS'
|
44
|
+
command :rm do |c|
|
45
|
+
c. switch [:a, :all], :negatable => false,
|
46
|
+
:desc => 'Deletes all servers'
|
47
|
+
|
48
|
+
c.action do |g, o, args|
|
49
|
+
if o[:a]
|
50
|
+
$config.delete_all_servers
|
51
|
+
else
|
52
|
+
exit_now!('ALIAS is required') if args.empty?
|
53
|
+
exit_now!("Unknown server alias: #{args.first}") unless $config.delete_server args.first
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
desc 'lists all servers'
|
59
|
+
command :list do |c|
|
60
|
+
c.flag [:s, :spacing], :default_value => 8,
|
61
|
+
:desc => 'Amount of whitespace between the columns',
|
62
|
+
:type => Integer
|
63
|
+
c.action do |g, o, args|
|
64
|
+
exit_now!('No servers added yet. Use `rubycon add` to add a new server.') if $config.servers.empty?
|
65
|
+
|
66
|
+
server_infos = Parallel.map($config.servers, :in_threads => $config.servers.size) do |s|
|
67
|
+
Rubycon::ServerInfo.new s
|
68
|
+
end
|
69
|
+
server_infos.select!{|i| i.reachable?}
|
70
|
+
name_max_width = ($config.servers.map {|s| s.name.length}).max
|
71
|
+
map_max_width = (server_infos.map{|i| i.map.length}).max
|
72
|
+
players_max_width = (server_infos.map{|i| "#{i.players_count}/#{i.players_max}".length}).max
|
73
|
+
ping_max_width = (server_infos.map{|i| i.ping.to_s.length}).max
|
74
|
+
|
75
|
+
puts "Server".ljust(name_max_width).bold + "Map".rjust(map_max_width + o[:s]).bold +
|
76
|
+
"Players".rjust(players_max_width + o[:s]).bold +
|
77
|
+
"Ping".rjust(ping_max_width + o[:s]).bold
|
78
|
+
|
79
|
+
$config.servers.zip(server_infos).each do |s, i|
|
80
|
+
if i.nil?
|
81
|
+
puts s.name.ljust(name_max_width).yellow + '?'.rjust(map_max_width + o[:s]).yellow +
|
82
|
+
'?/?'.rjust(players_max_width + o[:s]).yellow +
|
83
|
+
'?'.rjust(ping_max_width + o[:s]).yellow
|
84
|
+
else
|
85
|
+
puts s.name.ljust(name_max_width) + i.map.rjust(map_max_width + o[:s]) +
|
86
|
+
"#{i.players_count}/#{i.players_max}".rjust(players_max_width + o[:s]) +
|
87
|
+
i.ping.to_s.rjust(ping_max_width + o[:s])
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
desc 'starts a rcon session to the specified server'
|
94
|
+
arg_name 'ALIAS'
|
95
|
+
command :console do |c|
|
96
|
+
c.action do |g, o, args|
|
97
|
+
exit_now!('ALIAS is required') if args.empty?
|
98
|
+
server = $config.find_by_name args.first
|
99
|
+
exit_now!("Unknown server alias: #{args.first}") if server.nil?
|
100
|
+
puts 'Use CTRL+D to exit.'
|
101
|
+
Rubycon::RconSession.new server
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
desc 'executes a rcon command on specified server(s)'
|
106
|
+
arg_name 'ALIAS[ ALIAS]*'
|
107
|
+
command :execute do |c|
|
108
|
+
c. switch [:a, :all], :negatable => false,
|
109
|
+
:desc => 'Executes rcon command on all servers'
|
110
|
+
c.flag [:i, :command], :arg_name => 'COMMAND',
|
111
|
+
:desc => 'Rcon command'
|
112
|
+
c.action do |g, o, args|
|
113
|
+
exit_now!('COMMAND required') unless o[:i]
|
114
|
+
if o[:a]
|
115
|
+
servers = $config.servers
|
116
|
+
else
|
117
|
+
servers = []
|
118
|
+
exit_now!('ALIAS is required') if args.empty?
|
119
|
+
args.each do |arg|
|
120
|
+
server = $config.find_by_name arg
|
121
|
+
exit_now!("Unknown server alias: #{arg}") unless server
|
122
|
+
servers << server
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
responses = {}
|
127
|
+
Parallel.each(servers, :in_threads => servers.size) do |server|
|
128
|
+
executor = Rubycon::RconExecutor.new server, o[:i]
|
129
|
+
responses[server.name] = executor.response
|
130
|
+
end
|
131
|
+
|
132
|
+
responses.each_pair do |name, response|
|
133
|
+
puts "#{name.bold}:"
|
134
|
+
puts response
|
135
|
+
puts "---------------------------------"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
desc 'starts the game client and connects to the specified server'
|
141
|
+
arg_name 'ALIAS'
|
142
|
+
command :connect do |c|
|
143
|
+
c.action do |g, o, args|
|
144
|
+
exit_now!('ALIAS is required') if args.empty?
|
145
|
+
|
146
|
+
server = $config.find_by_name args.first
|
147
|
+
exit_now!("Unknown server alias: #{args.first}") if server.nil?
|
148
|
+
uri = "steam://connect/#{server.address}:#{server.port}"
|
149
|
+
|
150
|
+
case RbConfig::CONFIG['host_os']
|
151
|
+
when /mswin|mingw|cygwin/
|
152
|
+
system "start #{uri}"
|
153
|
+
when /darwin/
|
154
|
+
system "open #{uri}"
|
155
|
+
when /linux|bsd/
|
156
|
+
system "xdg-open #{uri}"
|
157
|
+
else
|
158
|
+
exit_now! 'Cannot connect to server. Couldn\'t identify your OS.'
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
pre do |g, command, o, args|
|
164
|
+
$config = Rubycon::Config.load(g[:c])
|
165
|
+
true
|
166
|
+
end
|
167
|
+
|
168
|
+
on_error do |e|
|
169
|
+
# puts e.inspect
|
170
|
+
# puts e.backtrace
|
171
|
+
true
|
172
|
+
end
|
4
173
|
|
5
|
-
|
174
|
+
exit run(ARGV)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'aruba/cucumber'
|
2
|
+
|
3
|
+
ENV['PATH'] = "#{File.expand_path(File.dirname(__FILE__) + '/../../bin')}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
|
4
|
+
LIB_DIR = File.join(File.expand_path(File.dirname(__FILE__)),'..','..','lib')
|
5
|
+
|
6
|
+
Before do
|
7
|
+
# Using "announce" causes massive warnings on 1.9.2
|
8
|
+
@puts = true
|
9
|
+
@original_rubylib = ENV['RUBYLIB']
|
10
|
+
ENV['RUBYLIB'] = LIB_DIR + File::PATH_SEPARATOR + ENV['RUBYLIB'].to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
After do
|
14
|
+
ENV['RUBYLIB'] = @original_rubylib
|
15
|
+
end
|
data/lib/rubycon.rb
CHANGED
@@ -1,2 +1,12 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'colored'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'parallel'
|
4
|
+
require 'readline'
|
5
|
+
require 'rubycon/config.rb'
|
6
|
+
require 'rubycon/rcon_executor.rb'
|
7
|
+
require 'rubycon/rcon_session.rb'
|
8
|
+
require 'rubycon/server.rb'
|
9
|
+
require 'rubycon/server_info.rb'
|
10
|
+
require 'rubycon/version.rb'
|
11
|
+
require 'steam-condenser'
|
12
|
+
require 'yaml'
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Rubycon
|
2
|
+
class Config
|
3
|
+
attr_reader :path, :servers
|
4
|
+
attr_accessor
|
5
|
+
|
6
|
+
def initialize(path)
|
7
|
+
@servers = []
|
8
|
+
@path = path
|
9
|
+
|
10
|
+
if File.exists?(path)
|
11
|
+
yaml = YAML.load_file(path)
|
12
|
+
yaml.each do |server|
|
13
|
+
@servers << server
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.load(path)
|
19
|
+
Config.new path
|
20
|
+
end
|
21
|
+
|
22
|
+
def save
|
23
|
+
FileUtils.makedirs File.dirname(@path)
|
24
|
+
|
25
|
+
servers.sort! {|a,b| a.name.downcase <=> b.name.downcase}
|
26
|
+
File.open(path, 'w') do |f|
|
27
|
+
f.puts servers.to_yaml
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_server(server)
|
32
|
+
@servers << server
|
33
|
+
save
|
34
|
+
end
|
35
|
+
|
36
|
+
def delete_all_servers
|
37
|
+
@servers = []
|
38
|
+
save
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete_server(name)
|
42
|
+
deleted_server = @servers.delete(find_by_name(name))
|
43
|
+
save
|
44
|
+
deleted_server
|
45
|
+
end
|
46
|
+
|
47
|
+
def find_by_name(name)
|
48
|
+
@servers.find {|server| name.downcase == server.name.downcase}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Rubycon
|
2
|
+
class RconExecutor
|
3
|
+
attr_reader :response
|
4
|
+
def initialize(server_info, command)
|
5
|
+
begin
|
6
|
+
@commands = []
|
7
|
+
@server_info = server_info
|
8
|
+
@session = SourceServer.new @server_info.address, @server_info.port
|
9
|
+
@session.rcon_auth(@server_info.rcon)
|
10
|
+
@response = rcon_exec command
|
11
|
+
rescue RCONNoAuthError
|
12
|
+
@response = 'Could not authenticate with gameserver. Wrong rcon password?'
|
13
|
+
rescue Errno::ECONNREFUSED
|
14
|
+
@response = 'Connection refused. Wrong host?'
|
15
|
+
rescue SteamCondenser::TimeoutError
|
16
|
+
@response = 'Connection timed out while sending command!'
|
17
|
+
rescue Exception => e
|
18
|
+
@response = "#{e.message}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def rcon_exec(line)
|
24
|
+
@session.rcon_exec(line)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,61 +1,52 @@
|
|
1
|
-
require 'steam-condenser'
|
2
|
-
require 'readline'
|
3
|
-
require 'highline/import'
|
4
|
-
|
5
1
|
module Rubycon
|
6
|
-
class
|
7
|
-
|
8
|
-
attr_accessor :host, :port, :rcon, :server, :commands
|
9
|
-
|
10
|
-
def initialize(host = nil, port = nil, rcon = nil)
|
11
|
-
begin
|
12
|
-
@host = host || ask_for_host
|
13
|
-
@port = port || ask_for_port
|
14
|
-
@rcon = rcon || ask_for_rcon
|
15
|
-
rescue EOFError, Interrupt
|
16
|
-
exit
|
17
|
-
end
|
18
|
-
|
19
|
-
@server = create_server
|
2
|
+
class RconSession
|
3
|
+
def initialize(server_info)
|
20
4
|
@commands = []
|
5
|
+
@server_info = server_info
|
6
|
+
@session = SourceServer.new @server_info.address, @server_info.port
|
7
|
+
|
21
8
|
setup_autocompletion_items
|
22
9
|
run_console
|
23
10
|
end
|
24
11
|
|
25
|
-
|
26
|
-
|
12
|
+
private
|
13
|
+
|
14
|
+
def reconnect
|
15
|
+
@session = SourceServer.new @server_info.address, @server_info.port
|
16
|
+
setup_autocompletion_items
|
27
17
|
end
|
28
18
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
32
|
-
q.above = 0
|
33
|
-
end
|
19
|
+
def setup_autocompletion_items
|
20
|
+
add_cvars_from_server
|
21
|
+
add_changelevel_commands
|
34
22
|
end
|
35
23
|
|
36
|
-
def
|
37
|
-
|
24
|
+
def add_cvars_from_server
|
25
|
+
rcon_exec('cvarlist').each_line do |l|
|
26
|
+
if l =~ /.*:.*:.*:.*/
|
27
|
+
@commands << (l.split).first
|
28
|
+
end
|
29
|
+
end
|
38
30
|
end
|
39
31
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
exit
|
32
|
+
def add_changelevel_commands
|
33
|
+
rcon_exec('maps *').each_line do |l|
|
34
|
+
if l =~ /PENDING.*/
|
35
|
+
@commands << "changelevel #{((l.split).last).sub('.bsp', '')}"
|
36
|
+
end
|
46
37
|
end
|
47
38
|
end
|
48
39
|
|
49
40
|
def auth_if_necessary
|
50
|
-
unless @
|
51
|
-
@
|
41
|
+
unless @session.rcon_authenticated?
|
42
|
+
@session.rcon_auth(@server_info.rcon)
|
52
43
|
end
|
53
44
|
end
|
54
45
|
|
55
46
|
def rcon_exec(line)
|
56
47
|
begin
|
57
48
|
auth_if_necessary
|
58
|
-
@
|
49
|
+
@session.rcon_exec(line)
|
59
50
|
rescue RCONNoAuthError
|
60
51
|
puts 'Could not authenticate with gameserver. Wrong rcon password?'
|
61
52
|
exit
|
@@ -63,38 +54,16 @@ module Rubycon
|
|
63
54
|
puts 'Connection refused. Wrong host?'
|
64
55
|
exit
|
65
56
|
rescue SteamCondenser::TimeoutError
|
66
|
-
puts 'Connection timed out
|
67
|
-
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def setup_autocompletion_items
|
72
|
-
add_cvars_from_server
|
73
|
-
add_changelevel_commands
|
74
|
-
end
|
75
|
-
|
76
|
-
def add_cvars_from_server
|
77
|
-
rcon_exec('cvarlist').each_line do |l|
|
78
|
-
if l =~ /.*:.*:.*:.*/
|
79
|
-
@commands << (l.split).first
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def add_changelevel_commands
|
85
|
-
rcon_exec('maps *').each_line do |l|
|
86
|
-
if l =~ /PENDING.*/
|
87
|
-
@commands << "changelevel #{((l.split).last).sub('.bsp', '')}"
|
88
|
-
end
|
57
|
+
puts '---Connection timed out while sending command!'
|
58
|
+
reconnect
|
89
59
|
end
|
90
60
|
end
|
91
61
|
|
92
62
|
def run_console
|
93
|
-
comp = proc { |s| commands.grep( /^#{Regexp.escape(s)}/ ) }
|
63
|
+
comp = proc { |s| @commands.grep( /^#{Regexp.escape(s)}/ ) }
|
94
64
|
Readline.completion_append_character = ' '
|
95
65
|
Readline.basic_word_break_characters = ''
|
96
66
|
Readline.completion_proc = comp
|
97
|
-
|
98
67
|
stty_save = `stty -g`.chomp
|
99
68
|
|
100
69
|
begin
|
@@ -103,12 +72,12 @@ module Rubycon
|
|
103
72
|
end
|
104
73
|
rescue Interrupt
|
105
74
|
system('stty', stty_save)
|
106
|
-
|
75
|
+
@session.disconnect
|
107
76
|
end
|
108
77
|
end
|
109
78
|
|
110
79
|
def readline_with_history
|
111
|
-
line = Readline.readline("
|
80
|
+
line = Readline.readline("> ", true)
|
112
81
|
return nil if line.nil?
|
113
82
|
if line =~ /^\s*$/ or Readline::HISTORY.to_a[-2] == line
|
114
83
|
Readline::HISTORY.pop
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Rubycon
|
2
|
+
class Server
|
3
|
+
attr_reader :name, :address, :port, :rcon
|
4
|
+
|
5
|
+
def initialize(name, address, port, rcon)
|
6
|
+
@name = name
|
7
|
+
@address = address
|
8
|
+
@port = port
|
9
|
+
@rcon = rcon
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.from_hash(hash)
|
13
|
+
Server.new(hash['name'], hash['address'], hash['port'], hash['rcon'])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Rubycon
|
2
|
+
class ServerInfo
|
3
|
+
attr_reader :map, :players_count, :players_max, :ping, :name
|
4
|
+
|
5
|
+
def initialize(server)
|
6
|
+
begin
|
7
|
+
conn = SourceServer.new server.address, server.port
|
8
|
+
@ping = conn.ping.round(0)
|
9
|
+
@players_count = conn.server_info[:number_of_players]
|
10
|
+
@players_max = conn.server_info[:max_players]
|
11
|
+
@map = conn.server_info[:map_name]
|
12
|
+
@name = conn.server_info[:server_name]
|
13
|
+
@reachable = true
|
14
|
+
rescue
|
15
|
+
@reachable = false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def reachable?
|
20
|
+
@reachable
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/rubycon/version.rb
CHANGED
data/rubycon.gemspec
CHANGED
@@ -1,21 +1,25 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
# Ensure we require the local version and not one we might have installed already
|
2
|
+
require File.join([File.dirname(__FILE__),'lib','rubycon','version.rb'])
|
3
|
+
spec = Gem::Specification.new do |s|
|
4
|
+
s.name = 'rubycon'
|
5
|
+
s.version = Rubycon::VERSION
|
6
|
+
s.author = 'Philipp Preß'
|
7
|
+
s.email = 'philipp.press@googlemail.com'
|
8
|
+
s.homepage = 'https://github.com/nTraum/rubycon'
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.summary = 'CLI to manage your Source dedicated game servers.'
|
11
|
+
s.description = File.read 'README.md'
|
12
|
+
s.files = `git ls-files`.split($/)
|
5
13
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
-
gem.require_paths = ["lib"]
|
19
|
-
gem.add_dependency('steam-condenser')
|
20
|
-
gem.add_dependency('highline')
|
14
|
+
s.require_paths << 'lib'
|
15
|
+
s.bindir = 'bin'
|
16
|
+
s.executables << 'rubycon'
|
17
|
+
s.add_development_dependency('aruba')
|
18
|
+
s.add_development_dependency('rake')
|
19
|
+
s.add_development_dependency('rdoc')
|
20
|
+
s.add_runtime_dependency('gli','2.5.6')
|
21
|
+
s.add_runtime_dependency('highline', '1.6.19')
|
22
|
+
s.add_runtime_dependency('steam-condenser', '1.3.5')
|
23
|
+
s.add_runtime_dependency('colored', '1.2')
|
24
|
+
s.add_runtime_dependency('parallel', '0.7.0')
|
21
25
|
end
|
data/rubycon.rdoc
ADDED
data/test/test_helper.rb
ADDED
metadata
CHANGED
@@ -1,25 +1,25 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubycon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.2'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
|
-
-
|
8
|
+
- Philipp Preß
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-06-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: aruba
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
21
|
version: '0'
|
22
|
-
type: :
|
22
|
+
type: :development
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
@@ -28,14 +28,14 @@ dependencies:
|
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
|
-
name:
|
31
|
+
name: rake
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
none: false
|
34
34
|
requirements:
|
35
35
|
- - ! '>='
|
36
36
|
- !ruby/object:Gem::Version
|
37
37
|
version: '0'
|
38
|
-
type: :
|
38
|
+
type: :development
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
@@ -43,10 +43,128 @@ dependencies:
|
|
43
43
|
- - ! '>='
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rdoc
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: gli
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - '='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 2.5.6
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - '='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 2.5.6
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: highline
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - '='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.6.19
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - '='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.6.19
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: steam-condenser
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - '='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 1.3.5
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - '='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.3.5
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: colored
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - '='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.2'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - '='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '1.2'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: parallel
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - '='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 0.7.0
|
134
|
+
type: :runtime
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - '='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: 0.7.0
|
142
|
+
description: ! "Rubycon is a CLI for managing Source dedicated game servers (TF2,
|
143
|
+
CS:S...). Think of it as a [HSLW](http://www.hlsw.org) clone, but terminal-based.\n\n\n\nFeatures:\n\n*
|
144
|
+
RCON session with auto completion\n* Overview of all your servers\n* Bulk execution
|
145
|
+
of rcon commands\n* Start game client and join servers from the command line\n\n#
|
146
|
+
Installation\n\nRubycon was written in Ruby, Version 1.9.3 is minimum to run rubycon.
|
147
|
+
(`ruby -v`).\nMake sure to have the following libraries installed:\n\n* RHEL based:
|
148
|
+
\ `yum install readline-devel bzip2-devel`\n* Debian based: `apt-get install libreadline-dev
|
149
|
+
libbz2-dev`\n\nInstall rubycon with the following command:\n\n`$ gem install rubycon`\n\n#
|
150
|
+
Usage\n\nFirst of all, add a game server to rubycon:\n\n```\n$ rubycon add my_server
|
151
|
+
\\\n --address=192.168.0.1 \\\n --rcon=foobar\n```\n\nTime to check out how
|
152
|
+
your server is doing:\n\n```\n$ rubycon list\nServer Map Players
|
153
|
+
\ Ping\nmy_server ctf_2fort 4/25 42\n```\n\nHop into
|
154
|
+
a rcon session:\n\n```\n$ rubycon console my_server\nUse CTRL+D to exit.\n> sta\nstar_memory
|
155
|
+
\ startdemos startmovie startupmenu stats status\n> status\nhostname:
|
156
|
+
MyServer\nversion : 1797820/24 5331 secure\nudp/ip : 192.168.0.1:27015 (public
|
157
|
+
ip: 192.168.0.1)\naccount : not logged in (No account specified)\nmap : ctf_2fort
|
158
|
+
at: 0 x, 0 y, 0 z\nsourcetv: port 27020, delay 90.0s\nplayers : 0 (25 max)\n\n#
|
159
|
+
userid name uniqueid connected ping loss state adr\n>\n```\n\nNeed
|
160
|
+
stats from all your servers? Yes sir:\n\n```\n$ rubycon execute --command=stats
|
161
|
+
--all\nmy_server:\nCPU In (KB/s) Out (KB/s) Uptime Map changes FPS Players
|
162
|
+
\ Connects\n0.00 0.00 0.00 5093 7 62.44 0 1\n---------------------------------\n```\n\nNeed
|
163
|
+
further help?\n`$ rubycon help`\n`$ rubycon execute help`\n`$ rubycon rm help`\n...\n\n#
|
164
|
+
Contributing\n\n* Fork it\n* Create your feature branch (`git checkout -b my-new-feature`)\n*
|
165
|
+
Commit your changes (`git commit -am 'Add some feature'`)\n* Push to the branch
|
166
|
+
(`git push origin my-new-feature`)\n* Create new Pull Request"
|
167
|
+
email: philipp.press@googlemail.com
|
50
168
|
executables:
|
51
169
|
- rubycon
|
52
170
|
extensions: []
|
@@ -54,20 +172,30 @@ extra_rdoc_files: []
|
|
54
172
|
files:
|
55
173
|
- .gitignore
|
56
174
|
- Gemfile
|
57
|
-
- LICENSE.txt
|
58
175
|
- README.md
|
59
176
|
- Rakefile
|
60
177
|
- bin/rubycon
|
178
|
+
- features/rubycon.feature
|
179
|
+
- features/step_definitions/rubycon_steps.rb
|
180
|
+
- features/support/env.rb
|
61
181
|
- lib/rubycon.rb
|
62
|
-
- lib/rubycon/
|
182
|
+
- lib/rubycon/config.rb
|
183
|
+
- lib/rubycon/rcon_executor.rb
|
184
|
+
- lib/rubycon/rcon_session.rb
|
185
|
+
- lib/rubycon/server.rb
|
186
|
+
- lib/rubycon/server_info.rb
|
63
187
|
- lib/rubycon/version.rb
|
64
188
|
- rubycon.gemspec
|
65
|
-
|
189
|
+
- rubycon.rdoc
|
190
|
+
- test/default_test.rb
|
191
|
+
- test/test_helper.rb
|
192
|
+
homepage: https://github.com/nTraum/rubycon
|
66
193
|
licenses: []
|
67
194
|
post_install_message:
|
68
195
|
rdoc_options: []
|
69
196
|
require_paths:
|
70
197
|
- lib
|
198
|
+
- lib
|
71
199
|
required_ruby_version: !ruby/object:Gem::Requirement
|
72
200
|
none: false
|
73
201
|
requirements:
|
@@ -85,6 +213,5 @@ rubyforge_project:
|
|
85
213
|
rubygems_version: 1.8.23
|
86
214
|
signing_key:
|
87
215
|
specification_version: 3
|
88
|
-
summary:
|
89
|
-
dedicated gameserver.
|
216
|
+
summary: CLI to manage your Source dedicated game servers.
|
90
217
|
test_files: []
|
data/LICENSE.txt
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
Copyright (c) 2013 nTraum
|
2
|
-
|
3
|
-
MIT License
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
-
a copy of this software and associated documentation files (the
|
7
|
-
"Software"), to deal in the Software without restriction, including
|
8
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
-
permit persons to whom the Software is furnished to do so, subject to
|
11
|
-
the following conditions:
|
12
|
-
|
13
|
-
The above copyright notice and this permission notice shall be
|
14
|
-
included in all copies or substantial portions of the Software.
|
15
|
-
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|