#!/usr/bin/env python3
# Licensed under GPLv3
#
# Simple http server to allow user control of n2n edge nodes
#
# Currently only for demonstration
# - needs nicer looking html written
# - needs more json interfaces in edge
#
# Try it out with
# http://localhost:8080/
# http://localhost:8080/edge/edges
# http://localhost:8080/edge/supernodes
import argparse
import socket
import json
import socketserver
import http.server
import signal
import functools
import base64
from http import HTTPStatus
import os
import sys
import importlib.machinery
import importlib.util
def import_filename(modulename, filename):
# look in the same dir as this script
pathname = os.path.join(os.path.dirname(os.path.abspath(__file__)),
filename)
loader = importlib.machinery.SourceFileLoader(modulename, pathname)
spec = importlib.util.spec_from_loader(modulename, loader)
module = importlib.util.module_from_spec(spec)
try:
loader.exec_module(module)
except FileNotFoundError:
print("Script {} not found".format(pathname), file=sys.stderr)
sys.exit(1)
return module
# We share the implementation of the RPC class with the n2n-ctl script. We
# cannot just import the module as 'n2n-ctl' has a dash in its name :-(
JsonUDP = import_filename('n2nctl', 'n2n-ctl').JsonUDP
pages = {
"/script.js": {
"content_type": "text/javascript",
"content": """
var verbose=-1;
function rows2verbose(id, unused, data) {
row0 = data[0]
verbose = row0['traceLevel']
let div = document.getElementById(id);
div.innerHTML=verbose
}
function rows2keyvalue(id, keys, data) {
let s = "
"
data.forEach((row) => {
keys.forEach((key) => {
if (key in row) {
s += "
" + key + "
" + row[key];
}
});
});
s += "
"
let div = document.getElementById(id);
div.innerHTML=s
}
function rows2keyvalueall(id, unused, data) {
let s = "
"
data.forEach((row) => {
Object.keys(row).forEach((key) => {
s += "
" + key + "
" + row[key];
});
});
s += "
"
let div = document.getElementById(id);
div.innerHTML=s
}
function rows2table(id, columns, data) {
let s = "
"
s += "
"
columns.forEach((col) => {
s += "
" + col
});
data.forEach((row) => {
s += "
"
columns.forEach((col) => {
val = row[col]
if (typeof val === "undefined") {
val = ''
}
s += "
" + val
});
});
s += "
"
let div = document.getElementById(id);
div.innerHTML=s
}
function do_get(url, id, handler, handler_param) {
fetch(url)
.then(function (response) {
if (!response.ok) {
throw new Error('Fetch got ' + response.status)
}
return response.json();
})
.then(function (data) {
handler(id,handler_param,data);
// update the timestamp on success
let now = Math.round(new Date().getTime() / 1000);
let time = document.getElementById('time');
time.innerHTML=now;
})
.catch(function (err) {
console.log('error: ' + err);
});
}
function do_post(url, body, id, handler, handler_param) {
fetch(url, {method:'POST', body: body})
.then(function (response) {
if (!response.ok) {
throw new Error('Fetch got ' + response.status)
}
return response.json();
})
.then(function (data) {
handler(id,handler_param,data);
})
.catch(function (err) {
console.log('error: ' + err);
});
}
function do_stop(tracelevel) {
// FIXME: uses global in script library
fetch(nodetype + '/stop', {method:'POST'})
}
function setverbose(tracelevel) {
if (tracelevel < 0) {
tracelevel = 0;
}
// FIXME: uses global in script library
do_post(
nodetype + '/verbose', tracelevel, 'verbose',
rows2verbose, null
);
}
function refresh_setup(interval) {
var timer = setInterval(refresh_job, interval);
}
""",
},
"/": {
"content_type": "text/html; charset=utf-8",
"content": """
n2n edge management