From 1b9869cc339dfca0ea64493dbbee924f9ac79377 Mon Sep 17 00:00:00 2001 From: tianxiu2b2t Date: Sat, 23 Mar 2024 18:23:03 +0800 Subject: [PATCH 1/9] Fix statistics for bytes --- bmclapi_dashboard/static/js/index.min.js | 2 +- core/__init__.py | 8 +++++++- core/api.py | 6 +++++- core/certificate.py | 3 +++ core/cluster.py | 26 +++++++++++++++++------- core/web.py | 25 ++++++++++++++++++++--- 6 files changed, 57 insertions(+), 13 deletions(-) diff --git a/bmclapi_dashboard/static/js/index.min.js b/bmclapi_dashboard/static/js/index.min.js index 7925578..62f72c4 100644 --- a/bmclapi_dashboard/static/js/index.min.js +++ b/bmclapi_dashboard/static/js/index.min.js @@ -1 +1 @@ -(()=>{const e=new TTB,t=e.createElement("div").class("root"),i=e.createFlex().class("header").style("align-items","center"),a=e.createElement("div").class("left"),r=e.createElement("div").class("arrow-background").append(e.createElement("div").class("arrow")),s=e.createElement("div").class("content"),n=e.createElement("div").class("copyright"),o=e.createElement("div").class("right"),l={},d=e.createElement("div").class("progress"),c=e=>{d.setStyle("width",100*e+"%"),100*e>=99&&setTimeout((()=>d.setStyle("width",0)),250)},h=()=>{s.clear();for(const t in l){const i=l[t],a=!!i.children,r=e.createFlex().class("button").id("left-list-"+t).append(e.createElement("p").setText(i.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+i.children[0].key:"")}));if(s.append(r),a){const r=e.createElement("div").style("display: none").class("side").id("left-list-"+t+"-sub");for(const s of i.children)r.append(e.createFlex().class("sidebutton").id("left-list-"+t+"-sub-"+s.key).append(e.createElement("div").class("cycle"),e.createElement("p").setText(s.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+s.key:"")})));s.append(r)}}},p=()=>{const t=e.getURLKey()||Object.keys(l)[0];for(const i of Object.keys(l))if(u!=t?i==t?(document.getElementById("left-list-"+i).classList.add("selected"),x=""):document.getElementById("left-list-"+i).classList.remove("selected"):u==i&&document.getElementById("left-list-"+i).classList.add("selected"),document.getElementById("left-list-"+i+"-sub")){document.getElementById("left-list-"+i+"-sub").style.display=i==t?"block":"none";const a=e.getURLKeyParams().key||Object.keys(Object.values(l)[0])[1];for(const e of l[i].children.map((e=>e.key)))e==a?(document.getElementById("left-list-"+i+"-sub-"+e).classList.add("selected"),x=a):document.getElementById("left-list-"+i+"-sub-"+e).classList.remove("selected")}},g=()=>{const t=e.getURLKey()||Object.keys(l)[0],i=x;p(),(u!=t||x&&x!=i)&&(u&&x&&x==i&&m(u,i,"disconnect"),m(t,x,"connect")),u=t},m=(t,i,a)=>{const r=(i?l[t].children.filter((e=>e.key==i))[0]:l[t]).core||{};if(f!=(t+=i?"-"+i:"")){if(f in r&&"disconnect"in r)try{r.disconnect()}catch(e){console.log(e)}for(;null!=document.getElementsByClassName("right")[0].firstChild;)document.getElementsByClassName("right")[0].removeChild(document.getElementsByClassName("right")[0].firstChild);f=t}if(a in r)try{document.getElementsByClassName("right")[0].style.display="none",page=[],"connect"==a&&"page"in r&&(c(.7),"init"in r&&r.init(),c(.8),page=r.page()||[]),c(.9),r[a](page),null!=page&&document.getElementsByClassName("right")[0].append(e.createElement("div").id("module-"+t).append(...Array.isArray(page)?page:[page]).valueOf()),document.getElementsByClassName("right")[0].style.display="block",c(1)}catch(e){console.log(e)}else c(1)};let u="",x="",f="";const b=new class{constructor(){this.websocket=e.websocket({url:"ws"+window.location.protocol.slice(4)+"//"+window.location.host+window.location.pathname,open:()=>{this.send("runtime",null),this.send("dashboard",null),this.send("qps"),this.send("status")},message:e=>{let t=new FileReader;t.onload=()=>{let e=t.result;const i=new DataInputStream(e);this.message(i.readString(),this._deserializeData(i))},t.readAsArrayBuffer(e.data)},close:()=>{this.runtime=null}}),this.runtime=null}send(e,t){const i=new DataOutputStream;i.writeString(e),i.write(this._serializeData(t)),b.websocket.send(i)}message(e,t){((e,...t)=>{var i=f.split("-",1),a=i[0],r=i[1];const s=(r?l[a].children.filter((e=>e.key==r))[0]:l[a]).core||{};e in s&&s[e](...t)})("_ws_message",e,t)}_deserializeData(e){const t=e.readVarInt();switch(t){case 0:return e.readString();case 1:return e.readBoolean();case 2:return parseFloat(e.readString());case 3:return parseInt(e.readString());case 4:{const t=e.readVarInt(),i=[];for(let a=0;a{if(e.includes(".")){const[r,s]=[e.slice(0,e.indexOf(".")),e.slice(e.indexOf(".")+1)];l[r]||(l[r]={icon:t,children:[],text:"",core:a}),"children"in l[r]||(l[r].children=[]),l[r].children.push({key:s,text:i,core:a})}else l[e]={key:e,icon:t,text:i,core:a}})("dashboard","","数据统计",new class{constructor(){this._page=[e.createFlex().append(e.createElement("div").append(e.createElement("div").class("panel").class("info-2").append(e.createElement("div").append(e.createElement("p").class("title").setText("运行时间"),e.createElement("p").class("value").setText(this._format_time(this.runtime))),e.createElement("div").append(e.createElement("p").class("title").setText("当前节点状态"),e.createElement("p").class("value").setText("-"))),e.createElement("div").class("panel").class("info-4").append(e.createElement("div").append(e.createElement("p").class("title").setText("今日下载量"),e.createElement("p").class("value").setText("0")),e.createElement("div").append(e.createElement("p").class("title").setText("今日流量"),e.createElement("p").class("value").setText("0")),e.createElement("div").append(e.createElement("p").class("title").setText("30天下载量"),e.createElement("p").class("value").setText("0")),e.createElement("div").append(e.createElement("p").class("title").setText("30天流量"),e.createElement("p").class("value").setText("0")))),e.createElement("div").class("panel").append(e.createElement("p").class("title").append("QPS - 五分钟内",e.createElement("div").style("margin-left: 8px; color: rgba(0, 0, 0, 0.7);").setText("0")),e.createElement("div").style("height: 84%; min-height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每小时访问文件数"),e.createElement("div").style("height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每小时访问文件大小"),e.createElement("div").style("height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每天访问文件数"),e.createElement("div").style("height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每天访问文件大小"),e.createElement("div").style("height: 128px"))).minWidth("324px").child(2).minWidth(512)],this._page[0].event("resize",(()=>{this._e_hits.resize(),this._e_bytes.resize(),this._e_daily_hits.resize(),this._e_daily_bytes.resize(),this._e_qps.resize()})),this.runtime=null,this._hourly=Array.from({length:24},((e,t)=>t+" 时")),this._runtimeTimer=setInterval((()=>this.updateRuntime()),1e3),this._dashboardTimer=setInterval((()=>{b.send("dashboard",null)}),1e4),setTimeout((()=>{this._qpsTimer=setInterval((()=>{b.send("qps")}),5e3)}),5-e.getTime()%5),this._e_options={tooltip:{trigger:"axis"},grid:{left:"3%",right:"4%",bottom:"3%",top:"20%",containLabel:!0},xAxis:{type:"category"},yAxis:{type:"value",min:1,max:10},series:[]},this._unit_bytes=["B","KB","MB","GB","TB","PB","EB"],this._unit_number=["","k","M","G","T","P","E"],this._e_hits=echarts.init(this._page[0].getChildrens()[2].getChildrens()[1].valueOf()),this._e_bytes=echarts.init(this._page[0].getChildrens()[3].getChildrens()[1].valueOf()),this._e_daily_hits=echarts.init(this._page[0].getChildrens()[4].getChildrens()[1].valueOf()),this._e_daily_bytes=echarts.init(this._page[0].getChildrens()[5].getChildrens()[1].valueOf()),this._e_qps=echarts.init(this._page[0].getChildrens()[1].getChildrens()[1].valueOf()),this._e_hits.setOption(this._e_options),this._e_bytes.setOption(this._e_options),this._e_hits.setOption({xAxis:{data:this._hourly}}),this._e_bytes.setOption({xAxis:{data:this._hourly}}),this._e_daily_hits.setOption(this._e_options),this._e_daily_bytes.setOption(this._e_options),this._e_qps.setOption({color:"#0fc6c2",tooltip:{trigger:"axis",formatter:t=>'
'+t[0].name+'
QPSAvg: '+t[0].data.value+" total: "+e.sum(...t[0].data.raw)+'
'},stateAnimation:{duration:300,easing:"cubicOut"},xAxis:{type:"category",show:!1},yAxis:{show:!1,type:"value"},grid:{top:10,bottom:10,right:0,left:0,show:!1,z:0,containLabel:!1,backgroundColor:"rgba(0,0,0,0)",borderWidth:1,borderColor:"#ccc"},series:[{type:"bar",barGap:"0",barMinHeight:4,itemStyle:{borderRadius:[2,2,0,0]},z:2,backgroundStyle:{color:"rgba(180, 180, 180, 0.2)",borderColor:null,borderWidth:0,borderType:"solid",borderRadius:0,shadowBlur:0,shadowColor:null,shadowOffsetX:0,shadowOffsetY:0},select:{itemStyle:{borderColor:"#212121"}}}]}),this._e_set_days(),setTimeout((()=>{this._page[0].update()}),100)}updateRuntime(){this._page[0].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(this._format_time(this.runtime,!0))}updateStatus(e){this._page[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(e)}_e_format_time(e){const t=new Date(e);return t.getHours().toString().padStart(2,0)+":"+t.getMinutes().toString().padStart(2,0)+":"+t.getSeconds().toString().padStart(2,0)}_e_set_days(){let t=Number.parseInt(e.getTime()/86400)-30,i=Array.from({length:31},((e,i)=>this._format_date(864e5*(t+i+1))));this._e_daily_hits.setOption({xAxis:{data:i}}),this._e_daily_bytes.setOption({xAxis:{data:i}})}disconnect(){clearInterval(this._runtimeTimer),clearInterval(this._qpsTimer)}connect(e){e.push(...this._page)}_e_templates(e,t=null){const i='
{name}{value}
';var a="";for(const r of e)a+=i.replace("{color}",r.color).replace("{name}",r.name).replace("{value}",t?t(r.value):r.value);return`
${e[0].name}
${a}
`}_ws_message(t,i){if("runtime"==t&&(this.runtime=i,this.updateRuntime()),"dashboard"==t){{const t=i.hourly;let a=Math.max(...t.map((e=>e._hour))),r=0,s=0;{const i=Array.from({length:a},((e,t)=>0)),s=Array.from({length:a},((e,t)=>0));for(const e of t)i[e._hour]=e.hits,s[e._hour]=e.cache_hits,a=Math.max(a,e._hour);this._e_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...i,...s)},series:[{name:"I/O访问数",data:i,type:"line",smooth:!0},{name:"缓存访问数",data:s,type:"line",smooth:!0}]}),r=e.sum(...i,...s)}{const i=Array.from({length:a},((e,t)=>0)),r=Array.from({length:a},((e,t)=>0));for(const e of t)i[e._hour]=e.bytes,r[e._hour]=e.cache_bytes;this._e_bytes.setOption({tooltip:{formatter:e=>this._e_templates(e,(e=>this._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...i,...r),axisLabel:{formatter:e=>this._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:i,type:"line",smooth:!0},{name:"缓存访问文件大小",data:r,type:"line",smooth:!0}]}),s=e.sum(...i,...r)}this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[1].setText(this._format_number_unit(r)),this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].getChildrens()[1].setText(this._format_bytes(s))}{const t=i.days;let a=0,r=0;{const i=Array.from({length:30},((e,t)=>0)),r=Array.from({length:30},((e,t)=>0));for(const e of t)i[e._day]=e.hits,r[e._day]=e.cache_hits;this._e_daily_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...i,...r)},series:[{name:"I/O访问数",data:i,type:"line",smooth:!0},{name:"缓存访问数",data:r,type:"line",smooth:!0}]}),a=e.sum(...i,...r)}{const i=Array.from({length:30},((e,t)=>0)),a=Array.from({length:30},((e,t)=>0));for(const e of t)i[e._day]=e.bytes,a[e._day]=e.cache_bytes;this._e_daily_bytes.setOption({tooltip:{formatter:e=>this._e_templates(e,(e=>this._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...i,...a),axisLabel:{formatter:e=>this._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:i,type:"line",smooth:!0},{name:"缓存访问文件大小",data:a,type:"line",smooth:!0}]}),r=e.sum(...i,...a)}this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[2].getChildrens()[1].setText(this._format_number_unit(a)),this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[3].getChildrens()[1].setText(this._format_bytes(r))}}if("qps"==t){const t=parseInt(e.getTimestamp()/1e3),s=(t%5!=0?5:0)-t%5+t,n=[];var a=[],r=[];for(let t=s-300;t<=s;t++){let s=i.hasOwnProperty(t)?i[t]:0;a.push(s),t%5==0&&(n.push({value:e.sum(...a)/a.length,raw:a}),a=[],r.push(this._e_format_time(1e3*t)))}this._page[0].valueOf().children[1].children[0].children[0].innerText=e.sum(...e.collectionSingleList(n.map((e=>[...e.raw])))),this._e_qps.setOption({xAxis:{data:r},series:[{data:n}]})}"status"==t&&this.updateStatus(i)}_format_number(e,t=null){return 0==e||(t=t||Math.min(Number.parseInt(Math.floor(Math.log(e)/Math.log(1e3))),this._unit_number.length))<=0?`${e}${this._unit_number[0]}`:`${(e/=1024**t).toFixed(1)}${this._unit_number[t]}`}_format_number_unit(e){var t=(e+"").split("."),i=t[0],a=t.length>=2?"."+t.slice(1).join("."):"";return i.toString().replace(/\B(?=(\d{3})+(?!\d))/g,", ")+a}_format_date(e){const t=new Date(e);return`${t.getFullYear().toString().padStart(4,"0")}-${(t.getMonth()+1).toString().padStart(2,"0")}-${t.getDate().toString().padStart(2,"0")}`}_format_time(t,i=!1){if(null==t)return"-";let a=Number.parseInt(t);return i&&(a=Number.parseInt(e.getTime()-a)),`${parseInt(a/60/60/24).toString().padStart(2,"0")} 天 ${parseInt(a/60/60%24).toString().padStart(2,"0")} 小时 ${parseInt(a/60%60).toString().padStart(2,"0")} 分钟 ${parseInt(a%60).toString().padStart(2,"0")} 秒`}_format_bytes(e,t=null){return 0==e||(t=t||Math.min(Number.parseInt(Math.floor(Math.log(e)/Math.log(1024))),this._unit_bytes.length))<=0?`${e.toFixed(2)}${this._unit_bytes[0]}`:`${(e/=1024**t).toFixed(2)}${this._unit_bytes[t]}`}});const y=()=>{h(),p()};i.append(e.createElement("h3").setText("Python OpenBMCLAPI Dashboard")),n.append(e.createElement("p").append(e.createElement("a").setAttribute("href","mailto:administrator@ttb-network.top").setText("TTB Network")," - ",e.VERSION)),r.event("click",(()=>{a.toggle("hide"),window.dispatchEvent(new Event("resize"))})),t.append(i,e.createElement("div").class("container").append(a.append(r,s,n),o)),window.addEventListener("resize",y),window.addEventListener("popstate",g),document.body.prepend(d.valueOf(),t.valueOf()),h(),e.set_styles({"body,ol,ul,h1,h2,h3,h4,h5,h6,p,th,td,dl,dd,form,fieldset,legend,input,textarea,select":"margin:0;padding:0",body:"font:12px;background:#fff;-webkit-text-size-adjust:100%",a:"color:#172c45;text-decoration:none",em:"font-style:normal",li:"list-style:none",img:"border:0;vertical-align:middle",table:"border-collapse:collapse;border-spacing:0",p:"word-wrap:break-word",":root":["--r-main-background-color: #F6F7F9","--r-background-color: #191919","--r-main-font-size: 42px","--r-main-color: #fff","--r-block-margin: 20px","--r-heading-margin: 0 0 20px 0","--r-heading-font: Source Sans Pro, Helvetica, sans-serif","--r-heading-color: #fff","--r-heading-line-height: 1.2","--r-heading-letter-spacing: normal","--r-heading-text-transform: uppercase","--r-heading-text-shadow: none","--r-heading-font-weight: 600","--r-heading1-text-shadow: none","--r-heading1-size: 2.5em","--r-heading2-size: 1.6em","--r-heading3-size: 1.3em","--r-heading4-size: 1em","--r-code-font: monospace","--r-link-color: #42affa","--r-link-color-dark: #068de9","--r-link-color-hover: #8dcffc","--r-selection-background-color: rgba(66, 175, 250, .75)","--r-selection-color: #fff","--r-overlay-element-bg-color: 240, 240, 240","--r-overlay-element-fg-color: 0, 0, 0","--r-ligting-color: rgb(15, 198, 194);"],".root .left":["position: fixed","min-height: calc(100vh - 72px)","max-height: calc(100vh - 72px)","min-width: 48px","max-width: 184px","margin-top: 16px","width: 256px","padding: 8px","padding-top: 0","background: var(--r-main-background-color)","transition: transform 200ms linear 0s;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .left .content":["overflow: auto","width: 95%"],".root .left.hide":["transform: translateX(-100%);"],".root .left .button":["cursor: pointer;","border-radius: 8px;","margin-bottom: 8px","padding: 4px","padding-left: 8px","transition: color 200ms linear 0s;"],".root .left .arrow-background":["position: absolute","background: var(--r-main-background-color)","width: 20px","height: 20px","left: 194px","margin-top: -16px","cursor: pointer"],".root .left .arrow":["width: 100%","height: 100%",'background-image: url("data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgc3R5bGU9IndpZHRoOiAxZW07aGVpZ2h0OiAxZW07dmVydGljYWwtYWxpZ246IG1pZGRsZTtmaWxsOiBjdXJyZW50Q29sb3I7b3ZlcmZsb3c6IGhpZGRlbjsiIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwLWlkPSI3NTUiPjxwYXRoIGQ9Ik0zMjUuMDQ4IDkzLjUxMWwtNjAuMDMwIDU5LjQzNSAzNTcuMTgxIDM1OS42MzEtMzYwLjE4NCAzNTYuNjAzIDU5LjUyMiA1OS45MyA0MjAuMjA3LTQxNi4wNDN6IiBmaWxsPSIjODQ4NDg0IiBwLWlkPSI3NTYiPjwvcGF0aD48L3N2Zz4=");'],".root .container .left.hide .arrow-background .arrow":["transform: rotate(0deg);"],".root .container .left .arrow-background .arrow":["transform: rotate(180deg);","transition: transform 100ms linear 0s;"],".root .left .button:hover":["color: var(--r-ligting-color)"],".root .left .button.selected":["background: var(--r-ligting-color)","box-shadow: rgba(15, 198, 194, 0.2) 0px 10px 25px 0px;","color: white"],".root .left .side":["margin-left: 8px"],".root .left .sidebutton":["padding: 2px","margin-bottom: 8px","cursor: pointer;","color: rgba(0, 0, 0, 0.5);","transition: color 200ms linear 0s;"],".root .left .sidebutton:hover":["color: var(--r-link-color-hover)"],".root .left .sidebutton.selected":["color: black","font-weight: bold"],".root .left .sidebutton:hover .cycle":["background: var(--r-link-color-hover)"],".root .left .sidebutton.selected .cycle":["width: 8px;","height: 8px;","background-color: rgb(15, 198, 194);","margin-right: 6px","margin-left: 2px","border-radius: 50%;"],".root .left .sidebutton .cycle":["width: 4px;","height: 4px;","margin: 4px","margin-right: 8px","background-color: rgba(0, 0, 0, 0.5);","transition: background-color 200ms linear 0s;","border-radius: 50%;"],".root .header":["position: fixed","height: 40px","min-height: 40px","min-width: 100vw","background: var(--r-main-background-color)","z-index: 1","padding: 8px","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .container":["position: relative;","top: 56px;"],".root .container .right":["padding-top: 16px","margin-left: 216px","transition: width 200ms linear 0s;","min-width: calc(100vw - 232px)","min-height: calc(100vh - 72px)"],".root .container .left.hide ~ .right":["margin-left: 0","min-width: 100vw"],".root .container .right .panel":["background-color: rgb(255, 255, 255);","color: rgb(0, 0, 0);","transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;","border-radius: 4px;","background-image: none;","padding: 24px;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;","margin: 16px;"],".panel.info-4":["display: flex","flex-warp: warp"],".panel.info-4 div":["width: 25%"],".panel.info-2":["display: flex","flex-warp: warp"],".panel.info-2 div":["width: 50%"],".panel .title":["display: flex","margin: 0px 0px 6px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.5);","font-size: 14px;"],".panel .value":["margin: 0px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.7);","font-size: 24px;"],".root .container .left.hide~.right":["margin-left: 32px","min-width: calc(100vw - 48px)"],".root .left .copyright":["position: fixed;","bottom: 2px"],".qps .icon":["width: 14px","height: 14px"],".qps":["display: flex","align-items: center"],".progress":["position: absolute;","z-index: 2","width: 0","height: 2px","background: var(--r-ligting-color)","transition: width 200ms linear 0s;"],body:["background-color: var(--r-main-background-color)"]}),g(),y()})(); \ No newline at end of file +(()=>{const e=new TTB,t=e.createElement("div").class("root"),i=e.createFlex().class("header").style("align-items","center"),a=e.createElement("div").class("left"),r=e.createElement("div").class("arrow-background").append(e.createElement("div").class("arrow")),s=e.createElement("div").class("content"),n=e.createElement("div").class("copyright"),o=e.createElement("div").class("right"),l={},d=e.createElement("div").class("progress"),c=e=>{d.setStyle("width",100*e+"%"),100*e>=99&&setTimeout((()=>d.setStyle("width",0)),250)},h=()=>{s.clear();for(const t in l){const i=l[t],a=!!i.children,r=e.createFlex().class("button").id("left-list-"+t).append(e.createElement("p").setText(i.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+i.children[0].key:"")}));if(s.append(r),a){const r=e.createElement("div").style("display: none").class("side").id("left-list-"+t+"-sub");for(const s of i.children)r.append(e.createFlex().class("sidebutton").id("left-list-"+t+"-sub-"+s.key).append(e.createElement("div").class("cycle"),e.createElement("p").setText(s.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+s.key:"")})));s.append(r)}}},p=()=>{const t=e.getURLKey()||Object.keys(l)[0];for(const i of Object.keys(l))if(u!=t?i==t?(document.getElementById("left-list-"+i).classList.add("selected"),x=""):document.getElementById("left-list-"+i).classList.remove("selected"):u==i&&document.getElementById("left-list-"+i).classList.add("selected"),document.getElementById("left-list-"+i+"-sub")){document.getElementById("left-list-"+i+"-sub").style.display=i==t?"block":"none";const a=e.getURLKeyParams().key||Object.keys(Object.values(l)[0])[1];for(const e of l[i].children.map((e=>e.key)))e==a?(document.getElementById("left-list-"+i+"-sub-"+e).classList.add("selected"),x=a):document.getElementById("left-list-"+i+"-sub-"+e).classList.remove("selected")}},g=()=>{const t=e.getURLKey()||Object.keys(l)[0],i=x;p(),(u!=t||x&&x!=i)&&(u&&x&&x==i&&m(u,i,"disconnect"),m(t,x,"connect")),u=t},m=(t,i,a)=>{const r=(i?l[t].children.filter((e=>e.key==i))[0]:l[t]).core||{};if(f!=(t+=i?"-"+i:"")){if(f in r&&"disconnect"in r)try{r.disconnect()}catch(e){console.log(e)}for(;null!=document.getElementsByClassName("right")[0].firstChild;)document.getElementsByClassName("right")[0].removeChild(document.getElementsByClassName("right")[0].firstChild);f=t}if(a in r)try{document.getElementsByClassName("right")[0].style.display="none",page=[],"connect"==a&&"page"in r&&(c(.7),"init"in r&&r.init(),c(.8),page=r.page()||[]),c(.9),r[a](page),null!=page&&document.getElementsByClassName("right")[0].append(e.createElement("div").id("module-"+t).append(...Array.isArray(page)?page:[page]).valueOf()),document.getElementsByClassName("right")[0].style.display="block",c(1)}catch(e){console.log(e)}else c(1)};let u="",x="",f="";const b=new class{constructor(){this.websocket=e.websocket({url:"ws"+window.location.protocol.slice(4)+"//"+window.location.host+window.location.pathname,open:()=>{this.send("runtime",null),this.send("dashboard",null),this.send("qps"),this.send("status")},message:e=>{let t=new FileReader;t.onload=()=>{let e=t.result;const i=new DataInputStream(e);this.message(i.readString(),this._deserializeData(i))},t.readAsArrayBuffer(e.data)},close:()=>{this.runtime=null}}),this.runtime=null}send(e,t){const i=new DataOutputStream;i.writeString(e),i.write(this._serializeData(t)),b.websocket.send(i)}message(e,t){((e,...t)=>{var i=f.split("-",1),a=i[0],r=i[1];const s=(r?l[a].children.filter((e=>e.key==r))[0]:l[a]).core||{};e in s&&s[e](...t)})("_ws_message",e,t)}_deserializeData(e){const t=e.readVarInt();switch(t){case 0:return e.readString();case 1:return e.readBoolean();case 2:return parseFloat(e.readString());case 3:return parseInt(e.readString());case 4:{const t=e.readVarInt(),i=[];for(let a=0;a{if(e.includes(".")){const[r,s]=[e.slice(0,e.indexOf(".")),e.slice(e.indexOf(".")+1)];l[r]||(l[r]={icon:t,children:[],text:"",core:a}),"children"in l[r]||(l[r].children=[]),l[r].children.push({key:s,text:i,core:a})}else l[e]={key:e,icon:t,text:i,core:a}})("dashboard","","数据统计",new class{constructor(){this._page=[e.createFlex().append(e.createElement("div").append(e.createElement("div").class("panel").class("info-2").append(e.createElement("div").append(e.createElement("p").class("title").setText("运行时间"),e.createElement("p").class("value").setText(this._format_time(this.runtime))),e.createElement("div").append(e.createElement("p").class("title").setText("当前节点状态"),e.createElement("p").class("value").setText("-"))),e.createElement("div").class("panel").class("info-4").append(e.createElement("div").append(e.createElement("p").class("title").setText("今日下载量"),e.createElement("p").class("value").setText("0")),e.createElement("div").append(e.createElement("p").class("title").setText("今日流量"),e.createElement("p").class("value").setText("0")),e.createElement("div").append(e.createElement("p").class("title").setText("30天下载量"),e.createElement("p").class("value").setText("0")),e.createElement("div").append(e.createElement("p").class("title").setText("30天流量"),e.createElement("p").class("value").setText("0")))),e.createElement("div").class("panel").append(e.createElement("p").class("title").append("QPS - 五分钟内",e.createElement("div").style("margin-left: 8px; color: rgba(0, 0, 0, 0.7);").setText("0")),e.createElement("div").style("height: 84%; min-height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每小时访问文件数"),e.createElement("div").style("height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每小时访问文件大小"),e.createElement("div").style("height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每天访问文件数"),e.createElement("div").style("height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每天访问文件大小"),e.createElement("div").style("height: 128px"))).minWidth("324px").child(2).minWidth(512)],this._page[0].event("resize",(()=>{this._e_hits.resize(),this._e_bytes.resize(),this._e_daily_hits.resize(),this._e_daily_bytes.resize(),this._e_qps.resize()})),this.runtime=null,this._hourly=Array.from({length:24},((e,t)=>t+" 时")),this._runtimeTimer=setInterval((()=>this.updateRuntime()),1e3),this._dashboardTimer=setInterval((()=>{b.send("dashboard",null)}),1e4),setTimeout((()=>{this._qpsTimer=setInterval((()=>{b.send("qps")}),5e3)}),5-e.getTime()%5),this._e_options={tooltip:{trigger:"axis"},grid:{left:"3%",right:"4%",bottom:"3%",top:"20%",containLabel:!0},xAxis:{type:"category"},yAxis:{type:"value",min:1,max:10},series:[]},this._unit_bytes=["B","KB","MB","GB","TB","PB","EB"],this._unit_number=["","k","M","G","T","P","E"],this._e_hits=echarts.init(this._page[0].getChildrens()[2].getChildrens()[1].valueOf()),this._e_bytes=echarts.init(this._page[0].getChildrens()[3].getChildrens()[1].valueOf()),this._e_daily_hits=echarts.init(this._page[0].getChildrens()[4].getChildrens()[1].valueOf()),this._e_daily_bytes=echarts.init(this._page[0].getChildrens()[5].getChildrens()[1].valueOf()),this._e_qps=echarts.init(this._page[0].getChildrens()[1].getChildrens()[1].valueOf()),this._e_hits.setOption(this._e_options),this._e_bytes.setOption(this._e_options),this._e_hits.setOption({xAxis:{data:this._hourly}}),this._e_bytes.setOption({xAxis:{data:this._hourly}}),this._e_daily_hits.setOption(this._e_options),this._e_daily_bytes.setOption(this._e_options),this._e_qps.setOption({color:"#0fc6c2",tooltip:{trigger:"axis",formatter:t=>'
'+t[0].name+'
QPSAvg: '+t[0].data.value+" total: "+e.sum(...t[0].data.raw)+'
'},stateAnimation:{duration:300,easing:"cubicOut"},xAxis:{type:"category",show:!1},yAxis:{show:!1,type:"value"},grid:{top:10,bottom:10,right:0,left:0,show:!1,z:0,containLabel:!1,backgroundColor:"rgba(0,0,0,0)",borderWidth:1,borderColor:"#ccc"},series:[{type:"bar",barGap:"0",barMinHeight:4,itemStyle:{borderRadius:[2,2,0,0]},z:2,backgroundStyle:{color:"rgba(180, 180, 180, 0.2)",borderColor:null,borderWidth:0,borderType:"solid",borderRadius:0,shadowBlur:0,shadowColor:null,shadowOffsetX:0,shadowOffsetY:0},select:{itemStyle:{borderColor:"#212121"}}}]}),this._e_set_days(),setTimeout((()=>{this._page[0].update()}),100)}updateRuntime(){this._page[0].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(this._format_time(this.runtime,!0))}updateStatus(e){this._page[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(e)}_e_format_time(e){const t=new Date(e);return t.getHours().toString().padStart(2,0)+":"+t.getMinutes().toString().padStart(2,0)+":"+t.getSeconds().toString().padStart(2,0)}_e_set_days(){let t=Number.parseInt(e.getTime()/86400)-30,i=Array.from({length:31},((e,i)=>this._format_date(864e5*(t+i))));this._e_daily_hits.setOption({xAxis:{data:i}}),this._e_daily_bytes.setOption({xAxis:{data:i}})}disconnect(){clearInterval(this._runtimeTimer),clearInterval(this._qpsTimer)}connect(e){e.push(...this._page)}_e_templates(e,t=null){const i='
{name}{value}
';var a="";for(const r of e)a+=i.replace("{color}",r.color).replace("{name}",r.name).replace("{value}",t?t(r.value):r.value);return`
${e[0].name}
${a}
`}_ws_message(t,i){if("runtime"==t&&(this.runtime=i,this.updateRuntime()),"dashboard"==t){{const t=i.hourly;let a=Math.max(...t.map((e=>e._hour))),r=0,s=0;{const i=Array.from({length:a},((e,t)=>0)),s=Array.from({length:a},((e,t)=>0));for(const e of t)i[e._hour]=e.hits,s[e._hour]=e.cache_hits,a=Math.max(a,e._hour);this._e_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...i,...s)},series:[{name:"I/O访问数",data:i,type:"line",smooth:!0},{name:"缓存访问数",data:s,type:"line",smooth:!0}]}),r=e.sum(...i,...s)}{const i=Array.from({length:a},((e,t)=>0)),r=Array.from({length:a},((e,t)=>0));for(const e of t)i[e._hour]=e.bytes,r[e._hour]=e.cache_bytes;this._e_bytes.setOption({tooltip:{formatter:e=>this._e_templates(e,(e=>this._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...i,...r),axisLabel:{formatter:e=>this._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:i,type:"line",smooth:!0},{name:"缓存访问文件大小",data:r,type:"line",smooth:!0}]}),s=e.sum(...i,...r)}this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[1].setText(this._format_number_unit(r)),this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].getChildrens()[1].setText(this._format_bytes(s))}{const t=i.days;let a=0,r=0;{const i=Array.from({length:30},((e,t)=>0)),r=Array.from({length:30},((e,t)=>0));for(const e of t)i[e._day]=e.hits,r[e._day]=e.cache_hits;this._e_daily_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...i,...r)},series:[{name:"I/O访问数",data:i,type:"line",smooth:!0},{name:"缓存访问数",data:r,type:"line",smooth:!0}]}),a=e.sum(...i,...r)}{const i=Array.from({length:30},((e,t)=>0)),a=Array.from({length:30},((e,t)=>0));for(const e of t)i[e._day]=e.bytes,a[e._day]=e.cache_bytes;this._e_daily_bytes.setOption({tooltip:{formatter:e=>this._e_templates(e,(e=>this._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...i,...a),axisLabel:{formatter:e=>this._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:i,type:"line",smooth:!0},{name:"缓存访问文件大小",data:a,type:"line",smooth:!0}]}),r=e.sum(...i,...a)}this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[2].getChildrens()[1].setText(this._format_number_unit(a)),this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[3].getChildrens()[1].setText(this._format_bytes(r))}}if("qps"==t){const t=parseInt(e.getTimestamp()/1e3),s=(t%5!=0?5:0)-t%5+t,n=[];var a=[],r=[];for(let t=s-300;t<=s;t++){let s=i.hasOwnProperty(t)?i[t]:0;a.push(s),t%5==0&&(n.push({value:e.sum(...a)/a.length,raw:a}),a=[],r.push(this._e_format_time(1e3*t)))}this._page[0].valueOf().children[1].children[0].children[0].innerText=e.sum(...e.collectionSingleList(n.map((e=>[...e.raw])))),this._e_qps.setOption({xAxis:{data:r},series:[{data:n}]})}"status"==t&&this.updateStatus(i)}_format_number(e,t=null){return 0==e||(t=t||Math.min(Number.parseInt(Math.floor(Math.log(e)/Math.log(1e3))),this._unit_number.length))<=0?`${e}${this._unit_number[0]}`:`${(e/=1024**t).toFixed(1)}${this._unit_number[t]}`}_format_number_unit(e){var t=(e+"").split("."),i=t[0],a=t.length>=2?"."+t.slice(1).join("."):"";return i.toString().replace(/\B(?=(\d{3})+(?!\d))/g,", ")+a}_format_date(e){const t=new Date(e);return`${t.getFullYear().toString().padStart(4,"0")}-${(t.getMonth()+1).toString().padStart(2,"0")}-${t.getDate().toString().padStart(2,"0")}`}_format_time(t,i=!1){if(null==t)return"-";let a=Number.parseInt(t);return i&&(a=Number.parseInt(e.getTime()-a)),`${parseInt(a/60/60/24).toString().padStart(2,"0")} 天 ${parseInt(a/60/60%24).toString().padStart(2,"0")} 小时 ${parseInt(a/60%60).toString().padStart(2,"0")} 分钟 ${parseInt(a%60).toString().padStart(2,"0")} 秒`}_format_bytes(e,t=null){return 0==e||(t=t||Math.min(Number.parseInt(Math.floor(Math.log(e)/Math.log(1024))),this._unit_bytes.length))<=0?`${e.toFixed(2)}${this._unit_bytes[0]}`:`${(e/=1024**t).toFixed(2)}${this._unit_bytes[t]}`}});const y=()=>{h(),p()};i.append(e.createElement("h3").setText("Python OpenBMCLAPI Dashboard")),n.append(e.createElement("p").append(e.createElement("a").setAttribute("href","mailto:administrator@ttb-network.top").setText("TTB Network")," - ",e.VERSION)),r.event("click",(()=>{a.toggle("hide"),window.dispatchEvent(new Event("resize"))})),t.append(i,e.createElement("div").class("container").append(a.append(r,s,n),o)),window.addEventListener("resize",y),window.addEventListener("popstate",g),document.body.prepend(d.valueOf(),t.valueOf()),h(),e.set_styles({"body,ol,ul,h1,h2,h3,h4,h5,h6,p,th,td,dl,dd,form,fieldset,legend,input,textarea,select":"margin:0;padding:0",body:"font:12px;background:#fff;-webkit-text-size-adjust:100%",a:"color:#172c45;text-decoration:none",em:"font-style:normal",li:"list-style:none",img:"border:0;vertical-align:middle",table:"border-collapse:collapse;border-spacing:0",p:"word-wrap:break-word",":root":["--r-main-background-color: #F6F7F9","--r-background-color: #191919","--r-main-font-size: 42px","--r-main-color: #fff","--r-block-margin: 20px","--r-heading-margin: 0 0 20px 0","--r-heading-font: Source Sans Pro, Helvetica, sans-serif","--r-heading-color: #fff","--r-heading-line-height: 1.2","--r-heading-letter-spacing: normal","--r-heading-text-transform: uppercase","--r-heading-text-shadow: none","--r-heading-font-weight: 600","--r-heading1-text-shadow: none","--r-heading1-size: 2.5em","--r-heading2-size: 1.6em","--r-heading3-size: 1.3em","--r-heading4-size: 1em","--r-code-font: monospace","--r-link-color: #42affa","--r-link-color-dark: #068de9","--r-link-color-hover: #8dcffc","--r-selection-background-color: rgba(66, 175, 250, .75)","--r-selection-color: #fff","--r-overlay-element-bg-color: 240, 240, 240","--r-overlay-element-fg-color: 0, 0, 0","--r-ligting-color: rgb(15, 198, 194);"],".root .left":["position: fixed","min-height: calc(100vh - 72px)","max-height: calc(100vh - 72px)","min-width: 48px","max-width: 184px","margin-top: 16px","width: 256px","padding: 8px","padding-top: 0","background: var(--r-main-background-color)","transition: transform 200ms linear 0s;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .left .content":["overflow: auto","width: 95%"],".root .left.hide":["transform: translateX(-100%);"],".root .left .button":["cursor: pointer;","border-radius: 8px;","margin-bottom: 8px","padding: 4px","padding-left: 8px","transition: color 200ms linear 0s;"],".root .left .arrow-background":["position: absolute","background: var(--r-main-background-color)","width: 20px","height: 20px","left: 194px","margin-top: -16px","cursor: pointer"],".root .left .arrow":["width: 100%","height: 100%",'background-image: url("data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgc3R5bGU9IndpZHRoOiAxZW07aGVpZ2h0OiAxZW07dmVydGljYWwtYWxpZ246IG1pZGRsZTtmaWxsOiBjdXJyZW50Q29sb3I7b3ZlcmZsb3c6IGhpZGRlbjsiIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwLWlkPSI3NTUiPjxwYXRoIGQ9Ik0zMjUuMDQ4IDkzLjUxMWwtNjAuMDMwIDU5LjQzNSAzNTcuMTgxIDM1OS42MzEtMzYwLjE4NCAzNTYuNjAzIDU5LjUyMiA1OS45MyA0MjAuMjA3LTQxNi4wNDN6IiBmaWxsPSIjODQ4NDg0IiBwLWlkPSI3NTYiPjwvcGF0aD48L3N2Zz4=");'],".root .container .left.hide .arrow-background .arrow":["transform: rotate(0deg);"],".root .container .left .arrow-background .arrow":["transform: rotate(180deg);","transition: transform 100ms linear 0s;"],".root .left .button:hover":["color: var(--r-ligting-color)"],".root .left .button.selected":["background: var(--r-ligting-color)","box-shadow: rgba(15, 198, 194, 0.2) 0px 10px 25px 0px;","color: white"],".root .left .side":["margin-left: 8px"],".root .left .sidebutton":["padding: 2px","margin-bottom: 8px","cursor: pointer;","color: rgba(0, 0, 0, 0.5);","transition: color 200ms linear 0s;"],".root .left .sidebutton:hover":["color: var(--r-link-color-hover)"],".root .left .sidebutton.selected":["color: black","font-weight: bold"],".root .left .sidebutton:hover .cycle":["background: var(--r-link-color-hover)"],".root .left .sidebutton.selected .cycle":["width: 8px;","height: 8px;","background-color: rgb(15, 198, 194);","margin-right: 6px","margin-left: 2px","border-radius: 50%;"],".root .left .sidebutton .cycle":["width: 4px;","height: 4px;","margin: 4px","margin-right: 8px","background-color: rgba(0, 0, 0, 0.5);","transition: background-color 200ms linear 0s;","border-radius: 50%;"],".root .header":["position: fixed","height: 40px","min-height: 40px","min-width: 100vw","background: var(--r-main-background-color)","z-index: 1","padding: 8px","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .container":["position: relative;","top: 56px;"],".root .container .right":["padding-top: 16px","margin-left: 216px","transition: width 200ms linear 0s;","min-width: calc(100vw - 232px)","min-height: calc(100vh - 72px)"],".root .container .left.hide ~ .right":["margin-left: 0","min-width: 100vw"],".root .container .right .panel":["background-color: rgb(255, 255, 255);","color: rgb(0, 0, 0);","transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;","border-radius: 4px;","background-image: none;","padding: 24px;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;","margin: 16px;"],".panel.info-4":["display: flex","flex-warp: warp"],".panel.info-4 div":["width: 25%"],".panel.info-2":["display: flex","flex-warp: warp"],".panel.info-2 div":["width: 50%"],".panel .title":["display: flex","margin: 0px 0px 6px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.5);","font-size: 14px;"],".panel .value":["margin: 0px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.7);","font-size: 24px;"],".root .container .left.hide~.right":["margin-left: 32px","min-width: calc(100vw - 48px)"],".root .left .copyright":["position: fixed;","bottom: 2px"],".qps .icon":["width: 14px","height: 14px"],".qps":["display: flex","align-items: center"],".progress":["position: absolute;","z-index: 2","width: 0","height: 2px","background: var(--r-ligting-color)","transition: width 200ms linear 0s;"],body:["background-color: var(--r-main-background-color)"]}),g(),y()})(); \ No newline at end of file diff --git a/core/__init__.py b/core/__init__.py index bae4f39..7e4f350 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -72,6 +72,11 @@ def disconnect(self, client: ProxyClient): if client not in self._tables: return self._tables.remove(client) + def get_origin_from_ip(self, ip: tuple[str, int]): + for target in self._tables: + if target.target.get_address() == ip: + return target.origin.get_address() + return None ssl_server: Optional[asyncio.Server] = None server: Optional[asyncio.Server] = None @@ -86,7 +91,7 @@ def disconnect(self, client: ProxyClient): DEBUG: bool = Config.get_boolean("advanced.debug") async def _handle_ssl(reader: asyncio.StreamReader, writer: asyncio.StreamWriter): - return await _handle_process(Client(reader, writer), True) + return await _handle_process(Client(reader, writer, peername = proxy.get_origin_from_ip(writer.get_extra_info("peername"))), True) async def _handle(reader: asyncio.StreamReader, writer: asyncio.StreamWriter): return await _handle_process(Client(reader, writer)) @@ -145,6 +150,7 @@ async def check_ports(): async def main(): global ssl_server, server, server_side_ssl, restart await web.init() + certificate.load_cert(Path(".ssl/cert"), Path(".ssl/key")) Timer.delay(check_ports, (), 5) while 1: try: diff --git a/core/api.py b/core/api.py index 5bf9e79..3a76f24 100644 --- a/core/api.py +++ b/core/api.py @@ -51,8 +51,9 @@ def set_data(self, data: io.BytesIO | memoryview | bytes): class Storage(metaclass=abc.ABCMeta): @abc.abstractmethod - async def get(self, file: str) -> File: + async def get(self, file: str, download: bool = False) -> File: """ + not download can't record file bytes and hits. return type: Path, str Path: Local File @@ -66,6 +67,9 @@ async def exists(self, hash: str) -> bool: async def get_size(self, hash: str) -> int: raise NotImplementedError @abc.abstractmethod + async def copy(self, origin: Path, hash: str) -> int: + raise NotImplementedError + @abc.abstractmethod async def write(self, hash: str, io: io.BytesIO) -> int: raise NotImplementedError @abc.abstractmethod diff --git a/core/certificate.py b/core/certificate.py index b72971c..b0900a9 100644 --- a/core/certificate.py +++ b/core/certificate.py @@ -1,3 +1,4 @@ +import os from pathlib import Path import ssl import time @@ -17,6 +18,8 @@ def load_cert(cert, key): global server_side_ssl, client_side_ssl, _loads + if not os.path.exists(cert) or not os.path.exists(key): + return False try: server_side_ssl.load_cert_chain(cert, key) client_side_ssl.load_verify_locations(cert) diff --git a/core/cluster.py b/core/cluster.py index 4ca3661..02686af 100644 --- a/core/cluster.py +++ b/core/cluster.py @@ -199,11 +199,12 @@ def __init__(self, dir: Path) -> None: self.cache: dict[str, File] = {} self.stats: stats.StorageStats = stats.get_storage(f"File_{self.dir}") self.timer = Timer.repeat(self.clear_cache, (), CHECK_CACHE, CHECK_CACHE) - async def get(self, hash: str) -> File: + async def get(self, hash: str, download: bool = False) -> File: if hash in self.cache: file = self.cache[hash] file.last_access = time.time() - self.stats.hit(file, cache = True) + if download: + self.stats.hit(file, cache = True) return file path = Path(str(self.dir) + f"/{hash[:2]}/{hash}") buf = io.BytesIO() @@ -213,12 +214,18 @@ async def get(self, hash: str) -> File: file = File(path, hash, buf.tell(), time.time(), time.time()) file.set_data(buf.getbuffer()) self.cache[hash] = file - self.stats.hit(file) + if download: + self.stats.hit(file) return file async def exists(self, hash: str) -> bool: return os.path.exists(str(self.dir) + f"/{hash[:2]}/{hash}") async def get_size(self, hash: str) -> int: return os.path.getsize(str(self.dir) + f"/{hash[:2]}/{hash}") + async def copy(self, origin: Path, hash: str): + Path(str(self.dir) + f"/{hash[:2]}/{hash}").parent.mkdir(exist_ok=True, parents=True) + async with aiofiles.open(str(self.dir) + f"/{hash[:2]}/{hash}", "wb") as w, aiofiles.open(origin, "rb") as r: + await w.write(await r.read()) + return r.tell() async def write(self, hash: str, io: io.BytesIO) -> int: Path(str(self.dir) + f"/{hash[:2]}/{hash}").parent.mkdir(exist_ok=True, parents=True) async with aiofiles.open(str(self.dir) + f"/{hash[:2]}/{hash}", "wb") as w: @@ -276,6 +283,9 @@ async def get_files_size(self, dir: str) -> int: for file in session: size += file.stat().st_size return size +class WebDav(Storage): + def __init__(self) -> None: + super().__init__() class Cluster: def __init__(self) -> None: self.sio = socketio.AsyncClient() @@ -403,7 +413,7 @@ async def start(self, ): await set_status("启动服务") await self.enable() async def get(self, hash): - return await self.storages[0].get(hash) + return await self.storages[0].get(hash, True) async def exists(self, hash): return await self.storages[0].exists(hash) async def enable(self) -> None: @@ -450,7 +460,7 @@ async def message(self, type, data: list[Any]): elif type == "keep-alive": if err: logger.error(f"Error: Unable to keep alive. Now reconnecting") - await self.disable() + await self.reconnect() if self.cur_storage: storage = self.cur_storage logger.info(f"Success keepalive, serve: {unit.format_number(storage.sync_hits)}({unit.format_bytes(storage.sync_bytes)})") @@ -486,14 +496,16 @@ async def _keepalive(self): "bytes": storage.get_total_bytes() - storage.get_last_bytes(), }) await self.start_keepalive(300) - async def _keepalive_timeout(self): - logger.warn("Failed to keepalive? Reconnect the main") + async def reconnect(self): try: await self.disable() except: ... await self.cert() await self.enable() + async def _keepalive_timeout(self): + logger.warn("Failed to keepalive? Reconnect the main") + await self.reconnect() async def cert(self): if Path(".ssl/cert").exists() == Path(".ssl/key").exists() == True: return diff --git a/core/web.py b/core/web.py index d3d4186..f247e51 100644 --- a/core/web.py +++ b/core/web.py @@ -12,6 +12,7 @@ from pathlib import Path import re import signal +import stat import struct import tempfile import time @@ -45,7 +46,7 @@ from core.config import Config from core.utils import Client from core.timer import Timer -import core.cluster as cluster +from core import cluster TIMEOUT: int = Config.get_integer("advanced.timeout") @@ -634,7 +635,9 @@ async def _iter(self): yield data else: yield b"" - + async def partial_content(self, length: int, request: "Request") -> int: + range = await request.get_headers("range", "") + return length async def __call__(self, request: "Request", client: Client) -> Any: content, length = io.BytesIO(), 0 if isinstance(self.content, Coroutine): @@ -661,6 +664,21 @@ async def __call__(self, request: "Request", client: Client) -> Any: length = content.stat().st_size else: length = len(content.getbuffer()) + start_bytes, end_bytes = 0, 0 + range_str = await request.get_headers('range', '') + range_match = re.search(r'bytes=(\d+)-(\d+)', range_str, re.S) or re.search(r'bytes=(\d+)-', range_str, re.S) + end_bytes = length - 1 + length = length - start_bytes if isinstance(self.content, Path) and self.content.is_file() and stat.S_ISREG(self.content.stat().st_mode) else length + if range_match: + start_bytes = int(range_match.group(1)) if range_match else 0 + if range_match.lastindex == 2: + end_bytes = int(range_match.group(2)) + self.set_headers({ + 'Accept-ranges': 'bytes', + 'Content-Range': f'bytes {start_bytes}-{end_bytes}/{length}' + }) + self.status_code = 206 if start_bytes > 0 else 200 + length = length - start_bytes self.set_headers( { **RESPONSE_HEADERS, @@ -686,11 +704,12 @@ async def __call__(self, request: "Request", client: Client) -> Any: client.write(header) if length != 0: if isinstance(content, io.BytesIO): - client.write(content.getbuffer()) + client.write(content.getbuffer()[start_bytes:]) await client.writer.drain() else: async with aiofiles.open(content, "rb") as r: cur_length: int = 0 + await r.seek(start_bytes, os.SEEK_SET) while (data := await r.read(min(IO_BUFFER, length - cur_length))): cur_length += len(data) client.write(data) From f603dea623dff32d0615a11bf54138c34e0c25ce Mon Sep 17 00:00:00 2001 From: tianxiu2b2t Date: Sat, 23 Mar 2024 18:26:00 +0800 Subject: [PATCH 2/9] Fix websocket is closed. Runtime is displaying --- bmclapi_dashboard/static/js/index.min.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bmclapi_dashboard/static/js/index.min.js b/bmclapi_dashboard/static/js/index.min.js index 62f72c4..19ab37b 100644 --- a/bmclapi_dashboard/static/js/index.min.js +++ b/bmclapi_dashboard/static/js/index.min.js @@ -1 +1 @@ -(()=>{const e=new TTB,t=e.createElement("div").class("root"),i=e.createFlex().class("header").style("align-items","center"),a=e.createElement("div").class("left"),r=e.createElement("div").class("arrow-background").append(e.createElement("div").class("arrow")),s=e.createElement("div").class("content"),n=e.createElement("div").class("copyright"),o=e.createElement("div").class("right"),l={},d=e.createElement("div").class("progress"),c=e=>{d.setStyle("width",100*e+"%"),100*e>=99&&setTimeout((()=>d.setStyle("width",0)),250)},h=()=>{s.clear();for(const t in l){const i=l[t],a=!!i.children,r=e.createFlex().class("button").id("left-list-"+t).append(e.createElement("p").setText(i.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+i.children[0].key:"")}));if(s.append(r),a){const r=e.createElement("div").style("display: none").class("side").id("left-list-"+t+"-sub");for(const s of i.children)r.append(e.createFlex().class("sidebutton").id("left-list-"+t+"-sub-"+s.key).append(e.createElement("div").class("cycle"),e.createElement("p").setText(s.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+s.key:"")})));s.append(r)}}},p=()=>{const t=e.getURLKey()||Object.keys(l)[0];for(const i of Object.keys(l))if(u!=t?i==t?(document.getElementById("left-list-"+i).classList.add("selected"),x=""):document.getElementById("left-list-"+i).classList.remove("selected"):u==i&&document.getElementById("left-list-"+i).classList.add("selected"),document.getElementById("left-list-"+i+"-sub")){document.getElementById("left-list-"+i+"-sub").style.display=i==t?"block":"none";const a=e.getURLKeyParams().key||Object.keys(Object.values(l)[0])[1];for(const e of l[i].children.map((e=>e.key)))e==a?(document.getElementById("left-list-"+i+"-sub-"+e).classList.add("selected"),x=a):document.getElementById("left-list-"+i+"-sub-"+e).classList.remove("selected")}},g=()=>{const t=e.getURLKey()||Object.keys(l)[0],i=x;p(),(u!=t||x&&x!=i)&&(u&&x&&x==i&&m(u,i,"disconnect"),m(t,x,"connect")),u=t},m=(t,i,a)=>{const r=(i?l[t].children.filter((e=>e.key==i))[0]:l[t]).core||{};if(f!=(t+=i?"-"+i:"")){if(f in r&&"disconnect"in r)try{r.disconnect()}catch(e){console.log(e)}for(;null!=document.getElementsByClassName("right")[0].firstChild;)document.getElementsByClassName("right")[0].removeChild(document.getElementsByClassName("right")[0].firstChild);f=t}if(a in r)try{document.getElementsByClassName("right")[0].style.display="none",page=[],"connect"==a&&"page"in r&&(c(.7),"init"in r&&r.init(),c(.8),page=r.page()||[]),c(.9),r[a](page),null!=page&&document.getElementsByClassName("right")[0].append(e.createElement("div").id("module-"+t).append(...Array.isArray(page)?page:[page]).valueOf()),document.getElementsByClassName("right")[0].style.display="block",c(1)}catch(e){console.log(e)}else c(1)};let u="",x="",f="";const b=new class{constructor(){this.websocket=e.websocket({url:"ws"+window.location.protocol.slice(4)+"//"+window.location.host+window.location.pathname,open:()=>{this.send("runtime",null),this.send("dashboard",null),this.send("qps"),this.send("status")},message:e=>{let t=new FileReader;t.onload=()=>{let e=t.result;const i=new DataInputStream(e);this.message(i.readString(),this._deserializeData(i))},t.readAsArrayBuffer(e.data)},close:()=>{this.runtime=null}}),this.runtime=null}send(e,t){const i=new DataOutputStream;i.writeString(e),i.write(this._serializeData(t)),b.websocket.send(i)}message(e,t){((e,...t)=>{var i=f.split("-",1),a=i[0],r=i[1];const s=(r?l[a].children.filter((e=>e.key==r))[0]:l[a]).core||{};e in s&&s[e](...t)})("_ws_message",e,t)}_deserializeData(e){const t=e.readVarInt();switch(t){case 0:return e.readString();case 1:return e.readBoolean();case 2:return parseFloat(e.readString());case 3:return parseInt(e.readString());case 4:{const t=e.readVarInt(),i=[];for(let a=0;a{if(e.includes(".")){const[r,s]=[e.slice(0,e.indexOf(".")),e.slice(e.indexOf(".")+1)];l[r]||(l[r]={icon:t,children:[],text:"",core:a}),"children"in l[r]||(l[r].children=[]),l[r].children.push({key:s,text:i,core:a})}else l[e]={key:e,icon:t,text:i,core:a}})("dashboard","","数据统计",new class{constructor(){this._page=[e.createFlex().append(e.createElement("div").append(e.createElement("div").class("panel").class("info-2").append(e.createElement("div").append(e.createElement("p").class("title").setText("运行时间"),e.createElement("p").class("value").setText(this._format_time(this.runtime))),e.createElement("div").append(e.createElement("p").class("title").setText("当前节点状态"),e.createElement("p").class("value").setText("-"))),e.createElement("div").class("panel").class("info-4").append(e.createElement("div").append(e.createElement("p").class("title").setText("今日下载量"),e.createElement("p").class("value").setText("0")),e.createElement("div").append(e.createElement("p").class("title").setText("今日流量"),e.createElement("p").class("value").setText("0")),e.createElement("div").append(e.createElement("p").class("title").setText("30天下载量"),e.createElement("p").class("value").setText("0")),e.createElement("div").append(e.createElement("p").class("title").setText("30天流量"),e.createElement("p").class("value").setText("0")))),e.createElement("div").class("panel").append(e.createElement("p").class("title").append("QPS - 五分钟内",e.createElement("div").style("margin-left: 8px; color: rgba(0, 0, 0, 0.7);").setText("0")),e.createElement("div").style("height: 84%; min-height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每小时访问文件数"),e.createElement("div").style("height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每小时访问文件大小"),e.createElement("div").style("height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每天访问文件数"),e.createElement("div").style("height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每天访问文件大小"),e.createElement("div").style("height: 128px"))).minWidth("324px").child(2).minWidth(512)],this._page[0].event("resize",(()=>{this._e_hits.resize(),this._e_bytes.resize(),this._e_daily_hits.resize(),this._e_daily_bytes.resize(),this._e_qps.resize()})),this.runtime=null,this._hourly=Array.from({length:24},((e,t)=>t+" 时")),this._runtimeTimer=setInterval((()=>this.updateRuntime()),1e3),this._dashboardTimer=setInterval((()=>{b.send("dashboard",null)}),1e4),setTimeout((()=>{this._qpsTimer=setInterval((()=>{b.send("qps")}),5e3)}),5-e.getTime()%5),this._e_options={tooltip:{trigger:"axis"},grid:{left:"3%",right:"4%",bottom:"3%",top:"20%",containLabel:!0},xAxis:{type:"category"},yAxis:{type:"value",min:1,max:10},series:[]},this._unit_bytes=["B","KB","MB","GB","TB","PB","EB"],this._unit_number=["","k","M","G","T","P","E"],this._e_hits=echarts.init(this._page[0].getChildrens()[2].getChildrens()[1].valueOf()),this._e_bytes=echarts.init(this._page[0].getChildrens()[3].getChildrens()[1].valueOf()),this._e_daily_hits=echarts.init(this._page[0].getChildrens()[4].getChildrens()[1].valueOf()),this._e_daily_bytes=echarts.init(this._page[0].getChildrens()[5].getChildrens()[1].valueOf()),this._e_qps=echarts.init(this._page[0].getChildrens()[1].getChildrens()[1].valueOf()),this._e_hits.setOption(this._e_options),this._e_bytes.setOption(this._e_options),this._e_hits.setOption({xAxis:{data:this._hourly}}),this._e_bytes.setOption({xAxis:{data:this._hourly}}),this._e_daily_hits.setOption(this._e_options),this._e_daily_bytes.setOption(this._e_options),this._e_qps.setOption({color:"#0fc6c2",tooltip:{trigger:"axis",formatter:t=>'
'+t[0].name+'
QPSAvg: '+t[0].data.value+" total: "+e.sum(...t[0].data.raw)+'
'},stateAnimation:{duration:300,easing:"cubicOut"},xAxis:{type:"category",show:!1},yAxis:{show:!1,type:"value"},grid:{top:10,bottom:10,right:0,left:0,show:!1,z:0,containLabel:!1,backgroundColor:"rgba(0,0,0,0)",borderWidth:1,borderColor:"#ccc"},series:[{type:"bar",barGap:"0",barMinHeight:4,itemStyle:{borderRadius:[2,2,0,0]},z:2,backgroundStyle:{color:"rgba(180, 180, 180, 0.2)",borderColor:null,borderWidth:0,borderType:"solid",borderRadius:0,shadowBlur:0,shadowColor:null,shadowOffsetX:0,shadowOffsetY:0},select:{itemStyle:{borderColor:"#212121"}}}]}),this._e_set_days(),setTimeout((()=>{this._page[0].update()}),100)}updateRuntime(){this._page[0].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(this._format_time(this.runtime,!0))}updateStatus(e){this._page[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(e)}_e_format_time(e){const t=new Date(e);return t.getHours().toString().padStart(2,0)+":"+t.getMinutes().toString().padStart(2,0)+":"+t.getSeconds().toString().padStart(2,0)}_e_set_days(){let t=Number.parseInt(e.getTime()/86400)-30,i=Array.from({length:31},((e,i)=>this._format_date(864e5*(t+i))));this._e_daily_hits.setOption({xAxis:{data:i}}),this._e_daily_bytes.setOption({xAxis:{data:i}})}disconnect(){clearInterval(this._runtimeTimer),clearInterval(this._qpsTimer)}connect(e){e.push(...this._page)}_e_templates(e,t=null){const i='
{name}{value}
';var a="";for(const r of e)a+=i.replace("{color}",r.color).replace("{name}",r.name).replace("{value}",t?t(r.value):r.value);return`
${e[0].name}
${a}
`}_ws_message(t,i){if("runtime"==t&&(this.runtime=i,this.updateRuntime()),"dashboard"==t){{const t=i.hourly;let a=Math.max(...t.map((e=>e._hour))),r=0,s=0;{const i=Array.from({length:a},((e,t)=>0)),s=Array.from({length:a},((e,t)=>0));for(const e of t)i[e._hour]=e.hits,s[e._hour]=e.cache_hits,a=Math.max(a,e._hour);this._e_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...i,...s)},series:[{name:"I/O访问数",data:i,type:"line",smooth:!0},{name:"缓存访问数",data:s,type:"line",smooth:!0}]}),r=e.sum(...i,...s)}{const i=Array.from({length:a},((e,t)=>0)),r=Array.from({length:a},((e,t)=>0));for(const e of t)i[e._hour]=e.bytes,r[e._hour]=e.cache_bytes;this._e_bytes.setOption({tooltip:{formatter:e=>this._e_templates(e,(e=>this._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...i,...r),axisLabel:{formatter:e=>this._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:i,type:"line",smooth:!0},{name:"缓存访问文件大小",data:r,type:"line",smooth:!0}]}),s=e.sum(...i,...r)}this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[1].setText(this._format_number_unit(r)),this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].getChildrens()[1].setText(this._format_bytes(s))}{const t=i.days;let a=0,r=0;{const i=Array.from({length:30},((e,t)=>0)),r=Array.from({length:30},((e,t)=>0));for(const e of t)i[e._day]=e.hits,r[e._day]=e.cache_hits;this._e_daily_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...i,...r)},series:[{name:"I/O访问数",data:i,type:"line",smooth:!0},{name:"缓存访问数",data:r,type:"line",smooth:!0}]}),a=e.sum(...i,...r)}{const i=Array.from({length:30},((e,t)=>0)),a=Array.from({length:30},((e,t)=>0));for(const e of t)i[e._day]=e.bytes,a[e._day]=e.cache_bytes;this._e_daily_bytes.setOption({tooltip:{formatter:e=>this._e_templates(e,(e=>this._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...i,...a),axisLabel:{formatter:e=>this._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:i,type:"line",smooth:!0},{name:"缓存访问文件大小",data:a,type:"line",smooth:!0}]}),r=e.sum(...i,...a)}this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[2].getChildrens()[1].setText(this._format_number_unit(a)),this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[3].getChildrens()[1].setText(this._format_bytes(r))}}if("qps"==t){const t=parseInt(e.getTimestamp()/1e3),s=(t%5!=0?5:0)-t%5+t,n=[];var a=[],r=[];for(let t=s-300;t<=s;t++){let s=i.hasOwnProperty(t)?i[t]:0;a.push(s),t%5==0&&(n.push({value:e.sum(...a)/a.length,raw:a}),a=[],r.push(this._e_format_time(1e3*t)))}this._page[0].valueOf().children[1].children[0].children[0].innerText=e.sum(...e.collectionSingleList(n.map((e=>[...e.raw])))),this._e_qps.setOption({xAxis:{data:r},series:[{data:n}]})}"status"==t&&this.updateStatus(i)}_format_number(e,t=null){return 0==e||(t=t||Math.min(Number.parseInt(Math.floor(Math.log(e)/Math.log(1e3))),this._unit_number.length))<=0?`${e}${this._unit_number[0]}`:`${(e/=1024**t).toFixed(1)}${this._unit_number[t]}`}_format_number_unit(e){var t=(e+"").split("."),i=t[0],a=t.length>=2?"."+t.slice(1).join("."):"";return i.toString().replace(/\B(?=(\d{3})+(?!\d))/g,", ")+a}_format_date(e){const t=new Date(e);return`${t.getFullYear().toString().padStart(4,"0")}-${(t.getMonth()+1).toString().padStart(2,"0")}-${t.getDate().toString().padStart(2,"0")}`}_format_time(t,i=!1){if(null==t)return"-";let a=Number.parseInt(t);return i&&(a=Number.parseInt(e.getTime()-a)),`${parseInt(a/60/60/24).toString().padStart(2,"0")} 天 ${parseInt(a/60/60%24).toString().padStart(2,"0")} 小时 ${parseInt(a/60%60).toString().padStart(2,"0")} 分钟 ${parseInt(a%60).toString().padStart(2,"0")} 秒`}_format_bytes(e,t=null){return 0==e||(t=t||Math.min(Number.parseInt(Math.floor(Math.log(e)/Math.log(1024))),this._unit_bytes.length))<=0?`${e.toFixed(2)}${this._unit_bytes[0]}`:`${(e/=1024**t).toFixed(2)}${this._unit_bytes[t]}`}});const y=()=>{h(),p()};i.append(e.createElement("h3").setText("Python OpenBMCLAPI Dashboard")),n.append(e.createElement("p").append(e.createElement("a").setAttribute("href","mailto:administrator@ttb-network.top").setText("TTB Network")," - ",e.VERSION)),r.event("click",(()=>{a.toggle("hide"),window.dispatchEvent(new Event("resize"))})),t.append(i,e.createElement("div").class("container").append(a.append(r,s,n),o)),window.addEventListener("resize",y),window.addEventListener("popstate",g),document.body.prepend(d.valueOf(),t.valueOf()),h(),e.set_styles({"body,ol,ul,h1,h2,h3,h4,h5,h6,p,th,td,dl,dd,form,fieldset,legend,input,textarea,select":"margin:0;padding:0",body:"font:12px;background:#fff;-webkit-text-size-adjust:100%",a:"color:#172c45;text-decoration:none",em:"font-style:normal",li:"list-style:none",img:"border:0;vertical-align:middle",table:"border-collapse:collapse;border-spacing:0",p:"word-wrap:break-word",":root":["--r-main-background-color: #F6F7F9","--r-background-color: #191919","--r-main-font-size: 42px","--r-main-color: #fff","--r-block-margin: 20px","--r-heading-margin: 0 0 20px 0","--r-heading-font: Source Sans Pro, Helvetica, sans-serif","--r-heading-color: #fff","--r-heading-line-height: 1.2","--r-heading-letter-spacing: normal","--r-heading-text-transform: uppercase","--r-heading-text-shadow: none","--r-heading-font-weight: 600","--r-heading1-text-shadow: none","--r-heading1-size: 2.5em","--r-heading2-size: 1.6em","--r-heading3-size: 1.3em","--r-heading4-size: 1em","--r-code-font: monospace","--r-link-color: #42affa","--r-link-color-dark: #068de9","--r-link-color-hover: #8dcffc","--r-selection-background-color: rgba(66, 175, 250, .75)","--r-selection-color: #fff","--r-overlay-element-bg-color: 240, 240, 240","--r-overlay-element-fg-color: 0, 0, 0","--r-ligting-color: rgb(15, 198, 194);"],".root .left":["position: fixed","min-height: calc(100vh - 72px)","max-height: calc(100vh - 72px)","min-width: 48px","max-width: 184px","margin-top: 16px","width: 256px","padding: 8px","padding-top: 0","background: var(--r-main-background-color)","transition: transform 200ms linear 0s;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .left .content":["overflow: auto","width: 95%"],".root .left.hide":["transform: translateX(-100%);"],".root .left .button":["cursor: pointer;","border-radius: 8px;","margin-bottom: 8px","padding: 4px","padding-left: 8px","transition: color 200ms linear 0s;"],".root .left .arrow-background":["position: absolute","background: var(--r-main-background-color)","width: 20px","height: 20px","left: 194px","margin-top: -16px","cursor: pointer"],".root .left .arrow":["width: 100%","height: 100%",'background-image: url("data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgc3R5bGU9IndpZHRoOiAxZW07aGVpZ2h0OiAxZW07dmVydGljYWwtYWxpZ246IG1pZGRsZTtmaWxsOiBjdXJyZW50Q29sb3I7b3ZlcmZsb3c6IGhpZGRlbjsiIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwLWlkPSI3NTUiPjxwYXRoIGQ9Ik0zMjUuMDQ4IDkzLjUxMWwtNjAuMDMwIDU5LjQzNSAzNTcuMTgxIDM1OS42MzEtMzYwLjE4NCAzNTYuNjAzIDU5LjUyMiA1OS45MyA0MjAuMjA3LTQxNi4wNDN6IiBmaWxsPSIjODQ4NDg0IiBwLWlkPSI3NTYiPjwvcGF0aD48L3N2Zz4=");'],".root .container .left.hide .arrow-background .arrow":["transform: rotate(0deg);"],".root .container .left .arrow-background .arrow":["transform: rotate(180deg);","transition: transform 100ms linear 0s;"],".root .left .button:hover":["color: var(--r-ligting-color)"],".root .left .button.selected":["background: var(--r-ligting-color)","box-shadow: rgba(15, 198, 194, 0.2) 0px 10px 25px 0px;","color: white"],".root .left .side":["margin-left: 8px"],".root .left .sidebutton":["padding: 2px","margin-bottom: 8px","cursor: pointer;","color: rgba(0, 0, 0, 0.5);","transition: color 200ms linear 0s;"],".root .left .sidebutton:hover":["color: var(--r-link-color-hover)"],".root .left .sidebutton.selected":["color: black","font-weight: bold"],".root .left .sidebutton:hover .cycle":["background: var(--r-link-color-hover)"],".root .left .sidebutton.selected .cycle":["width: 8px;","height: 8px;","background-color: rgb(15, 198, 194);","margin-right: 6px","margin-left: 2px","border-radius: 50%;"],".root .left .sidebutton .cycle":["width: 4px;","height: 4px;","margin: 4px","margin-right: 8px","background-color: rgba(0, 0, 0, 0.5);","transition: background-color 200ms linear 0s;","border-radius: 50%;"],".root .header":["position: fixed","height: 40px","min-height: 40px","min-width: 100vw","background: var(--r-main-background-color)","z-index: 1","padding: 8px","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .container":["position: relative;","top: 56px;"],".root .container .right":["padding-top: 16px","margin-left: 216px","transition: width 200ms linear 0s;","min-width: calc(100vw - 232px)","min-height: calc(100vh - 72px)"],".root .container .left.hide ~ .right":["margin-left: 0","min-width: 100vw"],".root .container .right .panel":["background-color: rgb(255, 255, 255);","color: rgb(0, 0, 0);","transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;","border-radius: 4px;","background-image: none;","padding: 24px;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;","margin: 16px;"],".panel.info-4":["display: flex","flex-warp: warp"],".panel.info-4 div":["width: 25%"],".panel.info-2":["display: flex","flex-warp: warp"],".panel.info-2 div":["width: 50%"],".panel .title":["display: flex","margin: 0px 0px 6px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.5);","font-size: 14px;"],".panel .value":["margin: 0px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.7);","font-size: 24px;"],".root .container .left.hide~.right":["margin-left: 32px","min-width: calc(100vw - 48px)"],".root .left .copyright":["position: fixed;","bottom: 2px"],".qps .icon":["width: 14px","height: 14px"],".qps":["display: flex","align-items: center"],".progress":["position: absolute;","z-index: 2","width: 0","height: 2px","background: var(--r-ligting-color)","transition: width 200ms linear 0s;"],body:["background-color: var(--r-main-background-color)"]}),g(),y()})(); \ No newline at end of file +(()=>{const e=new TTB,t=e.createElement("div").class("root"),i=e.createFlex().class("header").style("align-items","center"),a=e.createElement("div").class("left"),r=e.createElement("div").class("arrow-background").append(e.createElement("div").class("arrow")),s=e.createElement("div").class("content"),n=e.createElement("div").class("copyright"),o=e.createElement("div").class("right"),l={},d=e.createElement("div").class("progress"),c=e=>{d.setStyle("width",100*e+"%"),100*e>=99&&setTimeout((()=>d.setStyle("width",0)),250)},h=()=>{s.clear();for(const t in l){const i=l[t],a=!!i.children,r=e.createFlex().class("button").id("left-list-"+t).append(e.createElement("p").setText(i.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+i.children[0].key:"")}));if(s.append(r),a){const r=e.createElement("div").style("display: none").class("side").id("left-list-"+t+"-sub");for(const s of i.children)r.append(e.createFlex().class("sidebutton").id("left-list-"+t+"-sub-"+s.key).append(e.createElement("div").class("cycle"),e.createElement("p").setText(s.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+s.key:"")})));s.append(r)}}},p=()=>{const t=e.getURLKey()||Object.keys(l)[0];for(const i of Object.keys(l))if(u!=t?i==t?(document.getElementById("left-list-"+i).classList.add("selected"),x=""):document.getElementById("left-list-"+i).classList.remove("selected"):u==i&&document.getElementById("left-list-"+i).classList.add("selected"),document.getElementById("left-list-"+i+"-sub")){document.getElementById("left-list-"+i+"-sub").style.display=i==t?"block":"none";const a=e.getURLKeyParams().key||Object.keys(Object.values(l)[0])[1];for(const e of l[i].children.map((e=>e.key)))e==a?(document.getElementById("left-list-"+i+"-sub-"+e).classList.add("selected"),x=a):document.getElementById("left-list-"+i+"-sub-"+e).classList.remove("selected")}},g=()=>{const t=e.getURLKey()||Object.keys(l)[0],i=x;p(),(u!=t||x&&x!=i)&&(u&&x&&x==i&&m(u,i,"disconnect"),m(t,x,"connect")),u=t},m=(t,i,a)=>{const r=(i?l[t].children.filter((e=>e.key==i))[0]:l[t]).core||{};if(f!=(t+=i?"-"+i:"")){if(f in r&&"disconnect"in r)try{r.disconnect()}catch(e){console.log(e)}for(;null!=document.getElementsByClassName("right")[0].firstChild;)document.getElementsByClassName("right")[0].removeChild(document.getElementsByClassName("right")[0].firstChild);f=t}if(a in r)try{document.getElementsByClassName("right")[0].style.display="none",page=[],"connect"==a&&"page"in r&&(c(.7),"init"in r&&r.init(),c(.8),page=r.page()||[]),c(.9),r[a](page),null!=page&&document.getElementsByClassName("right")[0].append(e.createElement("div").id("module-"+t).append(...Array.isArray(page)?page:[page]).valueOf()),document.getElementsByClassName("right")[0].style.display="block",c(1)}catch(e){console.log(e)}else c(1)};let u="",x="",f="";const b=new class{constructor(){this.websocket=e.websocket({url:"ws"+window.location.protocol.slice(4)+"//"+window.location.host+window.location.pathname,open:()=>{this.send("runtime",null),this.send("dashboard",null),this.send("qps"),this.send("status")},message:e=>{let t=new FileReader;t.onload=()=>{let e=t.result;const i=new DataInputStream(e);this.message(i.readString(),this._deserializeData(i))},t.readAsArrayBuffer(e.data)},close:()=>{this.message("runtime",null)}})}send(e,t){const i=new DataOutputStream;i.writeString(e),i.write(this._serializeData(t)),b.websocket.send(i)}message(e,t){((e,...t)=>{var i=f.split("-",1),a=i[0],r=i[1];const s=(r?l[a].children.filter((e=>e.key==r))[0]:l[a]).core||{};e in s&&s[e](...t)})("_ws_message",e,t)}_deserializeData(e){const t=e.readVarInt();switch(t){case 0:return e.readString();case 1:return e.readBoolean();case 2:return parseFloat(e.readString());case 3:return parseInt(e.readString());case 4:{const t=e.readVarInt(),i=[];for(let a=0;a{if(e.includes(".")){const[r,s]=[e.slice(0,e.indexOf(".")),e.slice(e.indexOf(".")+1)];l[r]||(l[r]={icon:t,children:[],text:"",core:a}),"children"in l[r]||(l[r].children=[]),l[r].children.push({key:s,text:i,core:a})}else l[e]={key:e,icon:t,text:i,core:a}})("dashboard","","数据统计",new class{constructor(){this._page=[e.createFlex().append(e.createElement("div").append(e.createElement("div").class("panel").class("info-2").append(e.createElement("div").append(e.createElement("p").class("title").setText("运行时间"),e.createElement("p").class("value").setText(this._format_time(this.runtime))),e.createElement("div").append(e.createElement("p").class("title").setText("当前节点状态"),e.createElement("p").class("value").setText("-"))),e.createElement("div").class("panel").class("info-4").append(e.createElement("div").append(e.createElement("p").class("title").setText("今日下载量"),e.createElement("p").class("value").setText("0")),e.createElement("div").append(e.createElement("p").class("title").setText("今日流量"),e.createElement("p").class("value").setText("0")),e.createElement("div").append(e.createElement("p").class("title").setText("30天下载量"),e.createElement("p").class("value").setText("0")),e.createElement("div").append(e.createElement("p").class("title").setText("30天流量"),e.createElement("p").class("value").setText("0")))),e.createElement("div").class("panel").append(e.createElement("p").class("title").append("QPS - 五分钟内",e.createElement("div").style("margin-left: 8px; color: rgba(0, 0, 0, 0.7);").setText("0")),e.createElement("div").style("height: 84%; min-height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每小时访问文件数"),e.createElement("div").style("height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每小时访问文件大小"),e.createElement("div").style("height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每天访问文件数"),e.createElement("div").style("height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每天访问文件大小"),e.createElement("div").style("height: 128px"))).minWidth("324px").child(2).minWidth(512)],this._page[0].event("resize",(()=>{this._e_hits.resize(),this._e_bytes.resize(),this._e_daily_hits.resize(),this._e_daily_bytes.resize(),this._e_qps.resize()})),this.runtime=null,this._hourly=Array.from({length:24},((e,t)=>t+" 时")),this._runtimeTimer=setInterval((()=>this.updateRuntime()),1e3),this._dashboardTimer=setInterval((()=>{b.send("dashboard",null)}),1e4),setTimeout((()=>{this._qpsTimer=setInterval((()=>{b.send("qps")}),5e3)}),5-e.getTime()%5),this._e_options={tooltip:{trigger:"axis"},grid:{left:"3%",right:"4%",bottom:"3%",top:"20%",containLabel:!0},xAxis:{type:"category"},yAxis:{type:"value",min:1,max:10},series:[]},this._unit_bytes=["B","KB","MB","GB","TB","PB","EB"],this._unit_number=["","k","M","G","T","P","E"],this._e_hits=echarts.init(this._page[0].getChildrens()[2].getChildrens()[1].valueOf()),this._e_bytes=echarts.init(this._page[0].getChildrens()[3].getChildrens()[1].valueOf()),this._e_daily_hits=echarts.init(this._page[0].getChildrens()[4].getChildrens()[1].valueOf()),this._e_daily_bytes=echarts.init(this._page[0].getChildrens()[5].getChildrens()[1].valueOf()),this._e_qps=echarts.init(this._page[0].getChildrens()[1].getChildrens()[1].valueOf()),this._e_hits.setOption(this._e_options),this._e_bytes.setOption(this._e_options),this._e_hits.setOption({xAxis:{data:this._hourly}}),this._e_bytes.setOption({xAxis:{data:this._hourly}}),this._e_daily_hits.setOption(this._e_options),this._e_daily_bytes.setOption(this._e_options),this._e_qps.setOption({color:"#0fc6c2",tooltip:{trigger:"axis",formatter:t=>'
'+t[0].name+'
QPSAvg: '+t[0].data.value+" total: "+e.sum(...t[0].data.raw)+'
'},stateAnimation:{duration:300,easing:"cubicOut"},xAxis:{type:"category",show:!1},yAxis:{show:!1,type:"value"},grid:{top:10,bottom:10,right:0,left:0,show:!1,z:0,containLabel:!1,backgroundColor:"rgba(0,0,0,0)",borderWidth:1,borderColor:"#ccc"},series:[{type:"bar",barGap:"0",barMinHeight:4,itemStyle:{borderRadius:[2,2,0,0]},z:2,backgroundStyle:{color:"rgba(180, 180, 180, 0.2)",borderColor:null,borderWidth:0,borderType:"solid",borderRadius:0,shadowBlur:0,shadowColor:null,shadowOffsetX:0,shadowOffsetY:0},select:{itemStyle:{borderColor:"#212121"}}}]}),this._e_set_days(),setTimeout((()=>{this._page[0].update()}),100)}updateRuntime(){this._page[0].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(this._format_time(this.runtime,!0))}updateStatus(e){this._page[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(e)}_e_format_time(e){const t=new Date(e);return t.getHours().toString().padStart(2,0)+":"+t.getMinutes().toString().padStart(2,0)+":"+t.getSeconds().toString().padStart(2,0)}_e_set_days(){let t=Number.parseInt(e.getTime()/86400)-30,i=Array.from({length:31},((e,i)=>this._format_date(864e5*(t+i))));this._e_daily_hits.setOption({xAxis:{data:i}}),this._e_daily_bytes.setOption({xAxis:{data:i}})}disconnect(){clearInterval(this._runtimeTimer),clearInterval(this._qpsTimer)}connect(e){e.push(...this._page)}_e_templates(e,t=null){const i='
{name}{value}
';var a="";for(const r of e)a+=i.replace("{color}",r.color).replace("{name}",r.name).replace("{value}",t?t(r.value):r.value);return`
${e[0].name}
${a}
`}_ws_message(t,i){if("runtime"==t&&(this.runtime=i,this.updateRuntime()),"dashboard"==t){{const t=i.hourly;let a=Math.max(...t.map((e=>e._hour))),r=0,s=0;{const i=Array.from({length:a},((e,t)=>0)),s=Array.from({length:a},((e,t)=>0));for(const e of t)i[e._hour]=e.hits,s[e._hour]=e.cache_hits,a=Math.max(a,e._hour);this._e_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...i,...s)},series:[{name:"I/O访问数",data:i,type:"line",smooth:!0},{name:"缓存访问数",data:s,type:"line",smooth:!0}]}),r=e.sum(...i,...s)}{const i=Array.from({length:a},((e,t)=>0)),r=Array.from({length:a},((e,t)=>0));for(const e of t)i[e._hour]=e.bytes,r[e._hour]=e.cache_bytes;this._e_bytes.setOption({tooltip:{formatter:e=>this._e_templates(e,(e=>this._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...i,...r),axisLabel:{formatter:e=>this._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:i,type:"line",smooth:!0},{name:"缓存访问文件大小",data:r,type:"line",smooth:!0}]}),s=e.sum(...i,...r)}this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[1].setText(this._format_number_unit(r)),this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].getChildrens()[1].setText(this._format_bytes(s))}{const t=i.days;let a=0,r=0;{const i=Array.from({length:30},((e,t)=>0)),r=Array.from({length:30},((e,t)=>0));for(const e of t)i[e._day]=e.hits,r[e._day]=e.cache_hits;this._e_daily_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...i,...r)},series:[{name:"I/O访问数",data:i,type:"line",smooth:!0},{name:"缓存访问数",data:r,type:"line",smooth:!0}]}),a=e.sum(...i,...r)}{const i=Array.from({length:30},((e,t)=>0)),a=Array.from({length:30},((e,t)=>0));for(const e of t)i[e._day]=e.bytes,a[e._day]=e.cache_bytes;this._e_daily_bytes.setOption({tooltip:{formatter:e=>this._e_templates(e,(e=>this._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...i,...a),axisLabel:{formatter:e=>this._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:i,type:"line",smooth:!0},{name:"缓存访问文件大小",data:a,type:"line",smooth:!0}]}),r=e.sum(...i,...a)}this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[2].getChildrens()[1].setText(this._format_number_unit(a)),this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[3].getChildrens()[1].setText(this._format_bytes(r))}}if("qps"==t){const t=parseInt(e.getTimestamp()/1e3),s=(t%5!=0?5:0)-t%5+t,n=[];var a=[],r=[];for(let t=s-300;t<=s;t++){let s=i.hasOwnProperty(t)?i[t]:0;a.push(s),t%5==0&&(n.push({value:e.sum(...a)/a.length,raw:a}),a=[],r.push(this._e_format_time(1e3*t)))}this._page[0].valueOf().children[1].children[0].children[0].innerText=e.sum(...e.collectionSingleList(n.map((e=>[...e.raw])))),this._e_qps.setOption({xAxis:{data:r},series:[{data:n}]})}"status"==t&&this.updateStatus(i)}_format_number(e,t=null){return 0==e||(t=t||Math.min(Number.parseInt(Math.floor(Math.log(e)/Math.log(1e3))),this._unit_number.length))<=0?`${e}${this._unit_number[0]}`:`${(e/=1024**t).toFixed(1)}${this._unit_number[t]}`}_format_number_unit(e){var t=(e+"").split("."),i=t[0],a=t.length>=2?"."+t.slice(1).join("."):"";return i.toString().replace(/\B(?=(\d{3})+(?!\d))/g,", ")+a}_format_date(e){const t=new Date(e);return`${t.getFullYear().toString().padStart(4,"0")}-${(t.getMonth()+1).toString().padStart(2,"0")}-${t.getDate().toString().padStart(2,"0")}`}_format_time(t,i=!1){if(null==t)return"-";let a=Number.parseInt(t);return i&&(a=Number.parseInt(e.getTime()-a)),`${parseInt(a/60/60/24).toString().padStart(2,"0")} 天 ${parseInt(a/60/60%24).toString().padStart(2,"0")} 小时 ${parseInt(a/60%60).toString().padStart(2,"0")} 分钟 ${parseInt(a%60).toString().padStart(2,"0")} 秒`}_format_bytes(e,t=null){return 0==e||(t=t||Math.min(Number.parseInt(Math.floor(Math.log(e)/Math.log(1024))),this._unit_bytes.length))<=0?`${e.toFixed(2)}${this._unit_bytes[0]}`:`${(e/=1024**t).toFixed(2)}${this._unit_bytes[t]}`}});const y=()=>{h(),p()};i.append(e.createElement("h3").setText("Python OpenBMCLAPI Dashboard")),n.append(e.createElement("p").append(e.createElement("a").setAttribute("href","mailto:administrator@ttb-network.top").setText("TTB Network")," - ",e.VERSION)),r.event("click",(()=>{a.toggle("hide"),window.dispatchEvent(new Event("resize"))})),t.append(i,e.createElement("div").class("container").append(a.append(r,s,n),o)),window.addEventListener("resize",y),window.addEventListener("popstate",g),document.body.prepend(d.valueOf(),t.valueOf()),h(),e.set_styles({"body,ol,ul,h1,h2,h3,h4,h5,h6,p,th,td,dl,dd,form,fieldset,legend,input,textarea,select":"margin:0;padding:0",body:"font:12px;background:#fff;-webkit-text-size-adjust:100%",a:"color:#172c45;text-decoration:none",em:"font-style:normal",li:"list-style:none",img:"border:0;vertical-align:middle",table:"border-collapse:collapse;border-spacing:0",p:"word-wrap:break-word",":root":["--r-main-background-color: #F6F7F9","--r-background-color: #191919","--r-main-font-size: 42px","--r-main-color: #fff","--r-block-margin: 20px","--r-heading-margin: 0 0 20px 0","--r-heading-font: Source Sans Pro, Helvetica, sans-serif","--r-heading-color: #fff","--r-heading-line-height: 1.2","--r-heading-letter-spacing: normal","--r-heading-text-transform: uppercase","--r-heading-text-shadow: none","--r-heading-font-weight: 600","--r-heading1-text-shadow: none","--r-heading1-size: 2.5em","--r-heading2-size: 1.6em","--r-heading3-size: 1.3em","--r-heading4-size: 1em","--r-code-font: monospace","--r-link-color: #42affa","--r-link-color-dark: #068de9","--r-link-color-hover: #8dcffc","--r-selection-background-color: rgba(66, 175, 250, .75)","--r-selection-color: #fff","--r-overlay-element-bg-color: 240, 240, 240","--r-overlay-element-fg-color: 0, 0, 0","--r-ligting-color: rgb(15, 198, 194);"],".root .left":["position: fixed","min-height: calc(100vh - 72px)","max-height: calc(100vh - 72px)","min-width: 48px","max-width: 184px","margin-top: 16px","width: 256px","padding: 8px","padding-top: 0","background: var(--r-main-background-color)","transition: transform 200ms linear 0s;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .left .content":["overflow: auto","width: 95%"],".root .left.hide":["transform: translateX(-100%);"],".root .left .button":["cursor: pointer;","border-radius: 8px;","margin-bottom: 8px","padding: 4px","padding-left: 8px","transition: color 200ms linear 0s;"],".root .left .arrow-background":["position: absolute","background: var(--r-main-background-color)","width: 20px","height: 20px","left: 194px","margin-top: -16px","cursor: pointer"],".root .left .arrow":["width: 100%","height: 100%",'background-image: url("data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgc3R5bGU9IndpZHRoOiAxZW07aGVpZ2h0OiAxZW07dmVydGljYWwtYWxpZ246IG1pZGRsZTtmaWxsOiBjdXJyZW50Q29sb3I7b3ZlcmZsb3c6IGhpZGRlbjsiIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwLWlkPSI3NTUiPjxwYXRoIGQ9Ik0zMjUuMDQ4IDkzLjUxMWwtNjAuMDMwIDU5LjQzNSAzNTcuMTgxIDM1OS42MzEtMzYwLjE4NCAzNTYuNjAzIDU5LjUyMiA1OS45MyA0MjAuMjA3LTQxNi4wNDN6IiBmaWxsPSIjODQ4NDg0IiBwLWlkPSI3NTYiPjwvcGF0aD48L3N2Zz4=");'],".root .container .left.hide .arrow-background .arrow":["transform: rotate(0deg);"],".root .container .left .arrow-background .arrow":["transform: rotate(180deg);","transition: transform 100ms linear 0s;"],".root .left .button:hover":["color: var(--r-ligting-color)"],".root .left .button.selected":["background: var(--r-ligting-color)","box-shadow: rgba(15, 198, 194, 0.2) 0px 10px 25px 0px;","color: white"],".root .left .side":["margin-left: 8px"],".root .left .sidebutton":["padding: 2px","margin-bottom: 8px","cursor: pointer;","color: rgba(0, 0, 0, 0.5);","transition: color 200ms linear 0s;"],".root .left .sidebutton:hover":["color: var(--r-link-color-hover)"],".root .left .sidebutton.selected":["color: black","font-weight: bold"],".root .left .sidebutton:hover .cycle":["background: var(--r-link-color-hover)"],".root .left .sidebutton.selected .cycle":["width: 8px;","height: 8px;","background-color: rgb(15, 198, 194);","margin-right: 6px","margin-left: 2px","border-radius: 50%;"],".root .left .sidebutton .cycle":["width: 4px;","height: 4px;","margin: 4px","margin-right: 8px","background-color: rgba(0, 0, 0, 0.5);","transition: background-color 200ms linear 0s;","border-radius: 50%;"],".root .header":["position: fixed","height: 40px","min-height: 40px","min-width: 100vw","background: var(--r-main-background-color)","z-index: 1","padding: 8px","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .container":["position: relative;","top: 56px;"],".root .container .right":["padding-top: 16px","margin-left: 216px","transition: width 200ms linear 0s;","min-width: calc(100vw - 232px)","min-height: calc(100vh - 72px)"],".root .container .left.hide ~ .right":["margin-left: 0","min-width: 100vw"],".root .container .right .panel":["background-color: rgb(255, 255, 255);","color: rgb(0, 0, 0);","transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;","border-radius: 4px;","background-image: none;","padding: 24px;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;","margin: 16px;"],".panel.info-4":["display: flex","flex-warp: warp"],".panel.info-4 div":["width: 25%"],".panel.info-2":["display: flex","flex-warp: warp"],".panel.info-2 div":["width: 50%"],".panel .title":["display: flex","margin: 0px 0px 6px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.5);","font-size: 14px;"],".panel .value":["margin: 0px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.7);","font-size: 24px;"],".root .container .left.hide~.right":["margin-left: 32px","min-width: calc(100vw - 48px)"],".root .left .copyright":["position: fixed;","bottom: 2px"],".qps .icon":["width: 14px","height: 14px"],".qps":["display: flex","align-items: center"],".progress":["position: absolute;","z-index: 2","width: 0","height: 2px","background: var(--r-ligting-color)","transition: width 200ms linear 0s;"],body:["background-color: var(--r-main-background-color)"]}),g(),y()})(); \ No newline at end of file From dd55058543bf584060673db29d79a2356d4ea2e7 Mon Sep 17 00:00:00 2001 From: tianxiu2b2t Date: Sat, 23 Mar 2024 21:45:23 +0800 Subject: [PATCH 3/9] Fix somethings --- core/__init__.py | 5 +++-- core/cluster.py | 33 ++++++++++++++++++++------------- core/unit.py | 13 +++++++++++-- core/utils.py | 4 ++++ 4 files changed, 38 insertions(+), 17 deletions(-) diff --git a/core/__init__.py b/core/__init__.py index 7e4f350..fc09c45 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -73,8 +73,9 @@ def disconnect(self, client: ProxyClient): return self._tables.remove(client) def get_origin_from_ip(self, ip: tuple[str, int]): + # ip is connected client for target in self._tables: - if target.target.get_address() == ip: + if target.target.get_sock_address() == ip: return target.origin.get_address() return None @@ -107,7 +108,7 @@ async def _handle_process(client: Client, ssl: bool = False): await client.writer.drain() break if protocol == Protocol.Unknown and not ssl and ssl_server: - target = Client(*(await asyncio.open_connection("127.0.0.1", ssl_server.sockets[0].getsockname()[1]))) + target = Client(*(await asyncio.open_connection("127.0.0.1", ssl_server.sockets[0].getsockname()[1])), peername=client.get_address()) proxying = True await proxy.connect(client, target, header) break diff --git a/core/cluster.py b/core/cluster.py index 02686af..1ff6472 100644 --- a/core/cluster.py +++ b/core/cluster.py @@ -54,6 +54,7 @@ async def fetchToken(self): async with aiohttp.ClientSession( headers={"User-Agent": USER_AGENT}, base_url=BASE_URL ) as session: + logger.info("Fetching token") try: async with session.get( "/openbmclapi-agent/challenge", params={"clusterId": CLUSTER_ID} @@ -80,15 +81,14 @@ async def fetchToken(self): Timer.delay( self.fetchToken, delay=float(content["ttl"]) / 1000.0 - 600 ) + logger.info("Fetched token") except aiohttp.ClientError as e: logger.error(f"Error fetching token: {e}.") async def getToken(self) -> str: if not self.token: - logger.info("Fetching token") await self.fetchToken() - logger.info("Fetched token") return self.token or "" class ParseFileList: @@ -152,6 +152,8 @@ async def _download(self, pbar: tqdm, session: aiohttp.ClientSession): except: pbar.update(-size) await self.queues.put(file) + if cluster: + await cluster._check_files_sync_status("下载文件中", pbar, unit.format_more_bytes) await session.close() async def _mount_file(self, file: BMCLAPIFile): @@ -166,9 +168,12 @@ async def _mount_file(self, file: BMCLAPIFile): logger.error(traceback.format_exc()) if result != file.size: logger.error(f"Download file error: File {file.hash}({unit.format_bytes(file.size)}) copy to target file error: {file.hash}({unit.format_bytes(result)})") - os.remove(f"./cache/download/{file.hash[:2]}/{file.hash}") + try: + os.remove(f"./cache/download/{file.hash[:2]}/{file.hash}") + except: + ... async def download(self, storages: list['Storage'], miss: list[BMCLAPIFile]): - with tqdm(desc="Downloading files", unit="bytes", unit_divisor=1024, total=sum((file.size for file in miss)), unit_scale=True) as pbar: + with tqdm(desc="Downloading files", unit="b", unit_divisor=1024, total=sum((file.size for file in miss)), unit_scale=True) as pbar: self.storages = storages for file in miss: await self.queues.put(file) @@ -225,7 +230,7 @@ async def copy(self, origin: Path, hash: str): Path(str(self.dir) + f"/{hash[:2]}/{hash}").parent.mkdir(exist_ok=True, parents=True) async with aiofiles.open(str(self.dir) + f"/{hash[:2]}/{hash}", "wb") as w, aiofiles.open(origin, "rb") as r: await w.write(await r.read()) - return r.tell() + return origin.stat().st_size async def write(self, hash: str, io: io.BytesIO) -> int: Path(str(self.dir) + f"/{hash[:2]}/{hash}").parent.mkdir(exist_ok=True, parents=True) async with aiofiles.open(str(self.dir) + f"/{hash[:2]}/{hash}", "wb") as w: @@ -265,9 +270,10 @@ async def clear_cache(self): logger.info(f"Outdate caches: {unit.format_number(len(old_keys))}({unit.format_bytes(old_size)})") async def get_files(self, dir: str) -> list[str]: files = [] - with os.scandir(str(self.dir) + f"/{dir}") as session: - for file in session: - files.append(file.name) + if os.path.exists(str(self.dir) + f"/{dir}"): + with os.scandir(str(self.dir) + f"/{dir}") as session: + for file in session: + files.append(file.name) return files async def removes(self, hashs: list[str]) -> int: success = 0 @@ -279,9 +285,10 @@ async def removes(self, hashs: list[str]) -> int: return success async def get_files_size(self, dir: str) -> int: size = 0 - with os.scandir(str(self.dir) + f"/{dir}") as session: - for file in session: - size += file.stat().st_size + if os.path.exists(str(self.dir) + f"/{dir}"): + with os.scandir(str(self.dir) + f"/{dir}") as session: + for file in session: + size += file.stat().st_size return size class WebDav(Storage): def __init__(self) -> None: @@ -306,10 +313,10 @@ def _message(self, message): def add_storage(self, storage): self.storages.append(storage) - async def _check_files_sync_status(self, text: str, pbar: tqdm): + async def _check_files_sync_status(self, text: str, pbar: tqdm, format = unit.format_numbers): if self.check_files_timer: return - n, total = unit.format_numbers(pbar.n, pbar.total) + n, total = format(pbar.n, pbar.total) await set_status(f"{text} ({n}/{total})") async def check_files(self): diff --git a/core/unit.py b/core/unit.py index 5f2735c..5d9eb9e 100644 --- a/core/unit.py +++ b/core/unit.py @@ -12,13 +12,22 @@ def format_bytes(size): size = round(size / (1024 ** i), 2) return f"{size}{_BYTES_[i]}" +def format_more_bytes(*sizes): + size = max(*sizes) + if size == 0: + return (f"{size:.2f}{_NUMBER_[0]}" for size in sizes) + i = min(int(math.floor(math.log(size, 1024))), len(_BYTES_)) + if i != 0: + return (f"{round(size / (1024 ** i), 2)}{_BYTES_[i]}" for size in sizes) + return (f"{size}{_BYTES_[i]}" for size in sizes) + def format_bits(size): return format_bytes(size * 8) def format_number(number): if number == 0: return f"{number}{_NUMBER_[0]}" - i = min(int(math.floor(math.log(number, 1000))), len(_NUMBER_), 1) + i = min(int(math.floor(math.log(number, 1000))), len(_NUMBER_)) if i != 0: number = round(number // (1000 ** i), 2) return f"{number}{_NUMBER_[i]}" @@ -27,7 +36,7 @@ def format_numbers(*numbers): number = max(*numbers) if number == 0: return (f"{number}{_NUMBER_[0]}" for number in numbers) - i = min(int(math.floor(math.log(number, 1000))), len(_NUMBER_), 1) + i = min(int(math.floor(math.log(number, 1000))), len(_NUMBER_)) if i != 0: return (f"{round(number // (1000 ** i), 2)}{_NUMBER_[i]}" for number in numbers) return (f"{number}{_NUMBER_[i]}" for number in numbers) diff --git a/core/utils.py b/core/utils.py index 9f40bc9..69fec9c 100644 --- a/core/utils.py +++ b/core/utils.py @@ -41,6 +41,7 @@ class Client: compressed: bool = False is_ssl: bool = False peername: Optional[tuple[str, int]] = None + sockname: Optional[tuple[str, int]] = None closed: bool = False min_rate: int = Config.get_integer("advnaced.min_rate") min_rate_timestamp: int = Config.get_integer("advanced.min_rate_timestamp") @@ -113,6 +114,9 @@ async def __anext__(self): def get_address(self): return self.peername or self.writer.get_extra_info("peername")[:2] + + def get_sock_address(self): + return self.sockname or self.writer.get_extra_info("sockname")[:2] def get_ip(self): return self.get_address()[0] From 5a01e3e5a77e5c3fd0e96dd71fe83b2b3e1b9c88 Mon Sep 17 00:00:00 2001 From: tianxiu2b2t Date: Sun, 24 Mar 2024 04:15:46 +0800 Subject: [PATCH 4/9] Update Dashboard and fix item display --- bmclapi_dashboard/static/js/index.min.js | 2 +- bmclapi_dashboard/static/js/ttb.min.js | 2 +- core/__init__.py | 6 +++--- core/certificate.py | 13 ++++++------- core/cluster.py | 8 ++++++-- core/dashboard.py | 0 core/system.py | 11 +++++++++++ core/web.py | 4 ++-- 8 files changed, 30 insertions(+), 16 deletions(-) create mode 100644 core/dashboard.py create mode 100644 core/system.py diff --git a/bmclapi_dashboard/static/js/index.min.js b/bmclapi_dashboard/static/js/index.min.js index 19ab37b..3391c74 100644 --- a/bmclapi_dashboard/static/js/index.min.js +++ b/bmclapi_dashboard/static/js/index.min.js @@ -1 +1 @@ -(()=>{const e=new TTB,t=e.createElement("div").class("root"),i=e.createFlex().class("header").style("align-items","center"),a=e.createElement("div").class("left"),r=e.createElement("div").class("arrow-background").append(e.createElement("div").class("arrow")),s=e.createElement("div").class("content"),n=e.createElement("div").class("copyright"),o=e.createElement("div").class("right"),l={},d=e.createElement("div").class("progress"),c=e=>{d.setStyle("width",100*e+"%"),100*e>=99&&setTimeout((()=>d.setStyle("width",0)),250)},h=()=>{s.clear();for(const t in l){const i=l[t],a=!!i.children,r=e.createFlex().class("button").id("left-list-"+t).append(e.createElement("p").setText(i.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+i.children[0].key:"")}));if(s.append(r),a){const r=e.createElement("div").style("display: none").class("side").id("left-list-"+t+"-sub");for(const s of i.children)r.append(e.createFlex().class("sidebutton").id("left-list-"+t+"-sub-"+s.key).append(e.createElement("div").class("cycle"),e.createElement("p").setText(s.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+s.key:"")})));s.append(r)}}},p=()=>{const t=e.getURLKey()||Object.keys(l)[0];for(const i of Object.keys(l))if(u!=t?i==t?(document.getElementById("left-list-"+i).classList.add("selected"),x=""):document.getElementById("left-list-"+i).classList.remove("selected"):u==i&&document.getElementById("left-list-"+i).classList.add("selected"),document.getElementById("left-list-"+i+"-sub")){document.getElementById("left-list-"+i+"-sub").style.display=i==t?"block":"none";const a=e.getURLKeyParams().key||Object.keys(Object.values(l)[0])[1];for(const e of l[i].children.map((e=>e.key)))e==a?(document.getElementById("left-list-"+i+"-sub-"+e).classList.add("selected"),x=a):document.getElementById("left-list-"+i+"-sub-"+e).classList.remove("selected")}},g=()=>{const t=e.getURLKey()||Object.keys(l)[0],i=x;p(),(u!=t||x&&x!=i)&&(u&&x&&x==i&&m(u,i,"disconnect"),m(t,x,"connect")),u=t},m=(t,i,a)=>{const r=(i?l[t].children.filter((e=>e.key==i))[0]:l[t]).core||{};if(f!=(t+=i?"-"+i:"")){if(f in r&&"disconnect"in r)try{r.disconnect()}catch(e){console.log(e)}for(;null!=document.getElementsByClassName("right")[0].firstChild;)document.getElementsByClassName("right")[0].removeChild(document.getElementsByClassName("right")[0].firstChild);f=t}if(a in r)try{document.getElementsByClassName("right")[0].style.display="none",page=[],"connect"==a&&"page"in r&&(c(.7),"init"in r&&r.init(),c(.8),page=r.page()||[]),c(.9),r[a](page),null!=page&&document.getElementsByClassName("right")[0].append(e.createElement("div").id("module-"+t).append(...Array.isArray(page)?page:[page]).valueOf()),document.getElementsByClassName("right")[0].style.display="block",c(1)}catch(e){console.log(e)}else c(1)};let u="",x="",f="";const b=new class{constructor(){this.websocket=e.websocket({url:"ws"+window.location.protocol.slice(4)+"//"+window.location.host+window.location.pathname,open:()=>{this.send("runtime",null),this.send("dashboard",null),this.send("qps"),this.send("status")},message:e=>{let t=new FileReader;t.onload=()=>{let e=t.result;const i=new DataInputStream(e);this.message(i.readString(),this._deserializeData(i))},t.readAsArrayBuffer(e.data)},close:()=>{this.message("runtime",null)}})}send(e,t){const i=new DataOutputStream;i.writeString(e),i.write(this._serializeData(t)),b.websocket.send(i)}message(e,t){((e,...t)=>{var i=f.split("-",1),a=i[0],r=i[1];const s=(r?l[a].children.filter((e=>e.key==r))[0]:l[a]).core||{};e in s&&s[e](...t)})("_ws_message",e,t)}_deserializeData(e){const t=e.readVarInt();switch(t){case 0:return e.readString();case 1:return e.readBoolean();case 2:return parseFloat(e.readString());case 3:return parseInt(e.readString());case 4:{const t=e.readVarInt(),i=[];for(let a=0;a{if(e.includes(".")){const[r,s]=[e.slice(0,e.indexOf(".")),e.slice(e.indexOf(".")+1)];l[r]||(l[r]={icon:t,children:[],text:"",core:a}),"children"in l[r]||(l[r].children=[]),l[r].children.push({key:s,text:i,core:a})}else l[e]={key:e,icon:t,text:i,core:a}})("dashboard","","数据统计",new class{constructor(){this._page=[e.createFlex().append(e.createElement("div").append(e.createElement("div").class("panel").class("info-2").append(e.createElement("div").append(e.createElement("p").class("title").setText("运行时间"),e.createElement("p").class("value").setText(this._format_time(this.runtime))),e.createElement("div").append(e.createElement("p").class("title").setText("当前节点状态"),e.createElement("p").class("value").setText("-"))),e.createElement("div").class("panel").class("info-4").append(e.createElement("div").append(e.createElement("p").class("title").setText("今日下载量"),e.createElement("p").class("value").setText("0")),e.createElement("div").append(e.createElement("p").class("title").setText("今日流量"),e.createElement("p").class("value").setText("0")),e.createElement("div").append(e.createElement("p").class("title").setText("30天下载量"),e.createElement("p").class("value").setText("0")),e.createElement("div").append(e.createElement("p").class("title").setText("30天流量"),e.createElement("p").class("value").setText("0")))),e.createElement("div").class("panel").append(e.createElement("p").class("title").append("QPS - 五分钟内",e.createElement("div").style("margin-left: 8px; color: rgba(0, 0, 0, 0.7);").setText("0")),e.createElement("div").style("height: 84%; min-height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每小时访问文件数"),e.createElement("div").style("height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每小时访问文件大小"),e.createElement("div").style("height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每天访问文件数"),e.createElement("div").style("height: 128px")),e.createElement("div").class("panel").append(e.createElement("p").class("title").setText("每天访问文件大小"),e.createElement("div").style("height: 128px"))).minWidth("324px").child(2).minWidth(512)],this._page[0].event("resize",(()=>{this._e_hits.resize(),this._e_bytes.resize(),this._e_daily_hits.resize(),this._e_daily_bytes.resize(),this._e_qps.resize()})),this.runtime=null,this._hourly=Array.from({length:24},((e,t)=>t+" 时")),this._runtimeTimer=setInterval((()=>this.updateRuntime()),1e3),this._dashboardTimer=setInterval((()=>{b.send("dashboard",null)}),1e4),setTimeout((()=>{this._qpsTimer=setInterval((()=>{b.send("qps")}),5e3)}),5-e.getTime()%5),this._e_options={tooltip:{trigger:"axis"},grid:{left:"3%",right:"4%",bottom:"3%",top:"20%",containLabel:!0},xAxis:{type:"category"},yAxis:{type:"value",min:1,max:10},series:[]},this._unit_bytes=["B","KB","MB","GB","TB","PB","EB"],this._unit_number=["","k","M","G","T","P","E"],this._e_hits=echarts.init(this._page[0].getChildrens()[2].getChildrens()[1].valueOf()),this._e_bytes=echarts.init(this._page[0].getChildrens()[3].getChildrens()[1].valueOf()),this._e_daily_hits=echarts.init(this._page[0].getChildrens()[4].getChildrens()[1].valueOf()),this._e_daily_bytes=echarts.init(this._page[0].getChildrens()[5].getChildrens()[1].valueOf()),this._e_qps=echarts.init(this._page[0].getChildrens()[1].getChildrens()[1].valueOf()),this._e_hits.setOption(this._e_options),this._e_bytes.setOption(this._e_options),this._e_hits.setOption({xAxis:{data:this._hourly}}),this._e_bytes.setOption({xAxis:{data:this._hourly}}),this._e_daily_hits.setOption(this._e_options),this._e_daily_bytes.setOption(this._e_options),this._e_qps.setOption({color:"#0fc6c2",tooltip:{trigger:"axis",formatter:t=>'
'+t[0].name+'
QPSAvg: '+t[0].data.value+" total: "+e.sum(...t[0].data.raw)+'
'},stateAnimation:{duration:300,easing:"cubicOut"},xAxis:{type:"category",show:!1},yAxis:{show:!1,type:"value"},grid:{top:10,bottom:10,right:0,left:0,show:!1,z:0,containLabel:!1,backgroundColor:"rgba(0,0,0,0)",borderWidth:1,borderColor:"#ccc"},series:[{type:"bar",barGap:"0",barMinHeight:4,itemStyle:{borderRadius:[2,2,0,0]},z:2,backgroundStyle:{color:"rgba(180, 180, 180, 0.2)",borderColor:null,borderWidth:0,borderType:"solid",borderRadius:0,shadowBlur:0,shadowColor:null,shadowOffsetX:0,shadowOffsetY:0},select:{itemStyle:{borderColor:"#212121"}}}]}),this._e_set_days(),setTimeout((()=>{this._page[0].update()}),100)}updateRuntime(){this._page[0].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(this._format_time(this.runtime,!0))}updateStatus(e){this._page[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(e)}_e_format_time(e){const t=new Date(e);return t.getHours().toString().padStart(2,0)+":"+t.getMinutes().toString().padStart(2,0)+":"+t.getSeconds().toString().padStart(2,0)}_e_set_days(){let t=Number.parseInt(e.getTime()/86400)-30,i=Array.from({length:31},((e,i)=>this._format_date(864e5*(t+i))));this._e_daily_hits.setOption({xAxis:{data:i}}),this._e_daily_bytes.setOption({xAxis:{data:i}})}disconnect(){clearInterval(this._runtimeTimer),clearInterval(this._qpsTimer)}connect(e){e.push(...this._page)}_e_templates(e,t=null){const i='
{name}{value}
';var a="";for(const r of e)a+=i.replace("{color}",r.color).replace("{name}",r.name).replace("{value}",t?t(r.value):r.value);return`
${e[0].name}
${a}
`}_ws_message(t,i){if("runtime"==t&&(this.runtime=i,this.updateRuntime()),"dashboard"==t){{const t=i.hourly;let a=Math.max(...t.map((e=>e._hour))),r=0,s=0;{const i=Array.from({length:a},((e,t)=>0)),s=Array.from({length:a},((e,t)=>0));for(const e of t)i[e._hour]=e.hits,s[e._hour]=e.cache_hits,a=Math.max(a,e._hour);this._e_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...i,...s)},series:[{name:"I/O访问数",data:i,type:"line",smooth:!0},{name:"缓存访问数",data:s,type:"line",smooth:!0}]}),r=e.sum(...i,...s)}{const i=Array.from({length:a},((e,t)=>0)),r=Array.from({length:a},((e,t)=>0));for(const e of t)i[e._hour]=e.bytes,r[e._hour]=e.cache_bytes;this._e_bytes.setOption({tooltip:{formatter:e=>this._e_templates(e,(e=>this._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...i,...r),axisLabel:{formatter:e=>this._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:i,type:"line",smooth:!0},{name:"缓存访问文件大小",data:r,type:"line",smooth:!0}]}),s=e.sum(...i,...r)}this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[1].setText(this._format_number_unit(r)),this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].getChildrens()[1].setText(this._format_bytes(s))}{const t=i.days;let a=0,r=0;{const i=Array.from({length:30},((e,t)=>0)),r=Array.from({length:30},((e,t)=>0));for(const e of t)i[e._day]=e.hits,r[e._day]=e.cache_hits;this._e_daily_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...i,...r)},series:[{name:"I/O访问数",data:i,type:"line",smooth:!0},{name:"缓存访问数",data:r,type:"line",smooth:!0}]}),a=e.sum(...i,...r)}{const i=Array.from({length:30},((e,t)=>0)),a=Array.from({length:30},((e,t)=>0));for(const e of t)i[e._day]=e.bytes,a[e._day]=e.cache_bytes;this._e_daily_bytes.setOption({tooltip:{formatter:e=>this._e_templates(e,(e=>this._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...i,...a),axisLabel:{formatter:e=>this._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:i,type:"line",smooth:!0},{name:"缓存访问文件大小",data:a,type:"line",smooth:!0}]}),r=e.sum(...i,...a)}this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[2].getChildrens()[1].setText(this._format_number_unit(a)),this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[3].getChildrens()[1].setText(this._format_bytes(r))}}if("qps"==t){const t=parseInt(e.getTimestamp()/1e3),s=(t%5!=0?5:0)-t%5+t,n=[];var a=[],r=[];for(let t=s-300;t<=s;t++){let s=i.hasOwnProperty(t)?i[t]:0;a.push(s),t%5==0&&(n.push({value:e.sum(...a)/a.length,raw:a}),a=[],r.push(this._e_format_time(1e3*t)))}this._page[0].valueOf().children[1].children[0].children[0].innerText=e.sum(...e.collectionSingleList(n.map((e=>[...e.raw])))),this._e_qps.setOption({xAxis:{data:r},series:[{data:n}]})}"status"==t&&this.updateStatus(i)}_format_number(e,t=null){return 0==e||(t=t||Math.min(Number.parseInt(Math.floor(Math.log(e)/Math.log(1e3))),this._unit_number.length))<=0?`${e}${this._unit_number[0]}`:`${(e/=1024**t).toFixed(1)}${this._unit_number[t]}`}_format_number_unit(e){var t=(e+"").split("."),i=t[0],a=t.length>=2?"."+t.slice(1).join("."):"";return i.toString().replace(/\B(?=(\d{3})+(?!\d))/g,", ")+a}_format_date(e){const t=new Date(e);return`${t.getFullYear().toString().padStart(4,"0")}-${(t.getMonth()+1).toString().padStart(2,"0")}-${t.getDate().toString().padStart(2,"0")}`}_format_time(t,i=!1){if(null==t)return"-";let a=Number.parseInt(t);return i&&(a=Number.parseInt(e.getTime()-a)),`${parseInt(a/60/60/24).toString().padStart(2,"0")} 天 ${parseInt(a/60/60%24).toString().padStart(2,"0")} 小时 ${parseInt(a/60%60).toString().padStart(2,"0")} 分钟 ${parseInt(a%60).toString().padStart(2,"0")} 秒`}_format_bytes(e,t=null){return 0==e||(t=t||Math.min(Number.parseInt(Math.floor(Math.log(e)/Math.log(1024))),this._unit_bytes.length))<=0?`${e.toFixed(2)}${this._unit_bytes[0]}`:`${(e/=1024**t).toFixed(2)}${this._unit_bytes[t]}`}});const y=()=>{h(),p()};i.append(e.createElement("h3").setText("Python OpenBMCLAPI Dashboard")),n.append(e.createElement("p").append(e.createElement("a").setAttribute("href","mailto:administrator@ttb-network.top").setText("TTB Network")," - ",e.VERSION)),r.event("click",(()=>{a.toggle("hide"),window.dispatchEvent(new Event("resize"))})),t.append(i,e.createElement("div").class("container").append(a.append(r,s,n),o)),window.addEventListener("resize",y),window.addEventListener("popstate",g),document.body.prepend(d.valueOf(),t.valueOf()),h(),e.set_styles({"body,ol,ul,h1,h2,h3,h4,h5,h6,p,th,td,dl,dd,form,fieldset,legend,input,textarea,select":"margin:0;padding:0",body:"font:12px;background:#fff;-webkit-text-size-adjust:100%",a:"color:#172c45;text-decoration:none",em:"font-style:normal",li:"list-style:none",img:"border:0;vertical-align:middle",table:"border-collapse:collapse;border-spacing:0",p:"word-wrap:break-word",":root":["--r-main-background-color: #F6F7F9","--r-background-color: #191919","--r-main-font-size: 42px","--r-main-color: #fff","--r-block-margin: 20px","--r-heading-margin: 0 0 20px 0","--r-heading-font: Source Sans Pro, Helvetica, sans-serif","--r-heading-color: #fff","--r-heading-line-height: 1.2","--r-heading-letter-spacing: normal","--r-heading-text-transform: uppercase","--r-heading-text-shadow: none","--r-heading-font-weight: 600","--r-heading1-text-shadow: none","--r-heading1-size: 2.5em","--r-heading2-size: 1.6em","--r-heading3-size: 1.3em","--r-heading4-size: 1em","--r-code-font: monospace","--r-link-color: #42affa","--r-link-color-dark: #068de9","--r-link-color-hover: #8dcffc","--r-selection-background-color: rgba(66, 175, 250, .75)","--r-selection-color: #fff","--r-overlay-element-bg-color: 240, 240, 240","--r-overlay-element-fg-color: 0, 0, 0","--r-ligting-color: rgb(15, 198, 194);"],".root .left":["position: fixed","min-height: calc(100vh - 72px)","max-height: calc(100vh - 72px)","min-width: 48px","max-width: 184px","margin-top: 16px","width: 256px","padding: 8px","padding-top: 0","background: var(--r-main-background-color)","transition: transform 200ms linear 0s;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .left .content":["overflow: auto","width: 95%"],".root .left.hide":["transform: translateX(-100%);"],".root .left .button":["cursor: pointer;","border-radius: 8px;","margin-bottom: 8px","padding: 4px","padding-left: 8px","transition: color 200ms linear 0s;"],".root .left .arrow-background":["position: absolute","background: var(--r-main-background-color)","width: 20px","height: 20px","left: 194px","margin-top: -16px","cursor: pointer"],".root .left .arrow":["width: 100%","height: 100%",'background-image: url("data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgc3R5bGU9IndpZHRoOiAxZW07aGVpZ2h0OiAxZW07dmVydGljYWwtYWxpZ246IG1pZGRsZTtmaWxsOiBjdXJyZW50Q29sb3I7b3ZlcmZsb3c6IGhpZGRlbjsiIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwLWlkPSI3NTUiPjxwYXRoIGQ9Ik0zMjUuMDQ4IDkzLjUxMWwtNjAuMDMwIDU5LjQzNSAzNTcuMTgxIDM1OS42MzEtMzYwLjE4NCAzNTYuNjAzIDU5LjUyMiA1OS45MyA0MjAuMjA3LTQxNi4wNDN6IiBmaWxsPSIjODQ4NDg0IiBwLWlkPSI3NTYiPjwvcGF0aD48L3N2Zz4=");'],".root .container .left.hide .arrow-background .arrow":["transform: rotate(0deg);"],".root .container .left .arrow-background .arrow":["transform: rotate(180deg);","transition: transform 100ms linear 0s;"],".root .left .button:hover":["color: var(--r-ligting-color)"],".root .left .button.selected":["background: var(--r-ligting-color)","box-shadow: rgba(15, 198, 194, 0.2) 0px 10px 25px 0px;","color: white"],".root .left .side":["margin-left: 8px"],".root .left .sidebutton":["padding: 2px","margin-bottom: 8px","cursor: pointer;","color: rgba(0, 0, 0, 0.5);","transition: color 200ms linear 0s;"],".root .left .sidebutton:hover":["color: var(--r-link-color-hover)"],".root .left .sidebutton.selected":["color: black","font-weight: bold"],".root .left .sidebutton:hover .cycle":["background: var(--r-link-color-hover)"],".root .left .sidebutton.selected .cycle":["width: 8px;","height: 8px;","background-color: rgb(15, 198, 194);","margin-right: 6px","margin-left: 2px","border-radius: 50%;"],".root .left .sidebutton .cycle":["width: 4px;","height: 4px;","margin: 4px","margin-right: 8px","background-color: rgba(0, 0, 0, 0.5);","transition: background-color 200ms linear 0s;","border-radius: 50%;"],".root .header":["position: fixed","height: 40px","min-height: 40px","min-width: 100vw","background: var(--r-main-background-color)","z-index: 1","padding: 8px","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .container":["position: relative;","top: 56px;"],".root .container .right":["padding-top: 16px","margin-left: 216px","transition: width 200ms linear 0s;","min-width: calc(100vw - 232px)","min-height: calc(100vh - 72px)"],".root .container .left.hide ~ .right":["margin-left: 0","min-width: 100vw"],".root .container .right .panel":["background-color: rgb(255, 255, 255);","color: rgb(0, 0, 0);","transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;","border-radius: 4px;","background-image: none;","padding: 24px;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;","margin: 16px;"],".panel.info-4":["display: flex","flex-warp: warp"],".panel.info-4 div":["width: 25%"],".panel.info-2":["display: flex","flex-warp: warp"],".panel.info-2 div":["width: 50%"],".panel .title":["display: flex","margin: 0px 0px 6px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.5);","font-size: 14px;"],".panel .value":["margin: 0px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.7);","font-size: 24px;"],".root .container .left.hide~.right":["margin-left: 32px","min-width: calc(100vw - 48px)"],".root .left .copyright":["position: fixed;","bottom: 2px"],".qps .icon":["width: 14px","height: 14px"],".qps":["display: flex","align-items: center"],".progress":["position: absolute;","z-index: 2","width: 0","height: 2px","background: var(--r-ligting-color)","transition: width 200ms linear 0s;"],body:["background-color: var(--r-main-background-color)"]}),g(),y()})(); \ No newline at end of file +(()=>{const e=new TTB,t=e.createElement("div").class("root"),i=e.createFlex().class("header").style("align-items","center"),a=e.createElement("div").class("left"),r=e.createElement("div").class("arrow-background").append(e.createElement("div").class("arrow")),s=e.createElement("div").class("content"),n=e.createElement("div").class("copyright"),l=e.createElement("div").class("right"),o={},d=e.createElement("div").class("progress"),c=e=>{d.setStyle("width",100*e+"%"),100*e>=99&&setTimeout((()=>d.setStyle("width",0)),250)},p=()=>{s.clear();for(const t in o){const i=o[t],a=!!i.children,r=e.createFlex().class("button").id("left-list-"+t).append(e.createElement("p").setText(i.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+i.children[0].key:"")}));if(s.append(r),a){const r=e.createElement("div").style("display: none").class("side").id("left-list-"+t+"-sub");for(const s of i.children)r.append(e.createFlex().class("sidebutton").id("left-list-"+t+"-sub-"+s.key).append(e.createElement("div").class("cycle"),e.createElement("p").setText(s.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+s.key:"")})));s.append(r)}}},h=()=>{const t=e.getURLKey()||Object.keys(o)[0];for(const i of Object.keys(o))if(u!=t?i==t?(document.getElementById("left-list-"+i).classList.add("selected"),x=""):document.getElementById("left-list-"+i).classList.remove("selected"):u==i&&document.getElementById("left-list-"+i).classList.add("selected"),document.getElementById("left-list-"+i+"-sub")){document.getElementById("left-list-"+i+"-sub").style.display=i==t?"block":"none";const a=e.getURLKeyParams().key||Object.keys(Object.values(o)[0])[1];for(const e of o[i].children.map((e=>e.key)))e==a?(document.getElementById("left-list-"+i+"-sub-"+e).classList.add("selected"),x=a):document.getElementById("left-list-"+i+"-sub-"+e).classList.remove("selected")}},g=()=>{const t=e.getURLKey()||Object.keys(o)[0],i=x;h(),(u!=t||x&&x!=i)&&(u&&x&&x==i&&m(u,i,"disconnect"),m(t,x,"connect")),u=t},m=(t,i,a)=>{const r=(i?o[t].children.filter((e=>e.key==i))[0]:o[t]).core||{};if(f!=(t+=i?"-"+i:"")){if(f in r&&"disconnect"in r)try{r.disconnect()}catch(e){console.log(e)}for(;null!=document.getElementsByClassName("right")[0].firstChild;)document.getElementsByClassName("right")[0].removeChild(document.getElementsByClassName("right")[0].firstChild);f=t}if(a in r)try{document.getElementsByClassName("right")[0].style.display="none",page=[],"connect"==a&&"page"in r&&(c(.7),"init"in r&&r.init(),c(.8),page=r.page()||[]),c(.9),r[a](page),null!=page&&document.getElementsByClassName("right")[0].append(e.createElement("div").id("module-"+t).append(...Array.isArray(page)?page:[page]).valueOf()),document.getElementsByClassName("right")[0].style.display="block",c(1)}catch(e){console.log(e)}else c(1)};let u="",x="",f="";const y=()=>{p(),h()};i.append(e.createElement("h3").setText("Python OpenBMCLAPI Dashboard")),n.append(e.createElement("p").append(e.createElement("a").setAttribute("href","mailto:administrator@ttb-network.top").setText("TTB Network")," - ",e.VERSION)),r.event("click",(()=>{a.toggle("hide"),window.dispatchEvent(new Event("resize"))})),t.append(i,e.createElement("div").class("container").append(a.append(r,s,n),l)),window.addEventListener("resize",y),window.addEventListener("popstate",g),document.body.prepend(d.valueOf(),t.valueOf()),(()=>{new class{constructor(){this.ws=e.websocket("ws"+window.location.protocol.slice(4)+"//"+window.location.host+window.location.pathname,{onopen:()=>this.onopen(),onmessage:e=>{let t=new FileReader;t.onload=()=>{let e=t.result;const i=new DataInputStream(e);this.message(i.readString(),this._deserializeData(i))},t.readAsArrayBuffer(e.data)},onclose:()=>this.onclose()}),this._timer_qps=null,this._timer=null,this._timer_system=null}onclose(){}onopen(){this.send("runtime"),this.send("storage"),this.send("status"),this._timer_qps?.block(),this._timer?.block(),this._timer_system?.block(),this._timer_qps=e.runTaskRepeat((()=>{this.send("qps")}),0,5e3),this._timer=e.runTaskRepeat((()=>{this.send("dashboard")}),0,1e4),this._timer_system=e.runTaskRepeat((()=>{this.send("system")}),0,1e3)}send(e,t){const i=new DataOutputStream;i.writeString(e),i.write(this._serializeData(t)),this.ws.send(i)}message(i,a){if("runtime"==i&&(t.runtime=a,t.update()),"status"==i&&t.updateStatus(a),"dashboard"==i){const i=a.hourly,r=a.days;let s,n,l,o,d=Math.max(...i.map((e=>e._hour)));l=Array.from({length:d},((e,t)=>0)),o=Array.from({length:d},((e,t)=>0));for(const e of i)l[e._hour]=e.hits,o[e._hour]=e.cache_hits,d=Math.max(d,e._hour);t._e_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...l,...o)},series:[{name:"I/O访问数",data:l,type:"line",smooth:!0},{name:"缓存访问数",data:o,type:"line",smooth:!0}]}),s=e.sum(...l,...o),l=Array.from({length:d},((e,t)=>0)),o=Array.from({length:d},((e,t)=>0));for(const e of i)l[e._hour]=e.bytes,o[e._hour]=e.cache_bytes;t._e_bytes.setOption({tooltip:{formatter:e=>t._e_templates(e,(e=>t._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...l,...o),axisLabel:{formatter:e=>t._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:l,type:"line",smooth:!0},{name:"缓存访问文件大小",data:o,type:"line",smooth:!0}]}),n=e.sum(...l,...o),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(t._format_number_unit(s)),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(t._format_bytes(n)),l=Array.from({length:30},((e,t)=>0)),o=Array.from({length:30},((e,t)=>0));for(const e of r)l[e._day]=e.hits,o[e._day]=e.cache_hits;t._e_daily_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...l,...o)},series:[{name:"I/O访问数",data:l,type:"line",smooth:!0},{name:"缓存访问数",data:o,type:"line",smooth:!0}]}),s=e.sum(...l,...o);{const i=Array.from({length:30},((e,t)=>0)),a=Array.from({length:30},((e,t)=>0));for(const e of r)i[e._day]=e.bytes,a[e._day]=e.cache_bytes;t._e_daily_bytes.setOption({tooltip:{formatter:e=>t._e_templates(e,(e=>t._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...i,...a),axisLabel:{formatter:e=>t._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:i,type:"line",smooth:!0},{name:"缓存访问文件大小",data:a,type:"line",smooth:!0}]}),n=e.sum(...i,...a)}t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[2].getChildrens()[1].setText(t._format_number_unit(s)),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[3].getChildrens()[1].setText(t._format_bytes(n))}if("system"==i&&(t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(t._format_number_unit(a.connections)),t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(t._format_bytes(a.memory))),"qps"==i){const i=parseInt(e.getTimestamp()/1e3),n=(i%5!=0?5:0)-i%5+i,l=[];var r=[],s=[];for(let i=n-300;i<=n;i++){let n=a.hasOwnProperty(i)?a[i]:0;r.push(n),i%5==0&&(l.push({value:e.sum(...r)/r.length,raw:r}),r=[],s.push(t._e_format_time(1e3*i)))}t._page[1].getChildrens()[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].setText(t._format_number_unit(e.sum(...e.collectionSingleList(l.map((e=>[...e.raw])))))),t._e_qps.setOption({xAxis:{data:s},series:[{data:l}]})}console.log(i,a),((e,...t)=>{var i=f.split("-",1),a=i[0],r=i[1];const s=(r?o[a].children.filter((e=>e.key==r))[0]:o[a]).core||{};e in s&&s[e](...t)})("_ws_message",i,a)}_deserializeData(e){const t=e.readVarInt();switch(t){case 0:return e.readString();case 1:return e.readBoolean();case 2:return parseFloat(e.readString());case 3:return parseInt(e.readString());case 4:{const t=e.readVarInt(),i=[];for(let a=0;a{this._e_bytes.resize(),this._e_daily_bytes.resize(),this._e_hits.resize(),this._e_daily_hits.resize(),this._e_qps.resize()}))],this._updateTimer=setInterval((()=>this.update()),1e3),this._e_options={tooltip:{trigger:"axis"},grid:{left:"3%",right:"4%",bottom:"3%",top:"20%",containLabel:!0},xAxis:{type:"category"},yAxis:{type:"value",min:1,max:10},series:[]},this._unit_bytes=["B","KB","MB","GB","TB","PB","EB"],this._unit_number=["","k","M","G","T","P","E"],this._hourly=Array.from({length:24},((e,t)=>t+" 时")),this._e_qps=echarts.init(this._page[1].getChildrens()[1].getChildrens()[1].valueOf()),this._e_hits=echarts.init(this._page[1].getChildrens()[2].getChildrens()[1].valueOf()),this._e_bytes=echarts.init(this._page[1].getChildrens()[3].getChildrens()[1].valueOf()),this._e_daily_hits=echarts.init(this._page[1].getChildrens()[4].getChildrens()[1].valueOf()),this._e_daily_bytes=echarts.init(this._page[1].getChildrens()[5].getChildrens()[1].valueOf()),this._e_hits.setOption(this._e_options),this._e_bytes.setOption(this._e_options),this._e_hits.setOption({xAxis:{data:this._hourly}}),this._e_bytes.setOption({xAxis:{data:this._hourly}}),this._e_daily_hits.setOption(this._e_options),this._e_daily_bytes.setOption(this._e_options),this._e_qps.setOption({color:"#0fc6c2",tooltip:{trigger:"axis",formatter:t=>'
'+t[0].name+'
QPSAvg: '+t[0].data.value+" total: "+e.sum(...t[0].data.raw)+'
'},stateAnimation:{duration:300,easing:"cubicOut"},xAxis:{type:"category",show:!1},yAxis:{show:!1,type:"value"},grid:{top:10,bottom:10,right:0,left:0,show:!1,z:0,containLabel:!1,backgroundColor:"rgba(0,0,0,0)",borderWidth:1,borderColor:"#ccc"},series:[{type:"bar",barGap:"0",barMinHeight:4,itemStyle:{borderRadius:[2,2,0,0]},z:2,backgroundStyle:{color:"rgba(180, 180, 180, 0.2)",borderColor:null,borderWidth:0,borderType:"solid",borderRadius:0,shadowBlur:0,shadowColor:null,shadowOffsetX:0,shadowOffsetY:0},select:{itemStyle:{borderColor:"#212121"}}}]}),this.update(),setTimeout((()=>this._page[1].update()),1)}connect(e){e.push(...this._page)}update(){this._page[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(this._format_time(this.runtime,!0))}updateStatus(e){this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(e)}_format_time(t,i=!1){if(null==t)return"-";let a=Number.parseInt(t);return i&&(a=Number.parseInt(e.getTime()-a)),`${parseInt(a/60/60/24).toString().padStart(2,"0")} 天 ${parseInt(a/60/60%24).toString().padStart(2,"0")} 小时 ${parseInt(a/60%60).toString().padStart(2,"0")} 分钟 ${parseInt(a%60).toString().padStart(2,"0")} 秒`}_format_bytes(e,t=null){return 0==e||(t=t||Math.min(Number.parseInt(Math.floor(Math.log(e)/Math.log(1024))),this._unit_bytes.length))<=0?`${e.toFixed(2)}${this._unit_bytes[0]}`:`${(e/=1024**t).toFixed(2)}${this._unit_bytes[t]}`}_e_templates(e,t=null){const i='
{name}{value}
';var a="";for(const r of e)a+=i.replace("{color}",r.color).replace("{name}",r.name).replace("{value}",t?t(r.value):r.value);return`
${e[0].name}
${a}
`}_format_number_unit(e){var t=(e+"").split("."),i=t[0],a=t.length>=2?"."+t.slice(1).join("."):"";return i.toString().replace(/\B(?=(\d{3})+(?!\d))/g,", ")+a}_e_format_time(e){const t=new Date(e);return t.getHours().toString().padStart(2,0)+":"+t.getMinutes().toString().padStart(2,0)+":"+t.getSeconds().toString().padStart(2,0)}};((e,t,i,a)=>{if(e.includes(".")){const[r,s]=[e.slice(0,e.indexOf(".")),e.slice(e.indexOf(".")+1)];o[r]||(o[r]={icon:t,children:[],text:"",core:a}),"children"in o[r]||(o[r].children=[]),o[r].children.push({key:s,text:i,core:a})}else o[e]={key:e,icon:t,text:i,core:a}})("dashboard","","数据统计",t)})(),p(),e.set_styles({"body,ol,ul,h1,h2,h3,h4,h5,h6,p,th,td,dl,dd,form,fieldset,legend,input,textarea,select":"margin:0;padding:0",body:"font:12px;background:#fff;-webkit-text-size-adjust:100%",a:"color:#172c45;text-decoration:none",em:"font-style:normal",li:"list-style:none",img:"border:0;vertical-align:middle",table:"border-collapse:collapse;border-spacing:0",p:"word-wrap:break-word",":root":["--r-main-background-color: #F6F7F9","--r-background-color: #191919","--r-main-font-size: 42px","--r-main-color: #fff","--r-block-margin: 20px","--r-heading-margin: 0 0 20px 0","--r-heading-font: Source Sans Pro, Helvetica, sans-serif","--r-heading-color: #fff","--r-heading-line-height: 1.2","--r-heading-letter-spacing: normal","--r-heading-text-transform: uppercase","--r-heading-text-shadow: none","--r-heading-font-weight: 600","--r-heading1-text-shadow: none","--r-heading1-size: 2.5em","--r-heading2-size: 1.6em","--r-heading3-size: 1.3em","--r-heading4-size: 1em","--r-code-font: monospace","--r-link-color: #42affa","--r-link-color-dark: #068de9","--r-link-color-hover: #8dcffc","--r-selection-background-color: rgba(66, 175, 250, .75)","--r-selection-color: #fff","--r-overlay-element-bg-color: 240, 240, 240","--r-overlay-element-fg-color: 0, 0, 0","--r-ligting-color: rgb(15, 198, 194);"],".root .left":["position: fixed","min-height: calc(100vh - 72px)","max-height: calc(100vh - 72px)","min-width: 48px","max-width: 184px","margin-top: 16px","width: 256px","padding: 8px","padding-top: 0","background: var(--r-main-background-color)","transition: transform 200ms linear 0s;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .left .content":["overflow: auto","width: 95%"],".root .left.hide":["transform: translateX(-100%);"],".root .left .button":["cursor: pointer;","border-radius: 8px;","margin-bottom: 8px","padding: 4px","padding-left: 8px","transition: color 200ms linear 0s;"],".root .left .arrow-background":["position: absolute","background: var(--r-main-background-color)","width: 20px","height: 20px","left: 194px","margin-top: -16px","cursor: pointer"],".root .left .arrow":["width: 100%","height: 100%",'background-image: url("data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgc3R5bGU9IndpZHRoOiAxZW07aGVpZ2h0OiAxZW07dmVydGljYWwtYWxpZ246IG1pZGRsZTtmaWxsOiBjdXJyZW50Q29sb3I7b3ZlcmZsb3c6IGhpZGRlbjsiIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwLWlkPSI3NTUiPjxwYXRoIGQ9Ik0zMjUuMDQ4IDkzLjUxMWwtNjAuMDMwIDU5LjQzNSAzNTcuMTgxIDM1OS42MzEtMzYwLjE4NCAzNTYuNjAzIDU5LjUyMiA1OS45MyA0MjAuMjA3LTQxNi4wNDN6IiBmaWxsPSIjODQ4NDg0IiBwLWlkPSI3NTYiPjwvcGF0aD48L3N2Zz4=");'],".root .container .left.hide .arrow-background .arrow":["transform: rotate(0deg);"],".root .container .left .arrow-background .arrow":["transform: rotate(180deg);","transition: transform 100ms linear 0s;"],".root .left .button:hover":["color: var(--r-ligting-color)"],".root .left .button.selected":["background: var(--r-ligting-color)","box-shadow: rgba(15, 198, 194, 0.2) 0px 10px 25px 0px;","color: white"],".root .left .side":["margin-left: 8px"],".root .left .sidebutton":["padding: 2px","margin-bottom: 8px","cursor: pointer;","color: rgba(0, 0, 0, 0.5);","transition: color 200ms linear 0s;"],".root .left .sidebutton:hover":["color: var(--r-link-color-hover)"],".root .left .sidebutton.selected":["color: black","font-weight: bold"],".root .left .sidebutton:hover .cycle":["background: var(--r-link-color-hover)"],".root .left .sidebutton.selected .cycle":["width: 8px;","height: 8px;","background-color: rgb(15, 198, 194);","margin-right: 6px","margin-left: 2px","border-radius: 50%;"],".root .left .sidebutton .cycle":["width: 4px;","height: 4px;","margin: 4px","margin-right: 8px","background-color: rgba(0, 0, 0, 0.5);","transition: background-color 200ms linear 0s;","border-radius: 50%;"],".root .header":["position: fixed","height: 40px","min-height: 40px","min-width: 100vw","background: var(--r-main-background-color)","z-index: 1","padding: 8px","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .container":["position: relative;","top: 56px;"],".root .container .right":["padding-top: 16px","margin-left: 216px","transition: width 200ms linear 0s;","min-width: calc(100vw - 232px)","min-height: calc(100vh - 72px)"],".root .container .left.hide ~ .right":["margin-left: 0","min-width: 100vw"],".root .container .right .panel":["background-color: rgb(255, 255, 255);","color: rgb(0, 0, 0);","transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;","border-radius: 4px;","background-image: none;","padding: 24px;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;","margin: 16px;"],".panel.info-4":["display: flex","flex-warp: warp"],".panel.info-4 div":["width: 25%"],".panel.info-2":["display: flex","flex-warp: warp"],".panel.info-2 div":["width: 50%"],".panel .title":["display: flex","margin: 0px 0px 6px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.5);","font-size: 14px;"],".panel .value":["margin: 0px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.7);","font-size: 24px;"],".root .container .left.hide~.right":["margin-left: 32px","min-width: calc(100vw - 48px)"],".root .left .copyright":["position: fixed;","bottom: 2px"],".qps .icon":["width: 14px","height: 14px"],".qps":["display: flex","align-items: center"],".progress":["position: absolute;","z-index: 2","width: 0","height: 2px","background: var(--r-ligting-color)","transition: width 200ms linear 0s;"],body:["background-color: var(--r-main-background-color)"]}),g(),y()})(); \ No newline at end of file diff --git a/bmclapi_dashboard/static/js/ttb.min.js b/bmclapi_dashboard/static/js/ttb.min.js index 154c3dc..0769e22 100644 --- a/bmclapi_dashboard/static/js/ttb.min.js +++ b/bmclapi_dashboard/static/js/ttb.min.js @@ -1 +1 @@ -class TTBElement{constructor(t,e=!1){this.base=e?t:document.createElement(t),this._resize_handler=[],window.addEventListener("resize",((...t)=>this._resize(...t)))}setHTML(t){return this.base.innerHTML=t,this}setText(t){return this.base.innerText=t,this}title(t){return this.setText(t)}html(t){return this.setHTML(t)}append(...t){for(const e of t)e instanceof TTBElement?this.base.append(e.valueOf()):this.base.append(e);return this}id(t){return this.base.id=t,this}class(...t){for(const e of t)for(const t of e.split(" "))this.base.classList.add(t);return this}toggle(t){return this.base.classList.toggle(t),this}style(t){return this.base.style=t,this}_resize(...t){for(const e of this._resize_handler)try{e(...t)}catch(t){console.log(t,e)}}setStyle(t,e){return this.base.style[t]=e,this}valueOf(){return this.base}containsClass(...t){for(const e of t)for(const t of e.split(" "))if(this.base.classList.contains(t))return!0;return!1}setAttribute(t,e){return this.base.setAttribute(t,e),this}isDOM(t){return t instanceof HTMLElement||"[object HTMLUnknownElement]"===Object.prototype.toString.call(t)||t&&"object"==typeof t&&1===t.nodeType&&"string"==typeof t.nodeName}clear(){for(;null!=this.base.firstChild;)this.base.removeChild(this.base.firstChild);return this}event(t,e){return"resize"==t?(this._resize_handler.push(e),this):(this.base.addEventListener(t,e),this)}getChildrens(){return new Array(...this.base.children).map((t=>this.isDOM(t)&&t.classList.contains("ttb-flex")?new TTBElementFlex(t,!0):new TTBElement(t,!0)))}}class TTBElementFlex extends TTBElement{constructor(t="div",e=!1){super(t,e),this.class("ttb-flex"),this._minwidth=null,this._minheight=null,this._maxwidth=null,this._maxheight=null,this._updateTimer=null,this._child=1,this._childStyle="",this._tag=null,window.addEventListener("resize",(()=>this.update())),setTimeout((()=>this.update()),5)}append(...t){return super.append(...t.map((t=>this.isDOM(t)||t instanceof TTBElement?t:new TTBElement("div").setHTML(t)))),this.update(),this}tag(t){return this._tag=t,this}min_width(t){return this.minwidth=t,this.update(),this}max_width(t){return this.maxwidth=t,this.update(),this}min_height(t){return this.minheight=t,this.update(),this}max_height(t){return this.maxheight=t,this.update(),this}height(t){return this.setStyle("height",t),this}width(t){return this.setStyle("width",t),this}style(t,e){return g_TTB.set_style(".ttb-flex."+t+"_"+e,`${t}: ${e}`),this.class(t+"_"+e),this}update(){return this._update(),this}_update(){const t=super.valueOf().offsetWidth-1;let e=this._calcValueWithDisplay(this._minwidth||0,t),s=this._calcValueWithDisplay(this._maxwidth,t),r=g_TTB.clamp(e,t,s);const i=Math.max(0,Math.floor((r-1)/this._child));for(const s of this.getChildrens()){const n=window.getComputedStyle(s.valueOf()),h=parseInt(n.marginRight,10)+parseInt(n.marginLeft,10);s.valueOf().style=this._childStyle,s.setStyle("boxSizing","border-box"),s.setStyle("width",(rt instanceof TTBElementFlex)).forEach((t=>t.update())),this._resize()}_calcValueWithDisplay(t,e){return-1==t||null==t?e:"string"==typeof t&&t.includes("%")?Math.floor(e*(parseFloat(t.replace("%",""))/100)):t}childStyle(t){return this._childStyle=t,this.update(),this}minWidth(t){return this._minwidth=t,this.update(),this}minHeight(t){return this._minheight=t,this.update(),this}maxWidth(t){return this._maxwidth=t,this.update(),this}maxHeight(t){return this._maxheight=t,this.update(),this}child(t){return this._child=Math.max(1,Number.parseInt(t.toString())),this.update(),this}}class WebSocketClient{constructor(t={}){this.url=t.url,this.socket=null,this.reconnectAttempts=0,this.maxReconnectAttempts=5,this.reconnectInterval=5e3,this.parameters=t,this.websockets=[],this.initWebSocket()}initWebSocket(){this.socket=new WebSocket(this.url),this.bindEvents()}bindEvents(){this.socket.onopen=this.onOpen.bind(this),this.socket.onclose=this.onClose.bind(this),this.socket.onmessage=this.onMessage.bind(this),this.socket.onerror=this.onError.bind(this)}onOpen(){this.reconnectAttempts=0,this.parameters.open&&this.parameters.open(this)}onClose(t){this.reconnect(),this.parameters.close&&this.parameters.close(t)}onMessage(t){this.parameters.message&&this.parameters.message(t)}onError(t){this.reconnect(),this.parameters.error&&this.parameters.error(t)}send(t){this.socket.readyState===WebSocket.OPEN?this.socket.send(t instanceof BytesBuffer?t.toBytes():t):(this.close(),console.warn("WebSocket is not open. Cannot send data."),this.reconnect())}close(){this.socket&&this.socket.close(),this.parameters.close&&this.parameters.close()}reconnect(){this.reconnectAttempts{this.initWebSocket(),this.reconnectAttempts++}),this.reconnectInterval)}}class TTB{constructor(){this.VERSION="0.0.1",this.defaultStyles={".ttb-flex":["display: flex","flex-wrap: wrap"]},this.websockets=[],this.documentStyle=document.createElement("style"),this.styles={},this.set_styles(this.defaultStyles),document.head.append(this.documentStyle),window.addEventListener("beforeunload",(()=>{this.websockets.forEach((t=>t.object.close()))})),g_TTB=this}createFlex(){return new TTBElementFlex}createElement(t){return new TTBElement(t)}request(t={}){const e=t.method||"GET",s=t.path||"/",r=t.headers||{},i=!1!==t.async,n=t.username||null,h=t.password||null,a=t.responseType||"text";let o=new XMLHttpRequest;o.open(e,s,i,n,h);for(const t in r)o.setRequestHeader(t,r[t]);return o.responseType=a,o=t.xhr&&t.xhr(o)||o,new Promise(((e,s)=>{o.onload=function(){o.status>=200&&o.status<300?(t.success&&t.success(o.response),e(o.response)):(t.error&&t.error(o.status,o.statusText),s(new Error(`Request failed with status ${o.status}: ${o.statusText}`)))},o.onerror=function(){t.error&&t.error(o.status,o.statusText),s(new Error("Network Error"))},o.send(t.data||null)}))}websocket(t={}){return new WebSocketClient(t)}set_styles=t=>{for(const e in t)this.set_style(e,t[e])};set_style=(t,e)=>{Array.isArray(e)&&(e=e.join(";"));const s=`${t} { ${e} }`,r=document.createTextNode(s),i=this.documentStyle.sheet;if(i)try{i.insertRule(s,i.cssRules.length)}catch(t){this.documentStyle.appendChild(r)}else this.documentStyle.appendChild(r);this.styles[t]=e};calculateBytes(t){let e;return e="string"==typeof t?(new TextEncoder).encode(t).byteLength:t instanceof ArrayBuffer||t instanceof DataView||t instanceof Uint8Array?t.byteLength:t instanceof Blob?t.size:t instanceof BytesBuffer?t.len():(new TextEncoder).encode(String(t)).byteLength,e}sum(...t){let e=0;for(const s of t)e+=s;return e}avg(...t){return 0==t.length?0:this.sum(...t)/t.length}isDOM(t){return t instanceof HTMLElement||"[object HTMLUnknownElement]"===Object.prototype.toString.call(t)||t&&"object"==typeof t&&1===t.nodeType&&"string"==typeof t.nodeName}collectionSingleList(...t){var e=[];for(const s of t)Array.isArray(s)?e.push(...this.collectionSingleList(...s)):e.push(s);return e}getURLParams(){return-1!==window.location.hash.indexOf("#")?window.location.hash.slice(1):""}getURLKey(){var t=this.getURLParams();return(t.startsWith("/")?t.slice(1):t).slice(0,-1!==t.indexOf("?")?t.indexOf("?"):t.length)}getURLKeyParams(){var t=this.getURLParams();if(-1!==(t=t.startsWith("/")?t.slice(1):t).indexOf("?")){for(var e={},s=t.slice(t.indexOf("?")).substring(1).split("&"),r=0;r>=7}return e}static getVarIntLength(t){return this.getVarInt(t).length}}class BytesBuffer{constructor(...t){this.buffer=[],this.cur=0,this.write(...t)}write(...t){for(const e of t)if(e instanceof BytesBuffer)this.buffer.push(...e.buffer);else if(Number.isInteger(e))this.buffer.push(e<0?e+256:e);else if(Array.isArray(e)&&e.filter((t=>Number.isInteger(t))).length==e.length)e.forEach((t=>this.write(t)));else if(e instanceof Uint8Array)for(let t=0;tt.push(e))),t}}class DataOutputStream extends BytesBuffer{constructor(t){super(),this.write(t)}writeInteger(t){this.write(t>>24&255,t>>16&255,t>>8&255,t>>0&255)}writeBoolean(t){this.write(t?1:0)}writeFloat(t){const e=new Uint8Array(new Float32Array([t]).buffer);for(let t=0;t<4;t++)this.write(e[t])}writeDouble(t){const e=new Uint8Array(new Float64Array([t]).buffer);for(let t=0;t<8;t++)this.write(e[t])}writeVarInt(t){return this.write(MinecraftUtils.getVarInt(t)),this}writeString(t,e="utf-8"){return this.writeVarInt(t.length),this.write(new TextEncoder(e).encode(t)),this}writeLong(t){return t-=t>Math.pow(2,63)-1?Math.pow(2,64):t,this.write(t>>56&255,t>>48&255,t>>40&255,t>>32&255,t>>24&255,t>>16&255,t>>8&255,t>>0&255),this}writeUUID(t){return this.writeLong(t.int>>64),this.writeLong(0&t.int),this}}class DataInputStream extends BytesBuffer{readInteger(){let t=this.read(4);return(t[0]<<24)+(t[1]<<16)+(t[2]<<8)+(t[3]<<0)}readBoolean(){return Boolean(this.read(1)[0])}readShort(){if(value=this.read(2),value[0]|value[1]<0)throw EOFError();return(value[0]<<8)+(value[1]<<0)}readLong(){let t=this.read(8);return t=(t[0]<<56)+((255&t[1])<<48)+((255&t[2])<<40)+((255&t[3])<<32)+((255&t[4])<<24)+((255&t[5])<<16)+((255&t[6])<<8)+((255&t[7])<<0),t5)throw new Error("VarInt too big");if(128!=(128&t))break}return e>=2**31-1?e-2**31*2:e}readString(t=null,e="utf-8"){return new TextDecoder(e).decode(new Uint8Array(this.read(null==t?this.readVarInt():t)))}readBytes(t){return this.read(t)}readUUID(){let t=this.readLong(),e=this.readLong();return new UUID(t.toBytes().concat(e.toBytes()))}}g_TTB=null; \ No newline at end of file +class TTB{constructor(){this.VERSION="0.0.1",this.defaultStyles={".ttb-flex":["display: flex","flex-wrap: wrap"]},this.websockets=[],this.documentStyle=document.createElement("style"),this.styles={},this.set_styles(this.defaultStyles),document.head.append(this.documentStyle),window.addEventListener("beforeunload",(()=>{this.websockets.forEach((t=>t.object.close()))})),this._flexes=[],g_TTB=this}addFlex(t){this._flexes.push(t)}resizeFlex(t){for(const e of this._flexes)t.base!=e.base&&e.update(!1)}createFlex(){return new TTBElementFlex}createElement(t){return new TTBElement(t)}request(t={}){const e=t.method||"GET",s=t.path||"/",r=t.headers||{},i=!1!==t.async,n=t.username||null,h=t.password||null,a=t.responseType||"text";let l=new XMLHttpRequest;l.open(e,s,i,n,h);for(const t in r)l.setRequestHeader(t,r[t]);return l.responseType=a,l=t.xhr&&t.xhr(l)||l,new Promise(((e,s)=>{l.onload=function(){l.status>=200&&l.status<300?(t.success&&t.success(l.response),e(l.response)):(t.error&&t.error(l.status,l.statusText),s(new Error(`Request failed with status ${l.status}: ${l.statusText}`)))},l.onerror=function(){t.error&&t.error(l.status,l.statusText),s(new Error("Network Error"))},l.send(t.data||null)}))}websocket(t,e={}){return new WebSocketClient(t,e)}set_styles=t=>{for(const e in t)this.set_style(e,t[e])};set_style=(t,e)=>{Array.isArray(e)&&(e=e.join(";"));const s=`${t} { ${e} }`,r=document.createTextNode(s),i=this.documentStyle.sheet;if(i)try{i.insertRule(s,i.cssRules.length)}catch(t){this.documentStyle.appendChild(r)}else this.documentStyle.appendChild(r);this.styles[t]=e};calculateBytes(t){let e;return e="string"==typeof t?(new TextEncoder).encode(t).byteLength:t instanceof ArrayBuffer||t instanceof DataView||t instanceof Uint8Array?t.byteLength:t instanceof Blob?t.size:t instanceof BytesBuffer?t.len():(new TextEncoder).encode(String(t)).byteLength,e}sum(...t){let e=0;for(const s of t)e+=s;return e}avg(...t){return 0==t.length?0:this.sum(...t)/t.length}isDOM(t){return t instanceof HTMLElement||"[object HTMLUnknownElement]"===Object.prototype.toString.call(t)||t&&"object"==typeof t&&1===t.nodeType&&"string"==typeof t.nodeName}collectionSingleList(...t){var e=[];for(const s of t)Array.isArray(s)?e.push(...this.collectionSingleList(...s)):e.push(s);return e}getURLParams(){return-1!==window.location.hash.indexOf("#")?window.location.hash.slice(1):""}getURLKey(){var t=this.getURLParams();return(t.startsWith("/")?t.slice(1):t).slice(0,-1!==t.indexOf("?")?t.indexOf("?"):t.length)}getURLKeyParams(){var t=this.getURLParams();if(-1!==(t=t.startsWith("/")?t.slice(1):t).indexOf("?")){for(var e={},s=t.slice(t.indexOf("?")).substring(1).split("&"),r=0;rthis._resize(...t)))}setHTML(t){return this.base.innerHTML=t,this}setText(t){return this.base.innerText=t,this}title(t){return this.setText(t)}html(t){return this.setHTML(t)}append(...t){for(const e of t)e instanceof TTBElement?this.base.append(e.valueOf()):this.base.append(e);return this}id(t){return this.base.id=t,this}class(...t){for(const e of t)for(const t of e.split(" "))this.base.classList.add(t);return this}toggle(t){return this.base.classList.toggle(t),this}style(t){return this.base.style=t,this}_resize(...t){for(const e of this._resize_handler)try{e(...t)}catch(t){console.log(t,e)}}setStyle(t,e){return this.base.style[t]=e,this}valueOf(){return this.base}containsClass(...t){for(const e of t)for(const t of e.split(" "))if(this.base.classList.contains(t))return!0;return!1}setAttribute(t,e){return this.base.setAttribute(t,e),this}isDOM(t){return t instanceof HTMLElement||"[object HTMLUnknownElement]"===Object.prototype.toString.call(t)||t&&"object"==typeof t&&1===t.nodeType&&"string"==typeof t.nodeName}clear(){for(;null!=this.base.firstChild;)this.base.removeChild(this.base.firstChild);return this}event(t,e){return"resize"==t?(this._resize_handler.push(e),this):(this.base.addEventListener(t,e),this)}getChildrens(){return new Array(...this.base.children).map((t=>(this.isDOM(t)&&t.classList.contains("ttb-flex")&&g_TTB._flexes.filter((e=>e.valueOf()==t))[0],new TTBElement(t,!0))))}}class TTBElementFlex extends TTBElement{constructor(t="div",e=!1){super(t,e),g_TTB.addFlex(this),this.class("ttb-flex"),this._minwidth=null,this._minheight=null,this._maxwidth=null,this._maxheight=null,this._updateTimer=null,this._child=1,this._childStyle="",this._tag=null,this._resizes=[],this.update()}addResize(t){return this._resizes.push(t),this}append(...t){return super.append(...t.map((t=>this.isDOM(t)||t instanceof TTBElement?t:new TTBElement("div").setHTML(t)))),this}tag(t){return this._tag=t,this}min_width(t){return this.minwidth=t,this}max_width(t){return this.maxwidth=t,this}min_height(t){return this.minheight=t,this}max_height(t){return this.maxheight=t,this}height(t){return this.setStyle("height",t),this}width(t){return this.setStyle("width",t),this}style(t,e){return g_TTB.set_style(".ttb-flex."+t+"_"+e,`${t}: ${e}`),this.class(t+"_"+e),this}update(t=!0){const e=super.valueOf().offsetWidth-1;let s=this._calcValueWithDisplay(this._minwidth||0,e),r=this._calcValueWithDisplay(this._maxwidth,e),i=2*Number.parseInt(g_TTB.clamp(s,e,r)/2);const n=Math.max(0,Math.floor((i-1)/this._child));for(const t of this.getChildrens()){const r=window.getComputedStyle(t.valueOf()),h=parseInt(r.marginRight,10)+parseInt(r.marginLeft,10);t.valueOf().style=this._childStyle,t.setStyle("boxSizing","border-box"),t.setStyle("width",(i<=s?e:n-(Number.isNaN(h)?0:h))+"px")}for(const t of this._resizes)t();return t?(g_TTB.resizeFlex(t),this):this}_calcValueWithDisplay(t,e){return-1==t||null==t?e:"string"==typeof t&&t.includes("%")?Math.floor(e*(parseFloat(t.replace("%",""))/100)):t}childStyle(t){return this._childStyle=t,this}minWidth(t){return this._minwidth=t,this}minHeight(t){return this._minheight=t,this}maxWidth(t){return this._maxwidth=t,this}maxHeight(t){return this._maxheight=t,this}child(t){return this._child=Math.max(1,Number.parseInt(t.toString())),this}}class Task{constructor(t,e,s=null,...r){this.func=t,this.args=r,this.delay=e,this.interval=s,this._task=setTimeout((()=>this._run()),e)}_run(){try{this.func(...this.args)}catch(t){console.error(...t)}null!=this.interval&&(this._task=setTimeout((()=>this._run()),this.interval))}block(){null!=this._task&&clearTimeout(this._task),this._task=null}}class WebSocketClient{constructor(t,e={}){this.url=t,this.ws=null,this.reconnectInterval=1e3,this.messageQueue=[],this.handlers=e,this.stats={sent:{count:0,length:0},received:{count:0,length:0}},this.connect(),this.reconnectTask=null}close(){this.ws.close()}connect(){this.ws=new WebSocket(this.url),this.ws.onopen=()=>{for(null!==this.reconnectTask&&(clearInterval(this.reconnectTask),this.reconnectTask=null);this.messageQueue.length>0;){let t=this.messageQueue.shift();this.raw_send(t)}this.handlers.onopen&&this.handlers.onopen()},this.ws.onmessage=t=>{this.stats.received.count++,this.stats.received.length+=t.data.length,this.handlers.onmessage&&this.handlers.onmessage(t)},this.ws.onclose=()=>{this.ws=null,this.connect(),this.handlers.onclose&&this.handlers.onclose()}}send(t){this.ws&&this.ws.readyState===WebSocket.OPEN?(this.stats.sent.count++,this.stats.sent.length+=g_TTB.calculateBytes(t),this.ws.send(t instanceof BytesBuffer?t.toBytes():t)):(this.ws&&this.ws.readyState!==WebSocket.CLOSED||this.connect(),this.messageQueue.push(t))}getStats(){return this.stats}}class MinecraftUtils{static getVarInt(t){let e=[];for(;;){if(0==(4294967168&t)){e.push(t);break}e.push(127&t|128),t>>=7}return e}static getVarIntLength(t){return this.getVarInt(t).length}}class BytesBuffer{constructor(...t){this.buffer=[],this.cur=0,this.write(...t)}write(...t){for(const e of t)if(e instanceof BytesBuffer)this.buffer.push(...e.buffer);else if(Number.isInteger(e))this.buffer.push(e<0?e+256:e);else if(Array.isArray(e)&&e.filter((t=>Number.isInteger(t))).length==e.length)e.forEach((t=>this.write(t)));else if(e instanceof Uint8Array)for(let t=0;tt.push(e))),t}}class DataOutputStream extends BytesBuffer{constructor(t){super(),this.write(t)}writeInteger(t){this.write(t>>24&255,t>>16&255,t>>8&255,t>>0&255)}writeBoolean(t){this.write(t?1:0)}writeFloat(t){const e=new Uint8Array(new Float32Array([t]).buffer);for(let t=0;t<4;t++)this.write(e[t])}writeDouble(t){const e=new Uint8Array(new Float64Array([t]).buffer);for(let t=0;t<8;t++)this.write(e[t])}writeVarInt(t){return this.write(MinecraftUtils.getVarInt(t)),this}writeString(t,e="utf-8"){return this.writeVarInt(t.length),this.write(new TextEncoder(e).encode(t)),this}writeLong(t){return t-=t>Math.pow(2,63)-1?Math.pow(2,64):t,this.write(t>>56&255,t>>48&255,t>>40&255,t>>32&255,t>>24&255,t>>16&255,t>>8&255,t>>0&255),this}writeUUID(t){return this.writeLong(t.int>>64),this.writeLong(0&t.int),this}}class DataInputStream extends BytesBuffer{readInteger(){let t=this.read(4);return(t[0]<<24)+(t[1]<<16)+(t[2]<<8)+(t[3]<<0)}readBoolean(){return Boolean(this.read(1)[0])}readShort(){if(value=this.read(2),value[0]|value[1]<0)throw EOFError();return(value[0]<<8)+(value[1]<<0)}readLong(){let t=this.read(8);return t=(t[0]<<56)+((255&t[1])<<48)+((255&t[2])<<40)+((255&t[3])<<32)+((255&t[4])<<24)+((255&t[5])<<16)+((255&t[6])<<8)+((255&t[7])<<0),t5)throw new Error("VarInt too big");if(128!=(128&t))break}return e>=2**31-1?e-2**31*2:e}readString(t=null,e="utf-8"){return new TextDecoder(e).decode(new Uint8Array(this.read(null==t?this.readVarInt():t)))}readBytes(t){return this.read(t)}readUUID(){let t=this.readLong(),e=this.readLong();return new UUID(t.toBytes().concat(e.toBytes()))}}g_TTB=null; \ No newline at end of file diff --git a/core/__init__.py b/core/__init__.py index fc09c45..236ab70 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -128,7 +128,7 @@ async def check_ports(): global ssl_server, server, client_side_ssl, restart, check_port_key while 1: ports: list[tuple[asyncio.Server, ssl.SSLContext | None]] = [] - for service in ((server, None), (ssl_server, client_side_ssl if get_loads() != 0 else None)): + for service in ((server, None), (ssl_server, client_side_ssl if get_loaded() else None)): if not service[0]: continue ports.append((service[0], service[1])) @@ -156,9 +156,9 @@ async def main(): while 1: try: server = await asyncio.start_server(_handle, port=PORT) - ssl_server = await asyncio.start_server(_handle_ssl, port=0 if SSL_PORT == PORT else SSL_PORT, ssl=server_side_ssl if get_loads() != 0 else None) + ssl_server = await asyncio.start_server(_handle_ssl, port=0 if SSL_PORT == PORT else SSL_PORT, ssl=server_side_ssl if get_loaded() else None) logger.info(f"Listening server on {PORT}") - logger.info(f"Listening server on {ssl_server.sockets[0].getsockname()[1]} Loaded certificates: {get_loads()}") + logger.info(f"Listening server on {ssl_server.sockets[0].getsockname()[1]}") async with server, ssl_server: await asyncio.gather(server.serve_forever(), ssl_server.serve_forever()) except asyncio.CancelledError: diff --git a/core/certificate.py b/core/certificate.py index b0900a9..d403e24 100644 --- a/core/certificate.py +++ b/core/certificate.py @@ -14,24 +14,23 @@ client_side_ssl = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) client_side_ssl.check_hostname = False -_loads: int = 0 +_loaded: bool = False def load_cert(cert, key): - global server_side_ssl, client_side_ssl, _loads + global server_side_ssl, client_side_ssl, _loaded if not os.path.exists(cert) or not os.path.exists(key): return False try: server_side_ssl.load_cert_chain(cert, key) client_side_ssl.load_verify_locations(cert) - _loads += 1 + _loaded = True return True except: logger.error("Failed to load certificate: ", traceback.format_exc()) return False -def get_loads() -> int: - global _loads - return _loads +def get_loaded() -> bool: + return _loaded def load_text(cert: str, key: str): t = time.time() @@ -41,7 +40,7 @@ def load_text(cert: str, key: str): c.write(cert) k.write(key) if load_cert(cert_file, key_file): - logger.info("Loaded certificate from text! Current:", get_loads()) + logger.info("Loaded certificate from text!") core.restart = True if core.server: core.server.close() diff --git a/core/cluster.py b/core/cluster.py index 1ff6472..4c870cc 100644 --- a/core/cluster.py +++ b/core/cluster.py @@ -13,7 +13,7 @@ import socketio from tqdm import tqdm from core.config import Config -from core import certificate, unit +from core import certificate, system, unit from core.timer import Task, Timer import pyzstd as zstd import core.utils as utils @@ -394,7 +394,6 @@ async def check_files(self): if paths: for path in paths: os.remove(path) - pbar.disable() pbar.update(1) if dir: for d in dir: @@ -593,6 +592,11 @@ async def process(type: str, data: Any): async with aiohttp.ClientSession(BASE_URL) as session: async with session.get(data) as resp: return resp.json() + if type == "system": + return { + "memory": system.get_used_memory(), + "connections": system.get_connections() + } token = TokenManager() cluster: Optional[Cluster] = None diff --git a/core/dashboard.py b/core/dashboard.py new file mode 100644 index 0000000..e69de29 diff --git a/core/system.py b/core/system.py new file mode 100644 index 0000000..5ebb049 --- /dev/null +++ b/core/system.py @@ -0,0 +1,11 @@ +import os + +import psutil + +process: psutil.Process = psutil.Process(os.getpid()) + +def get_used_memory() -> int: + info = process.memory_full_info() + return info.uss +def get_connections() -> int: + return len(process.connections()) \ No newline at end of file diff --git a/core/web.py b/core/web.py index f247e51..727eee6 100644 --- a/core/web.py +++ b/core/web.py @@ -552,9 +552,9 @@ class Header: def __init__(self, header: dict[str, Any] | bytes | str | None = None) -> None: self._headers = {} if isinstance(header, bytes): - self._headers.update({v[0]: v[1] for v in (v.split(": ") for v in header.decode('utf-8').split("\r\n") if v.strip())}) + self._headers.update({v[0]: v[1] for v in (v.split(": ", 1) for v in header.decode('utf-8').split("\r\n") if v.strip()) if len(v) == 2}) elif isinstance(header, str): - self._headers.update({v[0]: v[1] for v in (v.split(": ") for v in header.split("\r\n") if v.strip())}) + self._headers.update({v[0]: v[1] for v in (v.split(": ") for v in header.split("\r\n") if v.strip()) if len(v) == 2}) elif isinstance(header, dict): self._headers.update(header) def get(self, key: str, def_ = None) -> Any: From 3b1fe2c061b500d017fce16b7ad719c2c7a6f245 Mon Sep 17 00:00:00 2001 From: tianxiu2b2t Date: Sun, 24 Mar 2024 04:19:28 +0800 Subject: [PATCH 5/9] Update dashboard and fix items display error --- bmclapi_dashboard/static/js/index.min.js | 2 +- bmclapi_dashboard/static/js/ttb.min.js | 2 +- core/api.py | 13 +++++-- core/cluster.py | 46 +++++++++++++++++++----- core/stats.py | 4 +-- core/system.py | 20 ++++++++++- 6 files changed, 70 insertions(+), 17 deletions(-) diff --git a/bmclapi_dashboard/static/js/index.min.js b/bmclapi_dashboard/static/js/index.min.js index 3391c74..cb4eab6 100644 --- a/bmclapi_dashboard/static/js/index.min.js +++ b/bmclapi_dashboard/static/js/index.min.js @@ -1 +1 @@ -(()=>{const e=new TTB,t=e.createElement("div").class("root"),i=e.createFlex().class("header").style("align-items","center"),a=e.createElement("div").class("left"),r=e.createElement("div").class("arrow-background").append(e.createElement("div").class("arrow")),s=e.createElement("div").class("content"),n=e.createElement("div").class("copyright"),l=e.createElement("div").class("right"),o={},d=e.createElement("div").class("progress"),c=e=>{d.setStyle("width",100*e+"%"),100*e>=99&&setTimeout((()=>d.setStyle("width",0)),250)},p=()=>{s.clear();for(const t in o){const i=o[t],a=!!i.children,r=e.createFlex().class("button").id("left-list-"+t).append(e.createElement("p").setText(i.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+i.children[0].key:"")}));if(s.append(r),a){const r=e.createElement("div").style("display: none").class("side").id("left-list-"+t+"-sub");for(const s of i.children)r.append(e.createFlex().class("sidebutton").id("left-list-"+t+"-sub-"+s.key).append(e.createElement("div").class("cycle"),e.createElement("p").setText(s.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+s.key:"")})));s.append(r)}}},h=()=>{const t=e.getURLKey()||Object.keys(o)[0];for(const i of Object.keys(o))if(u!=t?i==t?(document.getElementById("left-list-"+i).classList.add("selected"),x=""):document.getElementById("left-list-"+i).classList.remove("selected"):u==i&&document.getElementById("left-list-"+i).classList.add("selected"),document.getElementById("left-list-"+i+"-sub")){document.getElementById("left-list-"+i+"-sub").style.display=i==t?"block":"none";const a=e.getURLKeyParams().key||Object.keys(Object.values(o)[0])[1];for(const e of o[i].children.map((e=>e.key)))e==a?(document.getElementById("left-list-"+i+"-sub-"+e).classList.add("selected"),x=a):document.getElementById("left-list-"+i+"-sub-"+e).classList.remove("selected")}},g=()=>{const t=e.getURLKey()||Object.keys(o)[0],i=x;h(),(u!=t||x&&x!=i)&&(u&&x&&x==i&&m(u,i,"disconnect"),m(t,x,"connect")),u=t},m=(t,i,a)=>{const r=(i?o[t].children.filter((e=>e.key==i))[0]:o[t]).core||{};if(f!=(t+=i?"-"+i:"")){if(f in r&&"disconnect"in r)try{r.disconnect()}catch(e){console.log(e)}for(;null!=document.getElementsByClassName("right")[0].firstChild;)document.getElementsByClassName("right")[0].removeChild(document.getElementsByClassName("right")[0].firstChild);f=t}if(a in r)try{document.getElementsByClassName("right")[0].style.display="none",page=[],"connect"==a&&"page"in r&&(c(.7),"init"in r&&r.init(),c(.8),page=r.page()||[]),c(.9),r[a](page),null!=page&&document.getElementsByClassName("right")[0].append(e.createElement("div").id("module-"+t).append(...Array.isArray(page)?page:[page]).valueOf()),document.getElementsByClassName("right")[0].style.display="block",c(1)}catch(e){console.log(e)}else c(1)};let u="",x="",f="";const y=()=>{p(),h()};i.append(e.createElement("h3").setText("Python OpenBMCLAPI Dashboard")),n.append(e.createElement("p").append(e.createElement("a").setAttribute("href","mailto:administrator@ttb-network.top").setText("TTB Network")," - ",e.VERSION)),r.event("click",(()=>{a.toggle("hide"),window.dispatchEvent(new Event("resize"))})),t.append(i,e.createElement("div").class("container").append(a.append(r,s,n),l)),window.addEventListener("resize",y),window.addEventListener("popstate",g),document.body.prepend(d.valueOf(),t.valueOf()),(()=>{new class{constructor(){this.ws=e.websocket("ws"+window.location.protocol.slice(4)+"//"+window.location.host+window.location.pathname,{onopen:()=>this.onopen(),onmessage:e=>{let t=new FileReader;t.onload=()=>{let e=t.result;const i=new DataInputStream(e);this.message(i.readString(),this._deserializeData(i))},t.readAsArrayBuffer(e.data)},onclose:()=>this.onclose()}),this._timer_qps=null,this._timer=null,this._timer_system=null}onclose(){}onopen(){this.send("runtime"),this.send("storage"),this.send("status"),this._timer_qps?.block(),this._timer?.block(),this._timer_system?.block(),this._timer_qps=e.runTaskRepeat((()=>{this.send("qps")}),0,5e3),this._timer=e.runTaskRepeat((()=>{this.send("dashboard")}),0,1e4),this._timer_system=e.runTaskRepeat((()=>{this.send("system")}),0,1e3)}send(e,t){const i=new DataOutputStream;i.writeString(e),i.write(this._serializeData(t)),this.ws.send(i)}message(i,a){if("runtime"==i&&(t.runtime=a,t.update()),"status"==i&&t.updateStatus(a),"dashboard"==i){const i=a.hourly,r=a.days;let s,n,l,o,d=Math.max(...i.map((e=>e._hour)));l=Array.from({length:d},((e,t)=>0)),o=Array.from({length:d},((e,t)=>0));for(const e of i)l[e._hour]=e.hits,o[e._hour]=e.cache_hits,d=Math.max(d,e._hour);t._e_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...l,...o)},series:[{name:"I/O访问数",data:l,type:"line",smooth:!0},{name:"缓存访问数",data:o,type:"line",smooth:!0}]}),s=e.sum(...l,...o),l=Array.from({length:d},((e,t)=>0)),o=Array.from({length:d},((e,t)=>0));for(const e of i)l[e._hour]=e.bytes,o[e._hour]=e.cache_bytes;t._e_bytes.setOption({tooltip:{formatter:e=>t._e_templates(e,(e=>t._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...l,...o),axisLabel:{formatter:e=>t._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:l,type:"line",smooth:!0},{name:"缓存访问文件大小",data:o,type:"line",smooth:!0}]}),n=e.sum(...l,...o),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(t._format_number_unit(s)),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(t._format_bytes(n)),l=Array.from({length:30},((e,t)=>0)),o=Array.from({length:30},((e,t)=>0));for(const e of r)l[e._day]=e.hits,o[e._day]=e.cache_hits;t._e_daily_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...l,...o)},series:[{name:"I/O访问数",data:l,type:"line",smooth:!0},{name:"缓存访问数",data:o,type:"line",smooth:!0}]}),s=e.sum(...l,...o);{const i=Array.from({length:30},((e,t)=>0)),a=Array.from({length:30},((e,t)=>0));for(const e of r)i[e._day]=e.bytes,a[e._day]=e.cache_bytes;t._e_daily_bytes.setOption({tooltip:{formatter:e=>t._e_templates(e,(e=>t._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...i,...a),axisLabel:{formatter:e=>t._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:i,type:"line",smooth:!0},{name:"缓存访问文件大小",data:a,type:"line",smooth:!0}]}),n=e.sum(...i,...a)}t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[2].getChildrens()[1].setText(t._format_number_unit(s)),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[3].getChildrens()[1].setText(t._format_bytes(n))}if("system"==i&&(t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(t._format_number_unit(a.connections)),t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(t._format_bytes(a.memory))),"qps"==i){const i=parseInt(e.getTimestamp()/1e3),n=(i%5!=0?5:0)-i%5+i,l=[];var r=[],s=[];for(let i=n-300;i<=n;i++){let n=a.hasOwnProperty(i)?a[i]:0;r.push(n),i%5==0&&(l.push({value:e.sum(...r)/r.length,raw:r}),r=[],s.push(t._e_format_time(1e3*i)))}t._page[1].getChildrens()[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].setText(t._format_number_unit(e.sum(...e.collectionSingleList(l.map((e=>[...e.raw])))))),t._e_qps.setOption({xAxis:{data:s},series:[{data:l}]})}console.log(i,a),((e,...t)=>{var i=f.split("-",1),a=i[0],r=i[1];const s=(r?o[a].children.filter((e=>e.key==r))[0]:o[a]).core||{};e in s&&s[e](...t)})("_ws_message",i,a)}_deserializeData(e){const t=e.readVarInt();switch(t){case 0:return e.readString();case 1:return e.readBoolean();case 2:return parseFloat(e.readString());case 3:return parseInt(e.readString());case 4:{const t=e.readVarInt(),i=[];for(let a=0;a{this._e_bytes.resize(),this._e_daily_bytes.resize(),this._e_hits.resize(),this._e_daily_hits.resize(),this._e_qps.resize()}))],this._updateTimer=setInterval((()=>this.update()),1e3),this._e_options={tooltip:{trigger:"axis"},grid:{left:"3%",right:"4%",bottom:"3%",top:"20%",containLabel:!0},xAxis:{type:"category"},yAxis:{type:"value",min:1,max:10},series:[]},this._unit_bytes=["B","KB","MB","GB","TB","PB","EB"],this._unit_number=["","k","M","G","T","P","E"],this._hourly=Array.from({length:24},((e,t)=>t+" 时")),this._e_qps=echarts.init(this._page[1].getChildrens()[1].getChildrens()[1].valueOf()),this._e_hits=echarts.init(this._page[1].getChildrens()[2].getChildrens()[1].valueOf()),this._e_bytes=echarts.init(this._page[1].getChildrens()[3].getChildrens()[1].valueOf()),this._e_daily_hits=echarts.init(this._page[1].getChildrens()[4].getChildrens()[1].valueOf()),this._e_daily_bytes=echarts.init(this._page[1].getChildrens()[5].getChildrens()[1].valueOf()),this._e_hits.setOption(this._e_options),this._e_bytes.setOption(this._e_options),this._e_hits.setOption({xAxis:{data:this._hourly}}),this._e_bytes.setOption({xAxis:{data:this._hourly}}),this._e_daily_hits.setOption(this._e_options),this._e_daily_bytes.setOption(this._e_options),this._e_qps.setOption({color:"#0fc6c2",tooltip:{trigger:"axis",formatter:t=>'
'+t[0].name+'
QPSAvg: '+t[0].data.value+" total: "+e.sum(...t[0].data.raw)+'
'},stateAnimation:{duration:300,easing:"cubicOut"},xAxis:{type:"category",show:!1},yAxis:{show:!1,type:"value"},grid:{top:10,bottom:10,right:0,left:0,show:!1,z:0,containLabel:!1,backgroundColor:"rgba(0,0,0,0)",borderWidth:1,borderColor:"#ccc"},series:[{type:"bar",barGap:"0",barMinHeight:4,itemStyle:{borderRadius:[2,2,0,0]},z:2,backgroundStyle:{color:"rgba(180, 180, 180, 0.2)",borderColor:null,borderWidth:0,borderType:"solid",borderRadius:0,shadowBlur:0,shadowColor:null,shadowOffsetX:0,shadowOffsetY:0},select:{itemStyle:{borderColor:"#212121"}}}]}),this.update(),setTimeout((()=>this._page[1].update()),1)}connect(e){e.push(...this._page)}update(){this._page[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(this._format_time(this.runtime,!0))}updateStatus(e){this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(e)}_format_time(t,i=!1){if(null==t)return"-";let a=Number.parseInt(t);return i&&(a=Number.parseInt(e.getTime()-a)),`${parseInt(a/60/60/24).toString().padStart(2,"0")} 天 ${parseInt(a/60/60%24).toString().padStart(2,"0")} 小时 ${parseInt(a/60%60).toString().padStart(2,"0")} 分钟 ${parseInt(a%60).toString().padStart(2,"0")} 秒`}_format_bytes(e,t=null){return 0==e||(t=t||Math.min(Number.parseInt(Math.floor(Math.log(e)/Math.log(1024))),this._unit_bytes.length))<=0?`${e.toFixed(2)}${this._unit_bytes[0]}`:`${(e/=1024**t).toFixed(2)}${this._unit_bytes[t]}`}_e_templates(e,t=null){const i='
{name}{value}
';var a="";for(const r of e)a+=i.replace("{color}",r.color).replace("{name}",r.name).replace("{value}",t?t(r.value):r.value);return`
${e[0].name}
${a}
`}_format_number_unit(e){var t=(e+"").split("."),i=t[0],a=t.length>=2?"."+t.slice(1).join("."):"";return i.toString().replace(/\B(?=(\d{3})+(?!\d))/g,", ")+a}_e_format_time(e){const t=new Date(e);return t.getHours().toString().padStart(2,0)+":"+t.getMinutes().toString().padStart(2,0)+":"+t.getSeconds().toString().padStart(2,0)}};((e,t,i,a)=>{if(e.includes(".")){const[r,s]=[e.slice(0,e.indexOf(".")),e.slice(e.indexOf(".")+1)];o[r]||(o[r]={icon:t,children:[],text:"",core:a}),"children"in o[r]||(o[r].children=[]),o[r].children.push({key:s,text:i,core:a})}else o[e]={key:e,icon:t,text:i,core:a}})("dashboard","","数据统计",t)})(),p(),e.set_styles({"body,ol,ul,h1,h2,h3,h4,h5,h6,p,th,td,dl,dd,form,fieldset,legend,input,textarea,select":"margin:0;padding:0",body:"font:12px;background:#fff;-webkit-text-size-adjust:100%",a:"color:#172c45;text-decoration:none",em:"font-style:normal",li:"list-style:none",img:"border:0;vertical-align:middle",table:"border-collapse:collapse;border-spacing:0",p:"word-wrap:break-word",":root":["--r-main-background-color: #F6F7F9","--r-background-color: #191919","--r-main-font-size: 42px","--r-main-color: #fff","--r-block-margin: 20px","--r-heading-margin: 0 0 20px 0","--r-heading-font: Source Sans Pro, Helvetica, sans-serif","--r-heading-color: #fff","--r-heading-line-height: 1.2","--r-heading-letter-spacing: normal","--r-heading-text-transform: uppercase","--r-heading-text-shadow: none","--r-heading-font-weight: 600","--r-heading1-text-shadow: none","--r-heading1-size: 2.5em","--r-heading2-size: 1.6em","--r-heading3-size: 1.3em","--r-heading4-size: 1em","--r-code-font: monospace","--r-link-color: #42affa","--r-link-color-dark: #068de9","--r-link-color-hover: #8dcffc","--r-selection-background-color: rgba(66, 175, 250, .75)","--r-selection-color: #fff","--r-overlay-element-bg-color: 240, 240, 240","--r-overlay-element-fg-color: 0, 0, 0","--r-ligting-color: rgb(15, 198, 194);"],".root .left":["position: fixed","min-height: calc(100vh - 72px)","max-height: calc(100vh - 72px)","min-width: 48px","max-width: 184px","margin-top: 16px","width: 256px","padding: 8px","padding-top: 0","background: var(--r-main-background-color)","transition: transform 200ms linear 0s;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .left .content":["overflow: auto","width: 95%"],".root .left.hide":["transform: translateX(-100%);"],".root .left .button":["cursor: pointer;","border-radius: 8px;","margin-bottom: 8px","padding: 4px","padding-left: 8px","transition: color 200ms linear 0s;"],".root .left .arrow-background":["position: absolute","background: var(--r-main-background-color)","width: 20px","height: 20px","left: 194px","margin-top: -16px","cursor: pointer"],".root .left .arrow":["width: 100%","height: 100%",'background-image: url("data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgc3R5bGU9IndpZHRoOiAxZW07aGVpZ2h0OiAxZW07dmVydGljYWwtYWxpZ246IG1pZGRsZTtmaWxsOiBjdXJyZW50Q29sb3I7b3ZlcmZsb3c6IGhpZGRlbjsiIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwLWlkPSI3NTUiPjxwYXRoIGQ9Ik0zMjUuMDQ4IDkzLjUxMWwtNjAuMDMwIDU5LjQzNSAzNTcuMTgxIDM1OS42MzEtMzYwLjE4NCAzNTYuNjAzIDU5LjUyMiA1OS45MyA0MjAuMjA3LTQxNi4wNDN6IiBmaWxsPSIjODQ4NDg0IiBwLWlkPSI3NTYiPjwvcGF0aD48L3N2Zz4=");'],".root .container .left.hide .arrow-background .arrow":["transform: rotate(0deg);"],".root .container .left .arrow-background .arrow":["transform: rotate(180deg);","transition: transform 100ms linear 0s;"],".root .left .button:hover":["color: var(--r-ligting-color)"],".root .left .button.selected":["background: var(--r-ligting-color)","box-shadow: rgba(15, 198, 194, 0.2) 0px 10px 25px 0px;","color: white"],".root .left .side":["margin-left: 8px"],".root .left .sidebutton":["padding: 2px","margin-bottom: 8px","cursor: pointer;","color: rgba(0, 0, 0, 0.5);","transition: color 200ms linear 0s;"],".root .left .sidebutton:hover":["color: var(--r-link-color-hover)"],".root .left .sidebutton.selected":["color: black","font-weight: bold"],".root .left .sidebutton:hover .cycle":["background: var(--r-link-color-hover)"],".root .left .sidebutton.selected .cycle":["width: 8px;","height: 8px;","background-color: rgb(15, 198, 194);","margin-right: 6px","margin-left: 2px","border-radius: 50%;"],".root .left .sidebutton .cycle":["width: 4px;","height: 4px;","margin: 4px","margin-right: 8px","background-color: rgba(0, 0, 0, 0.5);","transition: background-color 200ms linear 0s;","border-radius: 50%;"],".root .header":["position: fixed","height: 40px","min-height: 40px","min-width: 100vw","background: var(--r-main-background-color)","z-index: 1","padding: 8px","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .container":["position: relative;","top: 56px;"],".root .container .right":["padding-top: 16px","margin-left: 216px","transition: width 200ms linear 0s;","min-width: calc(100vw - 232px)","min-height: calc(100vh - 72px)"],".root .container .left.hide ~ .right":["margin-left: 0","min-width: 100vw"],".root .container .right .panel":["background-color: rgb(255, 255, 255);","color: rgb(0, 0, 0);","transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;","border-radius: 4px;","background-image: none;","padding: 24px;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;","margin: 16px;"],".panel.info-4":["display: flex","flex-warp: warp"],".panel.info-4 div":["width: 25%"],".panel.info-2":["display: flex","flex-warp: warp"],".panel.info-2 div":["width: 50%"],".panel .title":["display: flex","margin: 0px 0px 6px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.5);","font-size: 14px;"],".panel .value":["margin: 0px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.7);","font-size: 24px;"],".root .container .left.hide~.right":["margin-left: 32px","min-width: calc(100vw - 48px)"],".root .left .copyright":["position: fixed;","bottom: 2px"],".qps .icon":["width: 14px","height: 14px"],".qps":["display: flex","align-items: center"],".progress":["position: absolute;","z-index: 2","width: 0","height: 2px","background: var(--r-ligting-color)","transition: width 200ms linear 0s;"],body:["background-color: var(--r-main-background-color)"]}),g(),y()})(); \ No newline at end of file +(()=>{const e=new TTB,t=e.createElement("div").class("root"),i=e.createFlex().class("header").style("align-items","center"),a=e.createElement("div").class("left"),r=e.createElement("div").class("arrow-background").append(e.createElement("div").class("arrow")),s=e.createElement("div").class("content"),n=e.createElement("div").class("copyright"),l=e.createElement("div").class("right"),o={},d=e.createElement("div").class("progress"),c=e=>{d.setStyle("width",100*e+"%"),100*e>=99&&setTimeout((()=>d.setStyle("width",0)),250)},p=()=>{s.clear();for(const t in o){const i=o[t],a=!!i.children,r=e.createFlex().class("button").id("left-list-"+t).append(e.createElement("p").setText(i.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+i.children[0].key:"")}));if(s.append(r),a){const r=e.createElement("div").style("display: none").class("side").id("left-list-"+t+"-sub");for(const s of i.children)r.append(e.createFlex().class("sidebutton").id("left-list-"+t+"-sub-"+s.key).append(e.createElement("div").class("cycle"),e.createElement("p").setText(s.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+s.key:"")})));s.append(r)}}},h=()=>{const t=e.getURLKey()||Object.keys(o)[0];for(const i of Object.keys(o))if(u!=t?i==t?(document.getElementById("left-list-"+i).classList.add("selected"),x=""):document.getElementById("left-list-"+i).classList.remove("selected"):u==i&&document.getElementById("left-list-"+i).classList.add("selected"),document.getElementById("left-list-"+i+"-sub")){document.getElementById("left-list-"+i+"-sub").style.display=i==t?"block":"none";const a=e.getURLKeyParams().key||Object.keys(Object.values(o)[0])[1];for(const e of o[i].children.map((e=>e.key)))e==a?(document.getElementById("left-list-"+i+"-sub-"+e).classList.add("selected"),x=a):document.getElementById("left-list-"+i+"-sub-"+e).classList.remove("selected")}},g=()=>{const t=e.getURLKey()||Object.keys(o)[0],i=x;h(),(u!=t||x&&x!=i)&&(u&&x&&x==i&&m(u,i,"disconnect"),m(t,x,"connect")),u=t},m=(t,i,a)=>{const r=(i?o[t].children.filter((e=>e.key==i))[0]:o[t]).core||{};if(f!=(t+=i?"-"+i:"")){if(f in r&&"disconnect"in r)try{r.disconnect()}catch(e){console.log(e)}for(;null!=document.getElementsByClassName("right")[0].firstChild;)document.getElementsByClassName("right")[0].removeChild(document.getElementsByClassName("right")[0].firstChild);f=t}if(a in r)try{document.getElementsByClassName("right")[0].style.display="none",page=[],"connect"==a&&"page"in r&&(c(.7),"init"in r&&r.init(),c(.8),page=r.page()||[]),c(.9),r[a](page),null!=page&&document.getElementsByClassName("right")[0].append(e.createElement("div").id("module-"+t).append(...Array.isArray(page)?page:[page]).valueOf()),document.getElementsByClassName("right")[0].style.display="block",c(1)}catch(e){console.log(e)}else c(1)};let u="",x="",f="";const y=()=>{p(),h()};i.append(e.createElement("h3").setText("Python OpenBMCLAPI Dashboard")),n.append(e.createElement("p").append(e.createElement("a").setAttribute("href","mailto:administrator@ttb-network.top").setText("TTB Network")," - ",e.VERSION)),r.event("click",(()=>{a.toggle("hide"),window.dispatchEvent(new Event("resize"))})),t.append(i,e.createElement("div").class("container").append(a.append(r,s,n),l)),window.addEventListener("resize",y),window.addEventListener("popstate",g),document.body.prepend(d.valueOf(),t.valueOf()),(()=>{new class{constructor(){this.ws=e.websocket("ws"+window.location.protocol.slice(4)+"//"+window.location.host+window.location.pathname,{onopen:()=>this.onopen(),onmessage:e=>{let t=new FileReader;t.onload=()=>{let e=t.result;const i=new DataInputStream(e);this.message(i.readString(),this._deserializeData(i))},t.readAsArrayBuffer(e.data)},onclose:()=>this.onclose()}),this._timer_qps=null,this._timer=null,this._timer_system=null}onclose(){}onopen(){this.send("runtime"),this.send("storage"),this.send("status"),this._timer_qps?.block(),this._timer?.block(),this._timer_system?.block(),this._timer_qps=e.runTaskRepeat((()=>{this.send("qps")}),0,5e3),this._timer=e.runTaskRepeat((()=>{this.send("dashboard")}),0,1e4),this._timer_system=e.runTaskRepeat((()=>{this.send("system")}),0,1e3)}send(e,t){const i=new DataOutputStream;i.writeString(e),i.write(this._serializeData(t)),this.ws.send(i)}message(i,a){if("runtime"==i&&(t.runtime=a,t.update()),"status"==i&&t.updateStatus(a),"dashboard"==i){const i=a.hourly,r=a.days;let s,n,l,o,d=Math.max(...i.map((e=>e._hour)));l=Array.from({length:d},((e,t)=>0)),o=Array.from({length:d},((e,t)=>0));for(const e of i)l[e._hour]=e.hits,o[e._hour]=e.cache_hits,d=Math.max(d,e._hour);t._e_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...l,...o)},series:[{name:"I/O访问数",data:l,type:"line",smooth:!0},{name:"缓存访问数",data:o,type:"line",smooth:!0}]}),s=e.sum(...l,...o),l=Array.from({length:d},((e,t)=>0)),o=Array.from({length:d},((e,t)=>0));for(const e of i)l[e._hour]=e.bytes,o[e._hour]=e.cache_bytes;t._e_bytes.setOption({tooltip:{formatter:e=>t._e_templates(e,(e=>t._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...l,...o),axisLabel:{formatter:e=>t._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:l,type:"line",smooth:!0},{name:"缓存访问文件大小",data:o,type:"line",smooth:!0}]}),n=e.sum(...l,...o),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(t._format_number_unit(s)),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(t._format_bytes(n)),l=Array.from({length:30},((e,t)=>0)),o=Array.from({length:30},((e,t)=>0));for(const e of r)l[e._day]=e.hits,o[e._day]=e.cache_hits;t._e_daily_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...l,...o)},series:[{name:"I/O访问数",data:l,type:"line",smooth:!0},{name:"缓存访问数",data:o,type:"line",smooth:!0}]}),s=e.sum(...l,...o);{const i=Array.from({length:30},((e,t)=>0)),a=Array.from({length:30},((e,t)=>0));for(const e of r)i[e._day]=e.bytes,a[e._day]=e.cache_bytes;t._e_daily_bytes.setOption({tooltip:{formatter:e=>t._e_templates(e,(e=>t._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...i,...a),axisLabel:{formatter:e=>t._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:i,type:"line",smooth:!0},{name:"缓存访问文件大小",data:a,type:"line",smooth:!0}]}),n=e.sum(...i,...a)}t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[2].getChildrens()[1].setText(t._format_number_unit(s)),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[3].getChildrens()[1].setText(t._format_bytes(n))}if("system"==i&&(t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(t._format_number_unit(a.connections)),t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(t._format_bytes(a.memory)),t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[2].getChildrens()[1].setText(`${t._format_number_unit(a.cache.total)}(${t._format_bytes(a.cache.bytes)})`),t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[3].getChildrens()[1].setText(a.cpu.toFixed(2)+"%")),"qps"==i){const i=parseInt(e.getTimestamp()/1e3),n=(i%5!=0?5:0)-i%5+i,l=[];var r=[],s=[];for(let i=n-300;i<=n;i++){let n=a.hasOwnProperty(i)?a[i]:0;r.push(n),i%5==0&&(l.push({value:e.sum(...r)/r.length,raw:r}),r=[],s.push(t._e_format_time(1e3*i)))}t._page[1].getChildrens()[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].setText(t._format_number_unit(e.sum(...e.collectionSingleList(l.map((e=>[...e.raw])))))),t._e_qps.setOption({xAxis:{data:s},series:[{data:l}]})}console.log(i,a),((e,...t)=>{var i=f.split("-",1),a=i[0],r=i[1];const s=(r?o[a].children.filter((e=>e.key==r))[0]:o[a]).core||{};e in s&&s[e](...t)})("_ws_message",i,a)}_deserializeData(e){const t=e.readVarInt();switch(t){case 0:return e.readString();case 1:return e.readBoolean();case 2:return parseFloat(e.readString());case 3:return parseInt(e.readString());case 4:{const t=e.readVarInt(),i=[];for(let a=0;a{this._e_bytes.resize(),this._e_daily_bytes.resize(),this._e_hits.resize(),this._e_daily_hits.resize(),this._e_qps.resize()}))],this._updateTimer=setInterval((()=>this.update()),1e3),this._e_options={tooltip:{trigger:"axis"},grid:{left:"3%",right:"4%",bottom:"3%",top:"20%",containLabel:!0},xAxis:{type:"category"},yAxis:{type:"value",min:1,max:10},series:[]},this._unit_bytes=["B","KB","MB","GB","TB","PB","EB"],this._unit_number=["","k","M","G","T","P","E"],this._hourly=Array.from({length:24},((e,t)=>t+" 时")),this._daily=Array.from({length:31},((e,t)=>t+" 天")),this._e_qps=echarts.init(this._page[1].getChildrens()[1].getChildrens()[1].valueOf()),this._e_hits=echarts.init(this._page[1].getChildrens()[2].getChildrens()[1].valueOf()),this._e_bytes=echarts.init(this._page[1].getChildrens()[3].getChildrens()[1].valueOf()),this._e_daily_hits=echarts.init(this._page[1].getChildrens()[4].getChildrens()[1].valueOf()),this._e_daily_bytes=echarts.init(this._page[1].getChildrens()[5].getChildrens()[1].valueOf()),this._e_hits.setOption(this._e_options),this._e_bytes.setOption(this._e_options),this._e_hits.setOption({xAxis:{data:this._hourly}}),this._e_bytes.setOption({xAxis:{data:this._hourly}}),this._e_daily_hits.setOption(this._e_options),this._e_daily_bytes.setOption(this._e_options),this._e_daily_hits.setOption({xAxis:{data:this._daily}}),this._e_daily_bytes.setOption({xAxis:{data:this._daily}}),this._e_qps.setOption({color:"#0fc6c2",tooltip:{trigger:"axis",formatter:t=>'
'+t[0].name+'
QPSAvg: '+t[0].data.value+" total: "+e.sum(...t[0].data.raw)+'
'},stateAnimation:{duration:300,easing:"cubicOut"},xAxis:{type:"category",show:!1},yAxis:{show:!1,type:"value"},grid:{top:10,bottom:10,right:0,left:0,show:!1,z:0,containLabel:!1,backgroundColor:"rgba(0,0,0,0)",borderWidth:1,borderColor:"#ccc"},series:[{type:"bar",barGap:"0",barMinHeight:4,itemStyle:{borderRadius:[2,2,0,0]},z:2,backgroundStyle:{color:"rgba(180, 180, 180, 0.2)",borderColor:null,borderWidth:0,borderType:"solid",borderRadius:0,shadowBlur:0,shadowColor:null,shadowOffsetX:0,shadowOffsetY:0},select:{itemStyle:{borderColor:"#212121"}}}]}),this.update(),setTimeout((()=>this._page[1].update()),1)}connect(e){e.push(...this._page)}update(){this._page[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(this._format_time(this.runtime,!0))}updateStatus(e){this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(e)}_format_time(t,i=!1){if(null==t)return"-";let a=Number.parseInt(t);return i&&(a=Number.parseInt(e.getTime()-a)),`${parseInt(a/60/60/24).toString().padStart(2,"0")} 天 ${parseInt(a/60/60%24).toString().padStart(2,"0")} 小时 ${parseInt(a/60%60).toString().padStart(2,"0")} 分钟 ${parseInt(a%60).toString().padStart(2,"0")} 秒`}_format_bytes(e,t=null){return 0==e||(t=t||Math.min(Number.parseInt(Math.floor(Math.log(e)/Math.log(1024))),this._unit_bytes.length))<=0?`${e.toFixed(2)}${this._unit_bytes[0]}`:`${(e/=1024**t).toFixed(2)}${this._unit_bytes[t]}`}_e_templates(e,t=null){const i='
{name}{value}
';var a="";for(const r of e)a+=i.replace("{color}",r.color).replace("{name}",r.name).replace("{value}",t?t(r.value):r.value);return`
${e[0].name}
${a}
`}_format_number_unit(e){var t=(e+"").split("."),i=t[0],a=t.length>=2?"."+t.slice(1).join("."):"";return i.toString().replace(/\B(?=(\d{3})+(?!\d))/g,", ")+a}_e_format_time(e){const t=new Date(e);return t.getHours().toString().padStart(2,0)+":"+t.getMinutes().toString().padStart(2,0)+":"+t.getSeconds().toString().padStart(2,0)}};((e,t,i,a)=>{if(e.includes(".")){const[r,s]=[e.slice(0,e.indexOf(".")),e.slice(e.indexOf(".")+1)];o[r]||(o[r]={icon:t,children:[],text:"",core:a}),"children"in o[r]||(o[r].children=[]),o[r].children.push({key:s,text:i,core:a})}else o[e]={key:e,icon:t,text:i,core:a}})("dashboard","","数据统计",t)})(),p(),e.set_styles({"body,ol,ul,h1,h2,h3,h4,h5,h6,p,th,td,dl,dd,form,fieldset,legend,input,textarea,select":"margin:0;padding:0",body:"font:12px;background:#fff;-webkit-text-size-adjust:100%",a:"color:#172c45;text-decoration:none",em:"font-style:normal",li:"list-style:none",img:"border:0;vertical-align:middle",table:"border-collapse:collapse;border-spacing:0",p:"word-wrap:break-word",":root":["--r-main-background-color: #F6F7F9","--r-background-color: #191919","--r-main-font-size: 42px","--r-main-color: #fff","--r-block-margin: 20px","--r-heading-margin: 0 0 20px 0","--r-heading-font: Source Sans Pro, Helvetica, sans-serif","--r-heading-color: #fff","--r-heading-line-height: 1.2","--r-heading-letter-spacing: normal","--r-heading-text-transform: uppercase","--r-heading-text-shadow: none","--r-heading-font-weight: 600","--r-heading1-text-shadow: none","--r-heading1-size: 2.5em","--r-heading2-size: 1.6em","--r-heading3-size: 1.3em","--r-heading4-size: 1em","--r-code-font: monospace","--r-link-color: #42affa","--r-link-color-dark: #068de9","--r-link-color-hover: #8dcffc","--r-selection-background-color: rgba(66, 175, 250, .75)","--r-selection-color: #fff","--r-overlay-element-bg-color: 240, 240, 240","--r-overlay-element-fg-color: 0, 0, 0","--r-ligting-color: rgb(15, 198, 194);"],".root .left":["position: fixed","min-height: calc(100vh - 72px)","max-height: calc(100vh - 72px)","min-width: 48px","max-width: 184px","margin-top: 16px","width: 256px","padding: 8px","padding-top: 0","background: var(--r-main-background-color)","transition: transform 200ms linear 0s;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .left .content":["overflow: auto","width: 95%"],".root .left.hide":["transform: translateX(-100%);"],".root .left .button":["cursor: pointer;","border-radius: 8px;","margin-bottom: 8px","padding: 4px","padding-left: 8px","transition: color 200ms linear 0s;"],".root .left .arrow-background":["position: absolute","background: var(--r-main-background-color)","width: 20px","height: 20px","left: 194px","margin-top: -16px","cursor: pointer"],".root .left .arrow":["width: 100%","height: 100%",'background-image: url("data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgc3R5bGU9IndpZHRoOiAxZW07aGVpZ2h0OiAxZW07dmVydGljYWwtYWxpZ246IG1pZGRsZTtmaWxsOiBjdXJyZW50Q29sb3I7b3ZlcmZsb3c6IGhpZGRlbjsiIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwLWlkPSI3NTUiPjxwYXRoIGQ9Ik0zMjUuMDQ4IDkzLjUxMWwtNjAuMDMwIDU5LjQzNSAzNTcuMTgxIDM1OS42MzEtMzYwLjE4NCAzNTYuNjAzIDU5LjUyMiA1OS45MyA0MjAuMjA3LTQxNi4wNDN6IiBmaWxsPSIjODQ4NDg0IiBwLWlkPSI3NTYiPjwvcGF0aD48L3N2Zz4=");'],".root .container .left.hide .arrow-background .arrow":["transform: rotate(0deg);"],".root .container .left .arrow-background .arrow":["transform: rotate(180deg);","transition: transform 100ms linear 0s;"],".root .left .button:hover":["color: var(--r-ligting-color)"],".root .left .button.selected":["background: var(--r-ligting-color)","box-shadow: rgba(15, 198, 194, 0.2) 0px 10px 25px 0px;","color: white"],".root .left .side":["margin-left: 8px"],".root .left .sidebutton":["padding: 2px","margin-bottom: 8px","cursor: pointer;","color: rgba(0, 0, 0, 0.5);","transition: color 200ms linear 0s;"],".root .left .sidebutton:hover":["color: var(--r-link-color-hover)"],".root .left .sidebutton.selected":["color: black","font-weight: bold"],".root .left .sidebutton:hover .cycle":["background: var(--r-link-color-hover)"],".root .left .sidebutton.selected .cycle":["width: 8px;","height: 8px;","background-color: rgb(15, 198, 194);","margin-right: 6px","margin-left: 2px","border-radius: 50%;"],".root .left .sidebutton .cycle":["width: 4px;","height: 4px;","margin: 4px","margin-right: 8px","background-color: rgba(0, 0, 0, 0.5);","transition: background-color 200ms linear 0s;","border-radius: 50%;"],".root .header":["position: fixed","height: 40px","min-height: 40px","min-width: 100vw","background: var(--r-main-background-color)","z-index: 1","padding: 8px","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .container":["position: relative;","top: 56px;"],".root .container .right":["padding-top: 16px","margin-left: 216px","transition: width 200ms linear 0s;","min-width: calc(100vw - 232px)","min-height: calc(100vh - 72px)"],".root .container .left.hide ~ .right":["margin-left: 0","min-width: 100vw"],".root .container .right .panel":["background-color: rgb(255, 255, 255);","color: rgb(0, 0, 0);","transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;","border-radius: 4px;","background-image: none;","padding: 24px;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;","margin: 16px;"],".panel.info-4":["display: flex","flex-warp: warp"],".panel.info-4 div":["width: 25%"],".panel.info-2":["display: flex","flex-warp: warp"],".panel.info-2 div":["width: 50%"],".panel .title":["display: flex","margin: 0px 0px 6px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.5);","font-size: 14px;"],".panel .value":["margin: 0px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.7);","font-size: 24px;"],".root .container .left.hide~.right":["margin-left: 32px","min-width: calc(100vw - 48px)"],".root .left .copyright":["position: fixed;","bottom: 2px"],".qps .icon":["width: 14px","height: 14px"],".qps":["display: flex","align-items: center"],".progress":["position: absolute;","z-index: 2","width: 0","height: 2px","background: var(--r-ligting-color)","transition: width 200ms linear 0s;"],body:["background-color: var(--r-main-background-color)"]}),g(),y()})(); \ No newline at end of file diff --git a/bmclapi_dashboard/static/js/ttb.min.js b/bmclapi_dashboard/static/js/ttb.min.js index 0769e22..584f998 100644 --- a/bmclapi_dashboard/static/js/ttb.min.js +++ b/bmclapi_dashboard/static/js/ttb.min.js @@ -1 +1 @@ -class TTB{constructor(){this.VERSION="0.0.1",this.defaultStyles={".ttb-flex":["display: flex","flex-wrap: wrap"]},this.websockets=[],this.documentStyle=document.createElement("style"),this.styles={},this.set_styles(this.defaultStyles),document.head.append(this.documentStyle),window.addEventListener("beforeunload",(()=>{this.websockets.forEach((t=>t.object.close()))})),this._flexes=[],g_TTB=this}addFlex(t){this._flexes.push(t)}resizeFlex(t){for(const e of this._flexes)t.base!=e.base&&e.update(!1)}createFlex(){return new TTBElementFlex}createElement(t){return new TTBElement(t)}request(t={}){const e=t.method||"GET",s=t.path||"/",r=t.headers||{},i=!1!==t.async,n=t.username||null,h=t.password||null,a=t.responseType||"text";let l=new XMLHttpRequest;l.open(e,s,i,n,h);for(const t in r)l.setRequestHeader(t,r[t]);return l.responseType=a,l=t.xhr&&t.xhr(l)||l,new Promise(((e,s)=>{l.onload=function(){l.status>=200&&l.status<300?(t.success&&t.success(l.response),e(l.response)):(t.error&&t.error(l.status,l.statusText),s(new Error(`Request failed with status ${l.status}: ${l.statusText}`)))},l.onerror=function(){t.error&&t.error(l.status,l.statusText),s(new Error("Network Error"))},l.send(t.data||null)}))}websocket(t,e={}){return new WebSocketClient(t,e)}set_styles=t=>{for(const e in t)this.set_style(e,t[e])};set_style=(t,e)=>{Array.isArray(e)&&(e=e.join(";"));const s=`${t} { ${e} }`,r=document.createTextNode(s),i=this.documentStyle.sheet;if(i)try{i.insertRule(s,i.cssRules.length)}catch(t){this.documentStyle.appendChild(r)}else this.documentStyle.appendChild(r);this.styles[t]=e};calculateBytes(t){let e;return e="string"==typeof t?(new TextEncoder).encode(t).byteLength:t instanceof ArrayBuffer||t instanceof DataView||t instanceof Uint8Array?t.byteLength:t instanceof Blob?t.size:t instanceof BytesBuffer?t.len():(new TextEncoder).encode(String(t)).byteLength,e}sum(...t){let e=0;for(const s of t)e+=s;return e}avg(...t){return 0==t.length?0:this.sum(...t)/t.length}isDOM(t){return t instanceof HTMLElement||"[object HTMLUnknownElement]"===Object.prototype.toString.call(t)||t&&"object"==typeof t&&1===t.nodeType&&"string"==typeof t.nodeName}collectionSingleList(...t){var e=[];for(const s of t)Array.isArray(s)?e.push(...this.collectionSingleList(...s)):e.push(s);return e}getURLParams(){return-1!==window.location.hash.indexOf("#")?window.location.hash.slice(1):""}getURLKey(){var t=this.getURLParams();return(t.startsWith("/")?t.slice(1):t).slice(0,-1!==t.indexOf("?")?t.indexOf("?"):t.length)}getURLKeyParams(){var t=this.getURLParams();if(-1!==(t=t.startsWith("/")?t.slice(1):t).indexOf("?")){for(var e={},s=t.slice(t.indexOf("?")).substring(1).split("&"),r=0;rthis._resize(...t)))}setHTML(t){return this.base.innerHTML=t,this}setText(t){return this.base.innerText=t,this}title(t){return this.setText(t)}html(t){return this.setHTML(t)}append(...t){for(const e of t)e instanceof TTBElement?this.base.append(e.valueOf()):this.base.append(e);return this}id(t){return this.base.id=t,this}class(...t){for(const e of t)for(const t of e.split(" "))this.base.classList.add(t);return this}toggle(t){return this.base.classList.toggle(t),this}style(t){return this.base.style=t,this}_resize(...t){for(const e of this._resize_handler)try{e(...t)}catch(t){console.log(t,e)}}setStyle(t,e){return this.base.style[t]=e,this}valueOf(){return this.base}containsClass(...t){for(const e of t)for(const t of e.split(" "))if(this.base.classList.contains(t))return!0;return!1}setAttribute(t,e){return this.base.setAttribute(t,e),this}isDOM(t){return t instanceof HTMLElement||"[object HTMLUnknownElement]"===Object.prototype.toString.call(t)||t&&"object"==typeof t&&1===t.nodeType&&"string"==typeof t.nodeName}clear(){for(;null!=this.base.firstChild;)this.base.removeChild(this.base.firstChild);return this}event(t,e){return"resize"==t?(this._resize_handler.push(e),this):(this.base.addEventListener(t,e),this)}getChildrens(){return new Array(...this.base.children).map((t=>(this.isDOM(t)&&t.classList.contains("ttb-flex")&&g_TTB._flexes.filter((e=>e.valueOf()==t))[0],new TTBElement(t,!0))))}}class TTBElementFlex extends TTBElement{constructor(t="div",e=!1){super(t,e),g_TTB.addFlex(this),this.class("ttb-flex"),this._minwidth=null,this._minheight=null,this._maxwidth=null,this._maxheight=null,this._updateTimer=null,this._child=1,this._childStyle="",this._tag=null,this._resizes=[],this.update()}addResize(t){return this._resizes.push(t),this}append(...t){return super.append(...t.map((t=>this.isDOM(t)||t instanceof TTBElement?t:new TTBElement("div").setHTML(t)))),this}tag(t){return this._tag=t,this}min_width(t){return this.minwidth=t,this}max_width(t){return this.maxwidth=t,this}min_height(t){return this.minheight=t,this}max_height(t){return this.maxheight=t,this}height(t){return this.setStyle("height",t),this}width(t){return this.setStyle("width",t),this}style(t,e){return g_TTB.set_style(".ttb-flex."+t+"_"+e,`${t}: ${e}`),this.class(t+"_"+e),this}update(t=!0){const e=super.valueOf().offsetWidth-1;let s=this._calcValueWithDisplay(this._minwidth||0,e),r=this._calcValueWithDisplay(this._maxwidth,e),i=2*Number.parseInt(g_TTB.clamp(s,e,r)/2);const n=Math.max(0,Math.floor((i-1)/this._child));for(const t of this.getChildrens()){const r=window.getComputedStyle(t.valueOf()),h=parseInt(r.marginRight,10)+parseInt(r.marginLeft,10);t.valueOf().style=this._childStyle,t.setStyle("boxSizing","border-box"),t.setStyle("width",(i<=s?e:n-(Number.isNaN(h)?0:h))+"px")}for(const t of this._resizes)t();return t?(g_TTB.resizeFlex(t),this):this}_calcValueWithDisplay(t,e){return-1==t||null==t?e:"string"==typeof t&&t.includes("%")?Math.floor(e*(parseFloat(t.replace("%",""))/100)):t}childStyle(t){return this._childStyle=t,this}minWidth(t){return this._minwidth=t,this}minHeight(t){return this._minheight=t,this}maxWidth(t){return this._maxwidth=t,this}maxHeight(t){return this._maxheight=t,this}child(t){return this._child=Math.max(1,Number.parseInt(t.toString())),this}}class Task{constructor(t,e,s=null,...r){this.func=t,this.args=r,this.delay=e,this.interval=s,this._task=setTimeout((()=>this._run()),e)}_run(){try{this.func(...this.args)}catch(t){console.error(...t)}null!=this.interval&&(this._task=setTimeout((()=>this._run()),this.interval))}block(){null!=this._task&&clearTimeout(this._task),this._task=null}}class WebSocketClient{constructor(t,e={}){this.url=t,this.ws=null,this.reconnectInterval=1e3,this.messageQueue=[],this.handlers=e,this.stats={sent:{count:0,length:0},received:{count:0,length:0}},this.connect(),this.reconnectTask=null}close(){this.ws.close()}connect(){this.ws=new WebSocket(this.url),this.ws.onopen=()=>{for(null!==this.reconnectTask&&(clearInterval(this.reconnectTask),this.reconnectTask=null);this.messageQueue.length>0;){let t=this.messageQueue.shift();this.raw_send(t)}this.handlers.onopen&&this.handlers.onopen()},this.ws.onmessage=t=>{this.stats.received.count++,this.stats.received.length+=t.data.length,this.handlers.onmessage&&this.handlers.onmessage(t)},this.ws.onclose=()=>{this.ws=null,this.connect(),this.handlers.onclose&&this.handlers.onclose()}}send(t){this.ws&&this.ws.readyState===WebSocket.OPEN?(this.stats.sent.count++,this.stats.sent.length+=g_TTB.calculateBytes(t),this.ws.send(t instanceof BytesBuffer?t.toBytes():t)):(this.ws&&this.ws.readyState!==WebSocket.CLOSED||this.connect(),this.messageQueue.push(t))}getStats(){return this.stats}}class MinecraftUtils{static getVarInt(t){let e=[];for(;;){if(0==(4294967168&t)){e.push(t);break}e.push(127&t|128),t>>=7}return e}static getVarIntLength(t){return this.getVarInt(t).length}}class BytesBuffer{constructor(...t){this.buffer=[],this.cur=0,this.write(...t)}write(...t){for(const e of t)if(e instanceof BytesBuffer)this.buffer.push(...e.buffer);else if(Number.isInteger(e))this.buffer.push(e<0?e+256:e);else if(Array.isArray(e)&&e.filter((t=>Number.isInteger(t))).length==e.length)e.forEach((t=>this.write(t)));else if(e instanceof Uint8Array)for(let t=0;tt.push(e))),t}}class DataOutputStream extends BytesBuffer{constructor(t){super(),this.write(t)}writeInteger(t){this.write(t>>24&255,t>>16&255,t>>8&255,t>>0&255)}writeBoolean(t){this.write(t?1:0)}writeFloat(t){const e=new Uint8Array(new Float32Array([t]).buffer);for(let t=0;t<4;t++)this.write(e[t])}writeDouble(t){const e=new Uint8Array(new Float64Array([t]).buffer);for(let t=0;t<8;t++)this.write(e[t])}writeVarInt(t){return this.write(MinecraftUtils.getVarInt(t)),this}writeString(t,e="utf-8"){return this.writeVarInt(t.length),this.write(new TextEncoder(e).encode(t)),this}writeLong(t){return t-=t>Math.pow(2,63)-1?Math.pow(2,64):t,this.write(t>>56&255,t>>48&255,t>>40&255,t>>32&255,t>>24&255,t>>16&255,t>>8&255,t>>0&255),this}writeUUID(t){return this.writeLong(t.int>>64),this.writeLong(0&t.int),this}}class DataInputStream extends BytesBuffer{readInteger(){let t=this.read(4);return(t[0]<<24)+(t[1]<<16)+(t[2]<<8)+(t[3]<<0)}readBoolean(){return Boolean(this.read(1)[0])}readShort(){if(value=this.read(2),value[0]|value[1]<0)throw EOFError();return(value[0]<<8)+(value[1]<<0)}readLong(){let t=this.read(8);return t=(t[0]<<56)+((255&t[1])<<48)+((255&t[2])<<40)+((255&t[3])<<32)+((255&t[4])<<24)+((255&t[5])<<16)+((255&t[6])<<8)+((255&t[7])<<0),t5)throw new Error("VarInt too big");if(128!=(128&t))break}return e>=2**31-1?e-2**31*2:e}readString(t=null,e="utf-8"){return new TextDecoder(e).decode(new Uint8Array(this.read(null==t?this.readVarInt():t)))}readBytes(t){return this.read(t)}readUUID(){let t=this.readLong(),e=this.readLong();return new UUID(t.toBytes().concat(e.toBytes()))}}g_TTB=null; \ No newline at end of file +class TTB{constructor(){this.VERSION="0.0.1",this.defaultStyles={".ttb-flex":["display: flex","flex-wrap: wrap"]},this.websockets=[],this.documentStyle=document.createElement("style"),this.styles={},this.set_styles(this.defaultStyles),document.head.append(this.documentStyle),window.addEventListener("beforeunload",(()=>{this.websockets.forEach((t=>t.object.close()))})),this._flexes=[],g_TTB=this}addFlex(t){this._flexes.push(t)}resizeFlex(t){for(const e of this._flexes)t.base!=e.base&&e.update(!1)}createFlex(){return new TTBElementFlex}createElement(t){return new TTBElement(t)}request(t={}){const e=t.method||"GET",s=t.path||"/",r=t.headers||{},i=!1!==t.async,n=t.username||null,h=t.password||null,a=t.responseType||"text";let l=new XMLHttpRequest;l.open(e,s,i,n,h);for(const t in r)l.setRequestHeader(t,r[t]);return l.responseType=a,l=t.xhr&&t.xhr(l)||l,new Promise(((e,s)=>{l.onload=function(){l.status>=200&&l.status<300?(t.success&&t.success(l.response),e(l.response)):(t.error&&t.error(l.status,l.statusText),s(new Error(`Request failed with status ${l.status}: ${l.statusText}`)))},l.onerror=function(){t.error&&t.error(l.status,l.statusText),s(new Error("Network Error"))},l.send(t.data||null)}))}websocket(t,e={}){return new WebSocketClient(t,e)}set_styles=t=>{for(const e in t)this.set_style(e,t[e])};set_style=(t,e)=>{Array.isArray(e)&&(e=e.join(";"));const s=`${t} { ${e} }`,r=document.createTextNode(s),i=this.documentStyle.sheet;if(i)try{i.insertRule(s,i.cssRules.length)}catch(t){this.documentStyle.appendChild(r)}else this.documentStyle.appendChild(r);this.styles[t]=e};calculateBytes(t){let e;return e="string"==typeof t?(new TextEncoder).encode(t).byteLength:t instanceof ArrayBuffer||t instanceof DataView||t instanceof Uint8Array?t.byteLength:t instanceof Blob?t.size:t instanceof BytesBuffer?t.len():(new TextEncoder).encode(String(t)).byteLength,e}sum(...t){let e=0;for(const s of t)e+=s;return e}avg(...t){return 0==t.length?0:this.sum(...t)/t.length}isDOM(t){return t instanceof HTMLElement||"[object HTMLUnknownElement]"===Object.prototype.toString.call(t)||t&&"object"==typeof t&&1===t.nodeType&&"string"==typeof t.nodeName}collectionSingleList(...t){var e=[];for(const s of t)Array.isArray(s)?e.push(...this.collectionSingleList(...s)):e.push(s);return e}getURLParams(){return-1!==window.location.hash.indexOf("#")?window.location.hash.slice(1):""}getURLKey(){var t=this.getURLParams();return(t.startsWith("/")?t.slice(1):t).slice(0,-1!==t.indexOf("?")?t.indexOf("?"):t.length)}getURLKeyParams(){var t=this.getURLParams();if(-1!==(t=t.startsWith("/")?t.slice(1):t).indexOf("?")){for(var e={},s=t.slice(t.indexOf("?")).substring(1).split("&"),r=0;rthis._resize(...t)))}setHTML(t){return this.base.innerHTML=t,this}setText(t){return this.base.innerText=t,this}title(t){return this.setText(t)}html(t){return this.setHTML(t)}append(...t){for(const e of t)e instanceof TTBElement?this.base.append(e.valueOf()):this.base.append(e);return this}id(t){return this.base.id=t,this}class(...t){for(const e of t)for(const t of e.split(" "))this.base.classList.add(t);return this}toggle(t){return this.base.classList.toggle(t),this}style(t){return this.base.style=t,this}_resize(...t){for(const e of this._resize_handler)try{e(...t)}catch(t){console.log(t,e)}}setStyle(t,e){return this.base.style[t]=e,this}valueOf(){return this.base}containsClass(...t){for(const e of t)for(const t of e.split(" "))if(this.base.classList.contains(t))return!0;return!1}setAttribute(t,e){return this.base.setAttribute(t,e),this}isDOM(t){return t instanceof HTMLElement||"[object HTMLUnknownElement]"===Object.prototype.toString.call(t)||t&&"object"==typeof t&&1===t.nodeType&&"string"==typeof t.nodeName}clear(){for(;null!=this.base.firstChild;)this.base.removeChild(this.base.firstChild);return this}event(t,e){return"resize"==t?(this._resize_handler.push(e),this):(this.base.addEventListener(t,e),this)}getChildrens(){return new Array(...this.base.children).map((t=>(this.isDOM(t)&&t.classList.contains("ttb-flex")&&g_TTB._flexes.filter((e=>e.valueOf()==t))[0],new TTBElement(t,!0))))}}class TTBElementFlex extends TTBElement{constructor(t="div",e=!1){super(t,e),g_TTB.addFlex(this),this.class("ttb-flex"),this._minwidth=null,this._minheight=null,this._maxwidth=null,this._maxheight=null,this._updateTimer=null,this._child=1,this._childStyle="",this._tag=null,this._resizes=[],this.update()}addResize(t){return this._resizes.push(t),this}append(...t){return super.append(...t.map((t=>this.isDOM(t)||t instanceof TTBElement?t:new TTBElement("div").setHTML(t)))),this}tag(t){return this._tag=t,this}min_width(t){return this.minwidth=t,this}max_width(t){return this.maxwidth=t,this}min_height(t){return this.minheight=t,this}max_height(t){return this.maxheight=t,this}height(t){return this.setStyle("height",t),this}width(t){return this.setStyle("width",t),this}style(t,e){return g_TTB.set_style(".ttb-flex."+t+"_"+e,`${t}: ${e}`),this.class(t+"_"+e),this}update(t=!0){const e=super.valueOf().offsetWidth-1;let s=this._calcValueWithDisplay(this._minwidth||0,e),r=this._calcValueWithDisplay(this._maxwidth,e),i=2*Number.parseInt(g_TTB.clamp(s,e,r)/2);const n=Math.max(0,Math.floor((i-1)/this._child));for(const t of this.getChildrens()){const r=window.getComputedStyle(t.valueOf()),h=parseInt(r.marginRight,10)+parseInt(r.marginLeft,10);t.valueOf().style=this._childStyle,t.setStyle("boxSizing","border-box"),t.setStyle("width",(i<=s?e:n-(Number.isNaN(h)?0:h))+"px")}for(const t of this._resizes)t();return t?(g_TTB.resizeFlex(t),this):this}_calcValueWithDisplay(t,e){return-1==t||null==t?e:"string"==typeof t&&t.includes("%")?Math.floor(e*(parseFloat(t.replace("%",""))/100)):t}childStyle(t){return this._childStyle=t,this}minWidth(t){return this._minwidth=t,this}minHeight(t){return this._minheight=t,this}maxWidth(t){return this._maxwidth=t,this}maxHeight(t){return this._maxheight=t,this}child(t){return this._child=Math.max(1,Number.parseInt(t.toString())),this}}class Task{constructor(t,e,s=null,...r){this.func=t,this.args=r,this.delay=e,this.interval=s,this._task=setTimeout((()=>this._run()),e)}_run(){try{this.func(...this.args)}catch(t){console.error(...t)}null!=this.interval&&(this._task=setTimeout((()=>this._run()),this.interval))}block(){null!=this._task&&clearTimeout(this._task),this._task=null}}class WebSocketClient{constructor(t,e={}){this.url=t,this.ws=null,this.reconnectInterval=1e3,this.messageQueue=[],this.handlers=e,this.stats={sent:{count:0,length:0},received:{count:0,length:0}},this.connect(),this.reconnectTask=null}close(){this.ws.close()}connect(){this.ws=new WebSocket(this.url),this.ws.onopen=()=>{for(null!==this.reconnectTask&&(clearInterval(this.reconnectTask),this.reconnectTask=null);this.messageQueue.length>0;){let t=this.messageQueue.shift();this.send(t)}this.handlers.onopen&&this.handlers.onopen()},this.ws.onmessage=t=>{this.stats.received.count++,this.stats.received.length+=t.data.length,this.handlers.onmessage&&this.handlers.onmessage(t)},this.ws.onclose=()=>{this.ws=null,this.connect(),this.handlers.onclose&&this.handlers.onclose()}}send(t){this.ws&&this.ws.readyState===WebSocket.OPEN?(this.stats.sent.count++,this.stats.sent.length+=g_TTB.calculateBytes(t),this.ws.send(t instanceof BytesBuffer?t.toBytes():t)):(this.ws&&this.ws.readyState!==WebSocket.CLOSED||this.connect(),this.messageQueue.push(t))}getStats(){return this.stats}}class MinecraftUtils{static getVarInt(t){let e=[];for(;;){if(0==(4294967168&t)){e.push(t);break}e.push(127&t|128),t>>=7}return e}static getVarIntLength(t){return this.getVarInt(t).length}}class BytesBuffer{constructor(...t){this.buffer=[],this.cur=0,this.write(...t)}write(...t){for(const e of t)if(e instanceof BytesBuffer)this.buffer.push(...e.buffer);else if(Number.isInteger(e))this.buffer.push(e<0?e+256:e);else if(Array.isArray(e)&&e.filter((t=>Number.isInteger(t))).length==e.length)e.forEach((t=>this.write(t)));else if(e instanceof Uint8Array)for(let t=0;tt.push(e))),t}}class DataOutputStream extends BytesBuffer{constructor(t){super(),this.write(t)}writeInteger(t){this.write(t>>24&255,t>>16&255,t>>8&255,t>>0&255)}writeBoolean(t){this.write(t?1:0)}writeFloat(t){const e=new Uint8Array(new Float32Array([t]).buffer);for(let t=0;t<4;t++)this.write(e[t])}writeDouble(t){const e=new Uint8Array(new Float64Array([t]).buffer);for(let t=0;t<8;t++)this.write(e[t])}writeVarInt(t){return this.write(MinecraftUtils.getVarInt(t)),this}writeString(t,e="utf-8"){return this.writeVarInt(t.length),this.write(new TextEncoder(e).encode(t)),this}writeLong(t){return t-=t>Math.pow(2,63)-1?Math.pow(2,64):t,this.write(t>>56&255,t>>48&255,t>>40&255,t>>32&255,t>>24&255,t>>16&255,t>>8&255,t>>0&255),this}writeUUID(t){return this.writeLong(t.int>>64),this.writeLong(0&t.int),this}}class DataInputStream extends BytesBuffer{readInteger(){let t=this.read(4);return(t[0]<<24)+(t[1]<<16)+(t[2]<<8)+(t[3]<<0)}readBoolean(){return Boolean(this.read(1)[0])}readShort(){if(value=this.read(2),value[0]|value[1]<0)throw EOFError();return(value[0]<<8)+(value[1]<<0)}readLong(){let t=this.read(8);return t=(t[0]<<56)+((255&t[1])<<48)+((255&t[2])<<40)+((255&t[3])<<32)+((255&t[4])<<24)+((255&t[5])<<16)+((255&t[6])<<8)+((255&t[7])<<0),t5)throw new Error("VarInt too big");if(128!=(128&t))break}return e>=2**31-1?e-2**31*2:e}readString(t=null,e="utf-8"){return new TextDecoder(e).decode(new Uint8Array(this.read(null==t?this.readVarInt():t)))}readBytes(t){return this.read(t)}readUUID(){let t=this.readLong(),e=this.readLong();return new UUID(t.toBytes().concat(e.toBytes()))}}g_TTB=null; \ No newline at end of file diff --git a/core/api.py b/core/api.py index 3a76f24..ec9fb14 100644 --- a/core/api.py +++ b/core/api.py @@ -34,6 +34,7 @@ class File: last_hit: float = 0 last_access: float = 0 data: Optional[io.BytesIO] = None + cache: bool = False def is_url(self): if not isinstance(self.path, str): return False @@ -49,11 +50,15 @@ def set_data(self, data: io.BytesIO | memoryview | bytes): data = io.BytesIO(data) self.data = io.BytesIO(zlib.compress(data.getbuffer())) +@dataclass +class StatsCache: + total: int = 0 + bytes: int = 0 + class Storage(metaclass=abc.ABCMeta): @abc.abstractmethod - async def get(self, file: str, download: bool = False) -> File: + async def get(self, file: str) -> File: """ - not download can't record file bytes and hits. return type: Path, str Path: Local File @@ -84,7 +89,9 @@ async def get_files_size(self, dir: str) -> int: @abc.abstractmethod async def removes(self, hashs: list[str]) -> int: raise NotImplementedError - + @abc.abstractmethod + async def get_cache_stats(self) -> StatsCache: + raise NotImplementedError def get_hash(org): if len(org) == 32: diff --git a/core/cluster.py b/core/cluster.py index 4c870cc..090883a 100644 --- a/core/cluster.py +++ b/core/cluster.py @@ -1,4 +1,5 @@ import asyncio +import dataclasses import hashlib import hmac import io @@ -25,6 +26,7 @@ from core.api import ( File, BMCLAPIFile, + StatsCache, Storage, get_hash, ) @@ -202,14 +204,12 @@ def __init__(self, dir: Path) -> None: raise FileExistsError("The path is file.") self.dir.mkdir(exist_ok=True, parents=True) self.cache: dict[str, File] = {} - self.stats: stats.StorageStats = stats.get_storage(f"File_{self.dir}") self.timer = Timer.repeat(self.clear_cache, (), CHECK_CACHE, CHECK_CACHE) - async def get(self, hash: str, download: bool = False) -> File: + async def get(self, hash: str) -> File: if hash in self.cache: file = self.cache[hash] file.last_access = time.time() - if download: - self.stats.hit(file, cache = True) + file.cache = True return file path = Path(str(self.dir) + f"/{hash[:2]}/{hash}") buf = io.BytesIO() @@ -219,8 +219,7 @@ async def get(self, hash: str, download: bool = False) -> File: file = File(path, hash, buf.tell(), time.time(), time.time()) file.set_data(buf.getbuffer()) self.cache[hash] = file - if download: - self.stats.hit(file) + file.cache = False return file async def exists(self, hash: str) -> bool: return os.path.exists(str(self.dir) + f"/{hash[:2]}/{hash}") @@ -290,6 +289,12 @@ async def get_files_size(self, dir: str) -> int: for file in session: size += file.stat().st_size return size + async def get_cache_stats(self) -> StatsCache: + stat = StatsCache() + for file in self.cache.values(): + stat.total += 1 + stat.bytes += file.size + return stat class WebDav(Storage): def __init__(self) -> None: super().__init__() @@ -297,6 +302,7 @@ class Cluster: def __init__(self) -> None: self.sio = socketio.AsyncClient() self.storages: list[Storage] = [] + self.storage_stats: dict[Storage, stats.StorageStats] = {} self.started = False self.sio.on("message", self._message) self.cur_storage: Optional[stats.SyncStorage] = None @@ -310,8 +316,16 @@ def _message(self, message): logger.info(f"[Remote] {message}") if "信任度过低" in message: self.trusted = False + def get_storages(self): + return self.storages.copy() def add_storage(self, storage): self.storages.append(storage) + type = "Unknown" + key = time.time() + if isinstance(storage, FileStorage): + type = "File" + key = storage.dir + self.storage_stats[storage] = stats.get_storage(f"{type}_{key}") async def _check_files_sync_status(self, text: str, pbar: tqdm, format = unit.format_numbers): if self.check_files_timer: @@ -418,8 +432,19 @@ async def start(self, ): await self.check_files() await set_status("启动服务") await self.enable() - async def get(self, hash): - return await self.storages[0].get(hash, True) + async def get(self, hash) -> File: + storage = self.storages[0] + stat = self.storage_stats[storage] + file = await storage.get(hash) + stat.hit(file) + return file + async def get_cache_stats(self) -> StatsCache: + stat = StatsCache() + for storage in self.storages: + t = await storage.get_cache_stats() + stat.total += t.total + stat.bytes += t.bytes + return stat async def exists(self, hash): return await self.storages[0].exists(hash) async def enable(self) -> None: @@ -595,7 +620,9 @@ async def process(type: str, data: Any): if type == "system": return { "memory": system.get_used_memory(), - "connections": system.get_connections() + "connections": system.get_connections(), + "cpu": system.get_cpus(), + "cache": dataclasses.asdict(await cluster.get_cache_stats()) if cluster else StatsCache() } token = TokenManager() @@ -615,6 +642,7 @@ async def set_status(text: str): async def init(): global cluster cluster = Cluster() + system.init() plugins.load_plugins() for plugin in plugins.get_plugins(): await plugin.init() diff --git a/core/stats.py b/core/stats.py index a9e686c..067433d 100644 --- a/core/stats.py +++ b/core/stats.py @@ -20,9 +20,9 @@ class StorageStats: def __init__(self, name) -> None: self._name = name self.reset() - def hit(self, file: File, cache: bool = False): + def hit(self, file: File): byte = file.size - if cache: + if file.cache: self._cache_hits += 1 self._cache_bytes += byte else: diff --git a/core/system.py b/core/system.py index 5ebb049..3feccd5 100644 --- a/core/system.py +++ b/core/system.py @@ -1,11 +1,29 @@ import os import psutil +import time + +from core.timer import Timer process: psutil.Process = psutil.Process(os.getpid()) +cpus: list[float] = [] + +def _cpu(): + global cpus + while 1: + for _ in range(max(len(cpus) - 600, 0)): + cpus.pop(0) + cpus.append(process.cpu_percent(1)) +def get_cpus(): + global cpus + if not cpus: + return 0 + return sum(cpus) / len(cpus) def get_used_memory() -> int: info = process.memory_full_info() return info.uss def get_connections() -> int: - return len(process.connections()) \ No newline at end of file + return len(process.connections()) +def init(): + Timer.delay(_cpu) \ No newline at end of file From 7d4bdcb12b0424b3fd866d8b2e2ec7d1e46ca1dc Mon Sep 17 00:00:00 2001 From: tianxiu2b2t Date: Sun, 24 Mar 2024 04:20:12 +0800 Subject: [PATCH 6/9] Update dashboard and fix items display error --- bmclapi_dashboard/static/js/index.min.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bmclapi_dashboard/static/js/index.min.js b/bmclapi_dashboard/static/js/index.min.js index cb4eab6..b745bc4 100644 --- a/bmclapi_dashboard/static/js/index.min.js +++ b/bmclapi_dashboard/static/js/index.min.js @@ -1 +1 @@ -(()=>{const e=new TTB,t=e.createElement("div").class("root"),i=e.createFlex().class("header").style("align-items","center"),a=e.createElement("div").class("left"),r=e.createElement("div").class("arrow-background").append(e.createElement("div").class("arrow")),s=e.createElement("div").class("content"),n=e.createElement("div").class("copyright"),l=e.createElement("div").class("right"),o={},d=e.createElement("div").class("progress"),c=e=>{d.setStyle("width",100*e+"%"),100*e>=99&&setTimeout((()=>d.setStyle("width",0)),250)},p=()=>{s.clear();for(const t in o){const i=o[t],a=!!i.children,r=e.createFlex().class("button").id("left-list-"+t).append(e.createElement("p").setText(i.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+i.children[0].key:"")}));if(s.append(r),a){const r=e.createElement("div").style("display: none").class("side").id("left-list-"+t+"-sub");for(const s of i.children)r.append(e.createFlex().class("sidebutton").id("left-list-"+t+"-sub-"+s.key).append(e.createElement("div").class("cycle"),e.createElement("p").setText(s.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+s.key:"")})));s.append(r)}}},h=()=>{const t=e.getURLKey()||Object.keys(o)[0];for(const i of Object.keys(o))if(u!=t?i==t?(document.getElementById("left-list-"+i).classList.add("selected"),x=""):document.getElementById("left-list-"+i).classList.remove("selected"):u==i&&document.getElementById("left-list-"+i).classList.add("selected"),document.getElementById("left-list-"+i+"-sub")){document.getElementById("left-list-"+i+"-sub").style.display=i==t?"block":"none";const a=e.getURLKeyParams().key||Object.keys(Object.values(o)[0])[1];for(const e of o[i].children.map((e=>e.key)))e==a?(document.getElementById("left-list-"+i+"-sub-"+e).classList.add("selected"),x=a):document.getElementById("left-list-"+i+"-sub-"+e).classList.remove("selected")}},g=()=>{const t=e.getURLKey()||Object.keys(o)[0],i=x;h(),(u!=t||x&&x!=i)&&(u&&x&&x==i&&m(u,i,"disconnect"),m(t,x,"connect")),u=t},m=(t,i,a)=>{const r=(i?o[t].children.filter((e=>e.key==i))[0]:o[t]).core||{};if(f!=(t+=i?"-"+i:"")){if(f in r&&"disconnect"in r)try{r.disconnect()}catch(e){console.log(e)}for(;null!=document.getElementsByClassName("right")[0].firstChild;)document.getElementsByClassName("right")[0].removeChild(document.getElementsByClassName("right")[0].firstChild);f=t}if(a in r)try{document.getElementsByClassName("right")[0].style.display="none",page=[],"connect"==a&&"page"in r&&(c(.7),"init"in r&&r.init(),c(.8),page=r.page()||[]),c(.9),r[a](page),null!=page&&document.getElementsByClassName("right")[0].append(e.createElement("div").id("module-"+t).append(...Array.isArray(page)?page:[page]).valueOf()),document.getElementsByClassName("right")[0].style.display="block",c(1)}catch(e){console.log(e)}else c(1)};let u="",x="",f="";const y=()=>{p(),h()};i.append(e.createElement("h3").setText("Python OpenBMCLAPI Dashboard")),n.append(e.createElement("p").append(e.createElement("a").setAttribute("href","mailto:administrator@ttb-network.top").setText("TTB Network")," - ",e.VERSION)),r.event("click",(()=>{a.toggle("hide"),window.dispatchEvent(new Event("resize"))})),t.append(i,e.createElement("div").class("container").append(a.append(r,s,n),l)),window.addEventListener("resize",y),window.addEventListener("popstate",g),document.body.prepend(d.valueOf(),t.valueOf()),(()=>{new class{constructor(){this.ws=e.websocket("ws"+window.location.protocol.slice(4)+"//"+window.location.host+window.location.pathname,{onopen:()=>this.onopen(),onmessage:e=>{let t=new FileReader;t.onload=()=>{let e=t.result;const i=new DataInputStream(e);this.message(i.readString(),this._deserializeData(i))},t.readAsArrayBuffer(e.data)},onclose:()=>this.onclose()}),this._timer_qps=null,this._timer=null,this._timer_system=null}onclose(){}onopen(){this.send("runtime"),this.send("storage"),this.send("status"),this._timer_qps?.block(),this._timer?.block(),this._timer_system?.block(),this._timer_qps=e.runTaskRepeat((()=>{this.send("qps")}),0,5e3),this._timer=e.runTaskRepeat((()=>{this.send("dashboard")}),0,1e4),this._timer_system=e.runTaskRepeat((()=>{this.send("system")}),0,1e3)}send(e,t){const i=new DataOutputStream;i.writeString(e),i.write(this._serializeData(t)),this.ws.send(i)}message(i,a){if("runtime"==i&&(t.runtime=a,t.update()),"status"==i&&t.updateStatus(a),"dashboard"==i){const i=a.hourly,r=a.days;let s,n,l,o,d=Math.max(...i.map((e=>e._hour)));l=Array.from({length:d},((e,t)=>0)),o=Array.from({length:d},((e,t)=>0));for(const e of i)l[e._hour]=e.hits,o[e._hour]=e.cache_hits,d=Math.max(d,e._hour);t._e_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...l,...o)},series:[{name:"I/O访问数",data:l,type:"line",smooth:!0},{name:"缓存访问数",data:o,type:"line",smooth:!0}]}),s=e.sum(...l,...o),l=Array.from({length:d},((e,t)=>0)),o=Array.from({length:d},((e,t)=>0));for(const e of i)l[e._hour]=e.bytes,o[e._hour]=e.cache_bytes;t._e_bytes.setOption({tooltip:{formatter:e=>t._e_templates(e,(e=>t._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...l,...o),axisLabel:{formatter:e=>t._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:l,type:"line",smooth:!0},{name:"缓存访问文件大小",data:o,type:"line",smooth:!0}]}),n=e.sum(...l,...o),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(t._format_number_unit(s)),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(t._format_bytes(n)),l=Array.from({length:30},((e,t)=>0)),o=Array.from({length:30},((e,t)=>0));for(const e of r)l[e._day]=e.hits,o[e._day]=e.cache_hits;t._e_daily_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...l,...o)},series:[{name:"I/O访问数",data:l,type:"line",smooth:!0},{name:"缓存访问数",data:o,type:"line",smooth:!0}]}),s=e.sum(...l,...o);{const i=Array.from({length:30},((e,t)=>0)),a=Array.from({length:30},((e,t)=>0));for(const e of r)i[e._day]=e.bytes,a[e._day]=e.cache_bytes;t._e_daily_bytes.setOption({tooltip:{formatter:e=>t._e_templates(e,(e=>t._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...i,...a),axisLabel:{formatter:e=>t._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:i,type:"line",smooth:!0},{name:"缓存访问文件大小",data:a,type:"line",smooth:!0}]}),n=e.sum(...i,...a)}t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[2].getChildrens()[1].setText(t._format_number_unit(s)),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[3].getChildrens()[1].setText(t._format_bytes(n))}if("system"==i&&(t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(t._format_number_unit(a.connections)),t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(t._format_bytes(a.memory)),t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[2].getChildrens()[1].setText(`${t._format_number_unit(a.cache.total)}(${t._format_bytes(a.cache.bytes)})`),t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[3].getChildrens()[1].setText(a.cpu.toFixed(2)+"%")),"qps"==i){const i=parseInt(e.getTimestamp()/1e3),n=(i%5!=0?5:0)-i%5+i,l=[];var r=[],s=[];for(let i=n-300;i<=n;i++){let n=a.hasOwnProperty(i)?a[i]:0;r.push(n),i%5==0&&(l.push({value:e.sum(...r)/r.length,raw:r}),r=[],s.push(t._e_format_time(1e3*i)))}t._page[1].getChildrens()[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].setText(t._format_number_unit(e.sum(...e.collectionSingleList(l.map((e=>[...e.raw])))))),t._e_qps.setOption({xAxis:{data:s},series:[{data:l}]})}console.log(i,a),((e,...t)=>{var i=f.split("-",1),a=i[0],r=i[1];const s=(r?o[a].children.filter((e=>e.key==r))[0]:o[a]).core||{};e in s&&s[e](...t)})("_ws_message",i,a)}_deserializeData(e){const t=e.readVarInt();switch(t){case 0:return e.readString();case 1:return e.readBoolean();case 2:return parseFloat(e.readString());case 3:return parseInt(e.readString());case 4:{const t=e.readVarInt(),i=[];for(let a=0;a{this._e_bytes.resize(),this._e_daily_bytes.resize(),this._e_hits.resize(),this._e_daily_hits.resize(),this._e_qps.resize()}))],this._updateTimer=setInterval((()=>this.update()),1e3),this._e_options={tooltip:{trigger:"axis"},grid:{left:"3%",right:"4%",bottom:"3%",top:"20%",containLabel:!0},xAxis:{type:"category"},yAxis:{type:"value",min:1,max:10},series:[]},this._unit_bytes=["B","KB","MB","GB","TB","PB","EB"],this._unit_number=["","k","M","G","T","P","E"],this._hourly=Array.from({length:24},((e,t)=>t+" 时")),this._daily=Array.from({length:31},((e,t)=>t+" 天")),this._e_qps=echarts.init(this._page[1].getChildrens()[1].getChildrens()[1].valueOf()),this._e_hits=echarts.init(this._page[1].getChildrens()[2].getChildrens()[1].valueOf()),this._e_bytes=echarts.init(this._page[1].getChildrens()[3].getChildrens()[1].valueOf()),this._e_daily_hits=echarts.init(this._page[1].getChildrens()[4].getChildrens()[1].valueOf()),this._e_daily_bytes=echarts.init(this._page[1].getChildrens()[5].getChildrens()[1].valueOf()),this._e_hits.setOption(this._e_options),this._e_bytes.setOption(this._e_options),this._e_hits.setOption({xAxis:{data:this._hourly}}),this._e_bytes.setOption({xAxis:{data:this._hourly}}),this._e_daily_hits.setOption(this._e_options),this._e_daily_bytes.setOption(this._e_options),this._e_daily_hits.setOption({xAxis:{data:this._daily}}),this._e_daily_bytes.setOption({xAxis:{data:this._daily}}),this._e_qps.setOption({color:"#0fc6c2",tooltip:{trigger:"axis",formatter:t=>'
'+t[0].name+'
QPSAvg: '+t[0].data.value+" total: "+e.sum(...t[0].data.raw)+'
'},stateAnimation:{duration:300,easing:"cubicOut"},xAxis:{type:"category",show:!1},yAxis:{show:!1,type:"value"},grid:{top:10,bottom:10,right:0,left:0,show:!1,z:0,containLabel:!1,backgroundColor:"rgba(0,0,0,0)",borderWidth:1,borderColor:"#ccc"},series:[{type:"bar",barGap:"0",barMinHeight:4,itemStyle:{borderRadius:[2,2,0,0]},z:2,backgroundStyle:{color:"rgba(180, 180, 180, 0.2)",borderColor:null,borderWidth:0,borderType:"solid",borderRadius:0,shadowBlur:0,shadowColor:null,shadowOffsetX:0,shadowOffsetY:0},select:{itemStyle:{borderColor:"#212121"}}}]}),this.update(),setTimeout((()=>this._page[1].update()),1)}connect(e){e.push(...this._page)}update(){this._page[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(this._format_time(this.runtime,!0))}updateStatus(e){this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(e)}_format_time(t,i=!1){if(null==t)return"-";let a=Number.parseInt(t);return i&&(a=Number.parseInt(e.getTime()-a)),`${parseInt(a/60/60/24).toString().padStart(2,"0")} 天 ${parseInt(a/60/60%24).toString().padStart(2,"0")} 小时 ${parseInt(a/60%60).toString().padStart(2,"0")} 分钟 ${parseInt(a%60).toString().padStart(2,"0")} 秒`}_format_bytes(e,t=null){return 0==e||(t=t||Math.min(Number.parseInt(Math.floor(Math.log(e)/Math.log(1024))),this._unit_bytes.length))<=0?`${e.toFixed(2)}${this._unit_bytes[0]}`:`${(e/=1024**t).toFixed(2)}${this._unit_bytes[t]}`}_e_templates(e,t=null){const i='
{name}{value}
';var a="";for(const r of e)a+=i.replace("{color}",r.color).replace("{name}",r.name).replace("{value}",t?t(r.value):r.value);return`
${e[0].name}
${a}
`}_format_number_unit(e){var t=(e+"").split("."),i=t[0],a=t.length>=2?"."+t.slice(1).join("."):"";return i.toString().replace(/\B(?=(\d{3})+(?!\d))/g,", ")+a}_e_format_time(e){const t=new Date(e);return t.getHours().toString().padStart(2,0)+":"+t.getMinutes().toString().padStart(2,0)+":"+t.getSeconds().toString().padStart(2,0)}};((e,t,i,a)=>{if(e.includes(".")){const[r,s]=[e.slice(0,e.indexOf(".")),e.slice(e.indexOf(".")+1)];o[r]||(o[r]={icon:t,children:[],text:"",core:a}),"children"in o[r]||(o[r].children=[]),o[r].children.push({key:s,text:i,core:a})}else o[e]={key:e,icon:t,text:i,core:a}})("dashboard","","数据统计",t)})(),p(),e.set_styles({"body,ol,ul,h1,h2,h3,h4,h5,h6,p,th,td,dl,dd,form,fieldset,legend,input,textarea,select":"margin:0;padding:0",body:"font:12px;background:#fff;-webkit-text-size-adjust:100%",a:"color:#172c45;text-decoration:none",em:"font-style:normal",li:"list-style:none",img:"border:0;vertical-align:middle",table:"border-collapse:collapse;border-spacing:0",p:"word-wrap:break-word",":root":["--r-main-background-color: #F6F7F9","--r-background-color: #191919","--r-main-font-size: 42px","--r-main-color: #fff","--r-block-margin: 20px","--r-heading-margin: 0 0 20px 0","--r-heading-font: Source Sans Pro, Helvetica, sans-serif","--r-heading-color: #fff","--r-heading-line-height: 1.2","--r-heading-letter-spacing: normal","--r-heading-text-transform: uppercase","--r-heading-text-shadow: none","--r-heading-font-weight: 600","--r-heading1-text-shadow: none","--r-heading1-size: 2.5em","--r-heading2-size: 1.6em","--r-heading3-size: 1.3em","--r-heading4-size: 1em","--r-code-font: monospace","--r-link-color: #42affa","--r-link-color-dark: #068de9","--r-link-color-hover: #8dcffc","--r-selection-background-color: rgba(66, 175, 250, .75)","--r-selection-color: #fff","--r-overlay-element-bg-color: 240, 240, 240","--r-overlay-element-fg-color: 0, 0, 0","--r-ligting-color: rgb(15, 198, 194);"],".root .left":["position: fixed","min-height: calc(100vh - 72px)","max-height: calc(100vh - 72px)","min-width: 48px","max-width: 184px","margin-top: 16px","width: 256px","padding: 8px","padding-top: 0","background: var(--r-main-background-color)","transition: transform 200ms linear 0s;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .left .content":["overflow: auto","width: 95%"],".root .left.hide":["transform: translateX(-100%);"],".root .left .button":["cursor: pointer;","border-radius: 8px;","margin-bottom: 8px","padding: 4px","padding-left: 8px","transition: color 200ms linear 0s;"],".root .left .arrow-background":["position: absolute","background: var(--r-main-background-color)","width: 20px","height: 20px","left: 194px","margin-top: -16px","cursor: pointer"],".root .left .arrow":["width: 100%","height: 100%",'background-image: url("data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgc3R5bGU9IndpZHRoOiAxZW07aGVpZ2h0OiAxZW07dmVydGljYWwtYWxpZ246IG1pZGRsZTtmaWxsOiBjdXJyZW50Q29sb3I7b3ZlcmZsb3c6IGhpZGRlbjsiIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwLWlkPSI3NTUiPjxwYXRoIGQ9Ik0zMjUuMDQ4IDkzLjUxMWwtNjAuMDMwIDU5LjQzNSAzNTcuMTgxIDM1OS42MzEtMzYwLjE4NCAzNTYuNjAzIDU5LjUyMiA1OS45MyA0MjAuMjA3LTQxNi4wNDN6IiBmaWxsPSIjODQ4NDg0IiBwLWlkPSI3NTYiPjwvcGF0aD48L3N2Zz4=");'],".root .container .left.hide .arrow-background .arrow":["transform: rotate(0deg);"],".root .container .left .arrow-background .arrow":["transform: rotate(180deg);","transition: transform 100ms linear 0s;"],".root .left .button:hover":["color: var(--r-ligting-color)"],".root .left .button.selected":["background: var(--r-ligting-color)","box-shadow: rgba(15, 198, 194, 0.2) 0px 10px 25px 0px;","color: white"],".root .left .side":["margin-left: 8px"],".root .left .sidebutton":["padding: 2px","margin-bottom: 8px","cursor: pointer;","color: rgba(0, 0, 0, 0.5);","transition: color 200ms linear 0s;"],".root .left .sidebutton:hover":["color: var(--r-link-color-hover)"],".root .left .sidebutton.selected":["color: black","font-weight: bold"],".root .left .sidebutton:hover .cycle":["background: var(--r-link-color-hover)"],".root .left .sidebutton.selected .cycle":["width: 8px;","height: 8px;","background-color: rgb(15, 198, 194);","margin-right: 6px","margin-left: 2px","border-radius: 50%;"],".root .left .sidebutton .cycle":["width: 4px;","height: 4px;","margin: 4px","margin-right: 8px","background-color: rgba(0, 0, 0, 0.5);","transition: background-color 200ms linear 0s;","border-radius: 50%;"],".root .header":["position: fixed","height: 40px","min-height: 40px","min-width: 100vw","background: var(--r-main-background-color)","z-index: 1","padding: 8px","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .container":["position: relative;","top: 56px;"],".root .container .right":["padding-top: 16px","margin-left: 216px","transition: width 200ms linear 0s;","min-width: calc(100vw - 232px)","min-height: calc(100vh - 72px)"],".root .container .left.hide ~ .right":["margin-left: 0","min-width: 100vw"],".root .container .right .panel":["background-color: rgb(255, 255, 255);","color: rgb(0, 0, 0);","transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;","border-radius: 4px;","background-image: none;","padding: 24px;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;","margin: 16px;"],".panel.info-4":["display: flex","flex-warp: warp"],".panel.info-4 div":["width: 25%"],".panel.info-2":["display: flex","flex-warp: warp"],".panel.info-2 div":["width: 50%"],".panel .title":["display: flex","margin: 0px 0px 6px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.5);","font-size: 14px;"],".panel .value":["margin: 0px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.7);","font-size: 24px;"],".root .container .left.hide~.right":["margin-left: 32px","min-width: calc(100vw - 48px)"],".root .left .copyright":["position: fixed;","bottom: 2px"],".qps .icon":["width: 14px","height: 14px"],".qps":["display: flex","align-items: center"],".progress":["position: absolute;","z-index: 2","width: 0","height: 2px","background: var(--r-ligting-color)","transition: width 200ms linear 0s;"],body:["background-color: var(--r-main-background-color)"]}),g(),y()})(); \ No newline at end of file +(()=>{const e=new TTB,t=e.createElement("div").class("root"),i=e.createFlex().class("header").style("align-items","center"),a=e.createElement("div").class("left"),r=e.createElement("div").class("arrow-background").append(e.createElement("div").class("arrow")),s=e.createElement("div").class("content"),n=e.createElement("div").class("copyright"),l=e.createElement("div").class("right"),o={},d=e.createElement("div").class("progress"),c=e=>{d.setStyle("width",100*e+"%"),100*e>=99&&setTimeout((()=>d.setStyle("width",0)),250)},p=()=>{s.clear();for(const t in o){const i=o[t],a=!!i.children,r=e.createFlex().class("button").id("left-list-"+t).append(e.createElement("p").setText(i.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+i.children[0].key:"")}));if(s.append(r),a){const r=e.createElement("div").style("display: none").class("side").id("left-list-"+t+"-sub");for(const s of i.children)r.append(e.createFlex().class("sidebutton").id("left-list-"+t+"-sub-"+s.key).append(e.createElement("div").class("cycle"),e.createElement("p").setText(s.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+s.key:"")})));s.append(r)}}},h=()=>{const t=e.getURLKey()||Object.keys(o)[0];for(const i of Object.keys(o))if(u!=t?i==t?(document.getElementById("left-list-"+i).classList.add("selected"),x=""):document.getElementById("left-list-"+i).classList.remove("selected"):u==i&&document.getElementById("left-list-"+i).classList.add("selected"),document.getElementById("left-list-"+i+"-sub")){document.getElementById("left-list-"+i+"-sub").style.display=i==t?"block":"none";const a=e.getURLKeyParams().key||Object.keys(Object.values(o)[0])[1];for(const e of o[i].children.map((e=>e.key)))e==a?(document.getElementById("left-list-"+i+"-sub-"+e).classList.add("selected"),x=a):document.getElementById("left-list-"+i+"-sub-"+e).classList.remove("selected")}},g=()=>{const t=e.getURLKey()||Object.keys(o)[0],i=x;h(),(u!=t||x&&x!=i)&&(u&&x&&x==i&&m(u,i,"disconnect"),m(t,x,"connect")),u=t},m=(t,i,a)=>{const r=(i?o[t].children.filter((e=>e.key==i))[0]:o[t]).core||{};if(f!=(t+=i?"-"+i:"")){if(f in r&&"disconnect"in r)try{r.disconnect()}catch(e){console.log(e)}for(;null!=document.getElementsByClassName("right")[0].firstChild;)document.getElementsByClassName("right")[0].removeChild(document.getElementsByClassName("right")[0].firstChild);f=t}if(a in r)try{document.getElementsByClassName("right")[0].style.display="none",page=[],"connect"==a&&"page"in r&&(c(.7),"init"in r&&r.init(),c(.8),page=r.page()||[]),c(.9),r[a](page),null!=page&&document.getElementsByClassName("right")[0].append(e.createElement("div").id("module-"+t).append(...Array.isArray(page)?page:[page]).valueOf()),document.getElementsByClassName("right")[0].style.display="block",c(1)}catch(e){console.log(e)}else c(1)};let u="",x="",f="";const y=()=>{p(),h()};i.append(e.createElement("h3").setText("Python OpenBMCLAPI Dashboard")),n.append(e.createElement("p").append(e.createElement("a").setAttribute("href","mailto:administrator@ttb-network.top").setText("TTB Network")," - ",e.VERSION)),r.event("click",(()=>{a.toggle("hide"),window.dispatchEvent(new Event("resize"))})),t.append(i,e.createElement("div").class("container").append(a.append(r,s,n),l)),window.addEventListener("resize",y),window.addEventListener("popstate",g),document.body.prepend(d.valueOf(),t.valueOf()),(()=>{new class{constructor(){this.ws=e.websocket("ws"+window.location.protocol.slice(4)+"//"+window.location.host+window.location.pathname,{onopen:()=>this.onopen(),onmessage:e=>{let t=new FileReader;t.onload=()=>{let e=t.result;const i=new DataInputStream(e);this.message(i.readString(),this._deserializeData(i))},t.readAsArrayBuffer(e.data)},onclose:()=>this.onclose()}),this._timer_qps=null,this._timer=null,this._timer_system=null}onclose(){}onopen(){this.send("runtime"),this.send("storage"),this.send("status"),this._timer_qps?.block(),this._timer?.block(),this._timer_system?.block(),this._timer_qps=e.runTaskRepeat((()=>{this.send("qps")}),0,5e3),this._timer=e.runTaskRepeat((()=>{this.send("dashboard")}),0,1e4),this._timer_system=e.runTaskRepeat((()=>{this.send("system")}),0,1e3)}send(e,t){const i=new DataOutputStream;i.writeString(e),i.write(this._serializeData(t)),this.ws.send(i)}message(i,a){if("runtime"==i&&(t.runtime=a,t.update()),"status"==i&&t.updateStatus(a),"dashboard"==i){const i=a.hourly,r=a.days;let s,n,l,o,d=Math.max(...i.map((e=>e._hour)));l=Array.from({length:d},((e,t)=>0)),o=Array.from({length:d},((e,t)=>0));for(const e of i)l[e._hour]=e.hits,o[e._hour]=e.cache_hits,d=Math.max(d,e._hour);t._e_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...l,...o)},series:[{name:"I/O访问数",data:l,type:"line",smooth:!0},{name:"缓存访问数",data:o,type:"line",smooth:!0}]}),s=e.sum(...l,...o),l=Array.from({length:d},((e,t)=>0)),o=Array.from({length:d},((e,t)=>0));for(const e of i)l[e._hour]=e.bytes,o[e._hour]=e.cache_bytes;t._e_bytes.setOption({tooltip:{formatter:e=>t._e_templates(e,(e=>t._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...l,...o),axisLabel:{formatter:e=>t._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:l,type:"line",smooth:!0},{name:"缓存访问文件大小",data:o,type:"line",smooth:!0}]}),n=e.sum(...l,...o),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(t._format_number_unit(s)),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(t._format_bytes(n)),l=Array.from({length:30},((e,t)=>0)),o=Array.from({length:30},((e,t)=>0));for(const e of r)l[e._day]=e.hits,o[e._day]=e.cache_hits;t._e_daily_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...l,...o)},series:[{name:"I/O访问数",data:l,type:"line",smooth:!0},{name:"缓存访问数",data:o,type:"line",smooth:!0}]}),s=e.sum(...l,...o);{const i=Array.from({length:30},((e,t)=>0)),a=Array.from({length:30},((e,t)=>0));for(const e of r)i[e._day]=e.bytes,a[e._day]=e.cache_bytes;t._e_daily_bytes.setOption({tooltip:{formatter:e=>t._e_templates(e,(e=>t._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...i,...a),axisLabel:{formatter:e=>t._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:i,type:"line",smooth:!0},{name:"缓存访问文件大小",data:a,type:"line",smooth:!0}]}),n=e.sum(...i,...a)}t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[2].getChildrens()[1].setText(t._format_number_unit(s)),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[3].getChildrens()[1].setText(t._format_bytes(n))}if("system"==i&&(t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(t._format_number_unit(a.connections)),t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(t._format_bytes(a.memory)),t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[2].getChildrens()[1].setText(`${t._format_number_unit(a.cache.total)}(${t._format_bytes(a.cache.bytes)})`),t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[3].getChildrens()[1].setText(a.cpu.toFixed(2)+"%")),"qps"==i){const i=parseInt(e.getTimestamp()/1e3),n=(i%5!=0?5:0)-i%5+i,l=[];var r=[],s=[];for(let i=n-300;i<=n;i++){let n=a.hasOwnProperty(i)?a[i]:0;r.push(n),i%5==0&&(l.push({value:e.sum(...r)/r.length,raw:r}),r=[],s.push(t._e_format_time(1e3*i)))}t._page[1].getChildrens()[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].setText(t._format_number_unit(e.sum(...e.collectionSingleList(l.map((e=>[...e.raw])))))),t._e_qps.setOption({xAxis:{data:s},series:[{data:l}]})}((e,...t)=>{var i=f.split("-",1),a=i[0],r=i[1];const s=(r?o[a].children.filter((e=>e.key==r))[0]:o[a]).core||{};e in s&&s[e](...t)})("_ws_message",i,a)}_deserializeData(e){const t=e.readVarInt();switch(t){case 0:return e.readString();case 1:return e.readBoolean();case 2:return parseFloat(e.readString());case 3:return parseInt(e.readString());case 4:{const t=e.readVarInt(),i=[];for(let a=0;a{this._e_bytes.resize(),this._e_daily_bytes.resize(),this._e_hits.resize(),this._e_daily_hits.resize(),this._e_qps.resize()}))],this._updateTimer=setInterval((()=>this.update()),1e3),this._e_options={tooltip:{trigger:"axis"},grid:{left:"3%",right:"4%",bottom:"3%",top:"20%",containLabel:!0},xAxis:{type:"category"},yAxis:{type:"value",min:1,max:10},series:[]},this._unit_bytes=["B","KB","MB","GB","TB","PB","EB"],this._unit_number=["","k","M","G","T","P","E"],this._hourly=Array.from({length:24},((e,t)=>t+" 时")),this._daily=Array.from({length:31},((e,t)=>t+" 天")),this._e_qps=echarts.init(this._page[1].getChildrens()[1].getChildrens()[1].valueOf()),this._e_hits=echarts.init(this._page[1].getChildrens()[2].getChildrens()[1].valueOf()),this._e_bytes=echarts.init(this._page[1].getChildrens()[3].getChildrens()[1].valueOf()),this._e_daily_hits=echarts.init(this._page[1].getChildrens()[4].getChildrens()[1].valueOf()),this._e_daily_bytes=echarts.init(this._page[1].getChildrens()[5].getChildrens()[1].valueOf()),this._e_hits.setOption(this._e_options),this._e_bytes.setOption(this._e_options),this._e_hits.setOption({xAxis:{data:this._hourly}}),this._e_bytes.setOption({xAxis:{data:this._hourly}}),this._e_daily_hits.setOption(this._e_options),this._e_daily_bytes.setOption(this._e_options),this._e_daily_hits.setOption({xAxis:{data:this._daily}}),this._e_daily_bytes.setOption({xAxis:{data:this._daily}}),this._e_qps.setOption({color:"#0fc6c2",tooltip:{trigger:"axis",formatter:t=>'
'+t[0].name+'
QPSAvg: '+t[0].data.value+" total: "+e.sum(...t[0].data.raw)+'
'},stateAnimation:{duration:300,easing:"cubicOut"},xAxis:{type:"category",show:!1},yAxis:{show:!1,type:"value"},grid:{top:10,bottom:10,right:0,left:0,show:!1,z:0,containLabel:!1,backgroundColor:"rgba(0,0,0,0)",borderWidth:1,borderColor:"#ccc"},series:[{type:"bar",barGap:"0",barMinHeight:4,itemStyle:{borderRadius:[2,2,0,0]},z:2,backgroundStyle:{color:"rgba(180, 180, 180, 0.2)",borderColor:null,borderWidth:0,borderType:"solid",borderRadius:0,shadowBlur:0,shadowColor:null,shadowOffsetX:0,shadowOffsetY:0},select:{itemStyle:{borderColor:"#212121"}}}]}),this.update(),setTimeout((()=>this._page[1].update()),1)}connect(e){e.push(...this._page)}update(){this._page[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(this._format_time(this.runtime,!0))}updateStatus(e){this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(e)}_format_time(t,i=!1){if(null==t)return"-";let a=Number.parseInt(t);return i&&(a=Number.parseInt(e.getTime()-a)),`${parseInt(a/60/60/24).toString().padStart(2,"0")} 天 ${parseInt(a/60/60%24).toString().padStart(2,"0")} 小时 ${parseInt(a/60%60).toString().padStart(2,"0")} 分钟 ${parseInt(a%60).toString().padStart(2,"0")} 秒`}_format_bytes(e,t=null){return 0==e||(t=t||Math.min(Number.parseInt(Math.floor(Math.log(e)/Math.log(1024))),this._unit_bytes.length))<=0?`${e.toFixed(2)}${this._unit_bytes[0]}`:`${(e/=1024**t).toFixed(2)}${this._unit_bytes[t]}`}_e_templates(e,t=null){const i='
{name}{value}
';var a="";for(const r of e)a+=i.replace("{color}",r.color).replace("{name}",r.name).replace("{value}",t?t(r.value):r.value);return`
${e[0].name}
${a}
`}_format_number_unit(e){var t=(e+"").split("."),i=t[0],a=t.length>=2?"."+t.slice(1).join("."):"";return i.toString().replace(/\B(?=(\d{3})+(?!\d))/g,", ")+a}_e_format_time(e){const t=new Date(e);return t.getHours().toString().padStart(2,0)+":"+t.getMinutes().toString().padStart(2,0)+":"+t.getSeconds().toString().padStart(2,0)}};((e,t,i,a)=>{if(e.includes(".")){const[r,s]=[e.slice(0,e.indexOf(".")),e.slice(e.indexOf(".")+1)];o[r]||(o[r]={icon:t,children:[],text:"",core:a}),"children"in o[r]||(o[r].children=[]),o[r].children.push({key:s,text:i,core:a})}else o[e]={key:e,icon:t,text:i,core:a}})("dashboard","","数据统计",t)})(),p(),e.set_styles({"body,ol,ul,h1,h2,h3,h4,h5,h6,p,th,td,dl,dd,form,fieldset,legend,input,textarea,select":"margin:0;padding:0",body:"font:12px;background:#fff;-webkit-text-size-adjust:100%",a:"color:#172c45;text-decoration:none",em:"font-style:normal",li:"list-style:none",img:"border:0;vertical-align:middle",table:"border-collapse:collapse;border-spacing:0",p:"word-wrap:break-word",":root":["--r-main-background-color: #F6F7F9","--r-background-color: #191919","--r-main-font-size: 42px","--r-main-color: #fff","--r-block-margin: 20px","--r-heading-margin: 0 0 20px 0","--r-heading-font: Source Sans Pro, Helvetica, sans-serif","--r-heading-color: #fff","--r-heading-line-height: 1.2","--r-heading-letter-spacing: normal","--r-heading-text-transform: uppercase","--r-heading-text-shadow: none","--r-heading-font-weight: 600","--r-heading1-text-shadow: none","--r-heading1-size: 2.5em","--r-heading2-size: 1.6em","--r-heading3-size: 1.3em","--r-heading4-size: 1em","--r-code-font: monospace","--r-link-color: #42affa","--r-link-color-dark: #068de9","--r-link-color-hover: #8dcffc","--r-selection-background-color: rgba(66, 175, 250, .75)","--r-selection-color: #fff","--r-overlay-element-bg-color: 240, 240, 240","--r-overlay-element-fg-color: 0, 0, 0","--r-ligting-color: rgb(15, 198, 194);"],".root .left":["position: fixed","min-height: calc(100vh - 72px)","max-height: calc(100vh - 72px)","min-width: 48px","max-width: 184px","margin-top: 16px","width: 256px","padding: 8px","padding-top: 0","background: var(--r-main-background-color)","transition: transform 200ms linear 0s;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .left .content":["overflow: auto","width: 95%"],".root .left.hide":["transform: translateX(-100%);"],".root .left .button":["cursor: pointer;","border-radius: 8px;","margin-bottom: 8px","padding: 4px","padding-left: 8px","transition: color 200ms linear 0s;"],".root .left .arrow-background":["position: absolute","background: var(--r-main-background-color)","width: 20px","height: 20px","left: 194px","margin-top: -16px","cursor: pointer"],".root .left .arrow":["width: 100%","height: 100%",'background-image: url("data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgc3R5bGU9IndpZHRoOiAxZW07aGVpZ2h0OiAxZW07dmVydGljYWwtYWxpZ246IG1pZGRsZTtmaWxsOiBjdXJyZW50Q29sb3I7b3ZlcmZsb3c6IGhpZGRlbjsiIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwLWlkPSI3NTUiPjxwYXRoIGQ9Ik0zMjUuMDQ4IDkzLjUxMWwtNjAuMDMwIDU5LjQzNSAzNTcuMTgxIDM1OS42MzEtMzYwLjE4NCAzNTYuNjAzIDU5LjUyMiA1OS45MyA0MjAuMjA3LTQxNi4wNDN6IiBmaWxsPSIjODQ4NDg0IiBwLWlkPSI3NTYiPjwvcGF0aD48L3N2Zz4=");'],".root .container .left.hide .arrow-background .arrow":["transform: rotate(0deg);"],".root .container .left .arrow-background .arrow":["transform: rotate(180deg);","transition: transform 100ms linear 0s;"],".root .left .button:hover":["color: var(--r-ligting-color)"],".root .left .button.selected":["background: var(--r-ligting-color)","box-shadow: rgba(15, 198, 194, 0.2) 0px 10px 25px 0px;","color: white"],".root .left .side":["margin-left: 8px"],".root .left .sidebutton":["padding: 2px","margin-bottom: 8px","cursor: pointer;","color: rgba(0, 0, 0, 0.5);","transition: color 200ms linear 0s;"],".root .left .sidebutton:hover":["color: var(--r-link-color-hover)"],".root .left .sidebutton.selected":["color: black","font-weight: bold"],".root .left .sidebutton:hover .cycle":["background: var(--r-link-color-hover)"],".root .left .sidebutton.selected .cycle":["width: 8px;","height: 8px;","background-color: rgb(15, 198, 194);","margin-right: 6px","margin-left: 2px","border-radius: 50%;"],".root .left .sidebutton .cycle":["width: 4px;","height: 4px;","margin: 4px","margin-right: 8px","background-color: rgba(0, 0, 0, 0.5);","transition: background-color 200ms linear 0s;","border-radius: 50%;"],".root .header":["position: fixed","height: 40px","min-height: 40px","min-width: 100vw","background: var(--r-main-background-color)","z-index: 1","padding: 8px","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .container":["position: relative;","top: 56px;"],".root .container .right":["padding-top: 16px","margin-left: 216px","transition: width 200ms linear 0s;","min-width: calc(100vw - 232px)","min-height: calc(100vh - 72px)"],".root .container .left.hide ~ .right":["margin-left: 0","min-width: 100vw"],".root .container .right .panel":["background-color: rgb(255, 255, 255);","color: rgb(0, 0, 0);","transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;","border-radius: 4px;","background-image: none;","padding: 24px;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;","margin: 16px;"],".panel.info-4":["display: flex","flex-warp: warp"],".panel.info-4 div":["width: 25%"],".panel.info-2":["display: flex","flex-warp: warp"],".panel.info-2 div":["width: 50%"],".panel .title":["display: flex","margin: 0px 0px 6px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.5);","font-size: 14px;"],".panel .value":["margin: 0px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.7);","font-size: 24px;"],".root .container .left.hide~.right":["margin-left: 32px","min-width: calc(100vw - 48px)"],".root .left .copyright":["position: fixed;","bottom: 2px"],".qps .icon":["width: 14px","height: 14px"],".qps":["display: flex","align-items: center"],".progress":["position: absolute;","z-index: 2","width: 0","height: 2px","background: var(--r-ligting-color)","transition: width 200ms linear 0s;"],body:["background-color: var(--r-main-background-color)"]}),g(),y()})(); \ No newline at end of file From eaea42b30342cbbe105d733c5839a7cb9dd59469 Mon Sep 17 00:00:00 2001 From: tianxiu2b2t Date: Sun, 24 Mar 2024 04:24:37 +0800 Subject: [PATCH 7/9] Delete some code from config.py --- core/config.py | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/core/config.py b/core/config.py index e98b947..d6f06bb 100644 --- a/core/config.py +++ b/core/config.py @@ -63,32 +63,4 @@ def _set_value(self, dict_obj, keys, value): dict_obj = dict_obj[key] dict_obj[keys[-1]] = value -"""class CFG: - def __init__(self, path: str) -> None: - self.file = Path(path) - logger.debug(f"Load config: {self.file.absolute()}") - self.cfg = {} - if self.file.exists(): - self.load() - - def load(self): - with open(self.file, "r", encoding="utf-8") as f: - self.cfg = yaml.load(f.read(), Loader=yaml.FullLoader) or {} - - def get(self, key): - value = self.cfg.get(key, None) - if value is None or value == "": - value = os.environ.get(key) - if value: - return value - logger.warn(f"{key} is not set! Does it exist?") - self.write(key, defaults[key]) - return value or (defaults[key] if key in defaults else value) - - def write(self, key, value): - self.cfg[key] = value - with open(self.file, "w", encoding="utf-8") as f: - yaml.dump(data=self.cfg, stream=f, allow_unicode=True) -""" - Config: CFG = CFG("./config/config.yml") From 57ac33ed04164e25d830052af60c557b3202ce04 Mon Sep 17 00:00:00 2001 From: tianxiu2b2t Date: Sun, 24 Mar 2024 04:35:34 +0800 Subject: [PATCH 8/9] Fix dashboard display text --- bmclapi_dashboard/static/js/index.min.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bmclapi_dashboard/static/js/index.min.js b/bmclapi_dashboard/static/js/index.min.js index b745bc4..9e8f3ac 100644 --- a/bmclapi_dashboard/static/js/index.min.js +++ b/bmclapi_dashboard/static/js/index.min.js @@ -1 +1 @@ -(()=>{const e=new TTB,t=e.createElement("div").class("root"),i=e.createFlex().class("header").style("align-items","center"),a=e.createElement("div").class("left"),r=e.createElement("div").class("arrow-background").append(e.createElement("div").class("arrow")),s=e.createElement("div").class("content"),n=e.createElement("div").class("copyright"),l=e.createElement("div").class("right"),o={},d=e.createElement("div").class("progress"),c=e=>{d.setStyle("width",100*e+"%"),100*e>=99&&setTimeout((()=>d.setStyle("width",0)),250)},p=()=>{s.clear();for(const t in o){const i=o[t],a=!!i.children,r=e.createFlex().class("button").id("left-list-"+t).append(e.createElement("p").setText(i.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+i.children[0].key:"")}));if(s.append(r),a){const r=e.createElement("div").style("display: none").class("side").id("left-list-"+t+"-sub");for(const s of i.children)r.append(e.createFlex().class("sidebutton").id("left-list-"+t+"-sub-"+s.key).append(e.createElement("div").class("cycle"),e.createElement("p").setText(s.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+s.key:"")})));s.append(r)}}},h=()=>{const t=e.getURLKey()||Object.keys(o)[0];for(const i of Object.keys(o))if(u!=t?i==t?(document.getElementById("left-list-"+i).classList.add("selected"),x=""):document.getElementById("left-list-"+i).classList.remove("selected"):u==i&&document.getElementById("left-list-"+i).classList.add("selected"),document.getElementById("left-list-"+i+"-sub")){document.getElementById("left-list-"+i+"-sub").style.display=i==t?"block":"none";const a=e.getURLKeyParams().key||Object.keys(Object.values(o)[0])[1];for(const e of o[i].children.map((e=>e.key)))e==a?(document.getElementById("left-list-"+i+"-sub-"+e).classList.add("selected"),x=a):document.getElementById("left-list-"+i+"-sub-"+e).classList.remove("selected")}},g=()=>{const t=e.getURLKey()||Object.keys(o)[0],i=x;h(),(u!=t||x&&x!=i)&&(u&&x&&x==i&&m(u,i,"disconnect"),m(t,x,"connect")),u=t},m=(t,i,a)=>{const r=(i?o[t].children.filter((e=>e.key==i))[0]:o[t]).core||{};if(f!=(t+=i?"-"+i:"")){if(f in r&&"disconnect"in r)try{r.disconnect()}catch(e){console.log(e)}for(;null!=document.getElementsByClassName("right")[0].firstChild;)document.getElementsByClassName("right")[0].removeChild(document.getElementsByClassName("right")[0].firstChild);f=t}if(a in r)try{document.getElementsByClassName("right")[0].style.display="none",page=[],"connect"==a&&"page"in r&&(c(.7),"init"in r&&r.init(),c(.8),page=r.page()||[]),c(.9),r[a](page),null!=page&&document.getElementsByClassName("right")[0].append(e.createElement("div").id("module-"+t).append(...Array.isArray(page)?page:[page]).valueOf()),document.getElementsByClassName("right")[0].style.display="block",c(1)}catch(e){console.log(e)}else c(1)};let u="",x="",f="";const y=()=>{p(),h()};i.append(e.createElement("h3").setText("Python OpenBMCLAPI Dashboard")),n.append(e.createElement("p").append(e.createElement("a").setAttribute("href","mailto:administrator@ttb-network.top").setText("TTB Network")," - ",e.VERSION)),r.event("click",(()=>{a.toggle("hide"),window.dispatchEvent(new Event("resize"))})),t.append(i,e.createElement("div").class("container").append(a.append(r,s,n),l)),window.addEventListener("resize",y),window.addEventListener("popstate",g),document.body.prepend(d.valueOf(),t.valueOf()),(()=>{new class{constructor(){this.ws=e.websocket("ws"+window.location.protocol.slice(4)+"//"+window.location.host+window.location.pathname,{onopen:()=>this.onopen(),onmessage:e=>{let t=new FileReader;t.onload=()=>{let e=t.result;const i=new DataInputStream(e);this.message(i.readString(),this._deserializeData(i))},t.readAsArrayBuffer(e.data)},onclose:()=>this.onclose()}),this._timer_qps=null,this._timer=null,this._timer_system=null}onclose(){}onopen(){this.send("runtime"),this.send("storage"),this.send("status"),this._timer_qps?.block(),this._timer?.block(),this._timer_system?.block(),this._timer_qps=e.runTaskRepeat((()=>{this.send("qps")}),0,5e3),this._timer=e.runTaskRepeat((()=>{this.send("dashboard")}),0,1e4),this._timer_system=e.runTaskRepeat((()=>{this.send("system")}),0,1e3)}send(e,t){const i=new DataOutputStream;i.writeString(e),i.write(this._serializeData(t)),this.ws.send(i)}message(i,a){if("runtime"==i&&(t.runtime=a,t.update()),"status"==i&&t.updateStatus(a),"dashboard"==i){const i=a.hourly,r=a.days;let s,n,l,o,d=Math.max(...i.map((e=>e._hour)));l=Array.from({length:d},((e,t)=>0)),o=Array.from({length:d},((e,t)=>0));for(const e of i)l[e._hour]=e.hits,o[e._hour]=e.cache_hits,d=Math.max(d,e._hour);t._e_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...l,...o)},series:[{name:"I/O访问数",data:l,type:"line",smooth:!0},{name:"缓存访问数",data:o,type:"line",smooth:!0}]}),s=e.sum(...l,...o),l=Array.from({length:d},((e,t)=>0)),o=Array.from({length:d},((e,t)=>0));for(const e of i)l[e._hour]=e.bytes,o[e._hour]=e.cache_bytes;t._e_bytes.setOption({tooltip:{formatter:e=>t._e_templates(e,(e=>t._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...l,...o),axisLabel:{formatter:e=>t._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:l,type:"line",smooth:!0},{name:"缓存访问文件大小",data:o,type:"line",smooth:!0}]}),n=e.sum(...l,...o),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(t._format_number_unit(s)),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(t._format_bytes(n)),l=Array.from({length:30},((e,t)=>0)),o=Array.from({length:30},((e,t)=>0));for(const e of r)l[e._day]=e.hits,o[e._day]=e.cache_hits;t._e_daily_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...l,...o)},series:[{name:"I/O访问数",data:l,type:"line",smooth:!0},{name:"缓存访问数",data:o,type:"line",smooth:!0}]}),s=e.sum(...l,...o);{const i=Array.from({length:30},((e,t)=>0)),a=Array.from({length:30},((e,t)=>0));for(const e of r)i[e._day]=e.bytes,a[e._day]=e.cache_bytes;t._e_daily_bytes.setOption({tooltip:{formatter:e=>t._e_templates(e,(e=>t._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...i,...a),axisLabel:{formatter:e=>t._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:i,type:"line",smooth:!0},{name:"缓存访问文件大小",data:a,type:"line",smooth:!0}]}),n=e.sum(...i,...a)}t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[2].getChildrens()[1].setText(t._format_number_unit(s)),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[3].getChildrens()[1].setText(t._format_bytes(n))}if("system"==i&&(t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(t._format_number_unit(a.connections)),t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(t._format_bytes(a.memory)),t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[2].getChildrens()[1].setText(`${t._format_number_unit(a.cache.total)}(${t._format_bytes(a.cache.bytes)})`),t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[3].getChildrens()[1].setText(a.cpu.toFixed(2)+"%")),"qps"==i){const i=parseInt(e.getTimestamp()/1e3),n=(i%5!=0?5:0)-i%5+i,l=[];var r=[],s=[];for(let i=n-300;i<=n;i++){let n=a.hasOwnProperty(i)?a[i]:0;r.push(n),i%5==0&&(l.push({value:e.sum(...r)/r.length,raw:r}),r=[],s.push(t._e_format_time(1e3*i)))}t._page[1].getChildrens()[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].setText(t._format_number_unit(e.sum(...e.collectionSingleList(l.map((e=>[...e.raw])))))),t._e_qps.setOption({xAxis:{data:s},series:[{data:l}]})}((e,...t)=>{var i=f.split("-",1),a=i[0],r=i[1];const s=(r?o[a].children.filter((e=>e.key==r))[0]:o[a]).core||{};e in s&&s[e](...t)})("_ws_message",i,a)}_deserializeData(e){const t=e.readVarInt();switch(t){case 0:return e.readString();case 1:return e.readBoolean();case 2:return parseFloat(e.readString());case 3:return parseInt(e.readString());case 4:{const t=e.readVarInt(),i=[];for(let a=0;a{this._e_bytes.resize(),this._e_daily_bytes.resize(),this._e_hits.resize(),this._e_daily_hits.resize(),this._e_qps.resize()}))],this._updateTimer=setInterval((()=>this.update()),1e3),this._e_options={tooltip:{trigger:"axis"},grid:{left:"3%",right:"4%",bottom:"3%",top:"20%",containLabel:!0},xAxis:{type:"category"},yAxis:{type:"value",min:1,max:10},series:[]},this._unit_bytes=["B","KB","MB","GB","TB","PB","EB"],this._unit_number=["","k","M","G","T","P","E"],this._hourly=Array.from({length:24},((e,t)=>t+" 时")),this._daily=Array.from({length:31},((e,t)=>t+" 天")),this._e_qps=echarts.init(this._page[1].getChildrens()[1].getChildrens()[1].valueOf()),this._e_hits=echarts.init(this._page[1].getChildrens()[2].getChildrens()[1].valueOf()),this._e_bytes=echarts.init(this._page[1].getChildrens()[3].getChildrens()[1].valueOf()),this._e_daily_hits=echarts.init(this._page[1].getChildrens()[4].getChildrens()[1].valueOf()),this._e_daily_bytes=echarts.init(this._page[1].getChildrens()[5].getChildrens()[1].valueOf()),this._e_hits.setOption(this._e_options),this._e_bytes.setOption(this._e_options),this._e_hits.setOption({xAxis:{data:this._hourly}}),this._e_bytes.setOption({xAxis:{data:this._hourly}}),this._e_daily_hits.setOption(this._e_options),this._e_daily_bytes.setOption(this._e_options),this._e_daily_hits.setOption({xAxis:{data:this._daily}}),this._e_daily_bytes.setOption({xAxis:{data:this._daily}}),this._e_qps.setOption({color:"#0fc6c2",tooltip:{trigger:"axis",formatter:t=>'
'+t[0].name+'
QPSAvg: '+t[0].data.value+" total: "+e.sum(...t[0].data.raw)+'
'},stateAnimation:{duration:300,easing:"cubicOut"},xAxis:{type:"category",show:!1},yAxis:{show:!1,type:"value"},grid:{top:10,bottom:10,right:0,left:0,show:!1,z:0,containLabel:!1,backgroundColor:"rgba(0,0,0,0)",borderWidth:1,borderColor:"#ccc"},series:[{type:"bar",barGap:"0",barMinHeight:4,itemStyle:{borderRadius:[2,2,0,0]},z:2,backgroundStyle:{color:"rgba(180, 180, 180, 0.2)",borderColor:null,borderWidth:0,borderType:"solid",borderRadius:0,shadowBlur:0,shadowColor:null,shadowOffsetX:0,shadowOffsetY:0},select:{itemStyle:{borderColor:"#212121"}}}]}),this.update(),setTimeout((()=>this._page[1].update()),1)}connect(e){e.push(...this._page)}update(){this._page[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(this._format_time(this.runtime,!0))}updateStatus(e){this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(e)}_format_time(t,i=!1){if(null==t)return"-";let a=Number.parseInt(t);return i&&(a=Number.parseInt(e.getTime()-a)),`${parseInt(a/60/60/24).toString().padStart(2,"0")} 天 ${parseInt(a/60/60%24).toString().padStart(2,"0")} 小时 ${parseInt(a/60%60).toString().padStart(2,"0")} 分钟 ${parseInt(a%60).toString().padStart(2,"0")} 秒`}_format_bytes(e,t=null){return 0==e||(t=t||Math.min(Number.parseInt(Math.floor(Math.log(e)/Math.log(1024))),this._unit_bytes.length))<=0?`${e.toFixed(2)}${this._unit_bytes[0]}`:`${(e/=1024**t).toFixed(2)}${this._unit_bytes[t]}`}_e_templates(e,t=null){const i='
{name}{value}
';var a="";for(const r of e)a+=i.replace("{color}",r.color).replace("{name}",r.name).replace("{value}",t?t(r.value):r.value);return`
${e[0].name}
${a}
`}_format_number_unit(e){var t=(e+"").split("."),i=t[0],a=t.length>=2?"."+t.slice(1).join("."):"";return i.toString().replace(/\B(?=(\d{3})+(?!\d))/g,", ")+a}_e_format_time(e){const t=new Date(e);return t.getHours().toString().padStart(2,0)+":"+t.getMinutes().toString().padStart(2,0)+":"+t.getSeconds().toString().padStart(2,0)}};((e,t,i,a)=>{if(e.includes(".")){const[r,s]=[e.slice(0,e.indexOf(".")),e.slice(e.indexOf(".")+1)];o[r]||(o[r]={icon:t,children:[],text:"",core:a}),"children"in o[r]||(o[r].children=[]),o[r].children.push({key:s,text:i,core:a})}else o[e]={key:e,icon:t,text:i,core:a}})("dashboard","","数据统计",t)})(),p(),e.set_styles({"body,ol,ul,h1,h2,h3,h4,h5,h6,p,th,td,dl,dd,form,fieldset,legend,input,textarea,select":"margin:0;padding:0",body:"font:12px;background:#fff;-webkit-text-size-adjust:100%",a:"color:#172c45;text-decoration:none",em:"font-style:normal",li:"list-style:none",img:"border:0;vertical-align:middle",table:"border-collapse:collapse;border-spacing:0",p:"word-wrap:break-word",":root":["--r-main-background-color: #F6F7F9","--r-background-color: #191919","--r-main-font-size: 42px","--r-main-color: #fff","--r-block-margin: 20px","--r-heading-margin: 0 0 20px 0","--r-heading-font: Source Sans Pro, Helvetica, sans-serif","--r-heading-color: #fff","--r-heading-line-height: 1.2","--r-heading-letter-spacing: normal","--r-heading-text-transform: uppercase","--r-heading-text-shadow: none","--r-heading-font-weight: 600","--r-heading1-text-shadow: none","--r-heading1-size: 2.5em","--r-heading2-size: 1.6em","--r-heading3-size: 1.3em","--r-heading4-size: 1em","--r-code-font: monospace","--r-link-color: #42affa","--r-link-color-dark: #068de9","--r-link-color-hover: #8dcffc","--r-selection-background-color: rgba(66, 175, 250, .75)","--r-selection-color: #fff","--r-overlay-element-bg-color: 240, 240, 240","--r-overlay-element-fg-color: 0, 0, 0","--r-ligting-color: rgb(15, 198, 194);"],".root .left":["position: fixed","min-height: calc(100vh - 72px)","max-height: calc(100vh - 72px)","min-width: 48px","max-width: 184px","margin-top: 16px","width: 256px","padding: 8px","padding-top: 0","background: var(--r-main-background-color)","transition: transform 200ms linear 0s;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .left .content":["overflow: auto","width: 95%"],".root .left.hide":["transform: translateX(-100%);"],".root .left .button":["cursor: pointer;","border-radius: 8px;","margin-bottom: 8px","padding: 4px","padding-left: 8px","transition: color 200ms linear 0s;"],".root .left .arrow-background":["position: absolute","background: var(--r-main-background-color)","width: 20px","height: 20px","left: 194px","margin-top: -16px","cursor: pointer"],".root .left .arrow":["width: 100%","height: 100%",'background-image: url("data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgc3R5bGU9IndpZHRoOiAxZW07aGVpZ2h0OiAxZW07dmVydGljYWwtYWxpZ246IG1pZGRsZTtmaWxsOiBjdXJyZW50Q29sb3I7b3ZlcmZsb3c6IGhpZGRlbjsiIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwLWlkPSI3NTUiPjxwYXRoIGQ9Ik0zMjUuMDQ4IDkzLjUxMWwtNjAuMDMwIDU5LjQzNSAzNTcuMTgxIDM1OS42MzEtMzYwLjE4NCAzNTYuNjAzIDU5LjUyMiA1OS45MyA0MjAuMjA3LTQxNi4wNDN6IiBmaWxsPSIjODQ4NDg0IiBwLWlkPSI3NTYiPjwvcGF0aD48L3N2Zz4=");'],".root .container .left.hide .arrow-background .arrow":["transform: rotate(0deg);"],".root .container .left .arrow-background .arrow":["transform: rotate(180deg);","transition: transform 100ms linear 0s;"],".root .left .button:hover":["color: var(--r-ligting-color)"],".root .left .button.selected":["background: var(--r-ligting-color)","box-shadow: rgba(15, 198, 194, 0.2) 0px 10px 25px 0px;","color: white"],".root .left .side":["margin-left: 8px"],".root .left .sidebutton":["padding: 2px","margin-bottom: 8px","cursor: pointer;","color: rgba(0, 0, 0, 0.5);","transition: color 200ms linear 0s;"],".root .left .sidebutton:hover":["color: var(--r-link-color-hover)"],".root .left .sidebutton.selected":["color: black","font-weight: bold"],".root .left .sidebutton:hover .cycle":["background: var(--r-link-color-hover)"],".root .left .sidebutton.selected .cycle":["width: 8px;","height: 8px;","background-color: rgb(15, 198, 194);","margin-right: 6px","margin-left: 2px","border-radius: 50%;"],".root .left .sidebutton .cycle":["width: 4px;","height: 4px;","margin: 4px","margin-right: 8px","background-color: rgba(0, 0, 0, 0.5);","transition: background-color 200ms linear 0s;","border-radius: 50%;"],".root .header":["position: fixed","height: 40px","min-height: 40px","min-width: 100vw","background: var(--r-main-background-color)","z-index: 1","padding: 8px","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .container":["position: relative;","top: 56px;"],".root .container .right":["padding-top: 16px","margin-left: 216px","transition: width 200ms linear 0s;","min-width: calc(100vw - 232px)","min-height: calc(100vh - 72px)"],".root .container .left.hide ~ .right":["margin-left: 0","min-width: 100vw"],".root .container .right .panel":["background-color: rgb(255, 255, 255);","color: rgb(0, 0, 0);","transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;","border-radius: 4px;","background-image: none;","padding: 24px;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;","margin: 16px;"],".panel.info-4":["display: flex","flex-warp: warp"],".panel.info-4 div":["width: 25%"],".panel.info-2":["display: flex","flex-warp: warp"],".panel.info-2 div":["width: 50%"],".panel .title":["display: flex","margin: 0px 0px 6px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.5);","font-size: 14px;"],".panel .value":["margin: 0px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.7);","font-size: 24px;"],".root .container .left.hide~.right":["margin-left: 32px","min-width: calc(100vw - 48px)"],".root .left .copyright":["position: fixed;","bottom: 2px"],".qps .icon":["width: 14px","height: 14px"],".qps":["display: flex","align-items: center"],".progress":["position: absolute;","z-index: 2","width: 0","height: 2px","background: var(--r-ligting-color)","transition: width 200ms linear 0s;"],body:["background-color: var(--r-main-background-color)"]}),g(),y()})(); \ No newline at end of file +(()=>{const e=new TTB,t=e.createElement("div").class("root"),i=e.createFlex().class("header").style("align-items","center"),a=e.createElement("div").class("left"),r=e.createElement("div").class("arrow-background").append(e.createElement("div").class("arrow")),s=e.createElement("div").class("content"),n=e.createElement("div").class("copyright"),l=e.createElement("div").class("right"),o={},d=e.createElement("div").class("progress"),c=e=>{d.setStyle("width",100*e+"%"),100*e>=99&&setTimeout((()=>d.setStyle("width",0)),250)},p=()=>{s.clear();for(const t in o){const i=o[t],a=!!i.children,r=e.createFlex().class("button").id("left-list-"+t).append(e.createElement("p").setText(i.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+i.children[0].key:"")}));if(s.append(r),a){const r=e.createElement("div").style("display: none").class("side").id("left-list-"+t+"-sub");for(const s of i.children)r.append(e.createFlex().class("sidebutton").id("left-list-"+t+"-sub-"+s.key).append(e.createElement("div").class("cycle"),e.createElement("p").setText(s.text)).style("align-items","center").height("32px").event("click",(()=>{window.location.hash=t+(a?"?key="+s.key:"")})));s.append(r)}}},h=()=>{const t=e.getURLKey()||Object.keys(o)[0];for(const i of Object.keys(o))if(u!=t?i==t?(document.getElementById("left-list-"+i).classList.add("selected"),x=""):document.getElementById("left-list-"+i).classList.remove("selected"):u==i&&document.getElementById("left-list-"+i).classList.add("selected"),document.getElementById("left-list-"+i+"-sub")){document.getElementById("left-list-"+i+"-sub").style.display=i==t?"block":"none";const a=e.getURLKeyParams().key||Object.keys(Object.values(o)[0])[1];for(const e of o[i].children.map((e=>e.key)))e==a?(document.getElementById("left-list-"+i+"-sub-"+e).classList.add("selected"),x=a):document.getElementById("left-list-"+i+"-sub-"+e).classList.remove("selected")}},g=()=>{const t=e.getURLKey()||Object.keys(o)[0],i=x;h(),(u!=t||x&&x!=i)&&(u&&x&&x==i&&m(u,i,"disconnect"),m(t,x,"connect")),u=t},m=(t,i,a)=>{const r=(i?o[t].children.filter((e=>e.key==i))[0]:o[t]).core||{};if(f!=(t+=i?"-"+i:"")){if(f in r&&"disconnect"in r)try{r.disconnect()}catch(e){console.log(e)}for(;null!=document.getElementsByClassName("right")[0].firstChild;)document.getElementsByClassName("right")[0].removeChild(document.getElementsByClassName("right")[0].firstChild);f=t}if(a in r)try{document.getElementsByClassName("right")[0].style.display="none",page=[],"connect"==a&&"page"in r&&(c(.7),"init"in r&&r.init(),c(.8),page=r.page()||[]),c(.9),r[a](page),null!=page&&document.getElementsByClassName("right")[0].append(e.createElement("div").id("module-"+t).append(...Array.isArray(page)?page:[page]).valueOf()),document.getElementsByClassName("right")[0].style.display="block",c(1)}catch(e){console.log(e)}else c(1)};let u="",x="",f="";const y=()=>{p(),h()};i.append(e.createElement("h3").setText("Python OpenBMCLAPI Dashboard")),n.append(e.createElement("p").append(e.createElement("a").setAttribute("href","mailto:administrator@ttb-network.top").setText("TTB Network")," - ",e.VERSION)),r.event("click",(()=>{a.toggle("hide"),window.dispatchEvent(new Event("resize"))})),t.append(i,e.createElement("div").class("container").append(a.append(r,s,n),l)),window.addEventListener("resize",y),window.addEventListener("popstate",g),document.body.prepend(d.valueOf(),t.valueOf()),(()=>{new class{constructor(){this.ws=e.websocket("ws"+window.location.protocol.slice(4)+"//"+window.location.host+window.location.pathname,{onopen:()=>this.onopen(),onmessage:e=>{let t=new FileReader;t.onload=()=>{let e=t.result;const i=new DataInputStream(e);this.message(i.readString(),this._deserializeData(i))},t.readAsArrayBuffer(e.data)},onclose:()=>this.onclose()}),this._timer_qps=null,this._timer=null,this._timer_system=null}onclose(){}onopen(){this.send("runtime"),this.send("storage"),this.send("status"),this._timer_qps?.block(),this._timer?.block(),this._timer_system?.block(),this._timer_qps=e.runTaskRepeat((()=>{this.send("qps")}),0,5e3),this._timer=e.runTaskRepeat((()=>{this.send("dashboard")}),0,1e4),this._timer_system=e.runTaskRepeat((()=>{this.send("system")}),0,1e3)}send(e,t){const i=new DataOutputStream;i.writeString(e),i.write(this._serializeData(t)),this.ws.send(i)}message(i,a){if("runtime"==i&&(t.runtime=a,t.update()),"status"==i&&t.updateStatus(a),"dashboard"==i){const i=a.hourly,r=a.days;let s,n,l,o,d=Math.max(...i.map((e=>e._hour)));l=Array.from({length:d},((e,t)=>0)),o=Array.from({length:d},((e,t)=>0));for(const e of i)l[e._hour]=e.hits,o[e._hour]=e.cache_hits,d=Math.max(d,e._hour);t._e_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...l,...o)},series:[{name:"I/O访问数",data:l,type:"line",smooth:!0},{name:"缓存访问数",data:o,type:"line",smooth:!0}]}),s=e.sum(...l,...o),l=Array.from({length:d},((e,t)=>0)),o=Array.from({length:d},((e,t)=>0));for(const e of i)l[e._hour]=e.bytes,o[e._hour]=e.cache_bytes;t._e_bytes.setOption({tooltip:{formatter:e=>t._e_templates(e,(e=>t._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...l,...o),axisLabel:{formatter:e=>t._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:l,type:"line",smooth:!0},{name:"缓存访问文件大小",data:o,type:"line",smooth:!0}]}),n=e.sum(...l,...o),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(t._format_number_unit(s)),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(t._format_bytes(n)),l=Array.from({length:30},((e,t)=>0)),o=Array.from({length:30},((e,t)=>0));for(const e of r)l[e._day]=e.hits,o[e._day]=e.cache_hits;t._e_daily_hits.setOption({legend:{data:["I/O访问数","缓存访问数"]},yAxis:{max:Math.max(10,...l,...o)},series:[{name:"I/O访问数",data:l,type:"line",smooth:!0},{name:"缓存访问数",data:o,type:"line",smooth:!0}]}),s=e.sum(...l,...o);{const i=Array.from({length:30},((e,t)=>0)),a=Array.from({length:30},((e,t)=>0));for(const e of r)i[e._day]=e.bytes,a[e._day]=e.cache_bytes;t._e_daily_bytes.setOption({tooltip:{formatter:e=>t._e_templates(e,(e=>t._format_bytes(e)))},legend:{data:["I/O访问文件大小","缓存访问文件大小"]},yAxis:{max:Math.max(10,...i,...a),axisLabel:{formatter:e=>t._format_bytes(e)}},series:[{name:"I/O访问文件大小",data:i,type:"line",smooth:!0},{name:"缓存访问文件大小",data:a,type:"line",smooth:!0}]}),n=e.sum(...i,...a)}t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[2].getChildrens()[1].setText(t._format_number_unit(s)),t._page[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].getChildrens()[3].getChildrens()[1].setText(t._format_bytes(n))}if("system"==i&&(t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(t._format_number_unit(a.connections)),t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(t._format_bytes(a.memory)),t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[2].getChildrens()[1].setText(`${t._format_number_unit(a.cache.total)}(${t._format_bytes(a.cache.bytes)})`),t._page[1].getChildrens()[0].getChildrens()[1].getChildrens()[0].getChildrens()[3].getChildrens()[1].setText(a.cpu.toFixed(2)+"%")),"qps"==i){const i=parseInt(e.getTimestamp()/1e3),n=(i%5!=0?5:0)-i%5+i,l=[];var r=[],s=[];for(let i=n-300;i<=n;i++){let n=a.hasOwnProperty(i)?a[i]:0;r.push(n),i%5==0&&(l.push({value:e.sum(...r)/r.length,raw:r}),r=[],s.push(t._e_format_time(1e3*i)))}t._page[1].getChildrens()[1].getChildrens()[0].getChildrens()[0].getChildrens()[0].setText(t._format_number_unit(e.sum(...e.collectionSingleList(l.map((e=>[...e.raw])))))),t._e_qps.setOption({xAxis:{data:s},series:[{data:l}]})}((e,...t)=>{var i=f.split("-",1),a=i[0],r=i[1];const s=(r?o[a].children.filter((e=>e.key==r))[0]:o[a]).core||{};e in s&&s[e](...t)})("_ws_message",i,a)}_deserializeData(e){const t=e.readVarInt();switch(t){case 0:return e.readString();case 1:return e.readBoolean();case 2:return parseFloat(e.readString());case 3:return parseInt(e.readString());case 4:{const t=e.readVarInt(),i=[];for(let a=0;a{this._e_bytes.resize(),this._e_daily_bytes.resize(),this._e_hits.resize(),this._e_daily_hits.resize(),this._e_qps.resize()}))],this._updateTimer=setInterval((()=>this.update()),1e3),this._e_options={tooltip:{trigger:"axis"},grid:{left:"3%",right:"4%",bottom:"3%",top:"20%",containLabel:!0},xAxis:{type:"category"},yAxis:{type:"value",min:1,max:10},series:[]},this._unit_bytes=["B","KB","MB","GB","TB","PB","EB"],this._unit_number=["","k","M","G","T","P","E"],this._hourly=Array.from({length:24},((e,t)=>t+" 时")),this._daily=Array.from({length:31},((e,t)=>t+" 天")),this._e_qps=echarts.init(this._page[1].getChildrens()[1].getChildrens()[1].valueOf()),this._e_hits=echarts.init(this._page[1].getChildrens()[2].getChildrens()[1].valueOf()),this._e_bytes=echarts.init(this._page[1].getChildrens()[3].getChildrens()[1].valueOf()),this._e_daily_hits=echarts.init(this._page[1].getChildrens()[4].getChildrens()[1].valueOf()),this._e_daily_bytes=echarts.init(this._page[1].getChildrens()[5].getChildrens()[1].valueOf()),this._e_hits.setOption(this._e_options),this._e_bytes.setOption(this._e_options),this._e_hits.setOption({xAxis:{data:this._hourly}}),this._e_bytes.setOption({xAxis:{data:this._hourly}}),this._e_daily_hits.setOption(this._e_options),this._e_daily_bytes.setOption(this._e_options),this._e_daily_hits.setOption({xAxis:{data:this._daily}}),this._e_daily_bytes.setOption({xAxis:{data:this._daily}}),this._e_qps.setOption({color:"#0fc6c2",tooltip:{trigger:"axis",formatter:t=>'
'+t[0].name+'
QPSAvg: '+t[0].data.value+" total: "+e.sum(...t[0].data.raw)+'
'},stateAnimation:{duration:300,easing:"cubicOut"},xAxis:{type:"category",show:!1},yAxis:{show:!1,type:"value"},grid:{top:10,bottom:10,right:0,left:0,show:!1,z:0,containLabel:!1,backgroundColor:"rgba(0,0,0,0)",borderWidth:1,borderColor:"#ccc"},series:[{type:"bar",barGap:"0",barMinHeight:4,itemStyle:{borderRadius:[2,2,0,0]},z:2,backgroundStyle:{color:"rgba(180, 180, 180, 0.2)",borderColor:null,borderWidth:0,borderType:"solid",borderRadius:0,shadowBlur:0,shadowColor:null,shadowOffsetX:0,shadowOffsetY:0},select:{itemStyle:{borderColor:"#212121"}}}]}),this.update(),setTimeout((()=>this._page[1].update()),1)}connect(e){e.push(...this._page)}update(){this._page[0].getChildrens()[0].getChildrens()[0].getChildrens()[1].setText(this._format_time(this.runtime,!0))}updateStatus(e){this._page[0].getChildrens()[0].getChildrens()[1].getChildrens()[1].setText(e)}_format_time(t,i=!1){if(null==t)return"-";let a=Number.parseInt(t);return i&&(a=Number.parseInt(e.getTime()-a)),`${parseInt(a/60/60/24).toString().padStart(2,"0")} 天 ${parseInt(a/60/60%24).toString().padStart(2,"0")} 小时 ${parseInt(a/60%60).toString().padStart(2,"0")} 分钟 ${parseInt(a%60).toString().padStart(2,"0")} 秒`}_format_bytes(e,t=null){return 0==e||(t=t||Math.min(Number.parseInt(Math.floor(Math.log(e)/Math.log(1024))),this._unit_bytes.length))<=0?`${e.toFixed(2)}${this._unit_bytes[0]}`:`${(e/=1024**t).toFixed(2)}${this._unit_bytes[t]}`}_e_templates(e,t=null){const i='
{name}{value}
';var a="";for(const r of e)a+=i.replace("{color}",r.color).replace("{name}",r.name).replace("{value}",t?t(r.value):r.value);return`
${e[0].name}
${a}
`}_format_number_unit(e){var t=(e+"").split("."),i=t[0],a=t.length>=2?"."+t.slice(1).join("."):"";return i.toString().replace(/\B(?=(\d{3})+(?!\d))/g,", ")+a}_e_format_time(e){const t=new Date(e);return t.getHours().toString().padStart(2,0)+":"+t.getMinutes().toString().padStart(2,0)+":"+t.getSeconds().toString().padStart(2,0)}};((e,t,i,a)=>{if(e.includes(".")){const[r,s]=[e.slice(0,e.indexOf(".")),e.slice(e.indexOf(".")+1)];o[r]||(o[r]={icon:t,children:[],text:"",core:a}),"children"in o[r]||(o[r].children=[]),o[r].children.push({key:s,text:i,core:a})}else o[e]={key:e,icon:t,text:i,core:a}})("dashboard","","数据统计",t)})(),p(),e.set_styles({"body,ol,ul,h1,h2,h3,h4,h5,h6,p,th,td,dl,dd,form,fieldset,legend,input,textarea,select":"margin:0;padding:0",body:"font:12px;background:#fff;-webkit-text-size-adjust:100%",a:"color:#172c45;text-decoration:none",em:"font-style:normal",li:"list-style:none",img:"border:0;vertical-align:middle",table:"border-collapse:collapse;border-spacing:0",p:"word-wrap:break-word",":root":["--r-main-background-color: #F6F7F9","--r-background-color: #191919","--r-main-font-size: 42px","--r-main-color: #fff","--r-block-margin: 20px","--r-heading-margin: 0 0 20px 0","--r-heading-font: Source Sans Pro, Helvetica, sans-serif","--r-heading-color: #fff","--r-heading-line-height: 1.2","--r-heading-letter-spacing: normal","--r-heading-text-transform: uppercase","--r-heading-text-shadow: none","--r-heading-font-weight: 600","--r-heading1-text-shadow: none","--r-heading1-size: 2.5em","--r-heading2-size: 1.6em","--r-heading3-size: 1.3em","--r-heading4-size: 1em","--r-code-font: monospace","--r-link-color: #42affa","--r-link-color-dark: #068de9","--r-link-color-hover: #8dcffc","--r-selection-background-color: rgba(66, 175, 250, .75)","--r-selection-color: #fff","--r-overlay-element-bg-color: 240, 240, 240","--r-overlay-element-fg-color: 0, 0, 0","--r-ligting-color: rgb(15, 198, 194);"],".root .left":["position: fixed","min-height: calc(100vh - 72px)","max-height: calc(100vh - 72px)","min-width: 48px","max-width: 184px","margin-top: 16px","width: 256px","padding: 8px","padding-top: 0","background: var(--r-main-background-color)","transition: transform 200ms linear 0s;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .left .content":["overflow: auto","width: 95%"],".root .left.hide":["transform: translateX(-100%);"],".root .left .button":["cursor: pointer;","border-radius: 8px;","margin-bottom: 8px","padding: 4px","padding-left: 8px","transition: color 200ms linear 0s;"],".root .left .arrow-background":["position: absolute","background: var(--r-main-background-color)","width: 20px","height: 20px","left: 194px","margin-top: -16px","cursor: pointer"],".root .left .arrow":["width: 100%","height: 100%",'background-image: url("data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgc3R5bGU9IndpZHRoOiAxZW07aGVpZ2h0OiAxZW07dmVydGljYWwtYWxpZ246IG1pZGRsZTtmaWxsOiBjdXJyZW50Q29sb3I7b3ZlcmZsb3c6IGhpZGRlbjsiIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwLWlkPSI3NTUiPjxwYXRoIGQ9Ik0zMjUuMDQ4IDkzLjUxMWwtNjAuMDMwIDU5LjQzNSAzNTcuMTgxIDM1OS42MzEtMzYwLjE4NCAzNTYuNjAzIDU5LjUyMiA1OS45MyA0MjAuMjA3LTQxNi4wNDN6IiBmaWxsPSIjODQ4NDg0IiBwLWlkPSI3NTYiPjwvcGF0aD48L3N2Zz4=");'],".root .container .left.hide .arrow-background .arrow":["transform: rotate(0deg);"],".root .container .left .arrow-background .arrow":["transform: rotate(180deg);","transition: transform 100ms linear 0s;"],".root .left .button:hover":["color: var(--r-ligting-color)"],".root .left .button.selected":["background: var(--r-ligting-color)","box-shadow: rgba(15, 198, 194, 0.2) 0px 10px 25px 0px;","color: white"],".root .left .side":["margin-left: 8px"],".root .left .sidebutton":["padding: 2px","margin-bottom: 8px","cursor: pointer;","color: rgba(0, 0, 0, 0.5);","transition: color 200ms linear 0s;"],".root .left .sidebutton:hover":["color: var(--r-link-color-hover)"],".root .left .sidebutton.selected":["color: black","font-weight: bold"],".root .left .sidebutton:hover .cycle":["background: var(--r-link-color-hover)"],".root .left .sidebutton.selected .cycle":["width: 8px;","height: 8px;","background-color: rgb(15, 198, 194);","margin-right: 6px","margin-left: 2px","border-radius: 50%;"],".root .left .sidebutton .cycle":["width: 4px;","height: 4px;","margin: 4px","margin-right: 8px","background-color: rgba(0, 0, 0, 0.5);","transition: background-color 200ms linear 0s;","border-radius: 50%;"],".root .header":["position: fixed","height: 40px","min-height: 40px","min-width: 100vw","background: var(--r-main-background-color)","z-index: 1","padding: 8px","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;"],".root .container":["position: relative;","top: 56px;"],".root .container .right":["padding-top: 16px","margin-left: 216px","transition: width 200ms linear 0s;","min-width: calc(100vw - 232px)","min-height: calc(100vh - 72px)"],".root .container .left.hide ~ .right":["margin-left: 0","min-width: 100vw"],".root .container .right .panel":["background-color: rgb(255, 255, 255);","color: rgb(0, 0, 0);","transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;","border-radius: 4px;","background-image: none;","padding: 24px;","box-shadow: rgba(145, 158, 171, 0.2) 0px 4px 10px;","margin: 16px;"],".panel.info-4":["display: flex","flex-warp: warp"],".panel.info-4 div":["width: 25%"],".panel.info-2":["display: flex","flex-warp: warp"],".panel.info-2 div":["width: 50%"],".panel .title":["display: flex","margin: 0px 0px 6px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.5);","font-size: 14px;"],".panel .value":["margin: 0px;","font-family: inherit;","font-weight: 400;","line-height: 1.5;","color: rgba(0, 0, 0, 0.7);","font-size: 24px;"],".root .container .left.hide~.right":["margin-left: 32px","min-width: calc(100vw - 48px)"],".root .left .copyright":["position: fixed;","bottom: 2px"],".qps .icon":["width: 14px","height: 14px"],".qps":["display: flex","align-items: center"],".progress":["position: absolute;","z-index: 2","width: 0","height: 2px","background: var(--r-ligting-color)","transition: width 200ms linear 0s;"],body:["background-color: var(--r-main-background-color)"]}),g(),y()})(); \ No newline at end of file From e527f516b2541a3f6199a9e33ae1bb23b35212a8 Mon Sep 17 00:00:00 2001 From: tianxiu2b2t Date: Sun, 24 Mar 2024 09:05:13 +0800 Subject: [PATCH 9/9] Fix get_file_hash not found io_buffer --- core/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/api.py b/core/api.py index d374e6d..cfdb1e6 100644 --- a/core/api.py +++ b/core/api.py @@ -103,7 +103,7 @@ def get_hash(org): async def get_file_hash(org: str, path: Path): hash = get_hash(org) async with aiofiles.open(path, "rb") as r: - while data := await r.read(Config.get("io_buffer")): + while data := await r.read(Config.get("advanced.io_buffer")): if not data: break hash.update(data)