window.onload = () => { const table_elem = document.getElementById("table"); const last_change = document.getElementById("last_change"); const last_ping = document.getElementById("last_ping"); const connected = document.getElementById("connected"); const free_ports = document.getElementById("free_ports"); const timeout_duration = 10*1000; const retry_timeout = 5*1000; let reconnect_timeout; let ping_timeout; let evtSource; let table = []; let last_update = new Date(); let direction = -1; let oldkey = "last_change"; table_elem.firstChild.firstChild.lastChild.className = "sort sort-down"; let time_ago = ms => { let value = ms / 1000; // let prev = 0; let unit = 0; let factors = [ [1, 'Sekunde', 'n'], [60, 'Minute', 'n'], [60, 'Stunde', 'n'], [24, 'Tag', 'en'], [7, 'Woche', 'n'], [4.348214, 'Monat', 'en'], [12, 'Jahr', 'en'], ]; for (let i in factors) { let factor = factors[i][0]; let new_value = Math.floor(value / factor); if (new_value == 0) break; // prev = Math.floor(value % factor); value = new_value; unit = i; } let factor = factors[unit]; return [value, factors[unit][1] + (value == 1 ? "" : factor[2])]; } sort = (element, key) => { console.log(key, oldkey, direction); if (key == oldkey) { direction *= -1; } else { oldkey = key; direction = -1; } for (let child of table_elem.firstChild.firstChild.children) { console.log(child); child.className = "" }; element.className = `sort ${direction > 0 ? "sort-up" : "sort-down"}`; do_sort(oldkey, direction); }; let do_sort = (key, direction) => { let is_number = !!~(["port", "number", "last_change"].indexOf(key)); console.log("is number:", is_number); table = table.sort((a, b) => (direction * ( is_number ? a[key] - b[key] : ('' +a[key]).localeCompare(b[key], "de-DE") ))); print_table(); console.log(table); }; let fmt = Intl.DateTimeFormat('de-DE', { dateStyle: 'medium', timeStyle: 'medium' }); let format_date = date => fmt.format(date).replace(', ', ' '); let format_time = date => fmt.format(date).split(', ', 2)[1]; let print_table = () => { while(table_elem.children.length > 1) { table_elem.removeChild(table_elem.lastChild); } for (let row of table) { let tr = document.createElement("tr"); let values = [ row.name === null ? "?" : row.name, row.number, row.port, row.status, time_ago(last_update - row.last_change) ]; let names = [ "name", "number", "port", "status", "last_change" ]; for(let i in values) { let value = values[i]; let name = names[i]; let td = document.createElement("td"); td.className = name; if (name == "last_change") { let [number, unit] = value; let span = document.createElement("span"); // span.className = "value"; span.innerText = number; td.appendChild(span); span = document.createElement("span"); span.className = "unit"; span.innerText = unit; td.appendChild(span); } else { td.innerText = value; } tr.appendChild(td); } table_elem.appendChild(tr) } }; let update_table = data => { console.log(data); const allowed_ports = data.allowed_ports.map(x => x.end - x.start + 1).reduce((a,b) => a + b, 0); free_ports.innerText = `Freie Ports: ${allowed_ports - Object.keys(data.allocated_ports).length - data.errored_ports.length}`; // last_change.innerHTML = `Letzte Änderung: ${format_date(new Date(+data.last_update * 1000))}`; table = []; for(let number in data.allocated_ports) { let port = data.allocated_ports[number]; number = +number; let {status, last_change} = data.port_state[port]; let rejector = data.rejectors[port] || null; if (rejector && rejector instanceof Array) { rejector = rejector.map(x => "0x"+x.toString(16).padStart(2, 0)).join(" ") } last_change = new Date(last_change * 1000); let name = data.names[number] || null; switch(status) { case "disconnected": status = rejector ? `getrennt: ${rejector}` : "getrennt"; break; case "idle": status = "bereit"; break; case "in_call": status = "anruf"; break; } table.push({port, number, status, last_change, rejector, name}) } for (let [timestamp, port] of data.errored_ports) { table.push({port, number: null, status: "Fehler", last_change: new Date(timestamp * 1000), rejector: null, name: ""}) } console.log(table); do_sort(oldkey, direction); print_table(); }; let format_event = (event, method) => (method || format_date)(new Date(+event.data * 1000)); let display_disconnected; let connect_event_source = () => { clearTimeout(reconnect_timeout); clearTimeout(ping_timeout); ping_timeout = setTimeout(connect_event_source, timeout_duration); evtSource && evtSource.close && evtSource.close(); evtSource = new EventSource("/events"); evtSource.addEventListener("change", event => { last_ping.innerText = `Stand: ${format_event(event, format_time)}`; last_update = new Date(+event.data * 1000); fetch("/data") .then(res => res.json()) .then(update_table); }); evtSource.addEventListener("ping", event => { clearTimeout(ping_timeout); ping_timeout = setTimeout(connect_event_source, timeout_duration); last_update = new Date(+event.data * 1000); last_ping.innerText = `Stand: ${format_event(event, format_time)}`; connected.className = "visible"; print_table(); clearTimeout(display_disconnected); display_disconnected = setTimeout(() => connected.className = "hidden", 5000); }); evtSource.onerror = () => { clearTimeout(reconnect_timeout); reconnect_timeout = setTimeout(connect_event_source, retry_timeout); }; } connect_event_source(); };