NEZ-3109 feat:explore页面支持对 promql 格式校验及format
This commit is contained in:
@@ -3535,6 +3535,8 @@ import logTab from './logTab'
|
||||
import promqlInputMixin from '@/components/common/mixin/promqlInput'
|
||||
import chartRightBox from '@/components/common/rightBox/chart/chartRightBox'
|
||||
import copy from '@/components/common/copy'
|
||||
import './promqlparser/wasm_exec.js'
|
||||
|
||||
export default {
|
||||
name: 'exploreItem',
|
||||
components: {
|
||||
@@ -3624,19 +3626,33 @@ export default {
|
||||
scrollbarWrap: null
|
||||
}
|
||||
},
|
||||
created () {
|
||||
async created () {
|
||||
this.getPanelData()
|
||||
this.resetExpression()
|
||||
await this.loadWebAssembly()
|
||||
this.initQueryFromPath()
|
||||
},
|
||||
mounted () {
|
||||
this.scrollbarWrap = this.$refs.exploreScrollbar
|
||||
this.scrollbarWrap.addEventListener('scroll', this.onScroll)
|
||||
this.initQueryFromPath()
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.scrollbarWrap.removeEventListener('scroll', this.onScroll)
|
||||
},
|
||||
methods: {
|
||||
async loadWebAssembly () {
|
||||
try {
|
||||
// eslint-disable-next-line no-undef
|
||||
const go = new Go()
|
||||
const result = await WebAssembly.instantiateStreaming(fetch('/static/promqlparser.wasm'), go.importObject)
|
||||
go.run(result.instance)
|
||||
// eslint-disable-next-line no-undef
|
||||
this.parsePromQL = parsePromQL
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
},
|
||||
parsePromQL () {},
|
||||
onScroll: bus.debounce(function () {
|
||||
this.showTopBtn = this.scrollbarWrap.scrollTop > 50
|
||||
}, 300),
|
||||
@@ -3953,7 +3969,7 @@ export default {
|
||||
} else {
|
||||
if (response.error) {
|
||||
this.$refs['promql-' + promqlIndex][0].setError(response.error)
|
||||
} else if(response.msg) {
|
||||
} else if (response.msg) {
|
||||
this.$refs['promql-' + promqlIndex][0].setError(response.msg)
|
||||
} else {
|
||||
this.$refs['promql-' + promqlIndex][0].setError(response)
|
||||
@@ -4102,6 +4118,24 @@ export default {
|
||||
this.setSearchTime(nowTimeType.type, nowTimeType.value)
|
||||
}
|
||||
if (this.expressions && this.expressions.length >= 1) {
|
||||
let error = false
|
||||
// 对 promql 格式校验及format
|
||||
if (this.showMetrics) {
|
||||
this.expressions.forEach((item, index) => {
|
||||
if (item != '' && this.promqlKeys[index].state) {
|
||||
const res = this.parsePromQL(item)
|
||||
if (res.status === 'error') {
|
||||
error = true
|
||||
this.$refs['promql-' + index][0].setError(res.message)
|
||||
} else {
|
||||
this.$set(this.expressions, index, res.result)
|
||||
this.$refs['promql-' + index][0].prettyCode()
|
||||
this.$refs['promql-' + index][0].setError('')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
if (error) { return }
|
||||
if (this.showMetrics) {
|
||||
this.queryTableData()
|
||||
this.queryChartData()
|
||||
|
||||
@@ -1158,10 +1158,20 @@ export default {
|
||||
this.expressionList[this.index] = insertTxt
|
||||
this.codeMirrorValue[this.index] = insertTxt
|
||||
this.initCodeMirror()
|
||||
}
|
||||
},
|
||||
/* setMsg:function(){
|
||||
this.appendMsg
|
||||
} */
|
||||
prettyCode () {
|
||||
this.$nextTick(() => {
|
||||
const text = this.newView.state.doc.toString()
|
||||
this.newView.dispatch(
|
||||
this.newView.state.update({
|
||||
changes: { from: 0, to: text.length, insert: this.codeMirrorValue[this.index] }
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
dropDownVisible (n, o) {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
module test.go
|
||||
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/dennwc/varint v1.0.0 // indirect
|
||||
github.com/go-kit/log v0.2.1 // indirect
|
||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.16.0 // indirect
|
||||
github.com/prometheus/client_model v0.4.0 // indirect
|
||||
github.com/prometheus/common v0.44.0 // indirect
|
||||
github.com/prometheus/procfs v0.11.0 // indirect
|
||||
github.com/prometheus/prometheus v0.46.0 // indirect
|
||||
github.com/stretchr/testify v1.8.4 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/goleak v1.2.1 // indirect
|
||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect
|
||||
golang.org/x/sys v0.10.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
@@ -0,0 +1,91 @@
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE=
|
||||
github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA=
|
||||
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
|
||||
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
|
||||
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd h1:PpuIBO5P3e9hpqBD0O/HjhShYuM6XE0i/lbE6J94kww=
|
||||
github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
|
||||
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
|
||||
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
|
||||
github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
|
||||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
|
||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
||||
github.com/prometheus/procfs v0.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk=
|
||||
github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
|
||||
github.com/prometheus/prometheus v0.46.0 h1:9JSdXnsuT6YsbODEhSQMwxNkGwPExfmzqG73vCMk/Kw=
|
||||
github.com/prometheus/prometheus v0.46.0/go.mod h1:10L5IJE5CEsjee1FnOcVswYXlPIscDWWt3IJ2UDYrz4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
||||
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw=
|
||||
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -0,0 +1,33 @@
|
||||
// 编译为wasm文件 在页面中引入
|
||||
package main
|
||||
|
||||
import (
|
||||
"syscall/js"
|
||||
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
)
|
||||
|
||||
func parsePromQL(this js.Value, args []js.Value) interface{} {
|
||||
promql := args[0].String()
|
||||
expr, err := parser.ParseExpr(promql)
|
||||
if err != nil {
|
||||
return map[string]interface{}{
|
||||
"status": "error",
|
||||
"message": err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"status": "success",
|
||||
"result": expr.Pretty(0),
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
c := make(chan struct{}, 0)
|
||||
|
||||
// 注册函数
|
||||
js.Global().Set("parsePromQL", js.FuncOf(parsePromQL))
|
||||
|
||||
<-c
|
||||
}
|
||||
@@ -0,0 +1,554 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
'use strict';
|
||||
|
||||
(() => {
|
||||
const enosys = () => {
|
||||
const err = new Error('not implemented')
|
||||
err.code = 'ENOSYS'
|
||||
return err
|
||||
}
|
||||
|
||||
if (!globalThis.fs) {
|
||||
let outputBuf = ''
|
||||
globalThis.fs = {
|
||||
constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused
|
||||
writeSync (fd, buf) {
|
||||
outputBuf += decoder.decode(buf)
|
||||
const nl = outputBuf.lastIndexOf('\n')
|
||||
if (nl != -1) {
|
||||
console.log(outputBuf.substring(0, nl))
|
||||
outputBuf = outputBuf.substring(nl + 1)
|
||||
}
|
||||
return buf.length
|
||||
},
|
||||
write (fd, buf, offset, length, position, callback) {
|
||||
if (offset !== 0 || length !== buf.length || position !== null) {
|
||||
callback(enosys())
|
||||
return
|
||||
}
|
||||
const n = this.writeSync(fd, buf)
|
||||
callback(null, n)
|
||||
},
|
||||
chmod (path, mode, callback) { callback(enosys()) },
|
||||
chown (path, uid, gid, callback) { callback(enosys()) },
|
||||
close (fd, callback) { callback(enosys()) },
|
||||
fchmod (fd, mode, callback) { callback(enosys()) },
|
||||
fchown (fd, uid, gid, callback) { callback(enosys()) },
|
||||
fstat (fd, callback) { callback(enosys()) },
|
||||
fsync (fd, callback) { callback(null) },
|
||||
ftruncate (fd, length, callback) { callback(enosys()) },
|
||||
lchown (path, uid, gid, callback) { callback(enosys()) },
|
||||
link (path, link, callback) { callback(enosys()) },
|
||||
lstat (path, callback) { callback(enosys()) },
|
||||
mkdir (path, perm, callback) { callback(enosys()) },
|
||||
open (path, flags, mode, callback) { callback(enosys()) },
|
||||
read (fd, buffer, offset, length, position, callback) { callback(enosys()) },
|
||||
readdir (path, callback) { callback(enosys()) },
|
||||
readlink (path, callback) { callback(enosys()) },
|
||||
rename (from, to, callback) { callback(enosys()) },
|
||||
rmdir (path, callback) { callback(enosys()) },
|
||||
stat (path, callback) { callback(enosys()) },
|
||||
symlink (path, link, callback) { callback(enosys()) },
|
||||
truncate (path, length, callback) { callback(enosys()) },
|
||||
unlink (path, callback) { callback(enosys()) },
|
||||
utimes (path, atime, mtime, callback) { callback(enosys()) }
|
||||
}
|
||||
}
|
||||
|
||||
if (!globalThis.process) {
|
||||
globalThis.process = {
|
||||
getuid () { return -1 },
|
||||
getgid () { return -1 },
|
||||
geteuid () { return -1 },
|
||||
getegid () { return -1 },
|
||||
getgroups () { throw enosys() },
|
||||
pid: -1,
|
||||
ppid: -1,
|
||||
umask () { throw enosys() },
|
||||
cwd () { throw enosys() },
|
||||
chdir () { throw enosys() }
|
||||
}
|
||||
}
|
||||
|
||||
if (!globalThis.crypto) {
|
||||
throw new Error('globalThis.crypto is not available, polyfill required (crypto.getRandomValues only)')
|
||||
}
|
||||
|
||||
if (!globalThis.performance) {
|
||||
throw new Error('globalThis.performance is not available, polyfill required (performance.now only)')
|
||||
}
|
||||
|
||||
if (!globalThis.TextEncoder) {
|
||||
throw new Error('globalThis.TextEncoder is not available, polyfill required')
|
||||
}
|
||||
|
||||
if (!globalThis.TextDecoder) {
|
||||
throw new Error('globalThis.TextDecoder is not available, polyfill required')
|
||||
}
|
||||
|
||||
const encoder = new TextEncoder('utf-8')
|
||||
const decoder = new TextDecoder('utf-8')
|
||||
|
||||
globalThis.Go = class {
|
||||
constructor () {
|
||||
this.argv = ['js']
|
||||
this.env = {}
|
||||
this.exit = (code) => {
|
||||
if (code !== 0) {
|
||||
console.warn('exit code:', code)
|
||||
}
|
||||
}
|
||||
this._exitPromise = new Promise((resolve) => {
|
||||
this._resolveExitPromise = resolve
|
||||
})
|
||||
this._pendingEvent = null
|
||||
this._scheduledTimeouts = new Map()
|
||||
this._nextCallbackTimeoutID = 1
|
||||
|
||||
const setInt64 = (addr, v) => {
|
||||
this.mem.setUint32(addr + 0, v, true)
|
||||
this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true)
|
||||
}
|
||||
|
||||
const getInt64 = (addr) => {
|
||||
const low = this.mem.getUint32(addr + 0, true)
|
||||
const high = this.mem.getInt32(addr + 4, true)
|
||||
return low + high * 4294967296
|
||||
}
|
||||
|
||||
const loadValue = (addr) => {
|
||||
const f = this.mem.getFloat64(addr, true)
|
||||
if (f === 0) {
|
||||
return undefined
|
||||
}
|
||||
if (!isNaN(f)) {
|
||||
return f
|
||||
}
|
||||
|
||||
const id = this.mem.getUint32(addr, true)
|
||||
return this._values[id]
|
||||
}
|
||||
|
||||
const storeValue = (addr, v) => {
|
||||
const nanHead = 0x7FF80000
|
||||
|
||||
if (typeof v === 'number' && v !== 0) {
|
||||
if (isNaN(v)) {
|
||||
this.mem.setUint32(addr + 4, nanHead, true)
|
||||
this.mem.setUint32(addr, 0, true)
|
||||
return
|
||||
}
|
||||
this.mem.setFloat64(addr, v, true)
|
||||
return
|
||||
}
|
||||
|
||||
if (v === undefined) {
|
||||
this.mem.setFloat64(addr, 0, true)
|
||||
return
|
||||
}
|
||||
|
||||
let id = this._ids.get(v)
|
||||
if (id === undefined) {
|
||||
id = this._idPool.pop()
|
||||
if (id === undefined) {
|
||||
id = this._values.length
|
||||
}
|
||||
this._values[id] = v
|
||||
this._goRefCounts[id] = 0
|
||||
this._ids.set(v, id)
|
||||
}
|
||||
this._goRefCounts[id]++
|
||||
let typeFlag = 0
|
||||
switch (typeof v) {
|
||||
case 'object':
|
||||
if (v !== null) {
|
||||
typeFlag = 1
|
||||
}
|
||||
break
|
||||
case 'string':
|
||||
typeFlag = 2
|
||||
break
|
||||
case 'symbol':
|
||||
typeFlag = 3
|
||||
break
|
||||
case 'function':
|
||||
typeFlag = 4
|
||||
break
|
||||
}
|
||||
this.mem.setUint32(addr + 4, nanHead | typeFlag, true)
|
||||
this.mem.setUint32(addr, id, true)
|
||||
}
|
||||
|
||||
const loadSlice = (addr) => {
|
||||
const array = getInt64(addr + 0)
|
||||
const len = getInt64(addr + 8)
|
||||
return new Uint8Array(this._inst.exports.mem.buffer, array, len)
|
||||
}
|
||||
|
||||
const loadSliceOfValues = (addr) => {
|
||||
const array = getInt64(addr + 0)
|
||||
const len = getInt64(addr + 8)
|
||||
const a = new Array(len)
|
||||
for (let i = 0; i < len; i++) {
|
||||
a[i] = loadValue(array + i * 8)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
const loadString = (addr) => {
|
||||
const saddr = getInt64(addr + 0)
|
||||
const len = getInt64(addr + 8)
|
||||
return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len))
|
||||
}
|
||||
|
||||
const timeOrigin = Date.now() - performance.now()
|
||||
this.importObject = {
|
||||
go: {
|
||||
// Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
|
||||
// may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported
|
||||
// function. A goroutine can switch to a new stack if the current stack is too small (see morestack function).
|
||||
// This changes the SP, thus we have to update the SP used by the imported function.
|
||||
|
||||
// func wasmExit(code int32)
|
||||
'runtime.wasmExit': (sp) => {
|
||||
sp >>>= 0
|
||||
const code = this.mem.getInt32(sp + 8, true)
|
||||
this.exited = true
|
||||
delete this._inst
|
||||
delete this._values
|
||||
delete this._goRefCounts
|
||||
delete this._ids
|
||||
delete this._idPool
|
||||
this.exit(code)
|
||||
},
|
||||
|
||||
// func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
|
||||
'runtime.wasmWrite': (sp) => {
|
||||
sp >>>= 0
|
||||
const fd = getInt64(sp + 8)
|
||||
const p = getInt64(sp + 16)
|
||||
const n = this.mem.getInt32(sp + 24, true)
|
||||
fs.writeSync(fd, new Uint8Array(this._inst.exports.mem.buffer, p, n))
|
||||
},
|
||||
|
||||
// func resetMemoryDataView()
|
||||
'runtime.resetMemoryDataView': (sp) => {
|
||||
sp >>>= 0
|
||||
this.mem = new DataView(this._inst.exports.mem.buffer)
|
||||
},
|
||||
|
||||
// func nanotime1() int64
|
||||
'runtime.nanotime1': (sp) => {
|
||||
sp >>>= 0
|
||||
setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000)
|
||||
},
|
||||
|
||||
// func walltime() (sec int64, nsec int32)
|
||||
'runtime.walltime': (sp) => {
|
||||
sp >>>= 0
|
||||
const msec = (new Date()).getTime()
|
||||
setInt64(sp + 8, msec / 1000)
|
||||
this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true)
|
||||
},
|
||||
|
||||
// func scheduleTimeoutEvent(delay int64) int32
|
||||
'runtime.scheduleTimeoutEvent': (sp) => {
|
||||
sp >>>= 0
|
||||
const id = this._nextCallbackTimeoutID
|
||||
this._nextCallbackTimeoutID++
|
||||
this._scheduledTimeouts.set(id, setTimeout(
|
||||
() => {
|
||||
this._resume()
|
||||
while (this._scheduledTimeouts.has(id)) {
|
||||
// for some reason Go failed to register the timeout event, log and try again
|
||||
// (temporary workaround for https://github.com/golang/go/issues/28975)
|
||||
console.warn('scheduleTimeoutEvent: missed timeout event')
|
||||
this._resume()
|
||||
}
|
||||
},
|
||||
getInt64(sp + 8) + 1 // setTimeout has been seen to fire up to 1 millisecond early
|
||||
))
|
||||
this.mem.setInt32(sp + 16, id, true)
|
||||
},
|
||||
|
||||
// func clearTimeoutEvent(id int32)
|
||||
'runtime.clearTimeoutEvent': (sp) => {
|
||||
sp >>>= 0
|
||||
const id = this.mem.getInt32(sp + 8, true)
|
||||
clearTimeout(this._scheduledTimeouts.get(id))
|
||||
this._scheduledTimeouts.delete(id)
|
||||
},
|
||||
|
||||
// func getRandomData(r []byte)
|
||||
'runtime.getRandomData': (sp) => {
|
||||
sp >>>= 0
|
||||
crypto.getRandomValues(loadSlice(sp + 8))
|
||||
},
|
||||
|
||||
// func finalizeRef(v ref)
|
||||
'syscall/js.finalizeRef': (sp) => {
|
||||
sp >>>= 0
|
||||
const id = this.mem.getUint32(sp + 8, true)
|
||||
this._goRefCounts[id]--
|
||||
if (this._goRefCounts[id] === 0) {
|
||||
const v = this._values[id]
|
||||
this._values[id] = null
|
||||
this._ids.delete(v)
|
||||
this._idPool.push(id)
|
||||
}
|
||||
},
|
||||
|
||||
// func stringVal(value string) ref
|
||||
'syscall/js.stringVal': (sp) => {
|
||||
sp >>>= 0
|
||||
storeValue(sp + 24, loadString(sp + 8))
|
||||
},
|
||||
|
||||
// func valueGet(v ref, p string) ref
|
||||
'syscall/js.valueGet': (sp) => {
|
||||
sp >>>= 0
|
||||
const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16))
|
||||
sp = this._inst.exports.getsp() >>> 0 // see comment above
|
||||
storeValue(sp + 32, result)
|
||||
},
|
||||
|
||||
// func valueSet(v ref, p string, x ref)
|
||||
'syscall/js.valueSet': (sp) => {
|
||||
sp >>>= 0
|
||||
Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32))
|
||||
},
|
||||
|
||||
// func valueDelete(v ref, p string)
|
||||
'syscall/js.valueDelete': (sp) => {
|
||||
sp >>>= 0
|
||||
Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16))
|
||||
},
|
||||
|
||||
// func valueIndex(v ref, i int) ref
|
||||
'syscall/js.valueIndex': (sp) => {
|
||||
sp >>>= 0
|
||||
storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)))
|
||||
},
|
||||
|
||||
// valueSetIndex(v ref, i int, x ref)
|
||||
'syscall/js.valueSetIndex': (sp) => {
|
||||
sp >>>= 0
|
||||
Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24))
|
||||
},
|
||||
|
||||
// func valueCall(v ref, m string, args []ref) (ref, bool)
|
||||
'syscall/js.valueCall': (sp) => {
|
||||
sp >>>= 0
|
||||
try {
|
||||
const v = loadValue(sp + 8)
|
||||
const m = Reflect.get(v, loadString(sp + 16))
|
||||
const args = loadSliceOfValues(sp + 32)
|
||||
const result = Reflect.apply(m, v, args)
|
||||
sp = this._inst.exports.getsp() >>> 0 // see comment above
|
||||
storeValue(sp + 56, result)
|
||||
this.mem.setUint8(sp + 64, 1)
|
||||
} catch (err) {
|
||||
sp = this._inst.exports.getsp() >>> 0 // see comment above
|
||||
storeValue(sp + 56, err)
|
||||
this.mem.setUint8(sp + 64, 0)
|
||||
}
|
||||
},
|
||||
|
||||
// func valueInvoke(v ref, args []ref) (ref, bool)
|
||||
'syscall/js.valueInvoke': (sp) => {
|
||||
sp >>>= 0
|
||||
try {
|
||||
const v = loadValue(sp + 8)
|
||||
const args = loadSliceOfValues(sp + 16)
|
||||
const result = Reflect.apply(v, undefined, args)
|
||||
sp = this._inst.exports.getsp() >>> 0 // see comment above
|
||||
storeValue(sp + 40, result)
|
||||
this.mem.setUint8(sp + 48, 1)
|
||||
} catch (err) {
|
||||
sp = this._inst.exports.getsp() >>> 0 // see comment above
|
||||
storeValue(sp + 40, err)
|
||||
this.mem.setUint8(sp + 48, 0)
|
||||
}
|
||||
},
|
||||
|
||||
// func valueNew(v ref, args []ref) (ref, bool)
|
||||
'syscall/js.valueNew': (sp) => {
|
||||
sp >>>= 0
|
||||
try {
|
||||
const v = loadValue(sp + 8)
|
||||
const args = loadSliceOfValues(sp + 16)
|
||||
const result = Reflect.construct(v, args)
|
||||
sp = this._inst.exports.getsp() >>> 0 // see comment above
|
||||
storeValue(sp + 40, result)
|
||||
this.mem.setUint8(sp + 48, 1)
|
||||
} catch (err) {
|
||||
sp = this._inst.exports.getsp() >>> 0 // see comment above
|
||||
storeValue(sp + 40, err)
|
||||
this.mem.setUint8(sp + 48, 0)
|
||||
}
|
||||
},
|
||||
|
||||
// func valueLength(v ref) int
|
||||
'syscall/js.valueLength': (sp) => {
|
||||
sp >>>= 0
|
||||
setInt64(sp + 16, parseInt(loadValue(sp + 8).length))
|
||||
},
|
||||
|
||||
// valuePrepareString(v ref) (ref, int)
|
||||
'syscall/js.valuePrepareString': (sp) => {
|
||||
sp >>>= 0
|
||||
const str = encoder.encode(String(loadValue(sp + 8)))
|
||||
storeValue(sp + 16, str)
|
||||
setInt64(sp + 24, str.length)
|
||||
},
|
||||
|
||||
// valueLoadString(v ref, b []byte)
|
||||
'syscall/js.valueLoadString': (sp) => {
|
||||
sp >>>= 0
|
||||
const str = loadValue(sp + 8)
|
||||
loadSlice(sp + 16).set(str)
|
||||
},
|
||||
|
||||
// func valueInstanceOf(v ref, t ref) bool
|
||||
'syscall/js.valueInstanceOf': (sp) => {
|
||||
sp >>>= 0
|
||||
this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0)
|
||||
},
|
||||
|
||||
// func copyBytesToGo(dst []byte, src ref) (int, bool)
|
||||
'syscall/js.copyBytesToGo': (sp) => {
|
||||
sp >>>= 0
|
||||
const dst = loadSlice(sp + 8)
|
||||
const src = loadValue(sp + 32)
|
||||
if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
|
||||
this.mem.setUint8(sp + 48, 0)
|
||||
return
|
||||
}
|
||||
const toCopy = src.subarray(0, dst.length)
|
||||
dst.set(toCopy)
|
||||
setInt64(sp + 40, toCopy.length)
|
||||
this.mem.setUint8(sp + 48, 1)
|
||||
},
|
||||
|
||||
// func copyBytesToJS(dst ref, src []byte) (int, bool)
|
||||
'syscall/js.copyBytesToJS': (sp) => {
|
||||
sp >>>= 0
|
||||
const dst = loadValue(sp + 8)
|
||||
const src = loadSlice(sp + 16)
|
||||
if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
|
||||
this.mem.setUint8(sp + 48, 0)
|
||||
return
|
||||
}
|
||||
const toCopy = src.subarray(0, dst.length)
|
||||
dst.set(toCopy)
|
||||
setInt64(sp + 40, toCopy.length)
|
||||
this.mem.setUint8(sp + 48, 1)
|
||||
},
|
||||
|
||||
debug: (value) => {
|
||||
console.log(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async run (instance) {
|
||||
if (!(instance instanceof WebAssembly.Instance)) {
|
||||
throw new Error('Go.run: WebAssembly.Instance expected')
|
||||
}
|
||||
this._inst = instance
|
||||
this.mem = new DataView(this._inst.exports.mem.buffer)
|
||||
this._values = [ // JS values that Go currently has references to, indexed by reference id
|
||||
NaN,
|
||||
0,
|
||||
null,
|
||||
true,
|
||||
false,
|
||||
globalThis,
|
||||
this
|
||||
]
|
||||
this._goRefCounts = new Array(this._values.length).fill(Infinity) // number of references that Go has to a JS value, indexed by reference id
|
||||
this._ids = new Map([ // mapping from JS values to reference ids
|
||||
[0, 1],
|
||||
[null, 2],
|
||||
[true, 3],
|
||||
[false, 4],
|
||||
[globalThis, 5],
|
||||
[this, 6]
|
||||
])
|
||||
this._idPool = [] // unused ids that have been garbage collected
|
||||
this.exited = false // whether the Go program has exited
|
||||
|
||||
// Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory.
|
||||
let offset = 4096
|
||||
|
||||
const strPtr = (str) => {
|
||||
const ptr = offset
|
||||
const bytes = encoder.encode(str + '\0')
|
||||
new Uint8Array(this.mem.buffer, offset, bytes.length).set(bytes)
|
||||
offset += bytes.length
|
||||
if (offset % 8 !== 0) {
|
||||
offset += 8 - (offset % 8)
|
||||
}
|
||||
return ptr
|
||||
}
|
||||
|
||||
const argc = this.argv.length
|
||||
|
||||
const argvPtrs = []
|
||||
this.argv.forEach((arg) => {
|
||||
argvPtrs.push(strPtr(arg))
|
||||
})
|
||||
argvPtrs.push(0)
|
||||
|
||||
const keys = Object.keys(this.env).sort()
|
||||
keys.forEach((key) => {
|
||||
argvPtrs.push(strPtr(`${key}=${this.env[key]}`))
|
||||
})
|
||||
argvPtrs.push(0)
|
||||
|
||||
const argv = offset
|
||||
argvPtrs.forEach((ptr) => {
|
||||
this.mem.setUint32(offset, ptr, true)
|
||||
this.mem.setUint32(offset + 4, 0, true)
|
||||
offset += 8
|
||||
})
|
||||
|
||||
// The linker guarantees global data starts from at least wasmMinDataAddr.
|
||||
// Keep in sync with cmd/link/internal/ld/data.go:wasmMinDataAddr.
|
||||
const wasmMinDataAddr = 4096 + 8192
|
||||
if (offset >= wasmMinDataAddr) {
|
||||
throw new Error('total length of command line and environment variables exceeds limit')
|
||||
}
|
||||
|
||||
this._inst.exports.run(argc, argv)
|
||||
if (this.exited) {
|
||||
this._resolveExitPromise()
|
||||
}
|
||||
await this._exitPromise
|
||||
}
|
||||
|
||||
_resume () {
|
||||
if (this.exited) {
|
||||
throw new Error('Go program has already exited')
|
||||
}
|
||||
this._inst.exports.resume()
|
||||
if (this.exited) {
|
||||
this._resolveExitPromise()
|
||||
}
|
||||
}
|
||||
|
||||
_makeFuncWrapper (id) {
|
||||
const go = this
|
||||
return function () {
|
||||
const event = { id: id, this: this, args: arguments }
|
||||
go._pendingEvent = event
|
||||
go._resume()
|
||||
return event.result
|
||||
}
|
||||
}
|
||||
}
|
||||
})()
|
||||
Reference in New Issue
Block a user