Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ install:

script:
- go test -v -race ./...
- gometalinter.v1 --cyclo-over=16 ./...
- gometalinter.v1 --cyclo-over=17 ./...
1 change: 1 addition & 0 deletions mockserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ var (
"instanceinfo": "serverinstance_database_version=26 serverinstance_filetransfer_port=30033 serverinstance_max_download_total_bandwidth=18446744073709551615 serverinstance_max_upload_total_bandwidth=18446744073709551615 serverinstance_guest_serverquery_group=1 serverinstance_serverquery_flood_commands=50 serverinstance_serverquery_flood_time=3 serverinstance_serverquery_ban_time=600 serverinstance_template_serveradmin_group=3 serverinstance_template_serverdefault_group=5 serverinstance_template_channeladmin_group=1 serverinstance_template_channeldefault_group=4 serverinstance_permissions_version=19 serverinstance_pending_connections_per_ip=0",
"serverrequestconnectioninfo": "connection_filetransfer_bandwidth_sent=0 connection_filetransfer_bandwidth_received=0 connection_filetransfer_bytes_sent_total=617 connection_filetransfer_bytes_received_total=0 connection_packets_sent_total=926413 connection_bytes_sent_total=92911395 connection_packets_received_total=650335 connection_bytes_received_total=61940731 connection_bandwidth_sent_last_second_total=0 connection_bandwidth_sent_last_minute_total=0 connection_bandwidth_received_last_second_total=0 connection_bandwidth_received_last_minute_total=0 connection_connected_time=49408 connection_packetloss_total=0.0000 connection_ping=0.0000",
"channellist": "cid=499 pid=0 channel_order=0 channel_name=Default\\sChannel total_clients=1 channel_needed_subscribe_power=0",
"clientinfo": `cid=20 client_idle_time=28122 client_unique_identifier=P5H2hrN6+gpQI4n\/dXp3p17vtY0= client_nickname=Rabe85 client_version=3.0.0-alpha24\s[Build:\s8785]\s(UI:\s8785) client_platform=Windows client_input_muted=0 client_output_muted=0 client_outputonly_muted=0 client_input_hardware=1 client_output_hardware=1 client_default_channel=\/20 client_meta_data client_is_recording=0 client_version_sign=+\/BWvaeokGg4YkO1v3ouZB5vtIIgUZ5bM5cRfxBstfnHUdro2ja+5b+3sFUzEy8\/vvEISXVD6U95blTb638MCQ== client_security_hash client_login_name client_database_id=8 client_channel_group_id=8 client_servergroups=6 client_created=1503431624 client_lastconnected=1530383977 client_totalconnections=138 client_away=0 client_away_message client_type=0 client_flag_avatar=dd213abf2a94396ece544b22c4e56821 client_talk_power=75 client_talk_request=0 client_talk_request_msg client_description client_is_talker=0 client_month_bytes_uploaded=0 client_month_bytes_downloaded=0 client_total_bytes_uploaded=0 client_total_bytes_downloaded=3014720 client_is_priority_speaker=1 client_nickname_phonetic=rabeh client_needed_serverquery_view_power=75 client_default_token client_icon_id=0 client_is_channel_commander=1 client_country=DE client_channel_group_inherited_channel_id=20 client_badges=overwolf=0 client_base64HashClientUID=kdohhblmninnfhaecihcijemaigdnkdhgjllefed connection_filetransfer_bandwidth_sent=0 connection_filetransfer_bandwidth_received=0 connection_packets_sent_total=46880 connection_bytes_sent_total=6426774 connection_packets_received_total=14098 connection_bytes_received_total=1644574 connection_bandwidth_sent_last_second_total=81 connection_bandwidth_sent_last_minute_total=92 connection_bandwidth_received_last_second_total=83 connection_bandwidth_received_last_minute_total=97 connection_connected_time=2084247 connection_client_ip=83.123.45.6`,
"clientlist": "clid=5 cid=7 client_database_id=40 client_nickname=ScP client_type=0 client_away=1 client_away_message=not\\shere",
"clientdblist": "cldbid=7 client_unique_identifier=DZhdQU58qyooEK4Fr8Ly738hEmc= client_nickname=MuhChy client_created=1259147468 client_lastconnected=1259421233",
"whoami": "virtualserver_status=online virtualserver_id=18 virtualserver_unique_identifier=gNITtWtKs9+Uh3L4LKv8\\/YHsn5c= virtualserver_port=9987 client_id=94 client_channel_id=432 client_nickname=serveradmin\\sfrom\\s127.0.0.1:49725 client_database_id=1 client_login_name=serveradmin client_unique_identifier=serveradmin client_origin_server_id=0",
Expand Down
121 changes: 116 additions & 5 deletions server_cmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,16 +263,16 @@ func (s *ServerMethods) Stop(id int) error {

// Group represents a virtual server group.
type Group struct {
ID int `ms:"sgid"`
ID int `ms:"sgid"`
Name string
Type int
IconID int
Saved bool `ms:"savedb"`
SortID int
NameMode int
ModifyPower int `ms:"n_modifyp"`
MemberAddPower int `ms:"n_member_addp"`
MemberRemovePower int `ms:"n_member_addp"`
ModifyPower int `ms:"n_modifyp"`
MemberAddPower int `ms:"n_member_addp"`
MemberRemovePower int `ms:"n_member_addp"`
}

// GroupList returns a list of available groups for the selected server.
Expand Down Expand Up @@ -340,14 +340,125 @@ func (s *ServerMethods) PrivilegeKeyAdd(ttype, id1, id2 int, options ...CmdArg)

// OnlineClient represents a client online on a virtual server.
type OnlineClient struct {
ID int `ms:"cid"`
ID int `ms:"clid"`
ChannelID int `ms:"cid"`
DatabaseID int `ms:"client_database_id"`
Nickname string `ms:"client_nickname"`
Type int `ms:"client_type"`
Away bool `ms:"client_away"`
AwayMessage string `ms:"client_away_message"`
}

// DetailedOnlineClient extends OnlineClient with all information from the
// clientinfo server query command about a client online on a virtual server.
type DetailedOnlineClient struct {
OnlineClient `ms:",squash"`

// Creation date and time of the clients first connection to the server.
Created time.Time `ms:"client_created"`
// Termination date and time of the clients last connection to the server.
// Note: The manual claims this to be the *creation* date and time but the
// values received while testing suggest otherwise.
LastConnected time.Time `ms:"client_lastconnected"`

// Empty or a string of 32 hexadecimal characters. Indicates whether the
// client has set an avatar or not.
// What platform the client is running on. For example "Windows".
Base64HashClientUID string `ms:"client_base64HashClientUID"`
// For example "83.123.45.6". According to the manual this is always IPv4.
ConnectionClientIP string `ms:"connection_client_ip"`
// For example "DE" for Germany.
Country string `ms:"client_country"`
// Takes the form of "/channelID"
DefaultChannel string `ms:"client_default_channel"`
DefaultToken string `ms:"client_default_token"`
Description string `ms:"client_description"`
LoginName string `ms:"client_login_name"`
NicknamePhonetic string `ms:"client_nickname_phonetic"`
SecurityHash string `ms:"client_security_hash"`
TalkRequestMsg string `ms:"client_talk_request_msg"`
UniqueIdentifier string `ms:"client_unique_identifier"`
FlagAvatar string `ms:"client_flag_avatar"`
Platform string `ms:"client_platform"`
// Which version of the Teamspeak client application this client uses.
Version string `ms:"client_version"`
VersionSign string `ms:"client_version_sign"`

// Milliseconds since the client connected to the server.
ConnectionConnectedTime int64 `ms:"connection_connected_time"`
ConnectionBytesReceivedTotal int64 `ms:"connection_bytes_received_total"`
ConnectionBytesSentTotal int64 `ms:"connection_bytes_sent_total"`
ConnectionPacketsReceivedTotal int64 `ms:"connection_packets_received_total"`
ConnectionPacketsSentTotal int64 `ms:"connection_packets_sent_total"`
// Milliseconds since the client did something, for example sending
// a message, muting themselves or talking.
IdleTime int64 `ms:"client_idle_time"`
MonthBytesDownloaded int64 `ms:"client_month_bytes_downloaded"`
MonthBytesUploaded int64 `ms:"client_month_bytes_uploaded"`
TotalBytesDownloaded int64 `ms:"client_total_bytes_downloaded"`
TotalBytesUploaded int64 `ms:"client_total_bytes_uploaded"`

// Current bandwidth used for outgoing file transfers (Bytes/s)
ConnectionFiletransferBandwidthSent int `ms:"connection_filetransfer_bandwidth_sent"`
// Current bandwidth used for incoming file transfers (Bytes/s)
ConnectionFiletransferBandwidthReceived int `ms:"connection_filetransfer_bandwidth_received"`
// Average bandwidth used for outgoing data in the last second (Bytes/s)
ConnectionBandwidthSentLastSecondTotal int `ms:"connection_bandwidth_sent_last_second_total"`
// Average bandwidth used for outgoing data in the last minute (Bytes/s)
ConnectionBandwidthSentLastMinuteTotal int `ms:"connection_bandwidth_sent_last_minute_total"`
// Average bandwidth used for incoming data in the last second (Bytes/s)
ConnectionBandwidthReceivedLastSecondTotal int `ms:"connection_bandwidth_received_last_second_total"`
// Average bandwidth used for incoming data in the last minute (Bytes/s)
ConnectionBandwidthReceivedLastMinuteTotal int `ms:"connection_bandwidth_received_last_minute_total"`
ChannelGroupID int `ms:"client_channel_group_id"`
ChannelGroupInheritedChannelID int `ms:"client_channel_group_inherited_channel_id"`
NeededServerqueryViewPower int `ms:"client_needed_serverquery_view_power"`
Servergroups int `ms:"client_servergroups"`
TalkPower int `ms:"client_talk_power"`
// How often the client has connected to the server.
Totalconnections int `ms:"client_totalconnections"`

// CRC32 checksum of the client icon
IconID uint32 `ms:"client_icon_id"`

// False if the client has their microphone disabled, for example
// because they unplugged it. Do not confuse this with InputMuted.
InputHardware bool `ms:"client_input_hardware"`
// True if the client has their microphone muted
InputMuted bool `ms:"client_input_muted"`
IsChannelCommander bool `ms:"client_is_channel_commander"`
IsPrioritySpeaker bool `ms:"client_is_priority_speaker"`
IsRecording bool `ms:"client_is_recording"`
// False if the client has their speakers disabled, for example
// because they are unplugged. Do not confuse this with OutputMuted.
OutputHardware bool `ms:"client_output_hardware"`
// True if the client has their speakers muted
OutputMuted bool `ms:"client_output_muted"`
OutputOnlyMuted bool `ms:"client_outputonly_muted"`
TalkRequest bool `ms:"client_talk_request"`

// Indicates whether the client is able to talk or not.
//TODO(Henner25): This is always 0, even if my talk power is high enough?
IsTalker bool `ms:"client_is_talker"`

//TODO(Henner25): I always got "overwolf=0". I assume it is a list of "key=value|key2=value2...". In that case, the type of this should be a map (or maybe an array, if it's only true/false).
//Badges string `ms:"client_badges"`

//TODO(Henner25): I never managed to receive any value for this field
//MetaData interface{} `ms:"client_meta_data"`
}

// ClientInfo returns detailed information about a single online client.
func (s *ServerMethods) ClientInfo(clientID int) (*DetailedOnlineClient, error) {
var client DetailedOnlineClient
if _, err := s.ExecCmd(NewCmd("clientinfo").WithArgs(NewArg("clid", clientID)).WithResponse(&client)); err != nil {
return nil, err
}

client.ID = clientID // the clientinfo command does not include the clid in the result set
return &client, nil
}

// ClientList returns a list of online clients.
func (s *ServerMethods) ClientList() ([]*OnlineClient, error) {
var clients []*OnlineClient
Expand Down
81 changes: 77 additions & 4 deletions server_cmds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ func TestCmdsServer(t *testing.T) {
return
}
expected := &Server{
Status: "template",
MaxClients: 32,
Name: "Test Server",
Status: "template",
MaxClients: 32,
Name: "Test Server",
AntiFloodPointsNeededCommandBlock: 150,
AntiFloodPointsNeededIPBlock: 250,
AntiFloodPointsTickReduce: 5,
Expand Down Expand Up @@ -251,6 +251,77 @@ func TestCmdsServer(t *testing.T) {
assert.Equal(t, expected, channels)
}

clientinfo := func(t *testing.T) {
client, err := c.Server.ClientInfo(8)
if !assert.NoError(t, err) {
return
}

expected := &DetailedOnlineClient{
OnlineClient: OnlineClient{
ID: 8,
ChannelID: 20,
DatabaseID: 8,
Nickname: "Rabe85",
Type: 0,
Away: false,
AwayMessage: "",
},
IdleTime: 28122,
UniqueIdentifier: "P5H2hrN6+gpQI4n/dXp3p17vtY0=",
Version: "3.0.0-alpha24 [Build: 8785] (UI: 8785)",
Platform: "Windows",
InputMuted: false,
OutputMuted: false,
OutputOnlyMuted: false,
InputHardware: true,
OutputHardware: true,
DefaultChannel: "/20",
IsRecording: false,
VersionSign: "+/BWvaeokGg4YkO1v3ouZB5vtIIgUZ5bM5cRfxBstfnHUdro2ja+5b+3sFUzEy8/vvEISXVD6U95blTb638MCQ==",
SecurityHash: "",
LoginName: "",
ChannelGroupID: 8,
Servergroups: 6,
Created: time.Unix(1503431624, 0),
LastConnected: time.Unix(1530383977, 0),
Totalconnections: 138,
FlagAvatar: "dd213abf2a94396ece544b22c4e56821",
TalkPower: 75,
TalkRequest: false,
TalkRequestMsg: "",
Description: "",
IsTalker: false,
MonthBytesUploaded: 0,
MonthBytesDownloaded: 0,
TotalBytesUploaded: 0,
TotalBytesDownloaded: 3014720,
IsPrioritySpeaker: true,
NicknamePhonetic: "rabeh",
NeededServerqueryViewPower: 75,
DefaultToken: "",
IconID: 0,
IsChannelCommander: true,
Country: "DE",
ChannelGroupInheritedChannelID: 20,
Base64HashClientUID: "kdohhblmninnfhaecihcijemaigdnkdhgjllefed",
ConnectionFiletransferBandwidthSent: 0,
ConnectionFiletransferBandwidthReceived: 0,
ConnectionPacketsSentTotal: 46880,
ConnectionBytesSentTotal: 6426774,
ConnectionPacketsReceivedTotal: 14098,
ConnectionBytesReceivedTotal: 1644574,
ConnectionBandwidthSentLastSecondTotal: 81,
ConnectionBandwidthSentLastMinuteTotal: 92,
ConnectionBandwidthReceivedLastSecondTotal: 83,
ConnectionBandwidthReceivedLastMinuteTotal: 97,
ConnectionConnectedTime: 2084247,
ConnectionClientIP: "83.123.45.6",
}

assert.Equal(t, expected, client)
}

clientlist := func(t *testing.T) {
clients, err := c.Server.ClientList()
if !assert.NoError(t, err) {
Expand All @@ -259,7 +330,8 @@ func TestCmdsServer(t *testing.T) {

expected := []*OnlineClient{
{
ID: 7,
ID: 5,
ChannelID: 7,
DatabaseID: 40,
Nickname: "ScP",
Type: 0,
Expand Down Expand Up @@ -308,6 +380,7 @@ func TestCmdsServer(t *testing.T) {
{"serverrequestconnectioninfo", serverrequestconnectioninfo},
{"instanceinfo", instanceinfo},
{"channellist", channellist},
{"clientinfo", clientinfo},
{"clientlist", clientlist},
{"clientdblist", clientdblist},
}
Expand Down