001package com.github.theholywaffle.teamspeak3; 002 003/* 004 * #%L 005 * TeamSpeak 3 Java API 006 * %% 007 * Copyright (C) 2014 Bert De Geyter 008 * %% 009 * Permission is hereby granted, free of charge, to any person obtaining a copy 010 * of this software and associated documentation files (the "Software"), to deal 011 * in the Software without restriction, including without limitation the rights 012 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 013 * copies of the Software, and to permit persons to whom the Software is 014 * furnished to do so, subject to the following conditions: 015 * 016 * The above copyright notice and this permission notice shall be included in 017 * all copies or substantial portions of the Software. 018 * 019 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 020 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 021 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 022 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 023 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 024 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 025 * THE SOFTWARE. 026 * #L% 027 */ 028 029import com.github.theholywaffle.teamspeak3.commands.Command; 030import com.github.theholywaffle.teamspeak3.commands.response.ResponseBuilder; 031import org.slf4j.Logger; 032import org.slf4j.LoggerFactory; 033 034import java.io.IOException; 035import java.io.PrintStream; 036import java.util.Collection; 037import java.util.concurrent.BlockingQueue; 038 039public class SocketWriter extends Thread { 040 041 private static final Logger log = LoggerFactory.getLogger(SocketWriter.class); 042 043 private final BlockingQueue<Command> sendQueue; 044 private final BlockingQueue<ResponseBuilder> receiveQueue; 045 private final int floodRate; 046 private final boolean logComms; 047 private final PrintStream out; 048 049 private volatile long lastCommandTime = System.currentTimeMillis(); 050 051 private Command interruptedCommand = null; 052 053 public SocketWriter(QueryIO io, TS3Config config) throws IOException { 054 super("[TeamSpeak-3-Java-API] SocketWriter"); 055 this.sendQueue = io.getSendQueue(); 056 this.receiveQueue = io.getReceiveQueue(); 057 this.floodRate = config.getFloodRate().getMs(); 058 this.logComms = config.getEnableCommunicationsLogging(); 059 this.out = new PrintStream(io.getSocket().getOutputStream(), true, "UTF-8"); 060 } 061 062 @Override 063 public void run() { 064 try { 065 // Initial sleep to prevent flood ban shortly after connecting 066 if (floodRate > 0) Thread.sleep(floodRate); 067 068 while (!isInterrupted()) { 069 final Command c = sendQueue.take(); 070 final String msg = c.toString(); 071 072 lastCommandTime = System.currentTimeMillis(); 073 074 try { 075 receiveQueue.put(new ResponseBuilder(c)); 076 } catch (InterruptedException e) { 077 // Properly handle commands removed from the sendQueue 078 // but not inserted into the receiveQueue 079 interruptedCommand = c; 080 interrupt(); 081 break; 082 } 083 084 if (logComms) log.debug("[{}] > {}", c.getName(), msg); 085 out.println(msg); 086 087 if (floodRate > 0) Thread.sleep(floodRate); 088 } 089 } catch (InterruptedException e) { 090 // Regular shutdown 091 interrupt(); 092 } 093 094 out.close(); 095 096 if (!isInterrupted()) { 097 log.warn("SocketWriter has stopped!"); 098 } 099 } 100 101 long getIdleTime() { 102 return System.currentTimeMillis() - lastCommandTime; 103 } 104 105 void drainCommandsTo(Collection<Command> commands) { 106 if (interruptedCommand != null) { 107 commands.add(interruptedCommand); 108 } 109 sendQueue.drainTo(commands); 110 } 111}