Add rcon support
This commit is contained in:
parent
2db8b7058d
commit
ffbc433b67
5
.github/workflows/integration.yml
vendored
5
.github/workflows/integration.yml
vendored
|
@ -28,4 +28,7 @@ jobs:
|
||||||
./integration_test/run.sh chat
|
./integration_test/run.sh chat
|
||||||
- name: Test reconnect
|
- name: Test reconnect
|
||||||
run: |
|
run: |
|
||||||
./integration_test/run.sh reconnect
|
./integration_test/run.sh reconnect
|
||||||
|
- name: Test rcon
|
||||||
|
run: |
|
||||||
|
./integration_test/run.sh rcon
|
|
@ -20,5 +20,5 @@ Signal.trap('INT') do
|
||||||
client.disconnect
|
client.disconnect
|
||||||
end
|
end
|
||||||
|
|
||||||
# connect and detach thread
|
# connect and block main thread
|
||||||
client.connect('localhost', 8303, detach: false)
|
client.connect('localhost', 8303, detach: false)
|
||||||
|
|
18
examples/07_rcon.rb
Executable file
18
examples/07_rcon.rb
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../lib/teeworlds-client'
|
||||||
|
|
||||||
|
client = TeeworldsClient.new
|
||||||
|
|
||||||
|
client.on_connected do |_|
|
||||||
|
client.rcon_auth(password: '123')
|
||||||
|
client.rcon('shutdown')
|
||||||
|
end
|
||||||
|
|
||||||
|
client.on_rcon_line do |ctx|
|
||||||
|
puts "[rcon] #{ctx.data[:line]}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# connect and block main thread
|
||||||
|
client.connect('localhost', 8303, detach: false)
|
18
integration_test/rcon_shutdown.rb
Executable file
18
integration_test/rcon_shutdown.rb
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../lib/teeworlds-client'
|
||||||
|
|
||||||
|
client = TeeworldsClient.new
|
||||||
|
|
||||||
|
client.on_connected do |_|
|
||||||
|
client.rcon_auth(password: 'rcon')
|
||||||
|
client.rcon('shutdown')
|
||||||
|
end
|
||||||
|
|
||||||
|
client.on_rcon_line do |ctx|
|
||||||
|
puts "[rcon] #{ctx.data[:line]}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# connect and block main thread
|
||||||
|
client.connect('localhost', 8377, detach: false)
|
|
@ -3,10 +3,12 @@
|
||||||
cd "$(dirname "$0")" || exit 1
|
cd "$(dirname "$0")" || exit 1
|
||||||
|
|
||||||
twbin=teeworlds_srv
|
twbin=teeworlds_srv
|
||||||
|
rubybin=send_chat_hello.rb
|
||||||
|
srvcfg='sv_rcon_password rcon;sv_port 8377;killme'
|
||||||
|
|
||||||
function cleanup() {
|
function cleanup() {
|
||||||
echo "[*] shutting down server ..."
|
echo "[*] shutting down server ..."
|
||||||
pkill -f "$twbin sv_port 8377;killme"
|
pkill -f "$twbin $srvcfg"
|
||||||
[[ "$_timout_pid" != "" ]] && kill "$_timout_pid" &> /dev/null
|
[[ "$_timout_pid" != "" ]] && kill "$_timout_pid" &> /dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,32 +17,47 @@ trap cleanup EXIT
|
||||||
function timeout() {
|
function timeout() {
|
||||||
local seconds="$1"
|
local seconds="$1"
|
||||||
sleep "$seconds"
|
sleep "$seconds"
|
||||||
pkill -f 'send_chat_hello.rb'
|
pkill -f "$rubybin"
|
||||||
|
echo "killing: $rubybin"
|
||||||
echo "Error: timeouted"
|
echo "Error: timeouted"
|
||||||
}
|
}
|
||||||
|
|
||||||
if [[ -x "$(command -v teeworlds_srv)" ]]
|
if [[ -x "$(command -v teeworlds_srv)" ]]
|
||||||
then
|
then
|
||||||
teeworlds_srv "sv_port 8377;killme" &> server.txt &
|
teeworlds_srv "$srvcfg" &> server.txt &
|
||||||
elif [[ -x "$(command -v teeworlds-server)" ]]
|
elif [[ -x "$(command -v teeworlds-server)" ]]
|
||||||
then
|
then
|
||||||
teeworlds-server "sv_port 8377;killme" &> server.txt &
|
teeworlds-server "$srvcfg" &> server.txt &
|
||||||
twbin='teeworlds-server'
|
twbin='teeworlds-server'
|
||||||
elif [[ -x "$(command -v teeworlds-srv)" ]]
|
elif [[ -x "$(command -v teeworlds-srv)" ]]
|
||||||
then
|
then
|
||||||
teeworlds-srv "sv_port 8377;killme" &> server.txt &
|
teeworlds-srv "$srvcfg" &> server.txt &
|
||||||
twbin='teeworlds-srv'
|
twbin='teeworlds-srv'
|
||||||
else
|
else
|
||||||
echo "Error: please install a teeworlds_srv"
|
echo "Error: please install a teeworlds_srv"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
timeout 3 killme &
|
|
||||||
_timout_pid=$!
|
|
||||||
|
|
||||||
testname="${1:-chat}"
|
testname="${1:-chat}"
|
||||||
|
|
||||||
echo "[*] running test '$testname' ..."
|
echo "[*] running test '$testname' ..."
|
||||||
|
|
||||||
|
if [ "$testname" == "chat" ]
|
||||||
|
then
|
||||||
|
rubybin=send_chat_hello.rb
|
||||||
|
elif [ "$testname" == "reconnect" ]
|
||||||
|
then
|
||||||
|
rubybin=reconnect.rb
|
||||||
|
elif [ "$testname" == "rcon" ]
|
||||||
|
then
|
||||||
|
rubybin=rcon_shutdown.rb
|
||||||
|
else
|
||||||
|
echo "Error: unkown test '$testname'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
timeout 3 killme &
|
||||||
|
_timout_pid=$!
|
||||||
|
|
||||||
function fail() {
|
function fail() {
|
||||||
local msg="$1"
|
local msg="$1"
|
||||||
tail client.txt
|
tail client.txt
|
||||||
|
@ -51,7 +68,7 @@ function fail() {
|
||||||
|
|
||||||
if [ "$testname" == "chat" ]
|
if [ "$testname" == "chat" ]
|
||||||
then
|
then
|
||||||
ruby ./send_chat_hello.rb &> client.txt
|
ruby "$rubybin" &> client.txt
|
||||||
|
|
||||||
if ! grep -q 'hello world' server.txt
|
if ! grep -q 'hello world' server.txt
|
||||||
then
|
then
|
||||||
|
@ -59,16 +76,24 @@ then
|
||||||
fi
|
fi
|
||||||
elif [ "$testname" == "reconnect" ]
|
elif [ "$testname" == "reconnect" ]
|
||||||
then
|
then
|
||||||
ruby ./reconnect.rb &> client.txt
|
ruby "$rubybin" &> client.txt
|
||||||
|
|
||||||
if ! grep -q 'bar' server.txt
|
if ! grep -q 'bar' server.txt
|
||||||
then
|
then
|
||||||
fail "Error: did not find 2nd chat message in server log"
|
fail "Error: did not find 2nd chat message in server log"
|
||||||
fi
|
fi
|
||||||
|
elif [ "$testname" == "rcon" ]
|
||||||
|
then
|
||||||
|
ruby "$rubybin" &> client.txt
|
||||||
|
|
||||||
|
if pgrep -f "$twbin $srvcfg"
|
||||||
|
then
|
||||||
|
fail "Error: server still running rcon shutdown failed"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
echo "Error: unkown test '$testname'"
|
echo "Error: unkown test '$testname'"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "[+] Test passed client sent chat message to server"
|
echo "[+] Test passed"
|
||||||
|
|
||||||
|
|
|
@ -106,6 +106,15 @@ class GameClient
|
||||||
@client.send_msg_startinfo
|
@client.send_msg_startinfo
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def on_rcon_line(chunk)
|
||||||
|
u = Unpacker.new(chunk.data[1..])
|
||||||
|
context = Context.new(
|
||||||
|
@client,
|
||||||
|
line: u.get_string
|
||||||
|
)
|
||||||
|
@client.hooks[:rcon_line]&.call(context)
|
||||||
|
end
|
||||||
|
|
||||||
def on_emoticon(chunk); end
|
def on_emoticon(chunk); end
|
||||||
|
|
||||||
def on_map_change(chunk)
|
def on_map_change(chunk)
|
||||||
|
|
|
@ -73,6 +73,10 @@ class TeeworldsClient
|
||||||
@hooks[:connected] = block
|
@hooks[:connected] = block
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def on_rcon_line(&block)
|
||||||
|
@hooks[:rcon_line] = block
|
||||||
|
end
|
||||||
|
|
||||||
def send_chat(str)
|
def send_chat(str)
|
||||||
@netbase.send_packet(
|
@netbase.send_packet(
|
||||||
NetChunk.create_vital_header({ vital: true }, 4 + str.length) +
|
NetChunk.create_vital_header({ vital: true }, 4 + str.length) +
|
||||||
|
@ -170,6 +174,42 @@ class TeeworldsClient
|
||||||
@netbase.send_packet(msg, 1)
|
@netbase.send_packet(msg, 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def rcon_auth(name, password = nil)
|
||||||
|
if name.instance_of?(Hash)
|
||||||
|
password = name[:password]
|
||||||
|
name = name[:name]
|
||||||
|
end
|
||||||
|
if password.nil?
|
||||||
|
raise "Error: password can not be empty\n" \
|
||||||
|
" provide two strings: name, password\n" \
|
||||||
|
" or a hash with the key :password\n" \
|
||||||
|
"\n" \
|
||||||
|
" rcon_auth('', '123')\n" \
|
||||||
|
" rcon_auth(password: '123')\n"
|
||||||
|
end
|
||||||
|
data = []
|
||||||
|
if name.nil? || name == ''
|
||||||
|
data += Packer.pack_str(password)
|
||||||
|
else # ddnet auth using name, password and some int?
|
||||||
|
data += Packer.pack_str(name)
|
||||||
|
data += Packer.pack_str(password)
|
||||||
|
data += Packer.pack_int(1)
|
||||||
|
end
|
||||||
|
msg = NetChunk.create_vital_header({ vital: true }, data.size + 1) +
|
||||||
|
[pack_msg_id(NETMSG_RCON_AUTH, system: true)] +
|
||||||
|
data
|
||||||
|
@netbase.send_packet(msg, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def rcon(command)
|
||||||
|
data = []
|
||||||
|
data += Packer.pack_str(command)
|
||||||
|
msg = NetChunk.create_vital_header({ vital: true }, data.size + 1) +
|
||||||
|
[pack_msg_id(NETMSG_RCON_CMD, system: true)] +
|
||||||
|
data
|
||||||
|
@netbase.send_packet(msg, 1)
|
||||||
|
end
|
||||||
|
|
||||||
def send_msg_startinfo
|
def send_msg_startinfo
|
||||||
data = []
|
data = []
|
||||||
|
|
||||||
|
@ -289,6 +329,8 @@ class TeeworldsClient
|
||||||
@game_client.on_connected
|
@game_client.on_connected
|
||||||
when NETMSG_NULL
|
when NETMSG_NULL
|
||||||
# should we be in alert here?
|
# should we be in alert here?
|
||||||
|
when NETMSG_RCON_LINE
|
||||||
|
@game_client.on_rcon_line(chunk)
|
||||||
else
|
else
|
||||||
puts "Unsupported system msg: #{chunk.msg}"
|
puts "Unsupported system msg: #{chunk.msg}"
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
Loading…
Reference in a new issue