statistics.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. "use strict"
  2. define(["lib/helper"], function (Helper) {
  3. function streamElement(type, stream) {
  4. var el = document.createElement(type)
  5. el.destroy = stream.onValue(update)
  6. function update(d) {
  7. el.textContent = d
  8. }
  9. return el
  10. }
  11. function streamNode(stream) {
  12. var el = document.createTextNode("")
  13. el.destroy = stream.onValue(update)
  14. function update(d) {
  15. el.textContent = d
  16. }
  17. return el
  18. }
  19. function mkRow(table, label, stream) {
  20. var tr = document.createElement("tr")
  21. var th = document.createElement("th")
  22. var td = streamElement("td", stream)
  23. th.textContent = label
  24. tr.appendChild(th)
  25. tr.appendChild(td)
  26. table.appendChild(tr)
  27. tr.destroy = function () {
  28. td.destroy()
  29. table.removeChild(tr)
  30. }
  31. return tr
  32. }
  33. function mkTrafficRow(table, children, label, stream, selector) {
  34. var tr = document.createElement("tr")
  35. var th = document.createElement("th")
  36. var td = document.createElement("td")
  37. th.textContent = label
  38. var traffic = stream.slidingWindow(2, 2)
  39. var pkts = streamNode(traffic.map(deltaUptime(selector + ".packets")).map(prettyPackets))
  40. var bw = streamNode(traffic.map(deltaUptime(selector + ".bytes")).map(prettyBits))
  41. var bytes = streamNode(stream.map(selector).map(".bytes").map(prettyBytes))
  42. td.appendChild(pkts)
  43. td.appendChild(document.createElement("br"))
  44. td.appendChild(bw)
  45. td.appendChild(document.createElement("br"))
  46. td.appendChild(bytes)
  47. tr.appendChild(th)
  48. tr.appendChild(td)
  49. table.appendChild(tr)
  50. children.push(pkts)
  51. children.push(bw)
  52. children.push(bytes)
  53. }
  54. function mkMeshVPN(el, stream) {
  55. var children = {}
  56. var init = false
  57. var h = document.createElement("h3")
  58. h.textContent = "Mesh-VPN"
  59. var table = document.createElement("table")
  60. var unsubscribe = stream.onValue( function (d) {
  61. function addPeer(peer, path) {
  62. return { peer: peer, path: path }
  63. }
  64. function addPeers(d, path) {
  65. if (!("peers" in d))
  66. return []
  67. var peers = []
  68. for (var peer in d.peers)
  69. peers.push(addPeer(peer, path + ".peers." + peer))
  70. return peers
  71. }
  72. function addGroup(d, path) {
  73. var peers = []
  74. peers = peers.concat(addPeers(d, path))
  75. if ("groups" in d)
  76. for (var group in d.groups)
  77. peers = peers.concat(addGroup(d.groups[group], path + ".groups." + group))
  78. return peers
  79. }
  80. if (d === undefined)
  81. clear()
  82. else {
  83. if (!init) {
  84. init = true
  85. el.appendChild(h)
  86. el.appendChild(table)
  87. }
  88. var peers = addGroup(d, "")
  89. var paths = new Set(peers.map(function (d) { return d.path } ))
  90. for (var path in children)
  91. if (!paths.has(path)) {
  92. children[path].destroy()
  93. delete children[path]
  94. }
  95. peers.forEach( function (peer) {
  96. if (!(peer.path in children))
  97. children[peer.path] = mkRow(table, peer.peer,
  98. stream.startWith(d)
  99. .map(peer.path)
  100. .filter(function (d) { return d !== undefined })
  101. .map(prettyPeer))
  102. })
  103. }
  104. })
  105. function clear() {
  106. if (init) {
  107. init = false
  108. el.removeChild(h)
  109. el.removeChild(table)
  110. }
  111. for (var peer in children)
  112. children[peer].destroy()
  113. children = {}
  114. }
  115. function destroy() {
  116. unsubscribe()
  117. clear()
  118. }
  119. return { destroy: destroy }
  120. }
  121. function deltaUptime(selector) {
  122. return function (d) {
  123. var deltaTime = d[1].uptime - d[0].uptime
  124. var d0 = Helper.dictGet(d[0], selector.split(".").splice(1))
  125. var d1 = Helper.dictGet(d[1], selector.split(".").splice(1))
  126. return (d1 - d0) / deltaTime
  127. }
  128. }
  129. function prettyPeer(d) {
  130. if (d === null)
  131. return "nicht verbunden"
  132. else
  133. return "verbunden (" + prettyUptime(d.established) + ")"
  134. }
  135. function prettyPackets(d) {
  136. var v = Helper.formatNumberFixed(d, 0)
  137. return v + " Pakete/s"
  138. }
  139. function prettyPrefix(prefixes, step, d) {
  140. var prefix = 0
  141. while (d > step && prefix < prefixes.length - 1) {
  142. d /= step
  143. prefix++
  144. }
  145. d = Helper.formatNumber(d, 3)
  146. return d + " " + prefixes[prefix]
  147. }
  148. function prettySize(d) {
  149. return prettyPrefix([ "", "k", "M", "G", "T" ], 1024, d)
  150. }
  151. function prettyBits(d) {
  152. return prettySize(d * 8) + "bps"
  153. }
  154. function prettyBytes(d) {
  155. return prettySize(d) + "B"
  156. }
  157. function prettyUptime(seconds) {
  158. var minutes = Math.round(seconds / 60)
  159. var days = Math.floor(minutes / 1440)
  160. var hours = Math.floor((minutes % 1440) / 60)
  161. minutes = Math.floor(minutes % 60)
  162. var out = ""
  163. if (days === 1)
  164. out += "1 Tag, "
  165. else if (days > 1)
  166. out += days + " Tage, "
  167. out += hours + ":"
  168. if (minutes < 10)
  169. out += "0"
  170. out += minutes
  171. return out
  172. }
  173. function prettyNVRAM(usage) {
  174. return Helper.formatNumber(usage * 100, 3) + "% belegt"
  175. }
  176. function prettyLoad(load) {
  177. return Helper.formatNumberFixed(load, 2)
  178. }
  179. function prettyRAM(memory) {
  180. var usage = 1 - (memory.free + memory.buffers + memory.cached) / memory.total
  181. return prettyNVRAM(usage)
  182. }
  183. return function (stream) {
  184. var children = []
  185. var el = document.createElement("div")
  186. var table = document.createElement("table")
  187. children.push(mkRow(table, "Laufzeit", stream.map(".uptime").map(prettyUptime)))
  188. children.push(mkRow(table, "Systemlast", stream.map(".loadavg").map(prettyLoad)))
  189. children.push(mkRow(table, "RAM", stream.map(".memory").map(prettyRAM)))
  190. children.push(mkRow(table, "NVRAM", stream.map(".rootfs_usage").map(prettyNVRAM)))
  191. children.push(mkRow(table, "Gateway", stream.map(".gateway")))
  192. children.push(mkRow(table, "Clients", stream.map(".clients.total")))
  193. el.appendChild(table)
  194. var h = document.createElement("h3")
  195. h.textContent = "Traffic"
  196. el.appendChild(h)
  197. table = document.createElement("table")
  198. mkTrafficRow(table, children, "Gesendet", stream, ".traffic.tx")
  199. mkTrafficRow(table, children, "Empfangen", stream, ".traffic.rx")
  200. mkTrafficRow(table, children, "Weitergeleitet", stream, ".traffic.forward")
  201. el.appendChild(table)
  202. children.push(mkMeshVPN(el, stream.map(".mesh_vpn")))
  203. function destroy() {
  204. children.forEach(function (d) {d.destroy()})
  205. }
  206. return { title: document.createTextNode("Statistik")
  207. , render: function (d) { d.appendChild(el) }
  208. , destroy: destroy
  209. }
  210. }
  211. })