function decompress(b64Data) { let strData = atob(b64Data); let charData = strData.split('').map(function(x){return x.charCodeAt(0);}); let binData = new Uint8Array(charData); let cs = new DecompressionStream("gzip"); let writer = cs.writable.getWriter(); writer.write(binData); writer.close(); return new Response(cs.readable).arrayBuffer().then(function (arrayBuffer) { return new TextDecoder().decode(arrayBuffer); }); } new Vue({ el: '#app', data() { return { props: { label: 'label', children: 'children' }, data: [], filterText: '', filterTextTime: null, currentNode: {}, currentNodeFlag: false, currentNodeData: [], }; }, watch: { filterText(val) { clearTimeout(this.filterTextTime); this.filterTextTime = setTimeout(() => { if (val.length > 0 && val.length < 3) { return } this.$refs.tree.filter(val); }, 1000); } }, created() { let matched = location.href.match('demo=(.*)'); let file = `/callstack?file=data/data.js`; if (matched) { file = `/callstack?file=${matched[1]}`; } axios.get(file).then(response => { let txt = response.data; this.setData(txt, /gz$/.test(file)); }).catch(function (error) { console.log(error); }); }, methods: { setTextarea(f, fl) { const reader = new FileReader(); reader.onload = (event) => { this.setData(event.target.result); }; reader.readAsText(f.raw); }, async setData(v, gz) { if (gz) v = await decompress(v); let tempData = []; let lines = v.split("\n"); lines.forEach((v2) => { if (v2.length < 23) { return } let secs = v2.substring(10, 22); let name = v2.substring(23).split(" at "); let root = this.getRoot(v2.substring(0, 10), tempData); let file = name.length > 1 ? name[1] : ''; if (!root) { root = { label: name[0], children: [], secs: secs, file: file, }; tempData.push(root) } else { let depth = name[0].match(/^\.+/); depth = depth ? depth[0].length : 0; let lastChild = this.getChildren(depth, root); if (lastChild && lastChild.children) { lastChild.children.push({ label: name[0].substring(depth), children: [], secs: secs, file: file, }) } } }); this.data = tempData; }, filterNode(value, data) { if (!value) return true; return data.label.indexOf(value) !== -1; }, getRoot(label, children) { label = label.trim(); for (let i in children) { if (children[i].label.includes(`goroutine-${label} `)) { return children[i]; } } return null; }, getChildren(depth, data) { if (depth <= 1) { return data; } if (!data.children || data.children.length == 0) { return null; } let lastChild = data.children[data.children.length - 1]; return this.getChildren(depth - 1, lastChild); }, currentCopy(event) { let el = $(event.currentTarget).parents('.el-tree-node'); let str = '
' + getLines('', el.eq(0)) + '
'; this.$alert(str, '', {dangerouslyUseHTMLString: true}); }, currentShow(data) { let base = 'https://521github.com'; if (data.file.includes("/go/src/")) { let path = data.file.replace(/^.*\/go([\d.]+)\/src\//, '/golang/go/blob/go$1/src/'); path = data.file.replace(/^.*\/go\/src\//, '/golang/go/blob/go1.20.6/src/'); window.open(base + path); } else if (data.file.includes("github.com")) { let path = data.file.replace(/^.*\/github.com/, '').replace('@', '/blob/'); window.open(base + path); } else { let str = `

${data.file}

`; this.$alert(str, '', {dangerouslyUseHTMLString: true}); } } } }); function getLines(pre, currNode) { let str = pre + '|-' + currNode.find('.el-tree-node__content .custom-label').html() + "\n"; let chi = currNode.find('> .el-tree-node__children > .el-tree-node'); chi.each(function(index, element) { if ($(element).parent().css('display') != 'none') { str += getLines(pre + ' ', $(element)); } }); return str; }