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

lowentry.ue4.classes.http.HttpServer Maven / Gradle / Ivy

There is a newer version: 9.9.9.DELETED
Show newest version
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