All Downloads are FREE. Search and download functionalities are using the official Maven repository.

lowentry.ue4.classes.sockets.SocketConnection Maven / Gradle / Ivy

There is a newer version: 3.0.1
Show newest version
package lowentry.ue4.classes.sockets;


import lowentry.ue4.classes.internal.CachedTime;
import lowentry.ue4.classes.sockets.SocketConnectionHandler.ConnectingStage;
import lowentry.ue4.classes.sockets.SocketTasks.CanceledLatentFunctionCallListener;
import lowentry.ue4.classes.sockets.SocketTasks.FailedFunctionCallListener;
import lowentry.ue4.classes.sockets.SocketTasks.FailedLatentFunctionCallListener;
import lowentry.ue4.classes.sockets.SocketTasks.ReceivedResponseFunctionCallListener;
import lowentry.ue4.classes.sockets.SocketTasks.ReceivedResponseLatentFunctionCallListener;
import lowentry.ue4.library.LowEntry;
import lowentry.ue4.libs.pyronet.craterstudio.util.concur.SimpleBlockingQueue;
import lowentry.ue4.libs.pyronet.jawnae.pyronet.PyroClient;
import lowentry.ue4.libs.pyronet.jawnae.pyronet.PyroException;
import lowentry.ue4.libs.pyronet.jawnae.pyronet.PyroSelector;
import lowentry.ue4.libs.pyronet.lowentry.pyronet.udp.PyroClientUdp;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;


public class SocketConnection
{
	protected static class InternalFunctionCall
	{
		FunctionCallListener listener;
		long                 timeoutTime;
	}
	
	
	public interface FunctionCallListener
	{
		void receivedResponse(final SocketConnection connection, final byte[] bytes);
		void failed(final SocketConnection connection);
	}
	
	
	protected static class InternalLatentFunctionCall
	{
		LatentFunctionCall         latentAction;
		LatentFunctionCallListener listener;
		long                       timeoutTime;
	}
	
	
	public interface LatentFunctionCallListener
	{
		void receivedResponse(final SocketConnection connection, final byte[] bytes);
		void canceled(final SocketConnection connection);
		void failed(final SocketConnection connection);
	}
	
	
	protected final PyroSelector             selector;
	protected final InetSocketAddress        address;
	protected final InetSocketAddress        addressUdp;
	protected final SocketConnectionListener socketListener;
	
	protected final SimpleBlockingQueue tasks;
	
	protected          PyroClient connection;
	protected volatile Object     attachment;
	protected          boolean    isDisconnecting;
	
	protected       PyroClientUdp connectionUdp;
	protected final ByteBuffer    connectionUdpNetworkBuffer;
	
	protected       int                                   nextFunctionCallId = 0;
	protected final HashMap functionCalls      = new HashMap<>();
	
	protected       int                                         nextLatentFunctionCallId = 0;
	protected final HashMap latentFunctionCalls      = new HashMap<>();
	
	protected long lastFunctionCallTimeoutCheck = CachedTime.millisSinceStart();
	
	
	public SocketConnection(final String host, final int portTcp, final SocketConnectionListener listener)
	{
		this.socketListener = listener;
		this.tasks = null;
		selector = new PyroSelector();
		address = new InetSocketAddress(host, portTcp);
		addressUdp = null;
		connectionUdpNetworkBuffer = null;
	}
	
	public SocketConnection(final InetSocketAddress endTcp, final SocketConnectionListener listener)
	{
		this.socketListener = listener;
		this.tasks = null;
		selector = new PyroSelector();
		address = endTcp;
		addressUdp = null;
		connectionUdpNetworkBuffer = null;
	}
	
	public SocketConnection(final String host, final int portTcp, final int portUdp, final SocketConnectionListener listener)
	{
		this.socketListener = listener;
		this.tasks = null;
		selector = new PyroSelector();
		address = new InetSocketAddress(host, portTcp);
		addressUdp = ((portUdp <= 0) ? null : new InetSocketAddress(host, portUdp));
		connectionUdpNetworkBuffer = ((addressUdp == null) ? null : ByteBuffer.allocate(PyroSelector.BUFFER_SIZE));
	}
	
