/*! @file @id $Id$ This is the main application as it is fully run in the user's browser. */ // 1 2 3 4 5 6 7 8 // 45678901234567890123456789012345678901234567890123456789012345678901234567890 var socket = io.connect(); var focused = null; var docker = new Docker(); function htmlenc(html) { return $('
').text(html).html(); } function htmldec(data) { return $('').html(data).text(); } /// Show error messsage /** Fades in an error message and logs to console. @param data (optional) The error can be a string or any structure. Strings are shown to the user, structures are logged only. @param stay (optional) If not given as @c true, reloads page after 5s. */ function error(data) { $("#status").fadeOut("slow", function() { $("#status").addClass("error") $("#status").removeClass("notice") $("#status").removeClass("success") if (data) { if (typeof data == 'string') { $("#status").html(data); console.log("error: "+data); } else { $("#status").html('unknown error: '+JSON.stringify(data)); console.log("error: ", data); console.log((new Error('stacktrace'))); } } else { $("#status").html('error'); console.log("error"); } $("#status").fadeIn("slow"); }); } /// Show notice messsage /** Fades in an notice message and logs to console. @param text (optional) The data is a string. */ function notice(text) { $("#status").fadeOut("slow", function() { $("#status").addClass("notice") $("#status").removeClass("error") $("#status").removeClass("success") if (text) { $("#status").html(text); console.log("notice: "+text); } else { $("#status").html(''); console.log("notice"); } $("#status").fadeIn("slow"); }); } /// Show notice messsage /** Fades in an success message and logs to console. @param text (optional) The data is a string. */ function success(text) { $("#status").fadeOut("slow", function() { $("#status").addClass("success") $("#status").removeClass("error") $("#status").removeClass("notice") if (text) { $("#status").html(text); console.log("success: "+text); } else { $("#status").html(''); console.log("success"); } $("#status").fadeIn("slow"); }); } /// Show status message in the main screen area /** @param text Text is a message or some complex HTML from the server. @param msg The success message text */ function status(text, msg) { $("#main").hide(); $("#main").html(text); if (msg) success(msg); else setTimeout("$('#status').fadeOut('slow')", 5000); zoom(0); stats(); $("#main").show(); $("form input:first-child").focus(); docker.containers.contextmenu("#main"); } function emit(signal, data) { console.log("<-snd "+signal, data); socket.emit(signal, data); } function connected() { console.log("server connected"); $("#connectionstatus #bad").hide(); $("#connectionstatus #good").show(); success("server connected"); } function disconnected() { console.log("server disconnected"); $("#connectionstatus #good").hide(); $("#connectionstatus #bad").show(); error("server disconnected", true); } function connectionstatus() { if (socket.connected) connected(); else disconnected(); } /// Toggle Menu Display function togglemenu() { $("#menu").toggle(); } /// Upload a configuration and send it to server function upload(evt) { if (!window.FileReader) return error("your browser does not support file upload", true); for (var i=0, f; f=evt.target.files[i]; ++i) { var file = f; var reader = new FileReader(); reader.onload = function(evt) { if (evt.target.error) return error("error reading file", true); if (evt.target.readyState==0) return notice("waiting for data …"); if (evt.target.readyState==1) return notice("loading data …"); emit("create", evt.target.result); } reader.readAsText(file); } } function create() { $("#create form fieldset input.add").click(function() { $(this).siblings("select").append('') }); //$("#preview").html(Viz("digraph {\nrankdir="+rankdir+";\n"+docker.containers.graph()+"\n}")); } var zoomlevel = 0; function zoom(incr = 0) { zoomlevel = (zoomlevel+incr)%2; switch (zoomlevel) { case 0: { $("#main svg").css("width", "auto"); $("#main svg").css("height", "auto"); $("#main svg").css("max-width", "100%"); $("#main svg").css("max-height", "100%"); } break; case 1: { $("#main svg").css("width", "100%"); $("#main svg").css("height", "auto"); $("#main svg").css("max-width", "100%"); $("#main svg").css("max-height", "none"); } break; case 2: { $("#main.svg").css("width", "auto"); $("#main.svg").css("height", "100%"); $("#main.svg").css("max-width", "none"); $("#main.svg").css("max-height", "100%"); } break; } } var viz = null; var vizmore = null; var rankdir = "LR"; function rotateviz() { if (!viz) return; if (rankdir == "LR") rankdir = "TB"; else rankdir = "LR"; showviz(); } function showviz(vizpath, more) { if (!vizpath) { vizpath = viz; more = vizmore; } else { viz = vizpath; vizmore = more; } res = "digraph {\n"+" rankdir="+rankdir+";\n"+viz+"\n}"; try { status(more?Viz(res)+more:Viz(res)); $('#main a > ellipse + text').attr('font-size', '12'); $('#main a > ellipse + text + text') .attr('font-weight', 'bold') .attr('font-size', '16') .each(function() {$(this).attr('y', parseFloat($(this).attr('y'))+1.0)}); $('#main a > ellipse + text + text + text').attr('font-size', '12'); } catch(e) { (res = res.split("\n")).forEach(function(v, i, a) { a[i] = ("000"+(i+1)).slice(-3)+": "+v; }); status(""+e+"
"+res.join("\n")+"");
    }
}
function details(name) {
    if (name) focused = name;
    else if (!focused) return overview();
    showviz(docker.containers.subgraph(focused));
}
/// Convert number of bytes to readable text
function size(num) {
    if (num>0.6*1024) {
        if (num>0.6*1024*1024) {
            if (num>0.6*1024*1024*1024) {
                if (num>0.6*1024*1024*1024*1024) {
                    return Math.round(num/1024/1024/1024/1024)+"TB";
                } else {
                    return Math.round(num/1024/1024/1024)+"GB";
                }
            } else {
                return Math.round(num/1024/1024)+"MB";
            }
        } else {
            return Math.round(num/1024)+"kB";
        }
    } else {
        return num+"B";
    }
}
var oldoldstats = null;
var oldstats = null;
function stats(data) {
    console.log("->rcv stats");
    if (!data && oldstats && oldoldstats) {
        data = oldstats;
        oldstats = oldoldstats;
    }
    if (oldstats) for (name in data) {
        var s = data[name];
        var o = oldstats[name];
        if (!o|| !s) continue;
        $('#main text + text:contains("'+name+'") + text')
            .html('cpu: '
                  +(Math.round((s.cpuacct.usage.data-o.cpuacct.usage.data)
                               /(s.cpuacct.usage.date-o.cpuacct.usage.date)
                               /100)
                    /100)
                  +'% mem: '
                  +size(s.memory.usage_in_bytes.data));
    }
    oldoldstats = oldstats;
    oldstats = data;
}
function images(i) {
    console.log("->rcv images");
    docker.images.set(i);
}
function containers(c) {
    console.log("->rcv containers");
    docker.containers.set(c);
    if (focused && docker.containers.exists(focused))
        details(focused);
    else
        overview();
}
function showImage() {
    $("#create").hide();
    $("#logs").hide();
    $("#console").hide();
    $("#close").hide();
    $("#imagetools").show();
    $("#main").show();
}
function showCreate() {
    $("#main").hide();
    $("#logs").hide();
    $("#console").hide();
    $("#imagetools").hide();
    $("#close").show();
    $("#create").show();
    create();
}
function showConsole() {
    $("#main").hide();
    $("#create").hide();
    $("#logs").hide();
    $("#imagetools").hide();
    $("#console").show();
    $("#close").show();
    // $("#command").focus();
    // $("#command").val("");
    // if ($("#screen").val()!="") $("#screen").append("\n");
}
function showLogs() {
    $("#main").hide();
    $("#create").hide();
    $("#console").hide();
    $("#imagetools").hide();
    $("#close").show();
    $("#logs").show();
}
function logs(data) {
    console.log("->rcv logs("+data.name+")");
    if (data.type=='done') {
        $("#logs").append('\nDONE');
    } else {
        $("#logs").append(''+htmlenc(data.text)+'');
    }
}
function strInsert(str, pos, txt) {
    return str.slice(0, pos)+txt+str.slice(pos);
}
function ansifilter(data) {
    console.log("ansifilter");
    var res = data;
    var pos = -1;
    var spans = 0;
    while ((pos=res.indexOf("\x1B[")) >= 0) {
        var end = res.indexOf("m", pos+2);
        if (end>0) {
            var control= res.slice(pos+2, end);
            res = res.slice(0, pos)+res.slice(end+1);
            control.split(';').forEach(function(c) {
                switch (parseInt(c)) {
                    // set
                    case 1: res = strInsert(res, pos, ''); ++spans; break;
                    case 2: res = strInsert(res, pos, ''); ++spans; break;
                    case 4: res = strInsert(res, pos, ''); ++spans; break;
                    case 5: res = strInsert(res, pos, ''); ++spans; break;
                    case 7: res = strInsert(res, pos, ''); ++spans; break;
                    case 8: res = strInsert(res, pos, ''); ++spans; break;
                    // reset
                    case 0: for (;spans;--spans) res = strInsert(res, pos, ""); break;
                    case 21: if (spans) --spans; res = strInsert(res, pos, ""); break;
                    case 22: if (spans) --spans; res = strInsert(res, pos, ""); break;
                    case 23: if (spans) --spans; res = strInsert(res, pos, ""); break;
                    case 25: if (spans) --spans; res = strInsert(res, pos, ""); break;
                    case 27: if (spans) --spans; res = strInsert(res, pos, ""); break;
                    case 28: if (spans) --spans; res = strInsert(res, pos, ""); break;
                    // fg colors
                    case 39: res = strInsert(res, pos, ''); ++spans; break;
                    case 30: res = strInsert(res, pos, ''); ++spans; break;
                    case 31: res = strInsert(res, pos, ''); ++spans; break;
                    case 32: res = strInsert(res, pos, ''); ++spans; break;
                    case 33: res = strInsert(res, pos, ''); ++spans; break;
                    case 34: res = strInsert(res, pos, ''); ++spans; break;
                    case 35: res = strInsert(res, pos, ''); ++spans; break;
                    case 36: res = strInsert(res, pos, ''); ++spans; break;
                    case 37: res = strInsert(res, pos, ''); ++spans; break;
                    case 90: res = strInsert(res, pos, ''); ++spans; break;
                    case 91: res = strInsert(res, pos, ''); ++spans; break;
                    case 92: res = strInsert(res, pos, ''); ++spans; break;
                    case 93: res = strInsert(res, pos, ''); ++spans; break;
                    case 94: res = strInsert(res, pos, ''); ++spans; break;
                    case 95: res = strInsert(res, pos, ''); ++spans; break;
                    case 96: res = strInsert(res, pos, ''); ++spans; break;
                    case 97: res = strInsert(res, pos, ''); ++spans; break;
                    // bg colors
                    case 49: res = strInsert(res, pos, ''); ++spans; break;
                    case 40: res = strInsert(res, pos, ''); ++spans; break;
                    case 41: res = strInsert(res, pos, ''); ++spans; break;
                    case 42: res = strInsert(res, pos, ''); ++spans; break;
                    case 43: res = strInsert(res, pos, ''); ++spans; break;
                    case 44: res = strInsert(res, pos, ''); ++spans; break;
                    case 45: res = strInsert(res, pos, ''); ++spans; break;
                    case 46: res = strInsert(res, pos, ''); ++spans; break;
                    case 47: res = strInsert(res, pos, ''); ++spans; break;
                    case 100: res = strInsert(res, pos, ''); ++spans; break;
                    case 101: res = strInsert(res, pos, ''); ++spans; break;
                    case 102: res = strInsert(res, pos, ''); ++spans; break;
                    case 103: res = strInsert(res, pos, ''); ++spans; break;
                    case 104: res = strInsert(res, pos, ''); ++spans; break;
                    case 105: res = strInsert(res, pos, ''); ++spans; break;
                    case 106: res = strInsert(res, pos, ''); ++spans; break;
                    case 107: res = strInsert(res, pos, ''); ++spans; break;
                    
                }
            });
        } else {
            break;
        }
    }
    for (;spans;--spans) res += "";
    console.log(res);
    return res.replace(/\r\r\n/g, '\n');
}
function ascii(txt) {
    var res = "";
    for (i=0; i