<?php
###############################################################################
# ConnectionManager.php
#
# @author Anil Kumar <akumar@codepunch.com>
# @link   https://codepunch.com
#
############################################################################### 

namespace 	CodePunch\LU;
use 		CodePunch\Base\Util as UTIL;
use			CodePunch\Base\Text as TEXT;

###############################################################################

class ConnectionManager  {
	
	private $authentication = null;
	
	###########################################################################
	
	const DEFAULT_CONNECTION_INTERVAL 	= 10;
	const DEFAULT_RDAP_CONNECTION_INTERVAL 	= 1;
	const DEFAULT_CONNECTION_BAN		= (1*3600)+10;
	const MAX_CONNECTION_INTERVAL		= (4*3600)+1;
	
	###########################################################################
	
	public function __construct($auth=null) {
		$this->authentication = $auth;
	}
	
	###########################################################################
	
	public function getAuthentication() {
		return $this->authentication;
	}
	
	###########################################################################
	# Block Whois Server temporarily
	
	public function blockWhoisServer($server)
	{
		$db = $this->authentication->getDatabase();
		$table = $db->getConnectionsTableName();
		$client = $this->authentication->getServerID();
		if($db->insertOrUpdateTable($table, array('client'=>$client, 'stop_lookups'=>1), "server", $server)) {
			$logger = new \CodePunch\Base\CPLogger();
			$logger->warning("Temporarily stopping lookups from $client to $server");
		}
	}
	
	###########################################################################
	# Save the Last Connection Time with slight randomization (specified by
	# $max_random_offset in seconds (+ or -)
	
	public function setLastConnectForServer($server, $max_random_offset=0)
	{
		$db = $this->authentication->getDatabase();
		$table = $db->getConnectionsTableName();
		$client = $this->authentication->getServerID();
		$offset = 0;
		if($max_random_offset != 0) 
			$offset = rand(1, abs($max_random_offset)) * ($max_random_offset < 0 ? -1 : 1);
		$rows = $db->getFromTable("*", $table, "client=? AND server=?", array($client, $server));
		$last_connected_at = date("Y-m-d H:i:s", time()+$offset);
		if(!isset($rows[0]) || !count($rows[0]))
			$db->insertIntoTable($table, array('server'=>$server, 'client'=>$client, 'last_connected_at'=>$last_connected_at));
		else
			$db->updateTable($table, array('last_connected_at'=>$last_connected_at), "client=? AND server=?", array($client, $server));
	}
	
	###########################################################################
	
	public function getProxy($usefor=null) {
		$ext_proxy = null;
		$auth = $this->getAuthentication();
		$setup = new \CodePunch\Config\Settings($auth);
		if($usefor) {
			$ut = $setup->getOption('proxy_'.strtolower($usefor), '0');
			if(intval($ut) == 0)
				return null;
		}
		$host = $setup->getOption('ext_proxy_host', '');
		if($host && strlen($host)) {
			$port = $setup->getOption('ext_proxy_port', '');
			$user = $setup->getOption('ext_proxy_user', '');
			$proxytype = $setup->getOption('ext_proxy_type', 'socks5');
			$password = $setup->getEncryptedOption('ext_proxy_password', '');
			$ext_proxy = array('type'=>$proxytype, 'url'=>$host, 'port'=>$port, 'user'=>$user, 'password'=>$password);
		}
		return $ext_proxy;
	}
	
	###########################################################################
	
	public function isIgnoreProxyConnectionIntervals($server) {
		// Ignore only for Whois Servers for now.
		if(stripos($server, "whois") !== false) {
			$setup = new \CodePunch\Config\Settings($this->getAuthentication());
			$host = $setup->getOption('ext_proxy_host', '');
			$proxy_type = $setup->getOption('ext_proxy_type', '');
			if($host && strlen($host) && $proxy_type == 'socks5') {
				$ignore = $setup->getOption('ignore_proxy_connection_intervals', '1');
				if($ignore == "1")
					return true;
			}
		}
		return false;
	}
	
	###########################################################################
	
	public function isConnectionsAllowedToServer($server)
	{
		if($this->isIgnoreProxyConnectionIntervals($server))
			return true;
		
		$db = $this->authentication->getDatabase();
		$connectionInterval = $db->findOneOf($db->getWhoisServersTableName(), "server", $server, "conninterval");
		if($connectionInterval === false || $connectionInterval < 0 ||  $connectionInterval > self::MAX_CONNECTION_INTERVAL) {
			if(stripos($server, "rdap") !== false)
				$connectionInterval = self::DEFAULT_RDAP_CONNECTION_INTERVAL;
			else
				$connectionInterval = self::DEFAULT_CONNECTION_INTERVAL;
		}
		
		$table = $db->getConnectionsTableName();
		$client = $this->authentication->getServerID();
		$rows = $db->getFromTable("*", $table, "client=? AND server=?", array($client, $server));
		if($rows !== false && is_array($rows) && isset($rows[0])) {
			$row = array_change_key_case($rows[0], CASE_LOWER);
			$last_connected_at = $row['last_connected_at'];

			if(isset($row['block_lookups']) && $row['block_lookups']) {
				if((time()-strtotime($last_connected_at)) < 130) {
					// Log errors for slightly more than 2 minutes, then stop logging.
					$logger = new \CodePunch\Base\CPLogger();
					$logger->error("Connections from $client to $server is blocked by admin.");
				}
				return false;
			}
			$stopi = self::DEFAULT_CONNECTION_BAN;
			if(isset($row['stop_interval']) && $row['stop_interval']) {
				$stopi = intval($row['stop_interval']);
				if($stopi < 900)
					$stopi = 900;
				else if($stopi > 345600) // 4 days
					$stopi = 345600;
			}

			if($row['stop_lookups']) 
				$connectionInterval = $stopi;
			$next_connect = strtotime($last_connected_at) + $connectionInterval;
			if($next_connect > time()) {
				if(($next_connect - time()) > ($stopi-130)) {
					// Log warnings for slightly more than 2 minutes, then stop logging.
					$logger = new \CodePunch\Base\CPLogger();
					$logger->warning("Connections from $client to $server is temporarily stopped till " . date("Y-m-d H:i:s", $next_connect));
				}
				return false;
			}
			if($row['stop_lookups']) {
				$db->updateTable($table, array('stop_lookups'=>false), "client=? AND server=?", array($client, $server));
			}
		}
		return true;
	}
}

###############################################################################
