StructuredSwift+Server.swift 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761
  1. /*
  2. * Copyright 2024, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. extension FunctionSignatureDescription {
  17. /// ```
  18. /// func <Method>(
  19. /// request: GRPCCore.ServerRequest<Input>,
  20. /// context: GRPCCore.ServerContext
  21. /// ) async throws -> GRPCCore.ServerResponse<Output>
  22. /// ```
  23. static func serverMethod(
  24. accessLevel: AccessModifier? = nil,
  25. name: String,
  26. input: String,
  27. output: String,
  28. streamingInput: Bool,
  29. streamingOutput: Bool
  30. ) -> Self {
  31. return FunctionSignatureDescription(
  32. accessModifier: accessLevel,
  33. kind: .function(name: name),
  34. parameters: [
  35. ParameterDescription(
  36. label: "request",
  37. type: .serverRequest(forType: input, streaming: streamingInput)
  38. ),
  39. ParameterDescription(label: "context", type: .serverContext),
  40. ],
  41. keywords: [.async, .throws],
  42. returnType: .identifierType(.serverResponse(forType: output, streaming: streamingOutput))
  43. )
  44. }
  45. }
  46. extension ProtocolDescription {
  47. /// ```
  48. /// protocol <Name>: GRPCCore.RegistrableRPCService {
  49. /// ...
  50. /// }
  51. /// ```
  52. static func streamingService(
  53. accessLevel: AccessModifier? = nil,
  54. name: String,
  55. methods: [MethodDescriptor]
  56. ) -> Self {
  57. func docs(for method: MethodDescriptor) -> String {
  58. let summary = """
  59. /// Handle the "\(method.name.normalizedBase)" method.
  60. """
  61. let parameters = """
  62. /// - Parameters:
  63. /// - request: A streaming request of `\(method.inputType)` messages.
  64. /// - context: Context providing information about the RPC.
  65. /// - Throws: Any error which occurred during the processing of the request. Thrown errors
  66. /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted
  67. /// to an internal error.
  68. /// - Returns: A streaming response of `\(method.outputType)` messages.
  69. """
  70. return Docs.interposeDocs(method.documentation, between: summary, and: parameters)
  71. }
  72. return ProtocolDescription(
  73. accessModifier: accessLevel,
  74. name: name,
  75. conformances: ["GRPCCore.RegistrableRPCService"],
  76. members: methods.map { method in
  77. .commentable(
  78. .preFormatted(docs(for: method)),
  79. .function(
  80. signature: .serverMethod(
  81. name: method.name.generatedLowerCase,
  82. input: method.inputType,
  83. output: method.outputType,
  84. streamingInput: true,
  85. streamingOutput: true
  86. )
  87. )
  88. )
  89. }
  90. )
  91. }
  92. }
  93. extension ExtensionDescription {
  94. /// ```
  95. /// extension <ExtensionName> {
  96. /// func registerMethods(with router: inout GRPCCore.RPCRouter) {
  97. /// // ...
  98. /// }
  99. /// }
  100. /// ```
  101. static func registrableRPCServiceDefaultImplementation(
  102. accessLevel: AccessModifier? = nil,
  103. on extensionName: String,
  104. serviceNamespace: String,
  105. methods: [MethodDescriptor],
  106. serializer: (String) -> String,
  107. deserializer: (String) -> String
  108. ) -> Self {
  109. return ExtensionDescription(
  110. onType: extensionName,
  111. declarations: [
  112. .function(
  113. .registerMethods(
  114. accessLevel: accessLevel,
  115. serviceNamespace: serviceNamespace,
  116. methods: methods,
  117. serializer: serializer,
  118. deserializer: deserializer
  119. )
  120. )
  121. ]
  122. )
  123. }
  124. }
  125. extension ProtocolDescription {
  126. /// ```
  127. /// protocol <Name>: <StreamingProtocol> {
  128. /// ...
  129. /// }
  130. /// ```
  131. static func service(
  132. accessLevel: AccessModifier? = nil,
  133. name: String,
  134. streamingProtocol: String,
  135. methods: [MethodDescriptor]
  136. ) -> Self {
  137. func docs(for method: MethodDescriptor) -> String {
  138. let summary = """
  139. /// Handle the "\(method.name.normalizedBase)" method.
  140. """
  141. let request: String
  142. if method.isInputStreaming {
  143. request = "A streaming request of `\(method.inputType)` messages."
  144. } else {
  145. request = "A request containing a single `\(method.inputType)` message."
  146. }
  147. let returns: String
  148. if method.isOutputStreaming {
  149. returns = "A streaming response of `\(method.outputType)` messages."
  150. } else {
  151. returns = "A response containing a single `\(method.outputType)` message."
  152. }
  153. let parameters = """
  154. /// - Parameters:
  155. /// - request: \(request)
  156. /// - context: Context providing information about the RPC.
  157. /// - Throws: Any error which occurred during the processing of the request. Thrown errors
  158. /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted
  159. /// to an internal error.
  160. /// - Returns: \(returns)
  161. """
  162. return Docs.interposeDocs(method.documentation, between: summary, and: parameters)
  163. }
  164. return ProtocolDescription(
  165. accessModifier: accessLevel,
  166. name: name,
  167. conformances: [streamingProtocol],
  168. members: methods.map { method in
  169. .commentable(
  170. .preFormatted(docs(for: method)),
  171. .function(
  172. signature: .serverMethod(
  173. name: method.name.generatedLowerCase,
  174. input: method.inputType,
  175. output: method.outputType,
  176. streamingInput: method.isInputStreaming,
  177. streamingOutput: method.isOutputStreaming
  178. )
  179. )
  180. )
  181. }
  182. )
  183. }
  184. }
  185. extension FunctionCallDescription {
  186. /// ```
  187. /// self.<Name>(request: request, context: context)
  188. /// ```
  189. static func serverMethodCallOnSelf(
  190. name: String,
  191. requestArgument: Expression = .identifierPattern("request")
  192. ) -> Self {
  193. return FunctionCallDescription(
  194. calledExpression: .memberAccess(
  195. MemberAccessDescription(
  196. left: .identifierPattern("self"),
  197. right: name
  198. )
  199. ),
  200. arguments: [
  201. FunctionArgumentDescription(
  202. label: "request",
  203. expression: requestArgument
  204. ),
  205. FunctionArgumentDescription(
  206. label: "context",
  207. expression: .identifierPattern("context")
  208. ),
  209. ]
  210. )
  211. }
  212. }
  213. extension ClosureInvocationDescription {
  214. /// ```
  215. /// { router, context in
  216. /// try await self.<Method>(
  217. /// request: request,
  218. /// context: context
  219. /// )
  220. /// }
  221. /// ```
  222. static func routerHandlerInvokingRPC(method: String) -> Self {
  223. return ClosureInvocationDescription(
  224. argumentNames: ["request", "context"],
  225. body: [
  226. .expression(
  227. .unaryKeyword(
  228. kind: .try,
  229. expression: .unaryKeyword(
  230. kind: .await,
  231. expression: .functionCall(.serverMethodCallOnSelf(name: method))
  232. )
  233. )
  234. )
  235. ]
  236. )
  237. }
  238. }
  239. /// ```
  240. /// router.registerHandler(
  241. /// forMethod: ...,
  242. /// deserializer: ...
  243. /// serializer: ...
  244. /// handler: { request, context in
  245. /// // ...
  246. /// }
  247. /// )
  248. /// ```
  249. extension FunctionCallDescription {
  250. static func registerWithRouter(
  251. serviceNamespace: String,
  252. methodNamespace: String,
  253. methodName: String,
  254. inputDeserializer: String,
  255. outputSerializer: String
  256. ) -> Self {
  257. return FunctionCallDescription(
  258. calledExpression: .memberAccess(
  259. .init(left: .identifierPattern("router"), right: "registerHandler")
  260. ),
  261. arguments: [
  262. FunctionArgumentDescription(
  263. label: "forMethod",
  264. expression: .identifierPattern("\(serviceNamespace).Method.\(methodNamespace).descriptor")
  265. ),
  266. FunctionArgumentDescription(
  267. label: "deserializer",
  268. expression: .identifierPattern(inputDeserializer)
  269. ),
  270. FunctionArgumentDescription(
  271. label: "serializer",
  272. expression: .identifierPattern(outputSerializer)
  273. ),
  274. FunctionArgumentDescription(
  275. label: "handler",
  276. expression: .closureInvocation(.routerHandlerInvokingRPC(method: methodName))
  277. ),
  278. ]
  279. )
  280. }
  281. }
  282. extension FunctionDescription {
  283. /// ```
  284. /// func registerMethods(with router: inout GRPCCore.RPCRouter) {
  285. /// // ...
  286. /// }
  287. /// ```
  288. static func registerMethods(
  289. accessLevel: AccessModifier? = nil,
  290. serviceNamespace: String,
  291. methods: [MethodDescriptor],
  292. serializer: (String) -> String,
  293. deserializer: (String) -> String
  294. ) -> Self {
  295. return FunctionDescription(
  296. accessModifier: accessLevel,
  297. kind: .function(name: "registerMethods"),
  298. parameters: [
  299. ParameterDescription(
  300. label: "with",
  301. name: "router",
  302. type: .rpcRouter,
  303. `inout`: true
  304. )
  305. ],
  306. body: methods.map { method in
  307. .functionCall(
  308. .registerWithRouter(
  309. serviceNamespace: serviceNamespace,
  310. methodNamespace: method.name.generatedUpperCase,
  311. methodName: method.name.generatedLowerCase,
  312. inputDeserializer: deserializer(method.inputType),
  313. outputSerializer: serializer(method.outputType)
  314. )
  315. )
  316. }
  317. )
  318. }
  319. }
  320. extension FunctionDescription {
  321. /// ```
  322. /// func <Name>(
  323. /// request: GRPCCore.StreamingServerRequest<Input>
  324. /// context: GRPCCore.ServerContext
  325. /// ) async throws -> GRPCCore.StreamingServerResponse<Output> {
  326. /// let response = try await self.<Name>(
  327. /// request: GRPCCore.ServerRequest(stream: request),
  328. /// context: context
  329. /// )
  330. /// return GRPCCore.StreamingServerResponse(single: response)
  331. /// }
  332. /// ```
  333. static func serverStreamingMethodsCallingMethod(
  334. accessLevel: AccessModifier? = nil,
  335. name: String,
  336. input: String,
  337. output: String,
  338. streamingInput: Bool,
  339. streamingOutput: Bool
  340. ) -> FunctionDescription {
  341. let signature: FunctionSignatureDescription = .serverMethod(
  342. accessLevel: accessLevel,
  343. name: name,
  344. input: input,
  345. output: output,
  346. // This method converts from the fully streamed version to the specified version.
  347. streamingInput: true,
  348. streamingOutput: true
  349. )
  350. // Call the underlying function.
  351. let functionCall: Expression = .functionCall(
  352. calledExpression: .memberAccess(
  353. MemberAccessDescription(
  354. left: .identifierPattern("self"),
  355. right: name
  356. )
  357. ),
  358. arguments: [
  359. FunctionArgumentDescription(
  360. label: "request",
  361. expression: streamingInput
  362. ? .identifierPattern("request")
  363. : .functionCall(
  364. calledExpression: .identifierType(.serverRequest(forType: nil, streaming: false)),
  365. arguments: [
  366. FunctionArgumentDescription(
  367. label: "stream",
  368. expression: .identifierPattern("request")
  369. )
  370. ]
  371. )
  372. ),
  373. FunctionArgumentDescription(
  374. label: "context",
  375. expression: .identifierPattern("context")
  376. ),
  377. ]
  378. )
  379. // Call the function and assign to 'response'.
  380. let response: Declaration = .variable(
  381. kind: .let,
  382. left: "response",
  383. right: .unaryKeyword(
  384. kind: .try,
  385. expression: .unaryKeyword(
  386. kind: .await,
  387. expression: functionCall
  388. )
  389. )
  390. )
  391. // Build the return statement.
  392. let returnExpression: Expression = .unaryKeyword(
  393. kind: .return,
  394. expression: streamingOutput
  395. ? .identifierPattern("response")
  396. : .functionCall(
  397. calledExpression: .identifierType(.serverResponse(forType: nil, streaming: true)),
  398. arguments: [
  399. FunctionArgumentDescription(
  400. label: "single",
  401. expression: .identifierPattern("response")
  402. )
  403. ]
  404. )
  405. )
  406. return Self(
  407. signature: signature,
  408. body: [.declaration(response), .expression(returnExpression)]
  409. )
  410. }
  411. }
  412. extension ExtensionDescription {
  413. /// ```
  414. /// extension <ExtensionName> {
  415. /// func <Name>(
  416. /// request: GRPCCore.StreamingServerRequest<Input>
  417. /// context: GRPCCore.ServerContext
  418. /// ) async throws -> GRPCCore.StreamingServerResponse<Output> {
  419. /// let response = try await self.<Name>(
  420. /// request: GRPCCore.ServerRequest(stream: request),
  421. /// context: context
  422. /// )
  423. /// return GRPCCore.StreamingServerResponse(single: response)
  424. /// }
  425. /// ...
  426. /// }
  427. /// ```
  428. static func streamingServiceProtocolDefaultImplementation(
  429. accessModifier: AccessModifier? = nil,
  430. on extensionName: String,
  431. methods: [MethodDescriptor]
  432. ) -> Self {
  433. return ExtensionDescription(
  434. onType: extensionName,
  435. declarations: methods.compactMap { method -> Declaration? in
  436. // Bidirectional streaming methods don't need a default implementation as their signatures
  437. // match across the two protocols.
  438. if method.isInputStreaming, method.isOutputStreaming { return nil }
  439. return .function(
  440. .serverStreamingMethodsCallingMethod(
  441. accessLevel: accessModifier,
  442. name: method.name.generatedLowerCase,
  443. input: method.inputType,
  444. output: method.outputType,
  445. streamingInput: method.isInputStreaming,
  446. streamingOutput: method.isOutputStreaming
  447. )
  448. )
  449. }
  450. )
  451. }
  452. }
  453. extension FunctionSignatureDescription {
  454. /// ```
  455. /// func <Name>(
  456. /// request: <Input>,
  457. /// context: GRPCCore.ServerContext,
  458. /// ) async throws -> <Output>
  459. /// ```
  460. ///
  461. /// ```
  462. /// func <Name>(
  463. /// request: GRPCCore.RPCAsyncSequence<Input, any Error>,
  464. /// response: GRPCCore.RPCAsyncWriter<Output>
  465. /// context: GRPCCore.ServerContext,
  466. /// ) async throws
  467. /// ```
  468. static func simpleServerMethod(
  469. accessLevel: AccessModifier? = nil,
  470. name: String,
  471. input: String,
  472. output: String,
  473. streamingInput: Bool,
  474. streamingOutput: Bool
  475. ) -> Self {
  476. var parameters: [ParameterDescription] = [
  477. ParameterDescription(
  478. label: "request",
  479. type: streamingInput ? .rpcAsyncSequence(forType: input) : .member(input)
  480. )
  481. ]
  482. if streamingOutput {
  483. parameters.append(ParameterDescription(label: "response", type: .rpcWriter(forType: output)))
  484. }
  485. parameters.append(ParameterDescription(label: "context", type: .serverContext))
  486. return FunctionSignatureDescription(
  487. accessModifier: accessLevel,
  488. kind: .function(name: name),
  489. parameters: parameters,
  490. keywords: [.async, .throws],
  491. returnType: streamingOutput ? nil : .identifier(.pattern(output))
  492. )
  493. }
  494. }
  495. extension ProtocolDescription {
  496. /// ```
  497. /// protocol SimpleServiceProtocol: <ServiceProtocol> {
  498. /// ...
  499. /// }
  500. /// ```
  501. static func simpleServiceProtocol(
  502. accessModifier: AccessModifier? = nil,
  503. name: String,
  504. serviceProtocol: String,
  505. methods: [MethodDescriptor]
  506. ) -> Self {
  507. func docs(for method: MethodDescriptor) -> String {
  508. let summary = """
  509. /// Handle the "\(method.name.normalizedBase)" method.
  510. """
  511. let requestText =
  512. method.isInputStreaming
  513. ? "A stream of `\(method.inputType)` messages."
  514. : "A `\(method.inputType)` message."
  515. var parameters = """
  516. /// - Parameters:
  517. /// - request: \(requestText)
  518. """
  519. if method.isOutputStreaming {
  520. parameters += "\n"
  521. parameters += """
  522. /// - response: A response stream of `\(method.outputType)` messages.
  523. """
  524. }
  525. parameters += "\n"
  526. parameters += """
  527. /// - context: Context providing information about the RPC.
  528. /// - Throws: Any error which occurred during the processing of the request. Thrown errors
  529. /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted
  530. /// to an internal error.
  531. """
  532. if !method.isOutputStreaming {
  533. parameters += "\n"
  534. parameters += """
  535. /// - Returns: A `\(method.outputType)` to respond with.
  536. """
  537. }
  538. return Docs.interposeDocs(method.documentation, between: summary, and: parameters)
  539. }
  540. return ProtocolDescription(
  541. accessModifier: accessModifier,
  542. name: name,
  543. conformances: [serviceProtocol],
  544. members: methods.map { method in
  545. .commentable(
  546. .preFormatted(docs(for: method)),
  547. .function(
  548. signature: .simpleServerMethod(
  549. name: method.name.generatedLowerCase,
  550. input: method.inputType,
  551. output: method.outputType,
  552. streamingInput: method.isInputStreaming,
  553. streamingOutput: method.isOutputStreaming
  554. )
  555. )
  556. )
  557. }
  558. )
  559. }
  560. }
  561. extension FunctionCallDescription {
  562. /// ```
  563. /// try await self.<Name>(
  564. /// request: request.message,
  565. /// response: writer,
  566. /// context: context
  567. /// )
  568. /// ```
  569. static func serviceMethodCallingSimpleMethod(
  570. name: String,
  571. input: String,
  572. output: String,
  573. streamingInput: Bool,
  574. streamingOutput: Bool
  575. ) -> Self {
  576. var arguments: [FunctionArgumentDescription] = [
  577. FunctionArgumentDescription(
  578. label: "request",
  579. expression: .identifierPattern("request").dot(streamingInput ? "messages" : "message")
  580. )
  581. ]
  582. if streamingOutput {
  583. arguments.append(
  584. FunctionArgumentDescription(
  585. label: "response",
  586. expression: .identifierPattern("writer")
  587. )
  588. )
  589. }
  590. arguments.append(
  591. FunctionArgumentDescription(
  592. label: "context",
  593. expression: .identifierPattern("context")
  594. )
  595. )
  596. return FunctionCallDescription(
  597. calledExpression: .try(.await(.identifierPattern("self").dot(name))),
  598. arguments: arguments
  599. )
  600. }
  601. }
  602. extension FunctionDescription {
  603. /// ```
  604. /// func <Name>(
  605. /// request: GRPCCore.ServerRequest<Input>,
  606. /// context: GRPCCore.ServerContext
  607. /// ) async throws -> GRPCCore.ServerResponse<Output> {
  608. /// return GRPCCore.ServerResponse<Output>(
  609. /// message: try await self.<Name>(
  610. /// request: request.message,
  611. /// context: context
  612. /// )
  613. /// metadata: [:]
  614. /// )
  615. /// }
  616. /// ```
  617. static func serviceProtocolDefaultImplementation(
  618. accessModifier: AccessModifier? = nil,
  619. name: String,
  620. input: String,
  621. output: String,
  622. streamingInput: Bool,
  623. streamingOutput: Bool
  624. ) -> Self {
  625. func makeUnaryOutputArguments() -> [FunctionArgumentDescription] {
  626. return [
  627. FunctionArgumentDescription(
  628. label: "message",
  629. expression: .functionCall(
  630. .serviceMethodCallingSimpleMethod(
  631. name: name,
  632. input: input,
  633. output: output,
  634. streamingInput: streamingInput,
  635. streamingOutput: streamingOutput
  636. )
  637. )
  638. ),
  639. FunctionArgumentDescription(label: "metadata", expression: .literal(.dictionary([]))),
  640. ]
  641. }
  642. func makeStreamingOutputArguments() -> [FunctionArgumentDescription] {
  643. return [
  644. FunctionArgumentDescription(label: "metadata", expression: .literal(.dictionary([]))),
  645. FunctionArgumentDescription(
  646. label: "producer",
  647. expression: .closureInvocation(
  648. argumentNames: ["writer"],
  649. body: [
  650. .expression(
  651. .functionCall(
  652. .serviceMethodCallingSimpleMethod(
  653. name: name,
  654. input: input,
  655. output: output,
  656. streamingInput: streamingInput,
  657. streamingOutput: streamingOutput
  658. )
  659. )
  660. ),
  661. .expression(.return(.literal(.dictionary([])))),
  662. ]
  663. )
  664. ),
  665. ]
  666. }
  667. return FunctionDescription(
  668. signature: .serverMethod(
  669. accessLevel: accessModifier,
  670. name: name,
  671. input: input,
  672. output: output,
  673. streamingInput: streamingInput,
  674. streamingOutput: streamingOutput
  675. ),
  676. body: [
  677. .expression(
  678. .functionCall(
  679. calledExpression: .return(
  680. .identifierType(
  681. .serverResponse(forType: output, streaming: streamingOutput)
  682. )
  683. ),
  684. arguments: streamingOutput ? makeStreamingOutputArguments() : makeUnaryOutputArguments()
  685. )
  686. )
  687. ]
  688. )
  689. }
  690. }
  691. extension ExtensionDescription {
  692. /// ```
  693. /// extension ServiceProtocol {
  694. /// ...
  695. /// }
  696. /// ```
  697. static func serviceProtocolDefaultImplementation(
  698. accessModifier: AccessModifier? = nil,
  699. on extensionName: String,
  700. methods: [MethodDescriptor]
  701. ) -> Self {
  702. ExtensionDescription(
  703. onType: extensionName,
  704. declarations: methods.map { method in
  705. .function(
  706. .serviceProtocolDefaultImplementation(
  707. accessModifier: accessModifier,
  708. name: method.name.generatedLowerCase,
  709. input: method.inputType,
  710. output: method.outputType,
  711. streamingInput: method.isInputStreaming,
  712. streamingOutput: method.isOutputStreaming
  713. )
  714. )
  715. }
  716. )
  717. }
  718. }