mirror of
https://github.com/Kong/insomnia
synced 2024-11-07 22:30:15 +00:00
gRPC server reflection support (#5518)
* eliminate grpc paths * add fake reflection ux * add grpc packages * basic ux * first working pass * package lock * reset selected protofile * fix types * ssl * improve naming * remove deprecated grpc url parse * remove broken test * replace grpc proto PR test with reflection
This commit is contained in:
parent
5b683f05df
commit
1bb9607c39
@ -3,6 +3,25 @@ __export_format: 4
|
||||
__export_date: 2022-12-02T13:10:54.407Z
|
||||
__export_source: insomnia.desktop.app:v2022.7.0-beta.6
|
||||
resources:
|
||||
- _id: greq_70ceba59d634442891ee523389458a9c
|
||||
parentId: fld_9f284a1171b84055959343e151fc6ce2
|
||||
modified: 1669986544274
|
||||
created: 1638200268776
|
||||
url: localhost:50051
|
||||
name: UnaryWithOutProtoFile
|
||||
description: ""
|
||||
protoFileId: ""
|
||||
protoMethodName: ""
|
||||
metadata: []
|
||||
body:
|
||||
text: |-
|
||||
{
|
||||
"latitude":"409146138",
|
||||
"longitude":"-746188906"
|
||||
}
|
||||
metaSortKey: -1638200268776
|
||||
isPrivate: false
|
||||
_type: grpc_request
|
||||
- _id: greq_70ceba59d634442891ee523389458a8c
|
||||
parentId: fld_9f284a1171b84055959343e151fc6ce2
|
||||
modified: 1669986544274
|
||||
|
2
packages/insomnia-smoke-test/package-lock.json
generated
2
packages/insomnia-smoke-test/package-lock.json
generated
@ -13,7 +13,7 @@
|
||||
"@grpc/proto-loader": "^0.6.11",
|
||||
"@jest/globals": "^28.1.0",
|
||||
"@playwright/test": "^1.26.1",
|
||||
"@ravanallc/grpc-server-reflection": "0.1.6",
|
||||
"@ravanallc/grpc-server-reflection": "^0.1.6",
|
||||
"@types/concurrently": "^6.0.1",
|
||||
"@types/express": "^4.17.11",
|
||||
"@types/express-graphql": "^0.9.0",
|
||||
|
@ -3,7 +3,7 @@ import { expect } from '@playwright/test';
|
||||
import { loadFixture } from '../../playwright/paths';
|
||||
import { test } from '../../playwright/test';
|
||||
|
||||
test('can send gRPC requests', async ({ app, page }) => {
|
||||
test('can send gRPC requests with reflection', async ({ app, page }) => {
|
||||
test.slow(process.platform === 'darwin' || process.platform === 'win32', 'Slow app start on these platforms');
|
||||
const statusTag = page.locator('[data-testid="response-status-tag"]:visible');
|
||||
const responseBody = page.locator('[data-testid="response-pane"] >> [data-testid="CodeEditor"]:visible', {
|
||||
@ -20,7 +20,13 @@ test('can send gRPC requests', async ({ app, page }) => {
|
||||
await page.click('div[role="dialog"] button:has-text("New")');
|
||||
await page.click('text=CollectionPreRelease gRPCjust now');
|
||||
await page.locator('button:has-text("Route Guide ExampleOPEN")').click();
|
||||
await page.click('button:has-text("gRPCUnary")');
|
||||
|
||||
await page.click('button:has-text("gRPCUnaryWithOutProtoFile")');
|
||||
await page.click('button:has-text("Select Method")');
|
||||
await page.click('button:has-text("Click to use server reflection")');
|
||||
await page.click('button:has-text("Select Method")');
|
||||
await page.click('button:has-text("U /RouteGuide/GetFeature")');
|
||||
|
||||
await page.locator('[data-testid="request-pane"] >> text=Unary').click();
|
||||
await page.click('text=Send');
|
||||
|
||||
|
198
packages/insomnia/package-lock.json
generated
198
packages/insomnia/package-lock.json
generated
@ -13,7 +13,7 @@
|
||||
"@apidevtools/swagger-parser": "10.1.0",
|
||||
"@getinsomnia/node-libcurl": "2.3.5-7",
|
||||
"@grpc/grpc-js": "^1.1.8",
|
||||
"@grpc/proto-loader": "^0.5.5",
|
||||
"@grpc/proto-loader": "^0.7.4",
|
||||
"@jest/globals": "^28.1.0",
|
||||
"@sentry/electron": "^3.0.7",
|
||||
"@stoplight/spectral-core": "^1.12.2",
|
||||
@ -32,6 +32,7 @@
|
||||
"electron-context-menu": "^3.1.1",
|
||||
"electron-log": "^4.4.3",
|
||||
"fs-extra": "^5.0.0",
|
||||
"grpc-reflection-js": "0.1.2",
|
||||
"hawk": "9.0.1",
|
||||
"hkdf": "^0.0.2",
|
||||
"html-entities": "^1.2.0",
|
||||
@ -1979,12 +1980,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@grpc/proto-loader": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.5.tgz",
|
||||
"integrity": "sha512-WwN9jVNdHRQoOBo9FDH7qU+mgfjPc8GygPYms3M+y3fbQLfnCe/Kv/E01t7JRgnrsOHH8euvSbed3mIalXhwqQ==",
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.4.tgz",
|
||||
"integrity": "sha512-MnWjkGwqQ3W8fx94/c1CwqLsNmHHv2t0CFn+9++6+cDphC1lolpg9M2OU0iebIjK//pBNX9e94ho+gjx6vz39w==",
|
||||
"dependencies": {
|
||||
"@types/long": "^4.0.1",
|
||||
"lodash.camelcase": "^4.3.0",
|
||||
"protobufjs": "^6.8.6"
|
||||
"long": "^4.0.0",
|
||||
"protobufjs": "^7.0.0",
|
||||
"yargs": "^16.2.0"
|
||||
},
|
||||
"bin": {
|
||||
"proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
@ -3481,7 +3488,7 @@
|
||||
"node_modules/@protobufjs/aspromise": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
|
||||
"integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78="
|
||||
"integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
|
||||
},
|
||||
"node_modules/@protobufjs/base64": {
|
||||
"version": "1.1.2",
|
||||
@ -3496,12 +3503,12 @@
|
||||
"node_modules/@protobufjs/eventemitter": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
|
||||
"integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A="
|
||||
"integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
|
||||
},
|
||||
"node_modules/@protobufjs/fetch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
|
||||
"integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=",
|
||||
"integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
|
||||
"dependencies": {
|
||||
"@protobufjs/aspromise": "^1.1.1",
|
||||
"@protobufjs/inquire": "^1.1.0"
|
||||
@ -3510,27 +3517,27 @@
|
||||
"node_modules/@protobufjs/float": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
|
||||
"integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E="
|
||||
"integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
|
||||
},
|
||||
"node_modules/@protobufjs/inquire": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
|
||||
"integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik="
|
||||
"integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
|
||||
},
|
||||
"node_modules/@protobufjs/path": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
|
||||
"integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0="
|
||||
"integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
|
||||
},
|
||||
"node_modules/@protobufjs/pool": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
|
||||
"integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q="
|
||||
"integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
|
||||
},
|
||||
"node_modules/@protobufjs/utf8": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
|
||||
"integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA="
|
||||
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
|
||||
},
|
||||
"node_modules/@react-aria/breadcrumbs": {
|
||||
"version": "3.3.1",
|
||||
@ -6358,6 +6365,11 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/google-protobuf": {
|
||||
"version": "3.15.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.6.tgz",
|
||||
"integrity": "sha512-pYVNNJ+winC4aek+lZp93sIKxnXt5qMkuKmaqS3WGuTq0Bw1ZDYNBgzG5kkdtwcv+GmYJGo3yEg6z2cKKAiEdw=="
|
||||
},
|
||||
"node_modules/@types/graceful-fs": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
|
||||
@ -6477,8 +6489,15 @@
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.14.182",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
|
||||
"integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q=="
|
||||
},
|
||||
"node_modules/@types/lodash.set": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash.set/-/lodash.set-4.3.7.tgz",
|
||||
"integrity": "sha512-bS5Wkg/nrT82YUfkNYPSccFrNZRL+irl7Yt4iM6OTSQ0VZJED2oUIVm15NkNtUAQ8SRhCe+axqERUV6MJgkeEg==",
|
||||
"dependencies": {
|
||||
"@types/lodash": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/long": {
|
||||
"version": "4.0.1",
|
||||
@ -8756,7 +8775,6 @@
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
@ -12129,6 +12147,11 @@
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/google-protobuf": {
|
||||
"version": "3.21.2",
|
||||
"resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz",
|
||||
"integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA=="
|
||||
},
|
||||
"node_modules/got": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
|
||||
@ -12326,6 +12349,21 @@
|
||||
"graphql": ">=0.11 <=16"
|
||||
}
|
||||
},
|
||||
"node_modules/grpc-reflection-js": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/grpc-reflection-js/-/grpc-reflection-js-0.1.2.tgz",
|
||||
"integrity": "sha512-ecLGJDCoRRyTNQ2jQYLsMQ0H9a/ZZ/6brU+6haGPS8GpQ93uYoFOc60ptO3bebS3xRPJQSIiSZClkBS5L9PYuw==",
|
||||
"dependencies": {
|
||||
"@types/google-protobuf": "^3.7.2",
|
||||
"@types/lodash.set": "^4.3.6",
|
||||
"google-protobuf": "^3.12.2",
|
||||
"lodash.set": "^4.3.2",
|
||||
"protobufjs": "^6.9.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@grpc/grpc-js": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/gtoken": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.5.tgz",
|
||||
@ -18553,9 +18591,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/protobufjs": {
|
||||
"version": "6.10.1",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.1.tgz",
|
||||
"integrity": "sha512-pb8kTchL+1Ceg4lFd5XUpK8PdWacbvV5SK2ULH2ebrYtl4GjJmS24m6CKME67jzV53tbJxHlnNOSqQHbTsR9JQ==",
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz",
|
||||
"integrity": "sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@protobufjs/aspromise": "^1.1.2",
|
||||
@ -18568,19 +18606,17 @@
|
||||
"@protobufjs/path": "^1.1.2",
|
||||
"@protobufjs/pool": "^1.1.0",
|
||||
"@protobufjs/utf8": "^1.1.0",
|
||||
"@types/long": "^4.0.1",
|
||||
"@types/node": "^13.7.0",
|
||||
"long": "^4.0.0"
|
||||
"@types/node": ">=13.7.0",
|
||||
"long": "^5.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"pbjs": "bin/pbjs",
|
||||
"pbts": "bin/pbts"
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/protobufjs/node_modules/@types/node": {
|
||||
"version": "13.13.30",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.30.tgz",
|
||||
"integrity": "sha512-HmqFpNzp3TSELxU/bUuRK+xzarVOAsR00hzcvM0TXrMlt/+wcSLa5q6YhTb6/cA6wqDCZLDcfd8fSL95x5h7AA=="
|
||||
"node_modules/protobufjs/node_modules/long": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz",
|
||||
"integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A=="
|
||||
},
|
||||
"node_modules/prr": {
|
||||
"version": "1.0.1",
|
||||
@ -21471,7 +21507,6 @@
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
@ -21488,7 +21523,6 @@
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
@ -21503,7 +21537,6 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
@ -21514,8 +21547,7 @@
|
||||
"node_modules/wrap-ansi/node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
@ -21676,7 +21708,6 @@
|
||||
"version": "16.2.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
|
||||
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"cliui": "^7.0.2",
|
||||
"escalade": "^3.1.1",
|
||||
@ -21694,7 +21725,6 @@
|
||||
"version": "20.2.9",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
|
||||
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
@ -21703,7 +21733,6 @@
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
@ -23216,7 +23245,7 @@
|
||||
"@types/long": "^4.0.1",
|
||||
"lodash.camelcase": "^4.3.0",
|
||||
"long": "^4.0.0",
|
||||
"protobufjs": "^6.9.0",
|
||||
"protobufjs": "7.1.2",
|
||||
"yargs": "^15.3.1"
|
||||
}
|
||||
},
|
||||
@ -23301,12 +23330,15 @@
|
||||
}
|
||||
},
|
||||
"@grpc/proto-loader": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.5.tgz",
|
||||
"integrity": "sha512-WwN9jVNdHRQoOBo9FDH7qU+mgfjPc8GygPYms3M+y3fbQLfnCe/Kv/E01t7JRgnrsOHH8euvSbed3mIalXhwqQ==",
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.4.tgz",
|
||||
"integrity": "sha512-MnWjkGwqQ3W8fx94/c1CwqLsNmHHv2t0CFn+9++6+cDphC1lolpg9M2OU0iebIjK//pBNX9e94ho+gjx6vz39w==",
|
||||
"requires": {
|
||||
"@types/long": "^4.0.1",
|
||||
"lodash.camelcase": "^4.3.0",
|
||||
"protobufjs": "^6.8.6"
|
||||
"long": "^4.0.0",
|
||||
"protobufjs": "7.1.2",
|
||||
"yargs": "^16.2.0"
|
||||
}
|
||||
},
|
||||
"@hapi/b64": {
|
||||
@ -24466,7 +24498,7 @@
|
||||
"@protobufjs/aspromise": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
|
||||
"integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78="
|
||||
"integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
|
||||
},
|
||||
"@protobufjs/base64": {
|
||||
"version": "1.1.2",
|
||||
@ -24481,12 +24513,12 @@
|
||||
"@protobufjs/eventemitter": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
|
||||
"integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A="
|
||||
"integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
|
||||
},
|
||||
"@protobufjs/fetch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
|
||||
"integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=",
|
||||
"integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
|
||||
"requires": {
|
||||
"@protobufjs/aspromise": "^1.1.1",
|
||||
"@protobufjs/inquire": "^1.1.0"
|
||||
@ -24495,27 +24527,27 @@
|
||||
"@protobufjs/float": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
|
||||
"integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E="
|
||||
"integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
|
||||
},
|
||||
"@protobufjs/inquire": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
|
||||
"integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik="
|
||||
"integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
|
||||
},
|
||||
"@protobufjs/path": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
|
||||
"integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0="
|
||||
"integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
|
||||
},
|
||||
"@protobufjs/pool": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
|
||||
"integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q="
|
||||
"integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
|
||||
},
|
||||
"@protobufjs/utf8": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
|
||||
"integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA="
|
||||
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
|
||||
},
|
||||
"@react-aria/breadcrumbs": {
|
||||
"version": "3.3.1",
|
||||
@ -26824,6 +26856,11 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/google-protobuf": {
|
||||
"version": "3.15.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.6.tgz",
|
||||
"integrity": "sha512-pYVNNJ+winC4aek+lZp93sIKxnXt5qMkuKmaqS3WGuTq0Bw1ZDYNBgzG5kkdtwcv+GmYJGo3yEg6z2cKKAiEdw=="
|
||||
},
|
||||
"@types/graceful-fs": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
|
||||
@ -26943,8 +26980,15 @@
|
||||
"@types/lodash": {
|
||||
"version": "4.14.182",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
|
||||
"integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q=="
|
||||
},
|
||||
"@types/lodash.set": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash.set/-/lodash.set-4.3.7.tgz",
|
||||
"integrity": "sha512-bS5Wkg/nrT82YUfkNYPSccFrNZRL+irl7Yt4iM6OTSQ0VZJED2oUIVm15NkNtUAQ8SRhCe+axqERUV6MJgkeEg==",
|
||||
"requires": {
|
||||
"@types/lodash": "*"
|
||||
}
|
||||
},
|
||||
"@types/long": {
|
||||
"version": "4.0.1",
|
||||
@ -28759,7 +28803,6 @@
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
@ -31340,6 +31383,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"google-protobuf": {
|
||||
"version": "3.21.2",
|
||||
"resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz",
|
||||
"integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA=="
|
||||
},
|
||||
"got": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
|
||||
@ -31492,6 +31540,18 @@
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"grpc-reflection-js": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/grpc-reflection-js/-/grpc-reflection-js-0.1.2.tgz",
|
||||
"integrity": "sha512-ecLGJDCoRRyTNQ2jQYLsMQ0H9a/ZZ/6brU+6haGPS8GpQ93uYoFOc60ptO3bebS3xRPJQSIiSZClkBS5L9PYuw==",
|
||||
"requires": {
|
||||
"@types/google-protobuf": "^3.7.2",
|
||||
"@types/lodash.set": "^4.3.6",
|
||||
"google-protobuf": "^3.12.2",
|
||||
"lodash.set": "^4.3.2",
|
||||
"protobufjs": "7.1.2"
|
||||
}
|
||||
},
|
||||
"gtoken": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.5.tgz",
|
||||
@ -36279,9 +36339,9 @@
|
||||
}
|
||||
},
|
||||
"protobufjs": {
|
||||
"version": "6.10.1",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.1.tgz",
|
||||
"integrity": "sha512-pb8kTchL+1Ceg4lFd5XUpK8PdWacbvV5SK2ULH2ebrYtl4GjJmS24m6CKME67jzV53tbJxHlnNOSqQHbTsR9JQ==",
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz",
|
||||
"integrity": "sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==",
|
||||
"requires": {
|
||||
"@protobufjs/aspromise": "^1.1.2",
|
||||
"@protobufjs/base64": "^1.1.2",
|
||||
@ -36293,15 +36353,14 @@
|
||||
"@protobufjs/path": "^1.1.2",
|
||||
"@protobufjs/pool": "^1.1.0",
|
||||
"@protobufjs/utf8": "^1.1.0",
|
||||
"@types/long": "^4.0.1",
|
||||
"@types/node": "^13.7.0",
|
||||
"long": "^4.0.0"
|
||||
"@types/node": ">=13.7.0",
|
||||
"long": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "13.13.30",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.30.tgz",
|
||||
"integrity": "sha512-HmqFpNzp3TSELxU/bUuRK+xzarVOAsR00hzcvM0TXrMlt/+wcSLa5q6YhTb6/cA6wqDCZLDcfd8fSL95x5h7AA=="
|
||||
"long": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz",
|
||||
"integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -38568,7 +38627,6 @@
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
@ -38579,7 +38637,6 @@
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
@ -38588,7 +38645,6 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
@ -38596,8 +38652,7 @@
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -38719,7 +38774,6 @@
|
||||
"version": "16.2.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
|
||||
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cliui": "^7.0.2",
|
||||
"escalade": "^3.1.1",
|
||||
@ -38733,16 +38787,14 @@
|
||||
"y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "20.2.9",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
|
||||
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="
|
||||
},
|
||||
"yauzl": {
|
||||
"version": "2.10.0",
|
||||
|
@ -47,7 +47,7 @@
|
||||
"@apidevtools/swagger-parser": "10.1.0",
|
||||
"@getinsomnia/node-libcurl": "2.3.5-7",
|
||||
"@grpc/grpc-js": "^1.1.8",
|
||||
"@grpc/proto-loader": "^0.5.5",
|
||||
"@grpc/proto-loader": "^0.7.4",
|
||||
"@jest/globals": "^28.1.0",
|
||||
"@sentry/electron": "^3.0.7",
|
||||
"@stoplight/spectral-core": "^1.12.2",
|
||||
@ -66,6 +66,7 @@
|
||||
"electron-context-menu": "^3.1.1",
|
||||
"electron-log": "^4.4.3",
|
||||
"fs-extra": "^5.0.0",
|
||||
"grpc-reflection-js": "0.1.2",
|
||||
"hawk": "9.0.1",
|
||||
"hkdf": "^0.0.2",
|
||||
"html-entities": "^1.2.0",
|
||||
@ -212,5 +213,8 @@
|
||||
},
|
||||
"dev": {
|
||||
"dev-server-port": 3334
|
||||
},
|
||||
"overrides": {
|
||||
"protobufjs": "7.1.2"
|
||||
}
|
||||
}
|
||||
|
@ -1,69 +0,0 @@
|
||||
import { describe, expect, it } from '@jest/globals';
|
||||
|
||||
import {
|
||||
getGrpcPathSegments,
|
||||
getShortGrpcPath,
|
||||
} from '../grpc-paths';
|
||||
|
||||
describe('getGrpcPathSegments', () => {
|
||||
it.each([
|
||||
['package', 'service', 'method'],
|
||||
['nested.package', 'service', 'method'],
|
||||
['another.nested.package', 'service', 'method'],
|
||||
['.another.package', 'service', 'method'],
|
||||
])(
|
||||
'should extract package, service and method from "/%s.%s/%s"',
|
||||
(packageName, serviceName, methodName) => {
|
||||
expect(getGrpcPathSegments(`/${packageName}.${serviceName}/${methodName}`)).toStrictEqual({
|
||||
packageName,
|
||||
serviceName,
|
||||
methodName,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it.each([['service', 'method']])(
|
||||
'should extract service and method from "/%s/%s"',
|
||||
(serviceName, methodName) => {
|
||||
expect(getGrpcPathSegments(`/${serviceName}/${methodName}`)).toStrictEqual({
|
||||
packageName: undefined,
|
||||
serviceName,
|
||||
methodName,
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('getShortGrpcPath', () => {
|
||||
it('should return shortened path', () => {
|
||||
const packageName = 'package';
|
||||
const serviceName = 'service';
|
||||
const methodName = 'method';
|
||||
const fullPath = '/package.service/method';
|
||||
const shortPath = getShortGrpcPath(
|
||||
{
|
||||
packageName,
|
||||
serviceName,
|
||||
methodName,
|
||||
},
|
||||
fullPath,
|
||||
);
|
||||
expect(shortPath).toBe('/service/method');
|
||||
});
|
||||
|
||||
it('should return full path', () => {
|
||||
const packageName = undefined;
|
||||
const serviceName = 'service';
|
||||
const methodName = 'method';
|
||||
const fullPath = '/service/method';
|
||||
const shortPath = getShortGrpcPath(
|
||||
{
|
||||
packageName,
|
||||
serviceName,
|
||||
methodName,
|
||||
},
|
||||
fullPath,
|
||||
);
|
||||
expect(shortPath).toBe(fullPath);
|
||||
});
|
||||
});
|
@ -1,76 +0,0 @@
|
||||
import { MethodDefinition } from '@grpc/grpc-js';
|
||||
|
||||
import { GrpcMethodType } from '../main/ipc/grpc';
|
||||
|
||||
const PROTO_PATH_REGEX = /^\/(?:(?<package>[\w.]+)\.)?(?<service>\w+)\/(?<method>\w+)$/;
|
||||
|
||||
interface GrpcPathSegments {
|
||||
packageName?: string;
|
||||
serviceName?: string;
|
||||
methodName?: string;
|
||||
}
|
||||
|
||||
// Split a full gRPC path into it's segments
|
||||
export const getGrpcPathSegments = (path: string): GrpcPathSegments => {
|
||||
const result = PROTO_PATH_REGEX.exec(path);
|
||||
const packageName = result?.groups?.package;
|
||||
const serviceName = result?.groups?.service;
|
||||
const methodName = result?.groups?.method;
|
||||
return {
|
||||
packageName,
|
||||
serviceName,
|
||||
methodName,
|
||||
};
|
||||
};
|
||||
|
||||
// If all segments are found, return a shorter path, otherwise the original path
|
||||
export const getShortGrpcPath = (
|
||||
{ packageName, serviceName, methodName }: GrpcPathSegments,
|
||||
fullPath: string,
|
||||
): string => {
|
||||
return packageName && serviceName && methodName ? `/${serviceName}/${methodName}` : fullPath;
|
||||
};
|
||||
|
||||
export interface GrpcMethodInfo {
|
||||
segments: GrpcPathSegments;
|
||||
type: GrpcMethodType;
|
||||
fullPath: string;
|
||||
}
|
||||
export const getMethodType = ({ requestStream, responseStream }: MethodDefinition<any, any>): GrpcMethodType => {
|
||||
if (requestStream && responseStream) {
|
||||
return 'bidi';
|
||||
}
|
||||
if (requestStream) {
|
||||
return 'client';
|
||||
}
|
||||
if (responseStream) {
|
||||
return 'server';
|
||||
}
|
||||
return 'unary';
|
||||
};
|
||||
|
||||
export const getMethodInfo = (method: MethodDefinition<any, any>): GrpcMethodInfo => ({
|
||||
segments: getGrpcPathSegments(method.path),
|
||||
type: getMethodType(method),
|
||||
fullPath: method.path,
|
||||
});
|
||||
|
||||
export const NO_PACKAGE_KEY = 'no-package';
|
||||
|
||||
function groupBy(list: {}[], keyGetter: (item: any) => string):Record<string, any[]> {
|
||||
const map = new Map();
|
||||
list.forEach(item => {
|
||||
const key = keyGetter(item);
|
||||
const collection = map.get(key);
|
||||
if (!collection) {
|
||||
map.set(key, [item]);
|
||||
} else {
|
||||
collection.push(item);
|
||||
}
|
||||
});
|
||||
return Object.fromEntries(map);
|
||||
}
|
||||
|
||||
export const groupGrpcMethodsByPackage = (methodInfoList: GrpcMethodInfo[]): Record<string, GrpcMethodInfo[]> => {
|
||||
return groupBy(methodInfoList, ({ segments }) => segments.packageName || NO_PACKAGE_KEY);
|
||||
};
|
@ -1,10 +1,11 @@
|
||||
import { Call, ClientDuplexStream, ClientReadableStream, MethodDefinition, ServiceError, StatusObject } from '@grpc/grpc-js';
|
||||
import { Call, ClientDuplexStream, ClientReadableStream, ServiceError, StatusObject } from '@grpc/grpc-js';
|
||||
import { credentials, makeGenericClientConstructor, Metadata, status } from '@grpc/grpc-js';
|
||||
import { AnyDefinition, EnumTypeDefinition, load, MessageTypeDefinition } from '@grpc/proto-loader';
|
||||
import * as protoLoader from '@grpc/proto-loader';
|
||||
import { AnyDefinition, EnumTypeDefinition, MessageTypeDefinition, PackageDefinition } from '@grpc/proto-loader';
|
||||
import electron, { ipcMain } from 'electron';
|
||||
import { IpcMainEvent } from 'electron';
|
||||
import * as grpcReflection from 'grpc-reflection-js';
|
||||
|
||||
import { getMethodInfo, getMethodType, GrpcMethodInfo } from '../../common/grpc-paths';
|
||||
import type { RenderedGrpcRequest, RenderedGrpcRequestBody } from '../../common/render';
|
||||
import * as models from '../../models';
|
||||
import type { GrpcRequest, GrpcRequestHeader } from '../../models/grpc-request';
|
||||
@ -28,6 +29,7 @@ export interface gRPCBridgeAPI {
|
||||
commit: typeof commit;
|
||||
cancel: typeof cancel;
|
||||
loadMethods: typeof loadMethods;
|
||||
loadMethodsFromReflection: typeof loadMethodsFromReflection;
|
||||
closeAll: typeof closeAll;
|
||||
}
|
||||
export function registergRPCHandlers() {
|
||||
@ -37,42 +39,107 @@ export function registergRPCHandlers() {
|
||||
ipcMain.on('grpc.cancel', (_, requestId) => cancel(requestId));
|
||||
ipcMain.on('grpc.closeAll', closeAll);
|
||||
ipcMain.handle('grpc.loadMethods', (_, requestId) => loadMethods(requestId));
|
||||
ipcMain.handle('grpc.loadMethodsFromReflection', (_, url) => loadMethodsFromReflection(url));
|
||||
}
|
||||
const loadMethodsFromFilePath = async (filePath: string, includeDirs: string[]): Promise<MethodDefs[]> => {
|
||||
try {
|
||||
const definition = await protoLoader.load(filePath, {
|
||||
keepCase: true,
|
||||
longs: String,
|
||||
enums: String,
|
||||
defaults: true,
|
||||
oneofs: true,
|
||||
includeDirs,
|
||||
});
|
||||
return getMethodsFromPackageDefinition(definition);
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
const loadMethods = async (protoFileId: string): Promise<GrpcMethodInfo[]> => {
|
||||
const protoFile = await models.protoFile.getById(protoFileId);
|
||||
invariant(protoFile, `Proto file ${protoFileId} not found`);
|
||||
const { filePath, dirs } = await writeProtoFile(protoFile);
|
||||
const definition = await load(filePath, {
|
||||
keepCase: true,
|
||||
longs: String,
|
||||
enums: String,
|
||||
defaults: true,
|
||||
oneofs: true,
|
||||
includeDirs: dirs,
|
||||
});
|
||||
const methods = Object.values(definition).filter((obj: AnyDefinition): obj is EnumTypeDefinition | MessageTypeDefinition => !obj.format).flatMap(Object.values);
|
||||
return methods.map(getMethodInfo);
|
||||
const methods = await loadMethodsFromFilePath(filePath, dirs);
|
||||
return methods.map(method => ({
|
||||
type: getMethodType(method),
|
||||
fullPath: method.path,
|
||||
}));
|
||||
};
|
||||
interface MethodDefs {
|
||||
path: string;
|
||||
requestStream: boolean;
|
||||
responseStream: boolean;
|
||||
requestSerialize: (value: any) => Buffer;
|
||||
responseDeserialize: (value: Buffer) => any;
|
||||
}
|
||||
const getMethodsFromReflection = async (host: string): Promise<MethodDefs[]> => {
|
||||
try {
|
||||
const { url, enableTls } = parseGrpcUrl(host);
|
||||
const client = new grpcReflection.Client(url, enableTls ? credentials.createSsl() : credentials.createInsecure());
|
||||
const services = await client.listServices() as string[];
|
||||
const methodsPromises = services.map(async service => {
|
||||
const fileContainingSymbol = await client.fileContainingSymbol(service);
|
||||
const descriptorMessage = fileContainingSymbol.toDescriptor('proto3');
|
||||
const tryToGetMethods = () => {
|
||||
try {
|
||||
console.log('[grpc] loading service from reflection:', service);
|
||||
const packageDefinition = protoLoader.loadFileDescriptorSetFromObject(descriptorMessage, {});
|
||||
return getMethodsFromPackageDefinition(packageDefinition);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
const methods = tryToGetMethods();
|
||||
return methods;
|
||||
});
|
||||
return (await Promise.all(methodsPromises)).flat();
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
const loadMethodsFromReflection = async (url: string): Promise<GrpcMethodInfo[]> => {
|
||||
const methods = await getMethodsFromReflection(url);
|
||||
return methods.map(method => ({
|
||||
type: getMethodType(method),
|
||||
fullPath: method.path,
|
||||
}));
|
||||
};
|
||||
export interface GrpcMethodInfo {
|
||||
type: GrpcMethodType;
|
||||
fullPath: string;
|
||||
}
|
||||
export const getMethodType = ({ requestStream, responseStream }: any): GrpcMethodType => {
|
||||
if (requestStream && responseStream) {
|
||||
return 'bidi';
|
||||
}
|
||||
if (requestStream) {
|
||||
return 'client';
|
||||
}
|
||||
if (responseStream) {
|
||||
return 'server';
|
||||
}
|
||||
return 'unary';
|
||||
};
|
||||
|
||||
// TODO: instead of reloading the methods from the protoFile,
|
||||
// just get it from what has already been loaded in the react component,
|
||||
// or from the cache
|
||||
// We can't send the method over IPC because of the following deprecation in Electron v9
|
||||
// https://www.electronjs.org/docs/breaking-changes#behavior-changed-sending-non-js-objects-over-ipc-now-throws-an-exception
|
||||
export const getSelectedMethod = async (request: GrpcRequest): Promise<MethodDefinition<any, any> | undefined> => {
|
||||
invariant(request.protoFileId, 'protoFileId is required');
|
||||
const protoFile = await models.protoFile.getById(request.protoFileId);
|
||||
invariant(protoFile?.protoText, `No proto file found for gRPC request ${request._id}`);
|
||||
const { filePath, dirs } = await writeProtoFile(protoFile);
|
||||
const definition = await load(filePath, {
|
||||
keepCase: true,
|
||||
longs: String,
|
||||
enums: String,
|
||||
defaults: true,
|
||||
oneofs: true,
|
||||
includeDirs: dirs,
|
||||
});
|
||||
return Object.values(definition).filter((obj: AnyDefinition): obj is EnumTypeDefinition | MessageTypeDefinition => !obj.format).flatMap(Object.values).find(c => c.path === request.protoMethodName);
|
||||
export const getSelectedMethod = async (request: GrpcRequest): Promise<MethodDefs | undefined> => {
|
||||
if (request.protoFileId) {
|
||||
const protoFile = await models.protoFile.getById(request.protoFileId);
|
||||
invariant(protoFile?.protoText, `No proto file found for gRPC request ${request._id}`);
|
||||
const { filePath, dirs } = await writeProtoFile(protoFile);
|
||||
const methods = await loadMethodsFromFilePath(filePath, dirs);
|
||||
invariant(methods, 'No methods found');
|
||||
return methods.find(c => c.path === request.protoMethodName);
|
||||
}
|
||||
const methods = await getMethodsFromReflection(request.url);
|
||||
invariant(methods, 'No reflection methods found');
|
||||
return methods.find(c => c.path === request.protoMethodName);
|
||||
};
|
||||
export const getMethodsFromPackageDefinition = (packageDefinition: PackageDefinition): MethodDefs[] => {
|
||||
return Object.values(packageDefinition)
|
||||
.filter((obj: AnyDefinition): obj is EnumTypeDefinition | MessageTypeDefinition => !obj.format)
|
||||
.flatMap(Object.values);
|
||||
};
|
||||
|
||||
export const start = (
|
||||
|
@ -1,59 +0,0 @@
|
||||
import { describe, expect, it } from '@jest/globals';
|
||||
|
||||
import { getMethodType } from '../../../common/grpc-paths';
|
||||
import { GrpcMethodType } from '../../../main/ipc/grpc';
|
||||
import { canClientStream } from '../../../ui/components/panes/grpc-request-pane';
|
||||
|
||||
describe('getMethodType', () => {
|
||||
it('should return unary', () => {
|
||||
expect(
|
||||
getMethodType({
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
}),
|
||||
).toBe('unary');
|
||||
});
|
||||
|
||||
it('should return server', () => {
|
||||
expect(
|
||||
getMethodType({
|
||||
requestStream: false,
|
||||
responseStream: true,
|
||||
}),
|
||||
).toBe('server');
|
||||
});
|
||||
|
||||
it('should return client', () => {
|
||||
expect(
|
||||
getMethodType({
|
||||
requestStream: true,
|
||||
responseStream: false,
|
||||
}),
|
||||
).toBe('client');
|
||||
});
|
||||
|
||||
it('should return bidi', () => {
|
||||
expect(
|
||||
getMethodType({
|
||||
requestStream: true,
|
||||
responseStream: true,
|
||||
}),
|
||||
).toBe('bidi');
|
||||
});
|
||||
});
|
||||
|
||||
describe('canClientStream', () => {
|
||||
it.each([
|
||||
'unary',
|
||||
'server',
|
||||
])('should not support client streaming with %o', (type: GrpcMethodType) =>
|
||||
expect(canClientStream(type)).toBe(false),
|
||||
);
|
||||
|
||||
it.each([
|
||||
'client',
|
||||
'bidi',
|
||||
])('should support client streaming with %o', (type: GrpcMethodType) =>
|
||||
expect(canClientStream(type)).toBe(true),
|
||||
);
|
||||
});
|
@ -1,12 +1,13 @@
|
||||
import { parse as urlParse } from 'url';
|
||||
|
||||
export const parseGrpcUrl = (grpcUrl: string) => {
|
||||
const { protocol, host, href } = urlParse(grpcUrl?.toLowerCase() || '');
|
||||
if (protocol === 'grpcs:') {
|
||||
return { url: host, enableTls: true };
|
||||
export const parseGrpcUrl = (grpcUrl: string): { url: string; enableTls: boolean } => {
|
||||
if (!grpcUrl) {
|
||||
return { url: '', enableTls: false };
|
||||
}
|
||||
if (protocol === 'grpc:') {
|
||||
return { url: host, enableTls: false };
|
||||
const lower = grpcUrl.toLowerCase();
|
||||
if (lower.startsWith('grpc://')) {
|
||||
return { url: lower.slice(7), enableTls: false };
|
||||
}
|
||||
return { url: href, enableTls: false };
|
||||
if (lower.startsWith('grpcs://')) {
|
||||
return { url: lower.slice(8), enableTls: true };
|
||||
}
|
||||
return { url: lower, enableTls: false };
|
||||
};
|
||||
|
@ -22,6 +22,7 @@ const grpc: gRPCBridgeAPI = {
|
||||
cancel: options => ipcRenderer.send('grpc.cancel', options),
|
||||
closeAll: () => ipcRenderer.send('grpc.closeAll'),
|
||||
loadMethods: options => ipcRenderer.invoke('grpc.loadMethods', options),
|
||||
loadMethodsFromReflection: options => ipcRenderer.invoke('grpc.loadMethodsFromReflection', options),
|
||||
};
|
||||
const main: Window['main'] = {
|
||||
restart: () => ipcRenderer.send('restart'),
|
||||
|
@ -1,13 +1,7 @@
|
||||
import React, { Fragment, FunctionComponent } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import {
|
||||
getGrpcPathSegments,
|
||||
getShortGrpcPath,
|
||||
groupGrpcMethodsByPackage,
|
||||
GrpcMethodInfo,
|
||||
NO_PACKAGE_KEY,
|
||||
} from '../../../../common/grpc-paths';
|
||||
import type { GrpcMethodInfo } from '../../../../main/ipc/grpc';
|
||||
import { Dropdown } from '../../base/dropdown/dropdown';
|
||||
import { DropdownButton } from '../../base/dropdown/dropdown-button';
|
||||
import { DropdownDivider } from '../../base/dropdown/dropdown-divider';
|
||||
@ -40,8 +34,38 @@ interface Props {
|
||||
selectedMethod?: GrpcMethodInfo;
|
||||
handleChange: (arg0: string) => void;
|
||||
handleChangeProtoFile: () => void;
|
||||
handleServerReflection: () => void;
|
||||
}
|
||||
const PROTO_PATH_REGEX = /^\/(?:(?<package>[\w.]+)\.)?(?<service>\w+)\/(?<method>\w+)$/;
|
||||
|
||||
export const NO_PACKAGE_KEY = 'no-package';
|
||||
|
||||
function groupBy(list: {}[], keyGetter: (item: any) => string):Record<string, any[]> {
|
||||
const map = new Map();
|
||||
list.forEach(item => {
|
||||
const key = keyGetter(item);
|
||||
const collection = map.get(key);
|
||||
if (!collection) {
|
||||
map.set(key, [item]);
|
||||
} else {
|
||||
collection.push(item);
|
||||
}
|
||||
});
|
||||
return Object.fromEntries(map);
|
||||
}
|
||||
|
||||
export const groupGrpcMethodsByPackage = (methodInfoList: GrpcMethodInfo[]): Record<string, GrpcMethodInfo[]> => {
|
||||
return groupBy(methodInfoList, ({ fullPath }) => PROTO_PATH_REGEX.exec(fullPath)?.groups?.package || NO_PACKAGE_KEY);
|
||||
};
|
||||
|
||||
// If all segments are found, return a shorter path, otherwise the original path
|
||||
export const getShortGrpcPath = (fullPath: string): string => {
|
||||
const result = PROTO_PATH_REGEX.exec(fullPath);
|
||||
const packageName = result?.groups?.package;
|
||||
const serviceName = result?.groups?.service;
|
||||
const methodName = result?.groups?.method;
|
||||
return packageName && serviceName && methodName ? `/${serviceName}/${methodName}` : fullPath;
|
||||
};
|
||||
const NormalCase = styled.span`
|
||||
text-transform: initial;
|
||||
`;
|
||||
@ -52,6 +76,7 @@ export const GrpcMethodDropdown: FunctionComponent<Props> = ({
|
||||
selectedMethod,
|
||||
handleChange,
|
||||
handleChangeProtoFile,
|
||||
handleServerReflection,
|
||||
}) => {
|
||||
const groupedByPkg = groupGrpcMethodsByPackage(methods);
|
||||
const selectedPath = selectedMethod?.fullPath;
|
||||
@ -64,10 +89,13 @@ export const GrpcMethodDropdown: FunctionComponent<Props> = ({
|
||||
buttonClass={DropdownMethodButton}
|
||||
>
|
||||
<Tooltip message={selectedPath || 'Select Method'} position="bottom" delay={500}>
|
||||
{!selectedPath ? 'Select Method' : getShortGrpcPath(getGrpcPathSegments(selectedPath), selectedPath)}
|
||||
{!selectedPath ? 'Select Method' : getShortGrpcPath(selectedPath)}
|
||||
<i className="fa fa-caret-down pad-left-sm" />
|
||||
</Tooltip>
|
||||
</DropdownButton>
|
||||
<DropdownItem onClick={handleServerReflection}>
|
||||
<em>Click to use server reflection</em>
|
||||
</DropdownItem>
|
||||
<DropdownItem onClick={handleChangeProtoFile}>
|
||||
<em>Click to change proto file</em>
|
||||
</DropdownItem>
|
||||
@ -82,7 +110,7 @@ export const GrpcMethodDropdown: FunctionComponent<Props> = ({
|
||||
<DropdownDivider>
|
||||
{name !== NO_PACKAGE_KEY && <NormalCase>pkg: {name}</NormalCase>}
|
||||
</DropdownDivider>
|
||||
{pkg.map(({ segments, type, fullPath }) => (
|
||||
{pkg.map(({ type, fullPath }) => (
|
||||
<DropdownItem
|
||||
key={fullPath}
|
||||
onClick={() => handleChange(fullPath)}
|
||||
@ -90,7 +118,7 @@ export const GrpcMethodDropdown: FunctionComponent<Props> = ({
|
||||
selected={fullPath === selectedPath}
|
||||
>
|
||||
<Tooltip message={fullPath} position="right" delay={500}>
|
||||
<DropdownMethodButtonLabel><GrpcMethodTag methodType={type} /> {getShortGrpcPath(segments, fullPath)}</DropdownMethodButtonLabel>
|
||||
<DropdownMethodButtonLabel><GrpcMethodTag methodType={type} /> {getShortGrpcPath(fullPath)}</DropdownMethodButtonLabel>
|
||||
</Tooltip>
|
||||
</DropdownItem>
|
||||
))}
|
||||
|
@ -169,6 +169,11 @@ export const GrpcRequestPane: FunctionComponent<Props> = ({
|
||||
});
|
||||
}}
|
||||
handleChangeProtoFile={() => setIsProtoModalOpen(true)}
|
||||
handleServerReflection={async () => {
|
||||
models.grpcRequest.update(activeRequest, { protoMethodName: '', protoFileId: '' });
|
||||
const methods = await window.main.grpc.loadMethodsFromReflection(activeRequest.url);
|
||||
setGrpcState({ ...grpcState, methods, reloadMethods: false });
|
||||
}}
|
||||
/>
|
||||
</StyledDropdown>
|
||||
|
||||
@ -204,11 +209,13 @@ export const GrpcRequestPane: FunctionComponent<Props> = ({
|
||||
requestId: activeRequest._id,
|
||||
};
|
||||
window.main.grpc.sendMessage(preparedMessage);
|
||||
setGrpcState({ ...grpcState, requestMessages:[...requestMessages, {
|
||||
id: generateId(),
|
||||
text:preparedMessage.body.text || '',
|
||||
created: Date.now(),
|
||||
}] });
|
||||
setGrpcState({
|
||||
...grpcState, requestMessages: [...requestMessages, {
|
||||
id: generateId(),
|
||||
text: preparedMessage.body.text || '',
|
||||
created: Date.now(),
|
||||
}],
|
||||
});
|
||||
|
||||
}}
|
||||
handleCommit={() => window.main.grpc.commit(activeRequest._id)}
|
||||
|
@ -3,8 +3,8 @@ import React, { FC, Fragment, useEffect, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { ChangeBufferEvent, database as db } from '../../common/database';
|
||||
import { GrpcMethodInfo } from '../../common/grpc-paths';
|
||||
import { generateId } from '../../common/misc';
|
||||
import type { GrpcMethodInfo } from '../../main/ipc/grpc';
|
||||
import * as models from '../../models';
|
||||
import { isGrpcRequest } from '../../models/grpc-request';
|
||||
import { getByParentId as getGrpcRequestMetaByParentId } from '../../models/grpc-request-meta';
|
||||
|
Loading…
Reference in New Issue
Block a user