rubycon 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
![Screenshot](http://i.imgur.com/cto9CnT.png)
|
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![Screenshot](http://i.imgur.com/cto9CnT.png)\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.
|