#!/usr/bin/env php
<?php

require 'Bencode.php';
require 'Cjdns.php';
require 'publicKey2ipv6.php';

define('PASSWORD', 'NONE');
define('URL',      'http://www.fc00.org/sendGraph');
define('EMAIL',    'your@email.here'); // update your email address, so I can contact you in case something goes wrong
//define('DEBUG', 1);

$cjdns = new Cjdns(PASSWORD, "127.0.0.1", 11234);
//$_nds = dump_node_store($cjdns);
$_nds = dump_near_nodes($cjdns);
if (defined('DEBUG'))
	echo "Nodes: ".count($_nds)."\n";

$nodes = []; $links = []; $edges = [];
foreach ($_nds as $node)
{
	if (defined('DEBUG')) echo 'Node '.(@++$i).' / '.count($_nds)."\n";
	$peers = get_peers($cjdns, $node['path']);

	foreach ($peers as $peer)
	if ($peer['ip'] != $node['ip'])
	{
		$x = parse_addr($peer['addr']);
		if (defined('DEBUG')) echo $node['ip'] . ' => '. $peer['ip']."\n";
		if (empty($links[$peer['ip'].$node['ip']]))
			$edges[] = ['a'=>$node['ip'], 'b'=>$peer['ip']];

		$nodes[$node['ip']] = ['ip'=>$x['ip'], 'version'=>@$x['version']];
		$nodes[$peer['ip']] = ['ip'=>$x['ip'], 'version'=>@$x['version']];

		$links[$peer['ip'].$node['ip']] = 1;
		$links[$node['ip'].$peer['ip']] = 1;
	}
}
$nodes = array_values($nodes);
if (defined('DEBUG'))
	echo "Edges: ".count($edges)."\n";

// send to server
$json_graph = ['nodes' => $nodes, 'edges' => $edges];
$payload = ['data'=>json_encode($json_graph), 'mail'=>EMAIL, 'version'=>2, 'name'=>'php'];
$data    = http_build_query($payload);
$context = stream_context_create(['http'=>[
	'method'  => 'POST',
	'header'  => "Content-Type: application/x-www-form-urlencoded\r\nContent-Length: ".strlen($data)."\r\n",
	'content' => $data,
]]);
$st = file_get_contents(URL, false, $context);
if (defined('DEBUG'))
	echo "Result: $st\n";


function get_peers($cjdns, $path, $nearbyPath='')
{
	if (!cache_get($path, $res))
	{
		if (defined('DEBUG')) echo "Call $path\n";
		$res = $cjdns->call('RouterModule_getPeers', ['path'=>$path] + ($nearbyPath?['nearbyPath'=>$nearbyPath]:[]));
		cache_set($path, $res);
	}

	if (empty($res['peers']) || $res['error'] != 'none') return [];
	$res = $res['peers'];
	foreach ($res as $k => $v) $res[$k] = ['addr'=>$v, 'ip'=>publicKey2ipv6(explode('.', $v)[5])];

	return $res;
}

function dump_near_nodes($cjdns)
{
	$nodes = []; $page = 0;
	if (cache_get('near_nodes', $nodes)) return $nodes;
	while (1)
	{
		$res = $cjdns->call('InterfaceController_peerStats', ['page'=>$page]);
		if (!empty($res['peers']))
		foreach ($res['peers'] as $a)
		{
			$x = parse_addr($a['addr']);
			$nodes[] = $x;
		}
		if (empty($res['more']) || $res['more'] != 1) break;
		$page++;
	}
	return cache_set('near_nodes', $nodes);
}

function dump_node_store($cjdns)
{
	$nodes = []; $page = 0;
	if (cache_get('nodes', $nodes)) return $nodes;
	while (1)
	{
		$res = $cjdns->call('NodeStore_dumpTable', ['page'=>$page]);
		if (!empty($res['routingTable']))
		foreach ($res['routingTable'] as $a)
		{
			$x = parse_addr($a['addr']);
			$nodes[] = $x;
		}
		if (empty($res['more']) || $res['more'] != 1) break;
		$page++;
	}
	return cache_set('nodes', $nodes);
}

function parse_addr($x)
{
	$x = explode('.', $x);
	return [
		'version'   =>       str_replace('v', '', $x[0]),
		'path'      =>       implode('.', array_slice($x, 1, 4)),
		'publicKey' => $pK = implode('.', array_slice($x, 5, 2)),
		'ip'        =>       publicKey2ipv6($pK),
	];
}


// DEBUG: cache functions

function cache_get($name, &$data)
{
	if (!defined('DEBUG')) return false;
	$fname = cache_fname($name);
	if (file_exists($fname) && (time() - filemtime($fname) < 60*60))
	{
		$data = json_decode(file_get_contents($fname), true);
		return true;
	}
	return false;
}

function cache_set($name, $data)
{
	if (defined('DEBUG')) file_put_contents(cache_fname($name), json_encode($data));
	return $data;
}

function cache_fname($name)
{
	$dir = './cache/';
	if (!file_exists($dir)) mkdir($dir);
	return $dir.$name.'.json';
}
