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.TS3Query.FloodRate; 030import com.github.theholywaffle.teamspeak3.TS3Query.Protocol; 031import com.github.theholywaffle.teamspeak3.api.reconnect.ConnectionHandler; 032import com.github.theholywaffle.teamspeak3.api.reconnect.ReconnectStrategy; 033 034/** 035 * Class used to configure the behavior of a {@link TS3Query}. 036 */ 037public class TS3Config { 038 039 private boolean frozen = false; 040 041 private String host = null; 042 private int queryPort = -1; 043 private Protocol protocol = Protocol.RAW; 044 private String username = null; 045 private String password = null; 046 private FloodRate floodRate = FloodRate.DEFAULT; 047 private boolean enableCommunicationsLogging = false; 048 private int commandTimeout = 4000; 049 private ReconnectStrategy reconnectStrategy = ReconnectStrategy.disconnect(); 050 private ConnectionHandler connectionHandler = null; 051 052 /** 053 * Sets the hostname or IP address of the TeamSpeak3 server to connect to. 054 * <p> 055 * Note that the query port <strong>is not</strong> part of the hostname - 056 * use {@link #setQueryPort(int)} for that purpose. 057 * </p><p> 058 * If the application is running on the same machine as the TS3 server, you can use 059 * {@code null} as the hostname. You can also use any other loopback address, 060 * such as {@code localhost} or {@code 127.0.0.1}. 061 * </p> 062 * 063 * @param host 064 * a valid hostname or IP address of a TeamSpeak3 server, or {@code null} 065 * 066 * @return this TS3Config object for chaining 067 */ 068 public TS3Config setHost(String host) { 069 checkFrozen(); 070 071 this.host = host; 072 return this; 073 } 074 075 String getHost() { 076 return host; 077 } 078 079 /** 080 * Sets the query port to use when connecting to the TeamSpeak3 server. 081 * <p> 082 * Note that the query uses a different port to connect to a server than the regular 083 * TeamSpeak3 clients. Regular clients use "voice ports", the query uses the "query port". 084 * </p><p> 085 * If you don't set the query port by calling this method, the query will use the default 086 * query port: 087 * </p> 088 * <ul> 089 * <li>{@code 10011} when connecting using {@link Protocol#RAW}</li> 090 * <li>{@code 10022} when connecting using {@link Protocol#SSH}</li> 091 * </ul> 092 * 093 * @param queryPort 094 * the query port to use, must be between {@code 1} and {@code 65535} 095 * 096 * @return this TS3Config object for chaining 097 * 098 * @throws IllegalArgumentException 099 * if the port is out of range 100 */ 101 public TS3Config setQueryPort(int queryPort) { 102 checkFrozen(); 103 104 if (queryPort <= 0 || queryPort > 65535) { 105 throw new IllegalArgumentException("Port out of range: " + queryPort); 106 } 107 this.queryPort = queryPort; 108 return this; 109 } 110 111 int getQueryPort() { 112 if (queryPort > 0) { 113 return queryPort; 114 } else { 115 // Query port not set by user, use default for chosen protocol 116 return protocol == Protocol.SSH ? 10022 : 10011; 117 } 118 } 119 120 /** 121 * Defines the protocol used to connect to the TeamSpeak3 server. 122 * By default, {@link Protocol#RAW} is used. 123 * 124 * @param protocol 125 * the connection protocol to use 126 * 127 * @return this TS3Config object for chaining 128 * 129 * @throws IllegalArgumentException 130 * if {@code protocol} is {@code null} 131 * @see Protocol Protocol 132 */ 133 public TS3Config setProtocol(Protocol protocol) { 134 checkFrozen(); 135 136 if (protocol == null) throw new IllegalArgumentException("protocol cannot be null!"); 137 this.protocol = protocol; 138 return this; 139 } 140 141 Protocol getProtocol() { 142 return protocol; 143 } 144 145 /** 146 * Authenticates the query with the TeamSpeak3 server using the given login credentials 147 * immediately after connecting. 148 * <p> 149 * Setting the login credentials is mandatory when using the {@link Protocol#SSH} protocol. 150 * </p><p> 151 * A server query login can be generated by heading over to the TeamSpeak3 Client, Tools, 152 * ServerQuery Login. Note that the server query will have the same permissions as the client who 153 * generated the credentials. 154 * </p> 155 * 156 * @param username 157 * the username used to authenticate the query 158 * @param password 159 * the password corresponding to {@code username} 160 * 161 * @return this TS3Config object for chaining 162 */ 163 public TS3Config setLoginCredentials(String username, String password) { 164 checkFrozen(); 165 166 this.username = username; 167 this.password = password; 168 return this; 169 } 170 171 boolean hasLoginCredentials() { 172 return username != null && password != null; 173 } 174 175 String getUsername() { 176 return username; 177 } 178 179 String getPassword() { 180 return password; 181 } 182 183 /** 184 * Sets the delay between sending commands. 185 * <p> 186 * If the query's hostname / IP has not been added to the server's {@code query_ip_whitelist.txt}, 187 * you need to use {@link FloodRate#DEFAULT} to prevent the query from being flood-banned. 188 * </p><p> 189 * Calling {@link FloodRate#custom} allows you to use a custom command delay if neither 190 * {@link FloodRate#UNLIMITED} nor {@link FloodRate#DEFAULT} fit your needs. 191 * </p> 192 * 193 * @param rate 194 * a {@link FloodRate} object that defines the delay between commands 195 * 196 * @return this TS3Config object for chaining 197 * 198 * @throws IllegalArgumentException 199 * if {@code rate} is {@code null} 200 * @see FloodRate FloodRate 201 */ 202 public TS3Config setFloodRate(FloodRate rate) { 203 checkFrozen(); 204 205 if (rate == null) throw new IllegalArgumentException("rate cannot be null!"); 206 this.floodRate = rate; 207 return this; 208 } 209 210 FloodRate getFloodRate() { 211 return floodRate; 212 } 213 214 /** 215 * Setting this value to {@code true} will log the communication between the 216 * query client and the TS3 server at the {@code DEBUG} level. 217 * <p> 218 * By default, this is turned off to prevent leaking IPs, tokens, passwords, etc. 219 * into the console and / or log files. 220 * </p> 221 * 222 * @param enable 223 * whether to log query commands 224 * 225 * @return this TS3Config object for chaining 226 */ 227 public TS3Config setEnableCommunicationsLogging(boolean enable) { 228 checkFrozen(); 229 230 enableCommunicationsLogging = enable; 231 return this; 232 } 233 234 boolean getEnableCommunicationsLogging() { 235 return enableCommunicationsLogging; 236 } 237 238 /** 239 * Sets how long the query should wait for any response to a command before disconnecting. 240 * <p> 241 * If the query doesn't receive any data from the TeamSpeak server after 242 * having waited for at least {@code commandTimeout} milliseconds, the connection 243 * is considered to be interrupted, and the query will try to reconnect according to 244 * its {@linkplain TS3Config#setReconnectStrategy(ReconnectStrategy) reconnect strategy}. 245 * </p><p> 246 * By default, this timeout is 4000 milliseconds. 247 * </p> 248 * 249 * @param commandTimeout 250 * the minimum amount of time to wait for any response, in milliseconds 251 * 252 * @return this TS3Config object for chaining 253 * 254 * @throws IllegalArgumentException 255 * if the timeout value is less than or equal to {@code 0} 256 */ 257 public TS3Config setCommandTimeout(int commandTimeout) { 258 checkFrozen(); 259 260 if (commandTimeout <= 0) { 261 throw new IllegalArgumentException("Timeout value must be greater than 0"); 262 } 263 264 this.commandTimeout = commandTimeout; 265 return this; 266 } 267 268 int getCommandTimeout() { 269 return commandTimeout; 270 } 271 272 /** 273 * Sets what strategy the query uses to reconnect after having been disconnected. 274 * <p> 275 * The different reconnect strategies let you control whether and after which delay the 276 * query will try to reconnect. By default, {@link ReconnectStrategy#disconnect()} is used, 277 * which doesn't try to reconnect and simply stops the query. 278 * </p><p> 279 * Note that when using a reconnect strategy, you probably also want to set the 280 * {@link ConnectionHandler} using {@link TS3Config#setConnectionHandler(ConnectionHandler)}. 281 * 282 * @param reconnectStrategy 283 * the reconnect strategy used when the query loses connection 284 * 285 * @return this TS3Config object for chaining 286 * 287 * @see ReconnectStrategy The reconnect strategies 288 * @see ConnectionHandler The connection handler 289 */ 290 public TS3Config setReconnectStrategy(ReconnectStrategy reconnectStrategy) { 291 checkFrozen(); 292 293 if (reconnectStrategy == null) throw new IllegalArgumentException("reconnectStrategy cannot be null!"); 294 this.reconnectStrategy = reconnectStrategy; 295 return this; 296 } 297 298 ReconnectStrategy getReconnectStrategy() { 299 return reconnectStrategy; 300 } 301 302 /** 303 * Sets the {@link ConnectionHandler} that defines the query's behaviour 304 * when connecting or disconnecting. 305 * <p> 306 * The following sample code illustrates how a reconnect strategy and connection handler can be 307 * used to print a message to the console every time the query connects or disconnects: 308 * </p> 309 * 310 * <pre> 311 * config.setReconnectStrategy(ReconnectStrategy.exponentialBackoff()); 312 * config.setConnectionHandler(new ConnectionHandler() { 313 * @Override 314 * public void onConnect(TS3Api api) { 315 * System.out.println("Successfully connected!"); 316 * } 317 * 318 * @Override 319 * public void onDisconnect(TS3Query query) { 320 * System.out.println("The query was disconnected!"); 321 * } 322 * }); 323 * </pre> 324 * 325 * @param connectionHandler 326 * the {@link ConnectionHandler} object 327 * 328 * @return this TS3Config object for chaining 329 * 330 * @see TS3Config#setReconnectStrategy(ReconnectStrategy) 331 */ 332 public TS3Config setConnectionHandler(ConnectionHandler connectionHandler) { 333 checkFrozen(); 334 335 this.connectionHandler = connectionHandler; 336 return this; 337 } 338 339 ConnectionHandler getConnectionHandler() { 340 return connectionHandler; 341 } 342 343 TS3Config freeze() { 344 frozen = true; 345 return this; 346 } 347 348 private void checkFrozen() { 349 if (frozen) { 350 throw new IllegalStateException("TS3Config cannot be modified after being used to create a TS3Query. " + 351 "Please make any changes to TS3Config *before* calling TS3Query's constructor."); 352 } 353 } 354}