
com.github.theholywaffle.teamspeak3.StreamReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of teamspeak3-api Show documentation
Show all versions of teamspeak3-api Show documentation
A Java 7 wrapper of the TeamSpeak 3 Server Query API.
The newest version!
package com.github.theholywaffle.teamspeak3;
/*
* #%L
* TeamSpeak 3 Java API
* %%
* Copyright (C) 2018 Bert De Geyter, Roger Baumgartner
* %%
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
* #L%
*/
import com.github.theholywaffle.teamspeak3.api.CommandFuture;
import com.github.theholywaffle.teamspeak3.api.exception.TS3CommandFailedException;
import com.github.theholywaffle.teamspeak3.api.wrapper.QueryError;
import com.github.theholywaffle.teamspeak3.commands.Command;
import com.github.theholywaffle.teamspeak3.commands.response.DefaultArrayResponse;
import com.github.theholywaffle.teamspeak3.commands.response.ResponseBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.SocketTimeoutException;
import java.nio.charset.StandardCharsets;
class StreamReader extends Thread {
private static final Logger log = LoggerFactory.getLogger(StreamReader.class);
private final TS3Query ts3;
private final Connection con;
private final BufferedReader in;
private final boolean logComms;
private CommandQueue commandQueue = null;
private ResponseBuilder responseBuilder = null;
private String lastEvent = "";
StreamReader(Connection connection, InputStream inStream, TS3Query query, TS3Config config) throws IOException {
super("[TeamSpeak-3-Java-API] StreamReader");
ts3 = query;
con = connection;
in = new BufferedReader(new InputStreamReader(inStream, StandardCharsets.UTF_8));
logComms = config.getEnableCommunicationsLogging();
readWelcomeMessage();
}
private void readWelcomeMessage() throws IOException {
for (int i = 0; i < 4 || in.ready(); ++i) {
String welcomeMessage = in.readLine();
if (logComms) log.debug("< {}", welcomeMessage);
}
}
@Override
public void run() {
while (!isInterrupted()) {
String line;
try {
// Will block until a full line of text could be read.
line = in.readLine();
} catch (SocketTimeoutException socketTimeout) {
// Really disconnected or just no data transferred for milliseconds?
if (con.isTimedOut()) {
log.error("Connection timed out.", socketTimeout);
break;
} else {
continue;
}
} catch (IOException io) {
if (!isInterrupted()) {
log.error("Connection error occurred.", io);
}
break;
}
if (line == null) {
// End of stream: connection terminated by server
log.error("Connection closed by the server.");
break;
} else if (line.isEmpty()) {
continue; // The server is sending garbage
}
if (line.startsWith("notify")) {
handleEvent(line);
} else {
con.resetIdleTime();
handleCommandResponse(line);
}
}
try {
in.close();
} catch (IOException ignored) {
// Ignore
}
if (!isInterrupted()) {
con.internalDisconnect();
}
}
private void handleEvent(String event) {
if (logComms) log.debug("[event] < {}", event);
// Filter out duplicate events for join, quit and channel move events
if (isDuplicate(event)) return;
String arr[] = event.split(" ", 2);
ts3.getEventManager().fireEvent(arr[0], arr[1]);
}
private void handleCommandResponse(String response) {
if (responseBuilder == null) {
commandQueue = con.getCommandQueue();
Command command = commandQueue.peekReceiveQueue();
if (command == null) {
log.warn("[UNHANDLED] < {}", response);
return;
}
responseBuilder = new ResponseBuilder(command);
}
if (logComms) log.debug("[{}] < {}", responseBuilder.getCommand().getName(), response);
if (response.startsWith("error ")) {
handleCommandError(responseBuilder, response);
commandQueue.removeFromReceiveQueue();
responseBuilder = null;
} else {
responseBuilder.appendResponse(response);
}
}
private void handleCommandError(ResponseBuilder responseBuilder, String error) {
Command command = responseBuilder.getCommand();
if (command.getName().equals("quit")) {
// Response to a quit command received, we're done
interrupt();
}
QueryError queryError = DefaultArrayResponse.parseError(error);
CommandFuture future = command.getFuture();
if (queryError.isSuccessful()) {
DefaultArrayResponse response = responseBuilder.buildResponse();
ts3.submitUserTask("Future SuccessListener (" + command.getName() + ")",
() -> future.set(response));
} else {
log.debug("TS3 command error: {}", queryError);
ts3.submitUserTask("Future FailureListener (" + command.getName() + ")",
() -> future.fail(new TS3CommandFailedException(queryError, command.getName())));
}
}
private boolean isDuplicate(String eventMessage) {
if (!(eventMessage.startsWith("notifyclientmoved")
|| eventMessage.startsWith("notifycliententerview")
|| eventMessage.startsWith("notifyclientleftview"))) {
// Event that will never cause duplicates
return false;
}
if (eventMessage.equals(lastEvent)) {
// Duplicate event!
lastEvent = ""; // Let's only ever filter one duplicate
return true;
}
lastEvent = eventMessage;
return false;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy