generate-server-setup.mjs 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import * as fs from "fs"
  2. import * as grpc from "@grpc/grpc-js"
  3. import * as protoLoader from "@grpc/proto-loader"
  4. import * as health from "grpc-health-check"
  5. import { fileURLToPath } from "url"
  6. import path from "path"
  7. const OUT_FILE = path.resolve("src/standalone/server-setup.ts")
  8. const DESCRIPTOR_SET = path.resolve("dist-standalone/proto/descriptor_set.pb")
  9. // Load service definitions.
  10. const clineDef = protoLoader.loadFileDescriptorSetFromBuffer(fs.readFileSync(DESCRIPTOR_SET))
  11. const healthDef = protoLoader.loadSync(health.protoPath)
  12. const packageDefinition = { ...clineDef, ...healthDef }
  13. const proto = grpc.loadPackageDefinition(packageDefinition)
  14. /**
  15. * Generate imports and function to add all the handlers to the server for all services defined in the proto files.
  16. */
  17. function generateHandlersAndExports() {
  18. let imports = []
  19. let handlerSetup = []
  20. for (const [name, def] of Object.entries(proto.cline)) {
  21. if (!def || !("service" in def)) {
  22. continue
  23. }
  24. const domain = name.replace(/Service$/, "")
  25. const dir = domain.charAt(0).toLowerCase() + domain.slice(1)
  26. imports.push(`// ${domain} Service`)
  27. handlerSetup.push(` // ${domain} Service`)
  28. handlerSetup.push(` server.addService(cline.${name}Service, {`)
  29. for (const [rpcName, rpc] of Object.entries(def.service)) {
  30. imports.push(`import { ${rpcName} } from "../core/controller/${dir}/${rpcName}"`)
  31. const requestType = "cline." + rpc.requestType.type.name
  32. if (rpc.requestStream) {
  33. throw new Error("Request streaming is not supported")
  34. }
  35. if (rpc.responseStream) {
  36. handlerSetup.push(` ${rpcName}: wrapStreamingResponse<${requestType},void>(${rpcName}, controller),`)
  37. } else {
  38. const responseType = "cline." + rpc.responseType.type.name
  39. handlerSetup.push(` ${rpcName}: wrapper<${requestType},${responseType}>(${rpcName}, controller),`)
  40. }
  41. }
  42. handlerSetup.push(` });`)
  43. imports.push("")
  44. handlerSetup.push("")
  45. }
  46. return {
  47. imports: imports.join("\n"),
  48. handlerSetup: handlerSetup.join("\n"),
  49. }
  50. }
  51. const { imports, handlerSetup } = generateHandlersAndExports()
  52. const scriptName = path.basename(fileURLToPath(import.meta.url))
  53. // Create output file
  54. let output = `// GENERATED CODE -- DO NOT EDIT!
  55. // Generated by ${scriptName}
  56. import * as grpc from "@grpc/grpc-js"
  57. import { cline } from "../generated/grpc-js"
  58. import { Controller } from "../core/controller"
  59. import { GrpcHandlerWrapper, GrpcStreamingResponseHandlerWrapper } from "./grpc-types"
  60. ${imports}
  61. export function addServices(
  62. server: grpc.Server,
  63. controller: Controller,
  64. wrapper: GrpcHandlerWrapper,
  65. wrapStreamingResponse: GrpcStreamingResponseHandlerWrapper,
  66. ): void {
  67. ${handlerSetup}
  68. }
  69. `
  70. // Write output file
  71. fs.writeFileSync(OUT_FILE, output)
  72. console.log(`Generated service handlers in ${OUT_FILE}.`)