	public SocketConnection(final InetSocketAddress endTcp, final InetSocketAddress endUdp, final SocketConnectionListener listener)
	{
		this.socketListener = listener;
		this.tasks = null;
		selector = new PyroSelector();
		address = endTcp;
		addressUdp = endUdp;
		connectionUdpNetworkBuffer = ((addressUdp == null) ? null : ByteBuffer.allocate(PyroSelector.BUFFER_SIZE));
	}
	
	
	public SocketConnection(final String host, final int portTcp, final SocketConnectionListener listener, final SimpleBlockingQueue tasks)
	{
		this.socketListener = listener;
		this.tasks = tasks;
		selector = new PyroSelector();
		address = new InetSocketAddress(host, portTcp);
		addressUdp = null;
		connectionUdpNetworkBuffer = null;
	}
	
	public SocketConnection(final InetSocketAddress endTcp, final SocketConnectionListener listener, final SimpleBlockingQueue tasks)
	{
		this.socketListener = listener;
		this.tasks = tasks;
		selector = new PyroSelector();
		address = endTcp;
		addressUdp = null;
		connectionUdpNetworkBuffer = null;
	}
	
	public SocketConnection(final String host, final int portTcp, final int portUdp, final SocketConnectionListener listener, final SimpleBlockingQueue tasks)
	{
		this.socketListener = listener;
		this.tasks = tasks;
		selector = new PyroSelector();
		address = new InetSocketAddress(host, portTcp);
		addressUdp = ((portUdp <= 0) ? null : new InetSocketAddress(host, portUdp));
		connectionUdpNetworkBuffer = ((addressUdp == null) ? null : ByteBuffer.allocate(PyroSelector.BUFFER_SIZE));
	}
	
