
lowentry.ue4.classes.http.HttpServer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java Show documentation
Show all versions of java Show documentation
A Java library for the Low Entry UE4 plugins.
package lowentry.ue4.classes.http;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import java.util.function.Consumer;
import javax.net.ServerSocketFactory;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import lowentry.ue4.classes.internal.CachedTime;
import lowentry.ue4.libs.pyronet.craterstudio.util.concur.SimpleBlockingQueue;
import lowentry.ue4.libs.pyronet.jawnae.pyronet.PyroException;
import lowentry.ue4.libs.pyronet.jawnae.pyronet.PyroSelector;
public class HttpServer implements Iterable
{
private static final int NEW_CONNECTIONS_QUEUE_SIZE = 500;
protected static final ThreadLocal serverTimeFormat = createServerTimeFormat();
protected final Thread networkThread;
protected final boolean secure;
protected final int port;
protected final HttpServerListener listener;
protected final ServerSocket server;
protected final List clients = new LinkedList();
protected final List removeClients = new ArrayList();
protected final ByteBuffer networkBuffer = ByteBuffer.allocate(PyroSelector.BUFFER_SIZE);
protected volatile boolean run = true;
protected final SimpleBlockingQueue tasks = new SimpleBlockingQueue();
public HttpServer(boolean secure, boolean acceptExternalConnections, int port, HttpServerListener listener) throws Throwable
{
this.networkThread = Thread.currentThread();
this.secure = secure;
this.port = port;
this.listener = listener;
this.server = initialize(secure, acceptExternalConnections, port);
}
protected static ThreadLocal createServerTimeFormat()
{
return new ThreadLocal()
{
@Override
protected SimpleDateFormat initialValue()
{
SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
return dateFormat;
}
};
}
protected ServerSocket initialize(boolean secure, boolean acceptExternalConnections, int port) throws Throwable
{
ServerSocketFactory serverSocketFactory = (secure ? SSLServerSocketFactory.getDefault() : ServerSocketFactory.getDefault());
ServerSocket server = serverSocketFactory.createServerSocket(port, NEW_CONNECTIONS_QUEUE_SIZE, (acceptExternalConnections ? null : InetAddress.getLoopbackAddress()));
if(secure && (server instanceof SSLServerSocket))
{
SSLServerSocket serverssl = (SSLServerSocket) server;
serverssl.setEnabledCipherSuites(serverssl.getSupportedCipherSuites());
serverssl.setEnabledProtocols(serverssl.getSupportedProtocols());
}
server.setSoTimeout(100);
return server;
}
/**
* Returns the port this server is listening to.
*/
public int getPort()
{
return port;
}
/**
* Returns true if it uses SSL/TLS (HTTPS), returns false otherwise (HTTP).
*/
public boolean isSecure()
{
return secure;
}
public final boolean isNetworkThread()
{
return (networkThread == Thread.currentThread());
}
public final Thread networkThread()
{
return networkThread;
}
public final void checkThread()
{
if(!isNetworkThread())
{
throw new PyroException("call from outside the network-thread, you must schedule tasks");
}
}
/**
* Executes pending tasks.
*
* Each listen takes between 0 and 100 milliseconds.
*
* WARNING: Only call this on the same thread this object was created in!
*/
public void listen()
{
checkThread();
executePendingTasks();
if(run)
{
{// remove disconnected clients >>
HttpClient[] removeClientsArray = null;
synchronized(removeClients)
{
if(removeClients.size() > 0)
{
removeClientsArray = removeClients.toArray(new HttpClient[removeClients.size()]);
removeClients.clear();
}
}
if(removeClientsArray != null)
{
synchronized(clients)
{
for(HttpClient client : removeClientsArray)
{
clients.remove(client);
}
}
for(HttpClient client : removeClientsArray)
{
internal_listenerClientDisconnected(client);
}
}
}// remove disconnected clients <<
{// tick clients >>
long time = CachedTime.nanoTime();
for(HttpClient client : clients)
{
try
{
client.listen(time);
}
catch(Throwable e)
{
client.disconnect();
}
}
}// tick clients <<
{// remove disconnected clients >>
HttpClient[] removeClientsArray = null;
synchronized(removeClients)
{
if(removeClients.size() > 0)
{
removeClientsArray = removeClients.toArray(new HttpClient[removeClients.size()]);
removeClients.clear();
}
}
if(removeClientsArray != null)
{
synchronized(clients)
{
for(HttpClient client : removeClientsArray)
{
clients.remove(client);
}
}
for(HttpClient client : removeClientsArray)
{
internal_listenerClientDisconnected(client);
}
}
}// remove disconnected clients <<
{// accept new clients >>
try
{
Socket s = server.accept();
HttpClient client = new HttpClient(this, s);
internal_listenerClientConnected(client);
synchronized(clients)
{
clients.add(client);
}
}
catch(SocketTimeoutException e)
{
}
catch(Throwable e)
{
}
}// accept new clients <<
}
if(!run && !server.isClosed())
{
{// disconnect clients >>
HttpClient[] removeClientsArray;
synchronized(removeClients)
{
removeClientsArray = removeClients.toArray(new HttpClient[removeClients.size()]);
removeClients.clear();
}
synchronized(clients)
{
for(HttpClient client : removeClientsArray)
{
clients.remove(client);
}
}
for(HttpClient client : removeClientsArray)
{
internal_listenerClientDisconnected(client);
}
}// disconnect clients <<
{// disconnect clients >>
HttpClient[] removeClientsArray;
synchronized(clients)
{
removeClientsArray = clients.toArray(new HttpClient[clients.size()]);
clients.clear();
for(HttpClient client : removeClientsArray)
{
client.internal_disconnect();
}
}
for(HttpClient client : removeClientsArray)
{
internal_listenerClientDisconnected(client);
}
}// disconnect clients <<
{// close server >>
try
{
server.close();
}
catch(Throwable e)
{
}
}// close server <<
}
executePendingTasks();
}
protected void executePendingTasks()
{
while(true)
{
Runnable task = this.tasks.poll();
if(task == null)
{
break;
}
try
{
task.run();
}
catch(Throwable cause)
{
cause.printStackTrace();
}
}
}
protected static String internal_getServerTime()
{
return serverTimeFormat.get().format(Calendar.getInstance().getTime());
}
protected void internal_listenerClientConnected(final HttpClient client)
{
listener.clientConnected(this, client);
}
protected void internal_listenerClientDisconnected(final HttpClient client)
{
listener.clientDisconnected(this, client);
}
protected void internal_listenerReceivedRequest(final HttpClient client, final HttpRequest request, final HttpResponse response)
{
listener.receivedRequest(this, client, request, response);
}
protected void internal_removeClient(HttpClient client)
{
synchronized(removeClients)
{
removeClients.add(client);
}
}
/**
* Returns an iterator to access all connected clients of this server.
*/
@Override
public Iterator iterator()
{
List copy = new ArrayList();
synchronized(clients)
{
copy.addAll(clients);
}
return copy.iterator();
}
/**
* Performs the given action for each element of the {@code Iterable} until
* all elements have been processed or the action throws an exception.
* Unless otherwise specified by the implementing class, actions are
* performed in the order of iteration (if an iteration order is
* specified). Exceptions thrown by the action are relayed to the caller.
*/
public void forEachClient(Consumer action)
{
forEach(action);
}
/**
* Returns the amount of connected clients.
*/
public int getClientCount()
{
synchronized(clients)
{
return clients.size();
}
}
/**
* Stops the server.
*/
public void terminate()
{
this.run = false;
}
/**
* This function will execute the given runnable on the thread this object was created in.
*/
public void execute(Runnable runnable)
{
if(isNetworkThread())
{
runnable.run();
}
else
{
tasks.put(runnable);
}
}
@Override
public String toString()
{
return getClass().getSimpleName() + "[" + server.getClass().getName() + "[/" + server.getInetAddress().getHostAddress() + ":" + server.getLocalPort() + "]]";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy