From 964936abdf3aa9e8ddd7e2aa686aa3af90b5a156 Mon Sep 17 00:00:00 2001 From: Manevolent Date: Wed, 1 Aug 2018 16:29:31 -0400 Subject: [PATCH] Working on commands, having trouble with acks right now --- .../manevolent/ts3j/command/MultiCommand.java | 9 +- .../response/AbstractCommandResponse.java | 6 +- .../client/AbstractTeamspeakClientSocket.java | 29 +- .../client/LocalTeamspeakClientSocket.java | 362 ++++++++++++++++-- .../manevolent/ts3j/ServerConnectionTest.java | 18 +- 5 files changed, 360 insertions(+), 64 deletions(-) diff --git a/src/main/java/com/github/manevolent/ts3j/command/MultiCommand.java b/src/main/java/com/github/manevolent/ts3j/command/MultiCommand.java index 0e66d28..c15554b 100644 --- a/src/main/java/com/github/manevolent/ts3j/command/MultiCommand.java +++ b/src/main/java/com/github/manevolent/ts3j/command/MultiCommand.java @@ -11,6 +11,7 @@ import java.util.*; public class MultiCommand implements Command { private final String name; private final ProtocolRole role; + private final List staticParameters = new LinkedList<>(); private final List commands; public MultiCommand(String name, ProtocolRole role, SingleCommand... params) { @@ -35,12 +36,12 @@ public class MultiCommand implements Command { @Override public Iterable getParameters() { - throw new UnsupportedOperationException(); + return staticParameters; } @Override public void add(CommandParameter parameter) { - throw new UnsupportedOperationException(); + staticParameters.add(parameter); } public List simplify() { @@ -58,9 +59,11 @@ public class MultiCommand implements Command { @Override public String build() { + SingleCommand staticSingle = new SingleCommand(getName(), getRole(), staticParameters); + StringBuilder builder = new StringBuilder(); - builder.append(getName().toLowerCase()); + builder.append(staticSingle.build()); List singleCommands = simplify(); diff --git a/src/main/java/com/github/manevolent/ts3j/command/response/AbstractCommandResponse.java b/src/main/java/com/github/manevolent/ts3j/command/response/AbstractCommandResponse.java index df10467..1067054 100644 --- a/src/main/java/com/github/manevolent/ts3j/command/response/AbstractCommandResponse.java +++ b/src/main/java/com/github/manevolent/ts3j/command/response/AbstractCommandResponse.java @@ -1,6 +1,7 @@ package com.github.manevolent.ts3j.command.response; import com.github.manevolent.ts3j.command.MultiCommand; +import com.github.manevolent.ts3j.util.Ts3Debugging; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -11,8 +12,7 @@ import java.util.function.Function; public abstract class AbstractCommandResponse implements CommandResponse { private final Function, T> processor; - private CompletableFuture> future = - new CompletableFuture<>(); + private final CompletableFuture> future = new CompletableFuture<>(); public AbstractCommandResponse(Function, T> processor) { this.processor = processor; @@ -36,10 +36,12 @@ public abstract class AbstractCommandResponse implements CommandResponse { @Override public T get() throws ExecutionException, InterruptedException { + Ts3Debugging.debug("WAITING ON " + future); return map(future.get()); } protected void completeSuccess(Iterable commands) { + Ts3Debugging.debug("SUCCEEDING " + future); future.complete(commands); } diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java b/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java index 9af8c5d..8b95601 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java @@ -373,7 +373,8 @@ public abstract class AbstractTeamspeakClientSocket packet.getHeader().getPacketId(), response = new PacketResponse( networkPacket, - networkPacket.getHeader().getType().canResend() ? Integer.MAX_VALUE : 0 + sendQueue, + networkPacket.getHeader().getType().canResend() ? 10 : 0 ) ); else @@ -560,20 +561,6 @@ public abstract class AbstractTeamspeakClientSocket } } - if (packet.getHeader().getType().canResend() && - packet.getHeader().getType() != PacketBodyType.INIT1) { - // Find if we already acknowledged this packet - if (!counter.put(packet.getHeader().getPacketId())) { - Ts3Debugging.debug("[PROTOCOL] Ignoring handling resent packet: " + - packet + " " + - packet.getHeader().getType().name() + " id=" + - packet.getHeader().getPacketId() + " generation=" + - packet.getHeader().getGeneration()); - - continue; // Drop the packet - } - } - // Find if the packet must be reassembled if (packet.getHeader().getType().isSplittable()) { packet = reassemblyQueue.get(packet.getHeader().getType()).put(packet); @@ -582,7 +569,7 @@ public abstract class AbstractTeamspeakClientSocket // Find if the packet is itself an acknowledgement boolean handle; - PacketResponse response; + final PacketResponse response; switch (packet.getHeader().getType()) { case ACK: response = sendQueue.get(((PacketBody6Ack)packet.getBody()).getPacketId()); @@ -601,6 +588,11 @@ public abstract class AbstractTeamspeakClientSocket response = null; } + if (packet.getHeader().getType().canResend() && packet.getHeader().getType() != PacketBodyType.INIT1) { + // Find if we already acknowledged this packet + handle = handle & counter.put(packet.getHeader().getPacketId()); + } + if (response != null) { response.acknowledge(packet); } else if (handle) { @@ -737,12 +729,14 @@ public abstract class AbstractTeamspeakClientSocket private class PacketResponse { private final NetworkPacket sentPacket; private final CompletableFuture future = new CompletableFuture<>(); + private final Map responsibleQueue; private long lastSent = 0L; private int tries = 1, maxTries; private boolean willResend; - public PacketResponse(NetworkPacket sentPacket,int maxTries) { + public PacketResponse(NetworkPacket sentPacket, Map responsibleQueue, int maxTries) { this.sentPacket = sentPacket; + this.responsibleQueue = responsibleQueue; this.maxTries = maxTries; this.lastSent = System.currentTimeMillis(); this.willResend = maxTries > 0; @@ -801,6 +795,7 @@ public abstract class AbstractTeamspeakClientSocket } public void acknowledge(Packet p) { + responsibleQueue.remove(sentPacket.getHeader().getPacketId()); future.complete(p); } diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/LocalTeamspeakClientSocket.java b/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/LocalTeamspeakClientSocket.java index 1885ecc..976cbaa 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/LocalTeamspeakClientSocket.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/LocalTeamspeakClientSocket.java @@ -1,15 +1,18 @@ package com.github.manevolent.ts3j.protocol.socket.client; +import com.github.manevolent.ts3j.api.Ban; import com.github.manevolent.ts3j.api.Channel; +import com.github.manevolent.ts3j.api.Client; +import com.github.manevolent.ts3j.api.Permission; import com.github.manevolent.ts3j.audio.Microphone; import com.github.manevolent.ts3j.command.*; import com.github.manevolent.ts3j.command.parameter.CommandSingleParameter; import com.github.manevolent.ts3j.command.response.AbstractCommandResponse; import com.github.manevolent.ts3j.command.response.CommandResponse; -import com.github.manevolent.ts3j.enums.CodecType; import com.github.manevolent.ts3j.event.TS3Event; import com.github.manevolent.ts3j.event.TS3Listener; import com.github.manevolent.ts3j.identity.LocalIdentity; +import com.github.manevolent.ts3j.identity.Uid; import com.github.manevolent.ts3j.protocol.NetworkPacket; import com.github.manevolent.ts3j.protocol.ProtocolRole; import com.github.manevolent.ts3j.protocol.client.ClientConnectionState; @@ -24,8 +27,11 @@ import java.net.*; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; import java.util.function.Function; +import java.util.stream.Collectors; public class LocalTeamspeakClientSocket extends AbstractTeamspeakClientSocket @@ -53,7 +59,7 @@ public class LocalTeamspeakClientSocket private int acceptingReturnCode = 0; private int lastReturnCode = 0; - private Map awaitingCommands = new HashMap<>(); + private Map awaitingCommands = new ConcurrentHashMap<>(); public LocalTeamspeakClientSocket() { super(); @@ -161,7 +167,7 @@ public class LocalTeamspeakClientSocket 0.020F, new MicrophoneTask() ); - + microphoneThread.setDaemon(true); microphoneThread.start(); } catch (TimeoutException e) { setState(ClientConnectionState.DISCONNECTED); @@ -229,20 +235,24 @@ public class LocalTeamspeakClientSocket ) throws IOException, TimeoutException { int returnCode; - ClientCommandResponse response; + final ClientCommandResponse response; // sync may not be necessary here synchronized (commandSendLock) { returnCode = lastReturnCode++; awaitingCommands.put(returnCode, response = new ClientCommandResponse<>(returnCode, processor)); + acceptingReturnCode = calculateAcceptingReturnCode(); } - command.add(new CommandSingleParameter("return_code", Integer.toString(returnCode))); - try { + command.add(new CommandSingleParameter("return_code", Integer.toString(returnCode))); + writePacket(new PacketBody2Command(getRole().getOut(), command)); } catch (Throwable e) { - awaitingCommands.remove(returnCode); + synchronized (commandSendLock) { + awaitingCommands.remove(returnCode); + acceptingReturnCode = calculateAcceptingReturnCode(); + } throw e; } @@ -255,31 +265,36 @@ public class LocalTeamspeakClientSocket Function processor ) throws IOException, TimeoutException { int returnCode; + final ClientCommandResponse> response; // sync may not be necessary here synchronized (commandSendLock) { returnCode = lastReturnCode++; + + command.add(new CommandSingleParameter("return_code", Integer.toString(returnCode))); + + awaitingCommands.put(returnCode, response = new ClientCommandResponse<>(returnCode, multiCommands -> { + List commands = new LinkedList<>(); + for (MultiCommand multiCommand : multiCommands) commands.addAll(multiCommand.simplify()); + + List results = new LinkedList<>(); + for (SingleCommand command1 : commands) + results.add(processor.apply(command1)); + + return results; + })); + + acceptingReturnCode = calculateAcceptingReturnCode(); } - command.add(new CommandSingleParameter("return_code", Integer.toString(returnCode))); - - ClientCommandResponse> response; - - awaitingCommands.put(returnCode, response = new ClientCommandResponse<>(returnCode, multiCommands -> { - List commands = new LinkedList<>(); - for (MultiCommand multiCommand : multiCommands) commands.addAll(multiCommand.simplify()); - - List results = new LinkedList<>(); - for (SingleCommand command1 : commands) - results.add(processor.apply(command1)); - - return results; - })); - try { writePacket(new PacketBody2Command(getRole().getOut(), command)); } catch (Throwable e) { - awaitingCommands.remove(returnCode); + synchronized (commandSendLock) { + awaitingCommands.remove(returnCode); + + acceptingReturnCode = calculateAcceptingReturnCode(); + } throw e; } @@ -302,6 +317,13 @@ public class LocalTeamspeakClientSocket } } + private int calculateAcceptingReturnCode() { + int lowest = Integer.MAX_VALUE; + for (Integer integer : awaitingCommands.keySet()) lowest = Math.min(lowest, integer); + + return lowest; + } + private class MicrophoneTask implements Runnable { @Override public void run() { @@ -349,26 +371,40 @@ public class LocalTeamspeakClientSocket public void process(AbstractTeamspeakClientSocket client, MultiCommand multiCommand) throws CommandProcessException { - if (multiCommand.getName().equalsIgnoreCase("error")) { - SingleCommand command = multiCommand.simplifyFirst(); - int errorId = Integer.parseInt(command.get("id").getValue()); - - switch (errorId) { - case 0: - completeSuccess(commands); - break; - default: - completeFailure(new CommandException(command.get("msg").getValue(), errorId)); - break; - } - - synchronized (awaitingCommands) { - awaitingCommands.remove(returnCode); - } - } else + if (multiCommand.getName().equalsIgnoreCase("error")) + handleError(multiCommand.simplifyOne()); + else commands.add(multiCommand); } + @Override + public void process(AbstractTeamspeakClientSocket client, + SingleCommand command) + throws CommandProcessException { + if (command.getName().equalsIgnoreCase("error")) + handleError(command); + else + commands.add(new MultiCommand(command.getName(), ProtocolRole.CLIENT, command)); + } + + private void handleError(SingleCommand command) { + int errorId = Integer.parseInt(command.get("id").getValue()); + + synchronized (awaitingCommands) { + awaitingCommands.remove(returnCode); + acceptingReturnCode = calculateAcceptingReturnCode(); + } + + switch (errorId) { + case 0: + completeSuccess(commands); + break; + default: + completeFailure(new CommandException(command.get("msg").getValue(), errorId)); + break; + } + } + public int getReturnCode() { return returnCode; } @@ -399,4 +435,250 @@ public class LocalTeamspeakClientSocket } } } + + /** + * Commands + */ + + public void addBan(String ip, String name, Uid uid, Integer timeInSeconds, String reason) + throws IOException, TimeoutException, ExecutionException, InterruptedException, CommandException { + Command banCommand = new SingleCommand("banadd", ProtocolRole.CLIENT); + + if (ip != null) banCommand.add(new CommandSingleParameter("ip", ip)); + if (name != null) banCommand.add(new CommandSingleParameter("name", name)); + if (uid != null) banCommand.add(new CommandSingleParameter("uid", uid.toBase64())); + if (timeInSeconds != null) banCommand.add(new CommandSingleParameter("time", timeInSeconds.toString())); + if (reason != null) banCommand.add(new CommandSingleParameter("banreason", reason)); + + executeCommand(banCommand).complete(); + } + + public Iterable banClient(int clid, Integer timeInSeconds, String reason) + throws IOException, TimeoutException, ExecutionException, InterruptedException, CommandException { + Command banCommand = new SingleCommand("banclient", ProtocolRole.CLIENT); + + banCommand.add(new CommandSingleParameter("clid", Integer.toString(clid))); + if (timeInSeconds != null) banCommand.add(new CommandSingleParameter("time", timeInSeconds.toString())); + if (reason != null) banCommand.add(new CommandSingleParameter("banreason", reason)); + + return executeMappedCommand(banCommand, command -> new Ban(command.toMap())).get(); + } + + public Iterable banDatabaseClient(int dbid, Integer timeInSeconds, String reason) + throws IOException, TimeoutException, ExecutionException, InterruptedException, CommandException { + Command banCommand = new SingleCommand("banclient", ProtocolRole.CLIENT); + + banCommand.add(new CommandSingleParameter("cldbid", Integer.toString(dbid))); + if (timeInSeconds != null) banCommand.add(new CommandSingleParameter("time", timeInSeconds.toString())); + if (reason != null) banCommand.add(new CommandSingleParameter("banreason", reason)); + + return executeMappedCommand(banCommand, command -> new Ban(command.toMap())).get(); + } + + public Iterable banClient(Uid uid, Integer timeInSeconds, String reason) + throws IOException, TimeoutException, ExecutionException, InterruptedException, CommandException { + Command banCommand = new SingleCommand("banclient", ProtocolRole.CLIENT); + + banCommand.add(new CommandSingleParameter("uid", uid.toBase64())); + if (timeInSeconds != null) banCommand.add(new CommandSingleParameter("time", timeInSeconds.toString())); + if (reason != null) banCommand.add(new CommandSingleParameter("banreason", reason)); + + return executeMappedCommand(banCommand, command -> new Ban(command.toMap())).get(); + } + + public Iterable banClient(Client client, Integer timeInSeconds, String reason) + throws InterruptedException, ExecutionException, TimeoutException, CommandException, IOException { + return banClient(client.getId(), timeInSeconds, reason); + } + + public void deleteBan(int banId) + throws IOException, TimeoutException, ExecutionException, InterruptedException, CommandException { + Command banCommand = new SingleCommand("deleteban", ProtocolRole.CLIENT); + + banCommand.add(new CommandSingleParameter("banid", Integer.toString(banId))); + + executeCommand(banCommand).complete(); + } + + public void deleteAllBans() + throws IOException, TimeoutException, ExecutionException, InterruptedException, CommandException { + executeCommand(new SingleCommand("bandelall", ProtocolRole.CLIENT)).complete(); + } + + // TODO notifybanlist is returned instead + public Iterable listBans() + throws InterruptedException, ExecutionException, TimeoutException, CommandException, IOException { + Command banCommand = new SingleCommand("banlist", ProtocolRole.CLIENT); + return executeMappedCommand(banCommand, command -> new Ban(command.toMap())).get(); + } + + public void deleteBan(Ban ban) + throws InterruptedException, ExecutionException, TimeoutException, CommandException, IOException { + deleteBan(ban.getId()); + } + + public CommandResponse> channelAddPermission(int channelId, Permission... permission) + throws IOException, TimeoutException { + MultiCommand command = new MultiCommand( + "channeladdperm", + ProtocolRole.CLIENT, + Arrays.stream(permission).map(x -> + new SingleCommand("channeladdperm", ProtocolRole.CLIENT, // name is redundant here + new CommandSingleParameter("permsid", x.getName()), + new CommandSingleParameter("permvalue", Integer.toString(x.getValue())) + )).collect(Collectors.toList() + )); + + command.add(new CommandSingleParameter("cid", Integer.toString(channelId))); + + return executeCommand(command); + } + + public CommandResponse> channelClientAddPermission(int channelId, + int clientDatabaseId, + Permission... permission) + throws IOException, TimeoutException { + MultiCommand command = new MultiCommand( + "channelclientaddperm", + ProtocolRole.CLIENT, + Arrays.stream(permission).map(x -> + new SingleCommand("channelclientaddperm", ProtocolRole.CLIENT, // name is redundant here + new CommandSingleParameter("permsid", x.getName()), + new CommandSingleParameter("permvalue", Integer.toString(x.getValue())) + )).collect(Collectors.toList() + )); + + command.add(new CommandSingleParameter("cid", Integer.toString(channelId))); + command.add(new CommandSingleParameter("cldbid", Integer.toString(channelId))); + + return executeCommand(command); + } + + public void channelClientDeletePermission(int channelId, + int clientDatabaseId, + Permission... permission) + throws IOException, TimeoutException, ExecutionException, InterruptedException { + MultiCommand command = new MultiCommand( + "channeldelperm", + ProtocolRole.CLIENT, + Arrays.stream(permission).map(x -> + new SingleCommand("channeldelperm", ProtocolRole.CLIENT, // name is redundant here + new CommandSingleParameter("permsid", x.getName()), + new CommandSingleParameter("permvalue", Integer.toString(x.getValue())) + )).collect(Collectors.toList() + )); + + command.add(new CommandSingleParameter("cid", Integer.toString(channelId))); + command.add(new CommandSingleParameter("cldbid", Integer.toString(channelId))); + + executeCommand(command).complete(); + } + + /** + * Displays a list of clients that are in the channel specified by the cid + parameter. Included information is the clientID, client database id, nickname, + channelID and client type. + Please take note that you can only view clients in channels that you are + currently subscribed to. + + Here is a list of the additional display paramters you will receive for + each of the possible modifier parameters. + + * @param channelId channel ID to look at + * @return list of channel clients + * @throws IOException + * @throws TimeoutException + */ + // TODO command not found + public Iterable listChannelClients(int channelId) + throws InterruptedException, ExecutionException, TimeoutException, CommandException, IOException { + Command command = new SingleCommand("channelclientlist", ProtocolRole.CLIENT); + + command.add(new CommandSingleParameter("cid", Integer.toString(channelId))); + + return executeMappedCommand(command, x -> new Client(x.toMap())).get(); + } + + /** + * Moves one or more clients specified with clid to the channel with ID cid. If + the target channel has a password, it needs to be specified with cpw. If the + channel has no password, the parameter can be omitted. + */ + public void clientMove(int clientId, int channelId, String password) + throws IOException, TimeoutException, ExecutionException, InterruptedException { + Command command = new SingleCommand("clientmove", ProtocolRole.CLIENT); + + command.add(new CommandSingleParameter("cid", Integer.toString(channelId))); + if (password != null) command.add(new CommandSingleParameter("cpw", Integer.toString(channelId))); + command.add(new CommandSingleParameter("clid", Integer.toString(clientId))); + + executeCommand(command).complete(); + } + + public void joinChannel(int channelId, String password) + throws InterruptedException, ExecutionException, TimeoutException, IOException { + clientMove(getClientId(), channelId, password); + } + + /** + * Moves one or more clients specified with clid to the channel with ID cid. If + the target channel has a password, it needs to be specified with cpw. If the + channel has no password, the parameter can be omitted. + */ + public Iterable listChannels() + throws IOException, TimeoutException, ExecutionException, InterruptedException { + Command command = new SingleCommand("channellist", ProtocolRole.CLIENT); + + return executeMappedCommand(command, x -> new Channel(x.toMap())).get(); + } + + /** + * Moves one or more clients specified with clid to the channel with ID cid. If + the target channel has a password, it needs to be specified with cpw. If the + channel has no password, the parameter can be omitted. + */ + public Iterable listClients() + throws IOException, TimeoutException, ExecutionException, InterruptedException { + Command command = new SingleCommand("clientlist", ProtocolRole.CLIENT); + + return executeMappedCommand(command, x -> new Client(x.toMap())).get(); + } + + /** + * Moves one or more clients specified with clid to the channel with ID cid. If + the target channel has a password, it needs to be specified with cpw. If the + channel has no password, the parameter can be omitted. + */ + public void clientPoke(int clientId, String message) + throws IOException, TimeoutException, ExecutionException, InterruptedException { + Command command = new SingleCommand("clientpoke", ProtocolRole.CLIENT); + + command.add(new CommandSingleParameter("clid", Integer.toString(clientId))); + command.add(new CommandSingleParameter("msg", message)); + + executeCommand(command).complete(); + } + + /** + * Kicks one or more clients specified with clid from their currently joined + channel or from the server, depending on reasonid. The reasonmsg parameter + specifies a text message sent to the kicked clients. This parameter is optional + and may only have a maximum of 40 characters. + */ + public void kick(Collection clientIds, String message) + throws IOException, TimeoutException, ExecutionException, InterruptedException { + MultiCommand command = new MultiCommand( + "clientkick", + ProtocolRole.CLIENT, + clientIds.stream().map(x -> + new SingleCommand("clientkick", ProtocolRole.CLIENT, // name is redundant here + new CommandSingleParameter("clid", Integer.toString(x)) + )).collect(Collectors.toList() + )); + + command.add(new CommandSingleParameter("reasonid", Integer.toString(5))); + command.add(new CommandSingleParameter("reasonmsg", message)); + + executeCommand(command).complete(); + } } diff --git a/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java b/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java index ee02934..c01bb6d 100644 --- a/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java +++ b/src/test/java/com/github/manevolent/ts3j/ServerConnectionTest.java @@ -1,9 +1,13 @@ package com.github.manevolent.ts3j; +import com.github.manevolent.ts3j.api.Ban; +import com.github.manevolent.ts3j.api.Channel; +import com.github.manevolent.ts3j.api.Client; import com.github.manevolent.ts3j.audio.Microphone; import com.github.manevolent.ts3j.command.SingleCommand; import com.github.manevolent.ts3j.enums.CodecType; import com.github.manevolent.ts3j.identity.LocalIdentity; +import com.github.manevolent.ts3j.identity.Uid; import com.github.manevolent.ts3j.protocol.ProtocolRole; import com.github.manevolent.ts3j.protocol.client.ClientConnectionState; import com.github.manevolent.ts3j.protocol.socket.client.LocalTeamspeakClientSocket; @@ -15,6 +19,7 @@ import java.math.BigInteger; import java.net.InetSocketAddress; import java.util.Base64; import java.util.Collections; +import java.util.Random; import java.util.stream.Collectors; import static org.junit.Assert.assertEquals; @@ -24,11 +29,15 @@ public class ServerConnectionTest { try { Ts3Debugging.setEnabled(true); - LocalIdentity localIdentity = LocalIdentity.generateNew(10); + LocalIdentity identity = LocalIdentity.load( + new BigInteger(Base64.getDecoder().decode("Tj6YXM3qyRv8n25L2pH+OEJnRUl4auQf8+znjYrOmWU=")) + ); + + identity.improveSecurity(10); LocalTeamspeakClientSocket client = new LocalTeamspeakClientSocket(); - client.setIdentity(localIdentity); + client.setIdentity(identity); client.setNickname("Hello from Java"); @@ -45,6 +54,11 @@ public class ServerConnectionTest { while (true) { Thread.sleep(1000L); + + for (Channel channel : client.listChannels()) { + Ts3Debugging.debug(channel.getName()); + } + } } catch (Throwable ex) { ex.printStackTrace();