xaizek / rocketgit (License: AGPLv3+) (since 2018-12-09)
Light and fast Git hosting solution suitable to serve both as a hub or as a personal code storage with its tickets, pull requests, API and much more.
<root> / inc / conn.inc.php (aab86e8088beeefb40d190f768c0158e3c248b23) (4,651B) (mode 100644) [raw]
<?php
$INC = isset($INC) ? $INC : dirname(__FILE__);

$rg_conns = array();
$rg_events = array('r' => array(), 'w' => array());

/*
 * Prepares a string to be sent over a socket
 */
function rg_conn_prepare($s)
{
	return rg_serialize($s);
}

/*
 * Shutts down a connection
 */
function rg_conn_shutdown($key, $what)
{
	global $rg_conns;

	if (!isset($rg_conns[$key]['socket']))
		return;

	if (!is_resource($rg_conns[$key]['socket']))
		return;

	@socket_shutdown($rg_conns[$key]['socket'], $what);
	rg_log($key . ': shutdown ' . $what);
}

/*
 * Destroys a connection
 */
function rg_conn_destroy($key)
{
	global $rg_conns;
	global $rg_events;

	if (!isset($rg_conns[$key]))
		rg_internal_error('key not defined!');

	if ($rg_conns[$key]['exit_on_close'])
		exit(1);

	if (isset($rg_conns[$key]['func_destroy']))
		$rg_conns[$key]['func_destroy']($key);

	if (isset($rg_events['r'][$key]))
		unset($rg_events['r'][$key]);
	if (isset($rg_events['w'][$key]))
		unset($rg_events['w'][$key]);
	if (isset($rg_conns[$key]['socket']))
		if (is_resource($rg_conns[$key]['socket']))
			@socket_close($rg_conns[$key]['socket']);
	unset($rg_conns[$key]);
}

/*
 * Registers a new socket
 */
function rg_conn_new($key, $socket)
{
	global $rg_conns;
	global $rg_events;

	$ip = '?';
	$port ='?';
	if (strcmp($key, 'master') != 0)
		@socket_getpeername($socket, $ip, $port);

	$rg_conns[$key] = array(
		'socket' => $socket,
		'recv' => '',
		'send' => '',
		'itime' => time(),
		'exit_on_close' => 0,
		'func_error' => 'rg_conn_func_error',
		'func_close' => 'rg_conn_func_close',
		'ip' => $ip,
		'port' => $port
	);

	$rg_events['r'][$key] = $socket;
	socket_set_nonblock($socket);

	if (strcmp($key, 'master') != 0)
		rg_log($key . ': new connection from ' . $ip . '/' . $port);
}

/*
 * Enqueues data to a socket
 */
function rg_conn_enq($key, $buf)
{
	global $rg_conns;
	global $rg_events;

	$s = &$rg_conns[$key];
	$s['send'] .= $buf;
	$rg_events['w'][$key] = $s['socket'];
}

/*
 * Called when a socket is ready to send data
 */
function rg_conn_send($key)
{
	global $rg_conns;
	global $rg_events;

	if (!isset($rg_conns[$key])) {
		//rg_log($key . ': key not present');
		return FALSE;
	}

	$s = &$rg_conns[$key];
	//rg_log($key . ': SEND: ' . $s['send']);
	$r = @socket_send($s['socket'], $s['send'], strlen($s['send']), 0);
	if ($r === FALSE) {
		rg_log($key . ': Cannot send: ' . socket_strerror(socket_last_error()));
		$s['func_error']($key);
		rg_conn_destroy($key);
		return FALSE;
	}

	$s['send'] = substr($s['send'], $r);
	if (empty($s['send']))
		unset($rg_events['w'][$key]);

	return $r;
}

/*
 * Called when a socket is ready to be read
 */
function rg_conn_recv($key)
{
	global $rg_conns;
	global $rg_events;

	$s = &$rg_conns[$key];

	if (isset($s['func_new'])) {
		$client = @socket_accept($s['socket']);
		if ($client === FALSE) {
			rg_log($key . ': cannot accept: '
				. socket_strerror(socket_last_error()));
			return;
		}

		if (isset($s['func_new_arg']))
			$arg = $s['func_new_arg'];
		else
			$arg = FALSE;

		socket_set_nonblock($client);
		$c = intval($client);
		rg_conn_new($c, $client);
		$s['func_new']($c, $arg);
		return;
	}

	$r = @socket_recv($s['socket'], $buf, 4096, 0);
	if ($r === FALSE) {
		rg_log($key . ': cannot receive: '
			. socket_strerror(socket_last_error()));
		$s['func_error']($key);
		rg_conn_destroy($key);
		return FALSE;
	}
	if ($r === 0) {
		rg_log($key . ': remote closed normally');
		$s['func_close']($key);
		rg_conn_destroy($key);
		return FALSE;
	}
	//rg_log($key . ': RECV: ' . $buf);

	$s['recv'] .= $buf;

	$used = $s['func_data']($key, $s['recv']);
	$s['recv'] = substr($s['recv'], $used);
	return;
}

/*
 * Function that waits for activity and calls different functions
 */
function rg_conn_wait($timeout)
{
	global $rg_conns;
	global $rg_events;

	$r2 = $rg_events['r'];
	$w2 = $rg_events['w'];
	$e2 = array();

	$r = @socket_select($r2, $w2, $e2, $timeout);
	if ($r === FALSE) {
		rg_log('Cannot select: ' . socket_strerror(socket_last_error()));
		return;
	}
	if ($r === 0)
		return;

	//if (!empty($r2))
	//	rg_log_ml('read events: ' . rg_array2string($r2));
	foreach ($r2 as $key => $sock)
		rg_conn_recv($key);

	//if (!empty($w2))
	//	rg_log_ml('write events: ' . rg_array2string($w2));
	foreach ($w2 as $key => $sock)
		rg_conn_send($key);

	//if (!empty($e2))
	//	rg_log_ml('error events: ' . rg_array2string($e2));
	foreach ($e2 as $key => $sock)
		rg_conn_destroy($key);
}

/*
 * Generic function called when there is an error on a socket
 */
function rg_conn_func_error($key)
{
}

/*
 * Generic function called when a socket closes
 */
function rg_conn_func_close($key)
{
}

Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/rocketgit

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/rocketgit

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master