	public SocketConnection(final InetSocketAddress endTcp, final InetSocketAddress endUdp, final SocketConnectionListener listener, final SimpleBlockingQueue tasks)
	{
		this.socketListener = listener;
		this.tasks = tasks;
		selector = new PyroSelector();
		address = endTcp;
		addressUdp = endUdp;
		connectionUdpNetworkBuffer = ((addressUdp == null) ? null : ByteBuffer.allocate(PyroSelector.BUFFER_SIZE));
	}
	
	
	/**
	 * Tries to connect, returns true if the connection was successful.
*
* WARNING: Only call this on the same thread this object was created in! Use {@link #execute(Runnable)} in case of doubt.
*/ public boolean connect() { selector.checkThread(); if(connectionUdp != null) { connectionUdp.shutdown(); connectionUdp = null; } if(connection != null) { connection.shutdown(); connection = null; } failAllFunctionCalls(); try { isDisconnecting = false; SocketConnectionHandler listener = createListener(); connection = selector.connect(address, listener); if(connection == null) { return false; } while(listener.connectingStage == ConnectingStage.WAITING) { listen(1); } if((listener.connectingStage == ConnectingStage.UNCONNECTABLE) || connection.isDisconnected()) { connection.shutdown(); connection = null; return false; } connection.write(ByteBuffer.wrap(new byte[]{13, 10, 13, 10})); // \r\n\r\n if(isConnected()) { if(addressUdp != null) { connectionUdp = new PyroClientUdp(addressUdp, listener); connection.write(ByteBuffer.wrap(LowEntry.integerToBytes(addressUdp.getPort()))); connection.write(ByteBuffer.wrap(LowEntry.integerToBytes(getLocalPortUdp()))); } else { connection.write(ByteBuffer.wrap(new byte[8])); } listener.callConnected(); } else { throw new Exception(); } } catch(Exception e) { if(connectionUdp != null) { connectionUdp.shutdown(); connectionUdp = null; } if(connection != null) { connection.shutdown(); connection = null; } return false; } return true; } protected SocketConnectionHandler createListener() { return new SocketConnectionHandler(socketListener, this); } /** * Executes pending tasks.
*
* WARNING: Only call this on the same thread this object was created in! Use {@link #execute(Runnable)} in case of doubt.
*/ public void listen() { listen(100); } /** * Executes pending tasks.
*
* WARNING: Only call this on the same thread this object was created in! Use {@link #execute(Runnable)} in case of doubt.
*/ public void listen(final long eventTimeout) { selector.checkThread(); if(eventTimeout <= 10) // too small for CachedTime.millisSinceStart() { pyroListen(eventTimeout); handleFunctionCallTimeouts(); return; } long startTime = CachedTime.millisSinceStart(); pyroListen(eventTimeout); long lastTime = CachedTime.millisSinceStart(); long timeSpend = (lastTime - startTime); while(timeSpend < (eventTimeout - 10)) { pyroListen(eventTimeout - timeSpend); long newTime = CachedTime.millisSinceStart(); if(newTime != lastTime) { lastTime = newTime; timeSpend = (lastTime - startTime); } } handleFunctionCallTimeouts(); } private void pyroListen(final long eventTimeout) { if(connectionUdp != null) { for(long i = 1; i <= eventTimeout; i++) { try { connectionUdp.listen(connectionUdpNetworkBuffer); } catch(Exception e) { } try { selector.select(1); } catch(Exception e) { } } } else { for(long i = 1; i <= eventTimeout; i++) { try { selector.select(1); } catch(Exception e) { } } } } protected void threadSafeFailedFunctionCall(final FunctionCallListener listener) { if(tasks == null) { if(selector.isNetworkThread()) { listener.failed(this); } else { selector.scheduleTask(new FailedFunctionCallListener(listener, this)); } } else { tasks.put(new FailedFunctionCallListener(listener, this)); } } protected void failedFunctionCall(final FunctionCallListener listener) { if(tasks == null) { listener.failed(this); } else { tasks.put(new FailedFunctionCallListener(listener, this)); } } protected void receivedResponseFunctionCall(final FunctionCallListener listener, final byte[] bytes) { if(tasks == null) { listener.receivedResponse(this, bytes); } else { tasks.put(new ReceivedResponseFunctionCallListener(listener, this, bytes)); } } protected void threadSafeFailedLatentFunctionCall(final LatentFunctionCallListener listener) { if(tasks == null) { if(selector.isNetworkThread()) { listener.failed(this); } else { selector.scheduleTask(new FailedLatentFunctionCallListener(listener, this)); } } else { tasks.put(new FailedLatentFunctionCallListener(listener, this)); } } protected void threadSafeCanceledLatentFunctionCall(final LatentFunctionCallListener listener) { if(tasks == null) { if(selector.isNetworkThread()) { listener.canceled(this); } else { selector.scheduleTask(new CanceledLatentFunctionCallListener(listener, this)); } } else { tasks.put(new CanceledLatentFunctionCallListener(listener, this)); } } protected void failedLatentFunctionCall(final LatentFunctionCallListener listener) { if(tasks == null) { listener.failed(this); } else { tasks.put(new FailedLatentFunctionCallListener(listener, this)); } } protected void canceledLatentFunctionCall(final LatentFunctionCallListener listener) { if(tasks == null) { listener.canceled(this); } else { tasks.put(new CanceledLatentFunctionCallListener(listener, this)); } } protected void receivedResponseLatentFunctionCall(final LatentFunctionCallListener listener, final byte[] bytes) { if(tasks == null) { listener.receivedResponse(this, bytes); } else { tasks.put(new ReceivedResponseLatentFunctionCallListener(listener, this, bytes)); } } /** * Takes care of the timeout functionality of the function calls. */ protected void handleFunctionCallTimeouts() { long time = CachedTime.millisSinceStart(); if((time - lastFunctionCallTimeoutCheck) < 1000) // 1 second { return; } lastFunctionCallTimeoutCheck = time; {// function calls >> List functionCallListeners = new LinkedList<>(); synchronized(functionCalls) { for(Iterator> iterator = functionCalls.entrySet().iterator(); iterator.hasNext(); ) { Entry entry = iterator.next(); InternalFunctionCall functionCall = entry.getValue(); if((time - functionCall.timeoutTime) >= 0) { iterator.remove(); if(functionCall.listener != null) { functionCallListeners.add(functionCall.listener); } } } } for(FunctionCallListener listener : functionCallListeners) { failedFunctionCall(listener); } }// function calls << {// latent function calls >> List functionCallListeners = new LinkedList<>(); synchronized(latentFunctionCalls) { for(Iterator> iterator = latentFunctionCalls.entrySet().iterator(); iterator.hasNext(); ) { Entry entry = iterator.next(); InternalLatentFunctionCall functionCall = entry.getValue(); if((time - functionCall.timeoutTime) >= 0) { iterator.remove(); if(functionCall.listener != null) { functionCallListeners.add(functionCall); } } } } for(InternalLatentFunctionCall functionCall : functionCallListeners) { if(functionCall.latentAction != null) { functionCall.latentAction.canceledByTimeout(); } if(functionCall.listener != null) { failedLatentFunctionCall(functionCall.listener); } } }// latent function calls << } /** * Fails all remaining function calls. */ public void failAllFunctionCalls() { {// function calls >> List functionCallListeners = new LinkedList<>(); synchronized(functionCalls) { for(Entry entry : functionCalls.entrySet()) { InternalFunctionCall functionCall = entry.getValue(); if(functionCall.listener != null) { functionCallListeners.add(functionCall.listener); } } functionCalls.clear(); } for(FunctionCallListener listener : functionCallListeners) { failedFunctionCall(listener); } }// function calls << {// latent function calls >> List functionCallListeners = new LinkedList<>(); synchronized(latentFunctionCalls) { for(Entry entry : latentFunctionCalls.entrySet()) { InternalLatentFunctionCall functionCall = entry.getValue(); if(functionCall.listener != null) { functionCallListeners.add(functionCall); } } latentFunctionCalls.clear(); } for(InternalLatentFunctionCall functionCall : functionCallListeners) { if(functionCall.latentAction != null) { functionCall.latentAction.canceledByDisconnecting(); } if(functionCall.listener != null) { failedLatentFunctionCall(functionCall.listener); } } }// latent function calls << } /** * Returns the next unused function call id. */ protected int reserveFunctionCallId(final InternalFunctionCall functionCall) { synchronized(functionCalls) { while(true) { if(nextFunctionCallId >= Integer.MAX_VALUE) { nextFunctionCallId = 0; } nextFunctionCallId++; if(!functionCalls.containsKey(nextFunctionCallId)) { int functionCallId = nextFunctionCallId; functionCalls.put(functionCallId, functionCall); return functionCallId; } } } } /** * Returns the next unused latent function call id. */ protected int reserveLatentFunctionCallId(final InternalLatentFunctionCall functionCall) { synchronized(latentFunctionCalls) { while(true) { if(nextLatentFunctionCallId >= Integer.MAX_VALUE) { nextLatentFunctionCallId = 0; } nextLatentFunctionCallId++; if(!latentFunctionCalls.containsKey(nextLatentFunctionCallId)) { int functionCallId = nextLatentFunctionCallId; latentFunctionCalls.put(functionCallId, functionCall); return functionCallId; } } } } /** * Attach any object to the connection, for example to store session information.
* Only one object can be attached at a time! */ public void setAttachment(final Object attachment) { this.attachment = attachment; } /** * Returns the previously attached object, or null if none is set.
* Call this function like this:
*
* YourClass object = connection.getAttachment();
*
* This will automatically take the type that the compiler thinks it has to be.
* To control the type manually, call this function like this:
*
* YourClass object = connection.<YourClass>getAttachment(); */ @SuppressWarnings("unchecked") public T getAttachment() { return (T) attachment; } /** * Returns true if the connection has an attachment. */ public boolean hasAttachment() { return (attachment != null); } /** * Returns the local socket address (host and port), can return null. */ public InetSocketAddress getLocalAddress() { if(connection == null) { return null; } return connection.getLocalAddress(); } /** * Returns the remote socket address (host and port), can return null. */ public InetSocketAddress getRemoteAddress() { if(connection == null) { return null; } return connection.getRemoteAddress(); } /** * Returns the local UDP port, returns 0 if there is no UDP connection. */ public int getLocalPortUdp() { if(connectionUdp == null) { return 0; } return connectionUdp.getLocalPort(); } /** * Will send the bytes immediately. */ public void sendUnreliableMessage(final byte[]... bytes) { sendUnreliableMessage(LowEntry.mergeBytes(bytes)); } /** * Will send the bytes immediately. */ public void sendUnreliableMessage(final byte[] bytes) { if(selector.isNetworkThread()) { if(bytes == null) { sendUnreliableMessageCode(ByteBuffer.allocate(0), true); } else { sendUnreliableMessageCode(ByteBuffer.wrap(bytes), true); } } else { if(bytes == null) { selector.scheduleTask(() -> sendUnreliableMessageCode(ByteBuffer.allocate(0), true)); } else { selector.scheduleTask(() -> sendUnreliableMessageCode(ByteBuffer.wrap(bytes), true)); } } } /** * Will send the bytes immediately, the ByteBuffer can be cleared and reused after calling this function. */ public void sendUnreliableMessage(final ByteBuffer bytes) { if(selector.isNetworkThread()) { if(bytes == null) { sendUnreliableMessageCode(ByteBuffer.allocate(0), true); } else { sendUnreliableMessageCode(bytes, false); } } else { if(bytes == null) { selector.scheduleTask(() -> sendUnreliableMessageCode(ByteBuffer.allocate(0), true)); } else { final ByteBuffer b = LowEntry.cloneByteBuffer(bytes, false); selector.scheduleTask(() -> sendUnreliableMessageCode(b, true)); } } } protected void sendUnreliableMessageCode(final ByteBuffer bytes, final boolean clonedBytes) { if(!isConnectedUdp()) { return; } connectionUdp.write(bytes); } /** * Will enqueue the bytes to send them. */ public void sendMessage(final byte[]... bytes) { sendMessage(LowEntry.mergeBytes(bytes)); } /** * Will enqueue the bytes to send them. */ public void sendMessage(final byte[] bytes) { final byte[] b = ((bytes == null) ? new byte[0] : bytes); if(selector.isNetworkThread()) { sendMessageCode(b); } else { selector.scheduleTask(() -> sendMessageCode(b)); } } protected void sendMessageCode(final byte[] bytes) { if(!isConnected()) { return; } ByteBuffer buffer = ByteBuffer.allocate(1 + SocketFunctions.uintByteCount(bytes.length)); buffer.put(SocketMessageType.MESSAGE); SocketFunctions.putUint(buffer, bytes.length); buffer.flip(); try { connection.write(buffer); if(bytes.length > 0) { connection.write(ByteBuffer.wrap(bytes)); } } catch(PyroException e) { } } /** * Will enqueue the bytes to send them. */ public void sendFunctionCall(final byte[] bytes, final FunctionCallListener functionCallListener) { sendFunctionCall(30, bytes, functionCallListener); } /** * Will enqueue the bytes to send them.
*
* Timeout is the timeout in seconds. */ public void sendFunctionCall(final float timeout, final byte[] bytes, final FunctionCallListener functionCallListener) { final byte[] b = ((bytes == null) ? new byte[0] : bytes); if(selector.isNetworkThread()) { sendFunctionCallCode(b, timeout, functionCallListener); } else { selector.scheduleTask(() -> sendFunctionCallCode(b, timeout, functionCallListener)); } } protected void sendFunctionCallCode(final byte[] bytes, final float timeout, final FunctionCallListener functionCallListener) { if(!isConnected()) { threadSafeFailedFunctionCall(functionCallListener); return; } InternalFunctionCall functionCall = new InternalFunctionCall(); functionCall.listener = functionCallListener; functionCall.timeoutTime = CachedTime.millisSinceStart() + (long) (timeout * 1000.0); int functionCallId = reserveFunctionCallId(functionCall); ByteBuffer buffer = ByteBuffer.allocate(1 + SocketFunctions.uintByteCount(functionCallId) + SocketFunctions.uintByteCount(bytes.length)); buffer.put(SocketMessageType.FUNCTION_CALL); SocketFunctions.putUint(buffer, functionCallId); SocketFunctions.putUint(buffer, bytes.length); buffer.flip(); try { connection.write(buffer); if(bytes.length > 0) { connection.write(ByteBuffer.wrap(bytes)); } } catch(PyroException e) { } } /** * Will enqueue the bytes to send them. */ public LatentFunctionCall sendLatentFunctionCall(final byte[] bytes, final LatentFunctionCallListener functionCallListener) { return sendLatentFunctionCall(30, bytes, functionCallListener); } /** * Will enqueue the bytes to send them.
*
* Timeout is the timeout in seconds. */ public LatentFunctionCall sendLatentFunctionCall(final float timeout, final byte[] bytes, final LatentFunctionCallListener functionCallListener) { final LatentFunctionCall latentAction = new LatentFunctionCall(this); latentAction.listener = functionCallListener; InternalLatentFunctionCall functionCall = new InternalLatentFunctionCall(); functionCall.latentAction = latentAction; functionCall.listener = functionCallListener; functionCall.timeoutTime = CachedTime.millisSinceStart() + (long) (timeout * 1000.0); latentAction.functionCallId = reserveLatentFunctionCallId(functionCall); {// send latent function call >> final byte[] b = ((bytes == null) ? new byte[0] : bytes); if(selector.isNetworkThread()) { sendLatentFunctionCallCode(latentAction, b, timeout, functionCallListener); } else { selector.scheduleTask(() -> sendLatentFunctionCallCode(latentAction, b, timeout, functionCallListener)); } }// send latent function call << return latentAction; } protected void sendLatentFunctionCallCode(final LatentFunctionCall latentAction, final byte[] bytes, final float timeout, final LatentFunctionCallListener functionCallListener) { if(latentAction.isDone() || latentAction.isCanceled() || latentAction.isFailed()) { return; } if(!isConnected()) { threadSafeFailedLatentFunctionCall(functionCallListener); latentAction.canceledByDisconnecting(); return; } ByteBuffer buffer = ByteBuffer.allocate(1 + SocketFunctions.uintByteCount(latentAction.functionCallId) + SocketFunctions.uintByteCount(bytes.length)); buffer.put(SocketMessageType.LATENT_FUNCTION_CALL); SocketFunctions.putUint(buffer, latentAction.functionCallId); SocketFunctions.putUint(buffer, bytes.length); buffer.flip(); try { connection.write(buffer); if(bytes.length > 0) { connection.write(ByteBuffer.wrap(bytes)); } } catch(PyroException e) { } } /** * Will enqueue the bytes to send them. */ protected void sendLatentFunctionCallCancel(final int functionCallId) { if(selector.isNetworkThread()) { sendLatentFunctionCallCancelCode(functionCallId); } else { selector.scheduleTask(() -> sendLatentFunctionCallCancelCode(functionCallId)); } } protected void sendLatentFunctionCallCancelCode(final int functionCallId) { if(!isConnected()) { return; } ByteBuffer buffer = ByteBuffer.allocate(1 + SocketFunctions.uintByteCount(functionCallId)); buffer.put(SocketMessageType.LATENT_FUNCTION_CALL_CANCELED); SocketFunctions.putUint(buffer, functionCallId); buffer.flip(); try { connection.write(buffer); } catch(PyroException e) { } } /** * Gracefully shuts down the connection. The connection * is closed after the last outbound bytes are sent. * Enqueuing new bytes after shutdown will not do anything. */ public void disconnect() { if(selector.isNetworkThread()) { if(isDisconnecting) { return; } isDisconnecting = true; selector.scheduleTask(() -> { if(connectionUdp != null) { connectionUdp.shutdown(); connectionUdp = null; } if(connection != null) { connection.shutdown(); connection = null; } }); } else { selector.scheduleTask(() -> { if(isDisconnecting) { return; } isDisconnecting = true; if(connectionUdp != null) { connectionUdp.shutdown(); connectionUdp = null; } if(connection != null) { connection.shutdown(); connection = null; } }); } } /** * Immediately drop the connection, regardless of any * pending outbound bytes. Actual behavior depends on * the socket linger settings. */ public void disconnectImmediately() { if(selector.isNetworkThread()) { if(isDisconnecting) { return; } isDisconnecting = true; selector.scheduleTask(() -> { if(connectionUdp != null) { connectionUdp.shutdown(); connectionUdp = null; } if(connection != null) { connection.dropConnection(); connection = null; } }); } else { selector.scheduleTask(() -> { if(isDisconnecting) { return; } isDisconnecting = true; if(connectionUdp != null) { connectionUdp.shutdown(); connectionUdp = null; } if(connection != null) { connection.dropConnection(); connection = null; } }); } } /** * Returns true when the connection is open.
*
* WARNING: Only call this on the same thread this object was created in! Use {@link #execute(Runnable)} in case of doubt.
*/ public boolean isConnected() { selector.checkThread(); return (!isDisconnecting && (connection != null) && !connection.isDisconnected()); } /** * Returns true when the connection is open (for UDP). */ protected boolean isConnectedUdp() { selector.checkThread(); return (!isDisconnecting && (connectionUdp != null)); } /** * Returns the PyroNet object of this wrapper. */ public PyroClient pyro() { return connection; } /** * Returns the selector. */ public PyroSelector selector() { return selector; } /** * Returns the PyroNet UDP object of this wrapper. */ public PyroClientUdp pyroUdp() { return connectionUdp; } /** * This function will execute the given runnable on the thread this object was created in. */ public void execute(Runnable runnable) { if(selector.isNetworkThread()) { runnable.run(); } else { selector.scheduleTask(runnable); } } /** * Returns true if this is the thread this object was created in. */ public boolean isNetworkThread() { return selector.isNetworkThread(); } public String getAddressText() { if(connection == null) { return "closed"; } if(connectionUdp == null) { return connection.getAddressText(); } return connection.getAddressText() + ", " + connectionUdp.getAddressText(); } @Override public String toString() { return getClass().getSimpleName() + "[" + getAddressText() + "]"; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy