├── serverpod_json_rpc_2_server ├── lib │ ├── src │ │ ├── generated │ │ │ ├── protocol.yaml │ │ │ ├── endpoints.dart │ │ │ └── protocol.dart │ │ └── channels │ │ │ ├── endpoint_rpc.dart │ │ │ └── endpoint_stream_channel.dart │ ├── serverpod_json_rpc_2_server.dart │ └── module.dart ├── pubspec_overrides.yaml ├── analysis_options.yaml ├── config │ └── generator.yaml ├── CHANGELOG.md ├── example │ └── example.dart ├── README.md ├── pubspec.yaml └── LICENSE ├── serverpod_json_rpc_2_client ├── lib │ ├── serverpod_json_rpc_2_client.dart │ ├── module.dart │ └── src │ │ ├── protocol │ │ ├── client.dart │ │ └── protocol.dart │ │ └── channels │ │ ├── endpoint_rpc.dart │ │ └── endpoint_stream_channel.dart ├── pubspec_overrides.yaml ├── analysis_options.yaml ├── example │ └── example.dart ├── .gitignore ├── README.md ├── CHANGELOG.md ├── pubspec.yaml └── LICENSE ├── serverpod_json_rpc_2_shared ├── analysis_options.yaml ├── lib │ ├── serverpod_json_rpc_2_shared.dart │ └── src │ │ ├── json_rpc_2_message.dart │ │ └── rpc_stream_channel_transformer.dart ├── example │ └── example.dart ├── README.md ├── CHANGELOG.md ├── pubspec.yaml └── LICENSE ├── pubspec.yaml ├── .github └── workflows │ ├── client_cd.yaml │ ├── server_cd.yaml │ ├── shared_cd.yaml │ ├── shared_ci.yaml │ ├── client_ci.yaml │ └── server_ci.yaml ├── .vscode └── tasks.json ├── .gitignore ├── melos.yaml ├── LICENSE └── README.md /serverpod_json_rpc_2_server/lib/src/generated/protocol.yaml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_client/lib/serverpod_json_rpc_2_client.dart: -------------------------------------------------------------------------------- 1 | export 'module.dart'; 2 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_server/lib/serverpod_json_rpc_2_server.dart: -------------------------------------------------------------------------------- 1 | export 'module.dart'; 2 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_shared/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:dart_test_tools/package.yaml 2 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: serverpod_json_rpc_2_melos 2 | 3 | environment: 4 | sdk: ^3.3.0 5 | 6 | dependencies: 7 | melos: 8 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_client/pubspec_overrides.yaml: -------------------------------------------------------------------------------- 1 | dependency_overrides: 2 | serverpod_json_rpc_2_shared: 3 | path: ../serverpod_json_rpc_2_shared 4 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_server/pubspec_overrides.yaml: -------------------------------------------------------------------------------- 1 | dependency_overrides: 2 | serverpod_json_rpc_2_shared: 3 | path: ../serverpod_json_rpc_2_shared 4 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_shared/lib/serverpod_json_rpc_2_shared.dart: -------------------------------------------------------------------------------- 1 | export 'src/json_rpc_2_message.dart'; 2 | export 'src/rpc_stream_channel_transformer.dart'; 3 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_client/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:dart_test_tools/package.yaml 2 | 3 | analyzer: 4 | exclude: 5 | - lib/src/protocol/**.dart 6 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_server/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:dart_test_tools/package.yaml 2 | 3 | analyzer: 4 | exclude: 5 | - lib/src/generated/**.dart 6 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_client/lib/module.dart: -------------------------------------------------------------------------------- 1 | export 'package:serverpod_client/serverpod_client.dart'; 2 | 3 | export 'src/channels/endpoint_rpc.dart'; 4 | export 'src/channels/endpoint_stream_channel.dart'; 5 | 6 | export 'src/protocol/protocol.dart'; 7 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_server/config/generator.yaml: -------------------------------------------------------------------------------- 1 | type: module 2 | nickname: serverpod_json_rpc_2 3 | client_package_path: ../serverpod_json_rpc_2_client 4 | 5 | extraClasses: 6 | - package:serverpod_json_rpc_2_shared/serverpod_json_rpc_2_shared.dart:JsonRpc2Message 7 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_server/lib/module.dart: -------------------------------------------------------------------------------- 1 | /// The module entrypoint 2 | library protocol; 3 | 4 | export 'src/channels/endpoint_rpc.dart'; 5 | export 'src/channels/endpoint_stream_channel.dart'; 6 | 7 | export 'src/generated/endpoints.dart'; 8 | export 'src/generated/protocol.dart'; 9 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_client/example/example.dart: -------------------------------------------------------------------------------- 1 | import 'package:serverpod_json_rpc_2_client/serverpod_json_rpc_2_client.dart'; 2 | 3 | Future connectStreamChannel(EndpointRef endpoint) async { 4 | await endpoint.client.openStreamingConnection(); 5 | 6 | // ignore: unused_local_variable 7 | final client = endpoint.createClient(); 8 | // ... 9 | } 10 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_client/.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .dart_tool/ 3 | .packages 4 | 5 | # Omit commiting pubspec.lock for library packages: 6 | # https://dart.dev/guides/libraries/private-files#pubspeclock 7 | pubspec.lock 8 | 9 | # Conventional directory for build outputs 10 | build/ 11 | 12 | # Directory created by dartdoc 13 | doc/api/ 14 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_shared/example/example.dart: -------------------------------------------------------------------------------- 1 | import 'package:serverpod_json_rpc_2_shared/src/rpc_stream_channel_transformer.dart'; 2 | import 'package:serverpod_serialization/serverpod_serialization.dart'; 3 | import 'package:stream_channel/stream_channel.dart'; 4 | 5 | void sampleCreateChannel(StreamChannel channel) => 6 | channel.transform(RpcStreamChannelTransformer()); 7 | -------------------------------------------------------------------------------- /.github/workflows/client_cd.yaml: -------------------------------------------------------------------------------- 1 | name: Publish serverpod_json_rpc_2_client to pub.dev 2 | 3 | on: 4 | push: 5 | tags: 6 | - "serverpod_json_rpc_2_client-v*" 7 | 8 | jobs: 9 | publish: 10 | name: Publish 11 | uses: Skycoder42/dart_test_tools/.github/workflows/publish.yml@main 12 | permissions: 13 | id-token: write 14 | with: 15 | tagPrefix: serverpod_json_rpc_2_client-v 16 | workingDirectory: serverpod_json_rpc_2_client 17 | -------------------------------------------------------------------------------- /.github/workflows/server_cd.yaml: -------------------------------------------------------------------------------- 1 | name: Publish serverpod_json_rpc_2_server to pub.dev 2 | 3 | on: 4 | push: 5 | tags: 6 | - "serverpod_json_rpc_2_server-v*" 7 | 8 | jobs: 9 | publish: 10 | name: Publish 11 | uses: Skycoder42/dart_test_tools/.github/workflows/publish.yml@main 12 | permissions: 13 | id-token: write 14 | with: 15 | tagPrefix: serverpod_json_rpc_2_server-v 16 | workingDirectory: serverpod_json_rpc_2_server 17 | -------------------------------------------------------------------------------- /.github/workflows/shared_cd.yaml: -------------------------------------------------------------------------------- 1 | name: Publish serverpod_json_rpc_2_shared to pub.dev 2 | 3 | on: 4 | push: 5 | tags: 6 | - "serverpod_json_rpc_2_shared-v*" 7 | 8 | jobs: 9 | publish: 10 | name: Publish 11 | uses: Skycoder42/dart_test_tools/.github/workflows/publish.yml@main 12 | permissions: 13 | id-token: write 14 | with: 15 | tagPrefix: serverpod_json_rpc_2_shared-v 16 | workingDirectory: serverpod_json_rpc_2_shared 17 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_server/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [1.0.0] - 2024-03-23 8 | ### Changed 9 | - Initial release 10 | 11 | [1.0.0]: https://github.com/Skycoder42/serverpod_json_rpc_2/releases/tag/serverpod_json_rpc_2_server-v1.0.0 12 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_server/example/example.dart: -------------------------------------------------------------------------------- 1 | import 'package:serverpod/serverpod.dart'; 2 | import 'package:serverpod_json_rpc_2_server/serverpod_json_rpc_2_server.dart'; 3 | 4 | class MyEndpoint extends Endpoint with EndpointStreamChannel { 5 | @override 6 | Future streamOpened(StreamingSession session) async { 7 | await super.streamOpened(session); 8 | 9 | // ignore: unused_local_variable 10 | final server = createServer(session); 11 | // ... 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_client/README.md: -------------------------------------------------------------------------------- 1 | # serverpod_json_rpc_2_client 2 | [![CI for package serverpod_json_rpc_2_client](https://github.com/Skycoder42/serverpod_json_rpc_2/actions/workflows/client_ci.yaml/badge.svg)](https://github.com/Skycoder42/serverpod_json_rpc_2/actions/workflows/client_ci.yaml) 3 | [![serverpod_json_rpc_2_client pub.dev version](https://img.shields.io/pub/v/serverpod_json_rpc_2_client)](https://pub.dev/packages/serverpod_json_rpc_2_client) 4 | 5 | The client package for the serverpod_json_rpc_2 module for JSON RPC 2.0. 6 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_server/README.md: -------------------------------------------------------------------------------- 1 | # serverpod_json_rpc_2_server 2 | [![CI for package serverpod_json_rpc_2_server](https://github.com/Skycoder42/serverpod_json_rpc_2/actions/workflows/server_ci.yaml/badge.svg)](https://github.com/Skycoder42/serverpod_json_rpc_2/actions/workflows/server_ci.yaml) 3 | [![serverpod_json_rpc_2_server pub.dev version](https://img.shields.io/pub/v/serverpod_json_rpc_2_server)](https://pub.dev/packages/serverpod_json_rpc_2_server) 4 | 5 | The server package for the serverpod_json_rpc_2 module for JSON RPC 2.0. 6 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_shared/README.md: -------------------------------------------------------------------------------- 1 | # serverpod_json_rpc_2_shared 2 | [![CI for package serverpod_json_rpc_2_shared](https://github.com/Skycoder42/serverpod_json_rpc_2/actions/workflows/shared_ci.yaml/badge.svg)](https://github.com/Skycoder42/serverpod_json_rpc_2/actions/workflows/shared_ci.yaml) 3 | [![serverpod_json_rpc_2_shared pub.dev version](https://img.shields.io/pub/v/serverpod_json_rpc_2_shared)](https://pub.dev/packages/serverpod_json_rpc_2_shared) 4 | 5 | A helper package that contains shared code the for serverpod_json_rpc_2 module. 6 | 7 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "shell", 6 | "command": "serverpod", 7 | "args": [ 8 | "generate", 9 | "-w" 10 | ], 11 | "options": { 12 | "cwd": "${workspaceFolder}/serverpod_json_rpc_2_server" 13 | }, 14 | "problemMatcher": [], 15 | "label": "serverpod: generate -w", 16 | "detail": "serverpod_json_rpc_2_server", 17 | "group": { 18 | "kind": "build" 19 | } 20 | }, 21 | { 22 | "label": "Build", 23 | "dependsOn": [ 24 | "serverpod: generate -w", 25 | ], 26 | "group": { 27 | "kind": "build", 28 | "isDefault": true 29 | } 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_shared/lib/src/json_rpc_2_message.dart: -------------------------------------------------------------------------------- 1 | import 'package:serverpod_serialization/serverpod_serialization.dart'; 2 | 3 | /// An internal helper model to wrap JSON RPC 2.0 messages 4 | class JsonRpc2Message with SerializableEntity { 5 | /// The raw json data being wrapped 6 | final dynamic raw; 7 | 8 | /// Construct message from [raw] json data 9 | JsonRpc2Message(this.raw); 10 | 11 | /// @nodoc 12 | factory JsonRpc2Message.fromJson( 13 | dynamic json, 14 | // ignore: avoid_unused_constructor_parameters 15 | SerializationManager serializationManager, 16 | ) => 17 | JsonRpc2Message(json); 18 | 19 | /// @nodoc 20 | @override 21 | dynamic toJson() => raw; 22 | } 23 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_server/lib/src/generated/endpoints.dart: -------------------------------------------------------------------------------- 1 | /* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */ 2 | /* To generate run: "serverpod generate" */ 3 | 4 | // ignore_for_file: library_private_types_in_public_api 5 | // ignore_for_file: public_member_api_docs 6 | // ignore_for_file: implementation_imports 7 | // ignore_for_file: use_super_parameters 8 | // ignore_for_file: type_literal_in_constant_pattern 9 | 10 | // ignore_for_file: no_leading_underscores_for_library_prefixes 11 | import 'package:serverpod/serverpod.dart' as _i1; 12 | 13 | class Endpoints extends _i1.EndpointDispatch { 14 | @override 15 | void initializeEndpoints(_i1.Server server) { 16 | var endpoints = {}; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_client/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [1.0.1] - 2024-03-24 8 | ### Fixed 9 | - Do not require the client to be in the connected state 10 | 11 | ## [1.0.0] - 2024-03-23 12 | ### Changed 13 | - Initial release 14 | 15 | [1.0.1]: https://github.com/Skycoder42/serverpod_json_rpc_2/compare/serverpod_json_rpc_2_client-v1.0.0...serverpod_json_rpc_2_client-v1.0.1 16 | [1.0.0]: https://github.com/Skycoder42/serverpod_json_rpc_2/releases/tag/serverpod_json_rpc_2_client-v1.0.0 17 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_shared/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [1.0.1] - 2024-03-24 8 | ### Fixed 9 | - Add chunked conversion support to RpcStreamChannelTransformer codecs 10 | 11 | ## [1.0.0] - 2024-03-23 12 | ### Changed 13 | - Initial release 14 | 15 | [1.0.1]: https://github.com/Skycoder42/serverpod_json_rpc_2/compare/serverpod_json_rpc_2_shared-v1.0.0...serverpod_json_rpc_2_shared-v1.0.1 16 | [1.0.0]: https://github.com/Skycoder42/serverpod_json_rpc_2/releases/tag/serverpod_json_rpc_2_shared-v1.0.0 17 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_client/lib/src/protocol/client.dart: -------------------------------------------------------------------------------- 1 | /* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */ 2 | /* To generate run: "serverpod generate" */ 3 | 4 | // ignore_for_file: library_private_types_in_public_api 5 | // ignore_for_file: public_member_api_docs 6 | // ignore_for_file: implementation_imports 7 | // ignore_for_file: use_super_parameters 8 | // ignore_for_file: type_literal_in_constant_pattern 9 | 10 | // ignore_for_file: no_leading_underscores_for_library_prefixes 11 | import 'package:serverpod_client/serverpod_client.dart' as _i1; 12 | 13 | class Caller extends _i1.ModuleEndpointCaller { 14 | Caller(_i1.ServerpodClientShared client) : super(client) {} 15 | 16 | @override 17 | Map get endpointRefLookup => {}; 18 | } 19 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_shared/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: serverpod_json_rpc_2_shared 2 | description: A helper package that contains shared code the for serverpod_json_rpc_2 module. 3 | version: 1.0.1 4 | homepage: https://github.com/Skycoder42/serverpod_json_rpc_2 5 | 6 | environment: 7 | sdk: ^3.3.0 8 | 9 | dependencies: 10 | json_rpc_2: ^3.0.2 11 | serverpod_serialization: ^1.2.5 12 | stream_channel: ^2.1.2 13 | 14 | dev_dependencies: 15 | custom_lint: ^0.6.4 16 | dart_pre_commit: ^5.3.0 17 | dart_test_tools: ^5.7.0 18 | 19 | cider: 20 | link_template: 21 | tag: https://github.com/Skycoder42/serverpod_json_rpc_2/releases/tag/serverpod_json_rpc_2_shared-v%tag% 22 | diff: https://github.com/Skycoder42/serverpod_json_rpc_2/compare/serverpod_json_rpc_2_shared-v%from%...serverpod_json_rpc_2_shared-v%to% 23 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_client/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: serverpod_json_rpc_2_client 2 | description: The client package for the serverpod_json_rpc_2 module for JSON RPC 2.0. 3 | version: 1.0.1 4 | homepage: https://github.com/Skycoder42/serverpod_json_rpc_2 5 | 6 | environment: 7 | sdk: ^3.3.0 8 | 9 | dependencies: 10 | json_rpc_2: ^3.0.2 11 | serverpod_client: ^1.2.5 12 | serverpod_json_rpc_2_shared: ^1.0.0 13 | stream_channel: ^2.1.2 14 | 15 | dev_dependencies: 16 | custom_lint: ^0.6.4 17 | dart_pre_commit: ^5.3.0 18 | dart_test_tools: ^5.7.0 19 | 20 | cider: 21 | link_template: 22 | tag: https://github.com/Skycoder42/serverpod_json_rpc_2/releases/tag/serverpod_json_rpc_2_client-v%tag% 23 | diff: https://github.com/Skycoder42/serverpod_json_rpc_2/compare/serverpod_json_rpc_2_client-v%from%...serverpod_json_rpc_2_client-v%to% 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | build/ 7 | # If you're building an application, you may want to check-in your pubspec.lock 8 | pubspec.lock 9 | 10 | # Directory created by dartdoc 11 | # If you don't generate documentation locally you can remove this line. 12 | doc/api/ 13 | 14 | # dotenv environment variables file 15 | .env* 16 | 17 | # Avoid committing generated Javascript files: 18 | *.dart.js 19 | *.info.json # Produced by the --dump-info flag. 20 | *.js # When generated by dart2js. Don't specify *.js if your 21 | # project includes source files written in JavaScript. 22 | *.js_ 23 | *.js.deps 24 | *.js.map 25 | 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | 29 | custom_lint.log 30 | -------------------------------------------------------------------------------- /.github/workflows/shared_ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI/CD for serverpod_json_rpc_2_shared 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | paths: 7 | - serverpod_json_rpc_2_shared/** 8 | - .github/workflows/shared_*.yaml 9 | pull_request: 10 | types: 11 | - opened 12 | - synchronize 13 | 14 | jobs: 15 | ci: 16 | name: CI 17 | uses: Skycoder42/dart_test_tools/.github/workflows/dart.yml@main 18 | with: 19 | workingDirectory: serverpod_json_rpc_2_shared 20 | unitTestPaths: "" 21 | minCoverage: 0 22 | 23 | cd: 24 | name: CD 25 | uses: Skycoder42/dart_test_tools/.github/workflows/release.yml@main 26 | needs: 27 | - ci 28 | with: 29 | workingDirectory: serverpod_json_rpc_2_shared 30 | tagPrefix: serverpod_json_rpc_2_shared-v 31 | secrets: 32 | githubToken: ${{ secrets.GH_PAT }} 33 | -------------------------------------------------------------------------------- /.github/workflows/client_ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI/CD for serverpod_json_rpc_2_client 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | paths: 7 | - serverpod_json_rpc_2_client/** 8 | - .github/workflows/client_*.yaml 9 | pull_request: 10 | types: 11 | - opened 12 | - synchronize 13 | 14 | jobs: 15 | ci: 16 | name: CI 17 | uses: Skycoder42/dart_test_tools/.github/workflows/dart.yml@main 18 | with: 19 | workingDirectory: serverpod_json_rpc_2_client 20 | unitTestPaths: "" 21 | minCoverage: 0 22 | panaScoreThreshold: 20 23 | 24 | cd: 25 | name: CD 26 | uses: Skycoder42/dart_test_tools/.github/workflows/release.yml@main 27 | needs: 28 | - ci 29 | with: 30 | workingDirectory: serverpod_json_rpc_2_client 31 | tagPrefix: serverpod_json_rpc_2_client-v 32 | secrets: 33 | githubToken: ${{ secrets.GH_PAT }} 34 | -------------------------------------------------------------------------------- /.github/workflows/server_ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI/CD for serverpod_json_rpc_2_server 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | paths: 7 | - serverpod_json_rpc_2_server/** 8 | - .github/workflows/server_*.yaml 9 | pull_request: 10 | types: 11 | - opened 12 | - synchronize 13 | 14 | jobs: 15 | ci: 16 | name: CI 17 | uses: Skycoder42/dart_test_tools/.github/workflows/dart.yml@main 18 | with: 19 | workingDirectory: serverpod_json_rpc_2_server 20 | unitTestPaths: "" 21 | minCoverage: 0 22 | panaScoreThreshold: 20 23 | 24 | cd: 25 | name: CD 26 | uses: Skycoder42/dart_test_tools/.github/workflows/release.yml@main 27 | needs: 28 | - ci 29 | with: 30 | workingDirectory: serverpod_json_rpc_2_server 31 | tagPrefix: serverpod_json_rpc_2_server-v 32 | secrets: 33 | githubToken: ${{ secrets.GH_PAT }} 34 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_server/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: serverpod_json_rpc_2_server 2 | description: The server package for the serverpod_json_rpc_2 module for JSON RPC 2.0. 3 | version: 1.0.0 4 | homepage: https://github.com/Skycoder42/serverpod_json_rpc_2 5 | 6 | environment: 7 | sdk: ^3.3.0 8 | 9 | dependencies: 10 | json_rpc_2: ^3.0.2 11 | meta: ^1.11.0 12 | serverpod: ^1.2.5 13 | serverpod_json_rpc_2_shared: ^1.0.0 14 | stream_channel: ^2.1.2 15 | 16 | dev_dependencies: 17 | custom_lint: ^0.6.4 18 | dart_pre_commit: ^5.3.0 19 | dart_test_tools: ^5.7.0 20 | 21 | dart_pre_commit: 22 | pull-up-dependencies: 23 | allowed: 24 | - meta 25 | 26 | cider: 27 | link_template: 28 | tag: https://github.com/Skycoder42/serverpod_json_rpc_2/releases/tag/serverpod_json_rpc_2_server-v%tag% 29 | diff: https://github.com/Skycoder42/serverpod_json_rpc_2/compare/serverpod_json_rpc_2_server-v%from%...serverpod_json_rpc_2_server-v%to% 30 | -------------------------------------------------------------------------------- /melos.yaml: -------------------------------------------------------------------------------- 1 | name: systemd_status 2 | 3 | packages: 4 | - serverpod_json_rpc_2_shared 5 | - serverpod_json_rpc_2_server 6 | - serverpod_json_rpc_2_client 7 | 8 | scripts: 9 | get: 10 | run: dart pub global run melos exec -- dart pub get 11 | description: Run 'pub get' in all projects 12 | 13 | upgrade: 14 | run: dart pub global run melos exec -- dart pub upgrade --major-versions 15 | description: Run 'pub get' in all projects 16 | 17 | pre-commit:init: 18 | run: >- 19 | bash -c "echo -e 20 | '#!/bin/sh\nexec dart pub global run melos run pre-commit:run' 21 | > .git/hooks/pre-commit && chmod a+x .git/hooks/pre-commit" 22 | description: Setup pre commit hooks 23 | 24 | pre-commit:remove: 25 | run: rm -f .git/hooks/pre-commit 26 | description: Remove pre commit hooks 27 | 28 | pre-commit:run: 29 | run: dart pub global run melos exec -c1 --depends-on=dart_pre_commit -- dart run dart_pre_commit 30 | description: Run pre commit hooks in all projects 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2024, Felix Barz 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_client/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2024, Felix Barz 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_server/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2024, Felix Barz 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_shared/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2024, Felix Barz 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # serverpod_json_rpc_2 2 | 3 | A serverpod module that allows to use JSON RPC 2.0 via the [json_rpc_2 package](https://pub.dev/packages/json_rpc_2). 4 | 5 | ## Packages: 6 | - [serverpod_json_rpc_2_shared](https://github.com/Skycoder42/serverpod_json_rpc_2/tree/main/serverpod_json_rpc_2_shared) 7 | [![CI for package serverpod_json_rpc_2_shared](https://github.com/Skycoder42/serverpod_json_rpc_2/actions/workflows/shared_ci.yaml/badge.svg)](https://github.com/Skycoder42/serverpod_json_rpc_2/actions/workflows/shared_ci.yaml) 8 | [![serverpod_json_rpc_2_shared pub.dev version](https://img.shields.io/pub/v/serverpod_json_rpc_2_shared)](https://pub.dev/packages/serverpod_json_rpc_2_shared) 9 | - [serverpod_json_rpc_2_server](https://github.com/Skycoder42/serverpod_json_rpc_2/tree/main/serverpod_json_rpc_2_server) 10 | [![CI for package serverpod_json_rpc_2_server](https://github.com/Skycoder42/serverpod_json_rpc_2/actions/workflows/server_ci.yaml/badge.svg)](https://github.com/Skycoder42/serverpod_json_rpc_2/actions/workflows/server_ci.yaml) 11 | [![serverpod_json_rpc_2_server pub.dev version](https://img.shields.io/pub/v/serverpod_json_rpc_2_server)](https://pub.dev/packages/serverpod_json_rpc_2_server) 12 | - [serverpod_json_rpc_2_client](https://github.com/Skycoder42/serverpod_json_rpc_2/tree/main/serverpod_json_rpc_2_client) 13 | [![CI for package serverpod_json_rpc_2_client](https://github.com/Skycoder42/serverpod_json_rpc_2/actions/workflows/client_ci.yaml/badge.svg)](https://github.com/Skycoder42/serverpod_json_rpc_2/actions/workflows/client_ci.yaml) 14 | [![serverpod_json_rpc_2_client pub.dev version](https://img.shields.io/pub/v/serverpod_json_rpc_2_client)](https://pub.dev/packages/serverpod_json_rpc_2_client) 15 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_client/lib/src/protocol/protocol.dart: -------------------------------------------------------------------------------- 1 | /* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */ 2 | /* To generate run: "serverpod generate" */ 3 | 4 | // ignore_for_file: library_private_types_in_public_api 5 | // ignore_for_file: public_member_api_docs 6 | // ignore_for_file: implementation_imports 7 | // ignore_for_file: use_super_parameters 8 | // ignore_for_file: type_literal_in_constant_pattern 9 | 10 | library protocol; // ignore_for_file: no_leading_underscores_for_library_prefixes 11 | 12 | import 'package:serverpod_client/serverpod_client.dart' as _i1; 13 | import 'package:serverpod_json_rpc_2_shared/serverpod_json_rpc_2_shared.dart' 14 | as _i2; 15 | export 'client.dart'; 16 | 17 | class Protocol extends _i1.SerializationManager { 18 | Protocol._(); 19 | 20 | factory Protocol() => _instance; 21 | 22 | static final Map customConstructors = {}; 23 | 24 | static final Protocol _instance = Protocol._(); 25 | 26 | @override 27 | T deserialize( 28 | dynamic data, [ 29 | Type? t, 30 | ]) { 31 | t ??= T; 32 | if (customConstructors.containsKey(t)) { 33 | return customConstructors[t]!(data, this) as T; 34 | } 35 | if (t == _i2.JsonRpc2Message) { 36 | return _i2.JsonRpc2Message.fromJson(data, this) as T; 37 | } 38 | if (t == _i1.getType<_i2.JsonRpc2Message?>()) { 39 | return (data != null ? _i2.JsonRpc2Message.fromJson(data, this) : null) 40 | as T; 41 | } 42 | return super.deserialize(data, t); 43 | } 44 | 45 | @override 46 | String? getClassNameForObject(Object data) { 47 | if (data is _i2.JsonRpc2Message) { 48 | return 'JsonRpc2Message'; 49 | } 50 | return super.getClassNameForObject(data); 51 | } 52 | 53 | @override 54 | dynamic deserializeByClassName(Map data) { 55 | if (data['className'] == 'JsonRpc2Message') { 56 | return deserialize<_i2.JsonRpc2Message>(data['data']); 57 | } 58 | return super.deserializeByClassName(data); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_shared/lib/src/rpc_stream_channel_transformer.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:serverpod_serialization/serverpod_serialization.dart'; 4 | import 'package:stream_channel/stream_channel.dart'; 5 | 6 | import 'json_rpc_2_message.dart'; 7 | 8 | class _ProxySink implements Sink { 9 | final Sink sink; 10 | final TOut Function(TIn data) converter; 11 | 12 | const _ProxySink(this.sink, this.converter); 13 | 14 | @override 15 | void add(TIn data) => sink.add(converter(data)); 16 | 17 | @override 18 | void close() => sink.close(); 19 | } 20 | 21 | class _RpcEncoder extends Converter { 22 | const _RpcEncoder(); 23 | 24 | @override 25 | SerializableEntity convert(dynamic input) => JsonRpc2Message(input); 26 | 27 | @override 28 | Sink startChunkedConversion(Sink sink) => 29 | _ProxySink(sink, convert); 30 | } 31 | 32 | class _RpcDecoder extends Converter { 33 | const _RpcDecoder(); 34 | 35 | @override 36 | dynamic convert(SerializableEntity input) => 37 | input is JsonRpc2Message ? input.raw : input; 38 | 39 | @override 40 | Sink startChunkedConversion(Sink sink) => 41 | _ProxySink(sink, convert); 42 | } 43 | 44 | class _RpcCodec extends Codec { 45 | const _RpcCodec(); 46 | 47 | @override 48 | _RpcDecoder get decoder => const _RpcDecoder(); 49 | 50 | @override 51 | _RpcEncoder get encoder => const _RpcEncoder(); 52 | } 53 | 54 | /// A transformer that wraps/unwraps generic JSON events as [JsonRpc2Message] 55 | /// 56 | /// This transformer can be applied to a [StreamChannel]<[SerializableEntity]>. 57 | /// The resulting stream channel accepts (and emits) any kind of data (that can 58 | /// be JSON de/serialized) and wraps it in a [JsonRpc2Message], before passing 59 | /// it to the transformed channel. 60 | class RpcStreamChannelTransformer 61 | extends StreamChannelTransformer { 62 | /// Default constructor 63 | RpcStreamChannelTransformer() : super.fromCodec(const _RpcCodec()); 64 | } 65 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_client/lib/src/channels/endpoint_rpc.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_rpc_2/json_rpc_2.dart' as rpc; 2 | import 'package:serverpod_client/serverpod_client.dart'; 3 | import 'package:serverpod_json_rpc_2_shared/serverpod_json_rpc_2_shared.dart'; 4 | import 'package:stream_channel/stream_channel.dart'; 5 | 6 | import 'endpoint_stream_channel.dart'; 7 | 8 | /// An extension on [EndpointRef]s that use the [EndpointStreamChannel] 9 | /// extension to create JSON RPC 2.0 instances. 10 | /// 11 | /// See [EndpointStreamChannel] for more details on how these channels behave. 12 | extension EndpointRpc on EndpointRef { 13 | /// Creates a [rpc.Client]. 14 | /// 15 | /// Internally, this uses [createStreamChannel] to obtain a stream channel for 16 | /// the endpoint. This methods throws for the same reasons as 17 | /// [createStreamChannel]. 18 | rpc.Client createClient() => rpc.Client.withoutJson(_createRpcChannel()); 19 | 20 | /// Creates a [rpc.Server]. 21 | /// 22 | /// Internally, this uses [createStreamChannel] to obtain a stream channel for 23 | /// the endpoint. This methods throws for the same reasons as 24 | /// [createStreamChannel]. 25 | rpc.Server createServer({ 26 | void Function(dynamic, dynamic)? onUnhandledError, 27 | bool strictProtocolChecks = true, 28 | }) => 29 | rpc.Server.withoutJson( 30 | _createRpcChannel(), 31 | onUnhandledError: onUnhandledError, 32 | strictProtocolChecks: strictProtocolChecks, 33 | ); 34 | 35 | /// Creates a [rpc.Peer]. 36 | /// 37 | /// Internally, this uses [createStreamChannel] to obtain a stream channel for 38 | /// the endpoint. This methods throws for the same reasons as 39 | /// [createStreamChannel]. 40 | rpc.Peer createPeer({ 41 | void Function(dynamic, dynamic)? onUnhandledError, 42 | bool strictProtocolChecks = true, 43 | }) => 44 | rpc.Peer.withoutJson( 45 | _createRpcChannel(), 46 | onUnhandledError: onUnhandledError, 47 | strictProtocolChecks: strictProtocolChecks, 48 | ); 49 | 50 | StreamChannel _createRpcChannel() => 51 | createStreamChannel().transform(RpcStreamChannelTransformer()); 52 | } 53 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_server/lib/src/channels/endpoint_rpc.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_rpc_2/json_rpc_2.dart' as rpc; 2 | import 'package:serverpod/serverpod.dart'; 3 | import 'package:serverpod_json_rpc_2_shared/serverpod_json_rpc_2_shared.dart'; 4 | import 'package:stream_channel/stream_channel.dart'; 5 | 6 | import 'endpoint_stream_channel.dart'; 7 | 8 | /// An extension on [Endpoint]s that uses the [EndpointStreamChannel] mixin to 9 | /// create JSON RPC 2.0 instances. 10 | /// 11 | /// See [EndpointStreamChannel] for more details on how these channels behave. 12 | extension EndpointRpc on EndpointStreamChannel { 13 | /// Creates a [rpc.Client] for the given [session]. 14 | /// 15 | /// Internally, this uses [channelFor] to obtain a stream channel for the 16 | /// session. This methods returns `null` for the same reasons as [channelFor]. 17 | rpc.Client? createClient(StreamingSession session) { 18 | final rpcChannel = _rpcChannelFor(session); 19 | if (rpcChannel == null) { 20 | return null; 21 | } 22 | return rpc.Client.withoutJson(rpcChannel); 23 | } 24 | 25 | /// Creates a [rpc.Server] for the given [session]. 26 | /// 27 | /// Internally, this uses [channelFor] to obtain a stream channel for the 28 | /// session. This methods returns `null` for the same reasons as [channelFor]. 29 | rpc.Server? createServer( 30 | StreamingSession session, { 31 | void Function(dynamic, dynamic)? onUnhandledError, 32 | bool strictProtocolChecks = true, 33 | }) { 34 | final rpcChannel = _rpcChannelFor(session); 35 | if (rpcChannel == null) { 36 | return null; 37 | } 38 | return rpc.Server.withoutJson( 39 | rpcChannel, 40 | onUnhandledError: onUnhandledError, 41 | strictProtocolChecks: strictProtocolChecks, 42 | ); 43 | } 44 | 45 | /// Creates a [rpc.Peer] for the given [session]. 46 | /// 47 | /// Internally, this uses [channelFor] to obtain a stream channel for the 48 | /// session. This methods returns `null` for the same reasons as [channelFor]. 49 | rpc.Peer? createPeer( 50 | StreamingSession session, { 51 | void Function(dynamic, dynamic)? onUnhandledError, 52 | bool strictProtocolChecks = true, 53 | }) { 54 | final rpcChannel = _rpcChannelFor(session); 55 | if (rpcChannel == null) { 56 | return null; 57 | } 58 | return rpc.Peer.withoutJson( 59 | rpcChannel, 60 | onUnhandledError: onUnhandledError, 61 | strictProtocolChecks: strictProtocolChecks, 62 | ); 63 | } 64 | 65 | StreamChannel? _rpcChannelFor(StreamingSession session) => 66 | channelFor(session)?.transform(RpcStreamChannelTransformer()); 67 | } 68 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_server/lib/src/generated/protocol.dart: -------------------------------------------------------------------------------- 1 | /* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */ 2 | /* To generate run: "serverpod generate" */ 3 | 4 | // ignore_for_file: library_private_types_in_public_api 5 | // ignore_for_file: public_member_api_docs 6 | // ignore_for_file: implementation_imports 7 | // ignore_for_file: use_super_parameters 8 | // ignore_for_file: type_literal_in_constant_pattern 9 | 10 | library protocol; // ignore_for_file: no_leading_underscores_for_library_prefixes 11 | 12 | import 'package:serverpod/serverpod.dart' as _i1; 13 | import 'package:serverpod/protocol.dart' as _i2; 14 | import 'package:serverpod_json_rpc_2_shared/serverpod_json_rpc_2_shared.dart' 15 | as _i3; 16 | 17 | class Protocol extends _i1.SerializationManagerServer { 18 | Protocol._(); 19 | 20 | factory Protocol() => _instance; 21 | 22 | static final Map customConstructors = {}; 23 | 24 | static final Protocol _instance = Protocol._(); 25 | 26 | static final List<_i2.TableDefinition> targetTableDefinitions = []; 27 | 28 | @override 29 | T deserialize( 30 | dynamic data, [ 31 | Type? t, 32 | ]) { 33 | t ??= T; 34 | if (customConstructors.containsKey(t)) { 35 | return customConstructors[t]!(data, this) as T; 36 | } 37 | if (t == _i3.JsonRpc2Message) { 38 | return _i3.JsonRpc2Message.fromJson(data, this) as T; 39 | } 40 | if (t == _i1.getType<_i3.JsonRpc2Message?>()) { 41 | return (data != null ? _i3.JsonRpc2Message.fromJson(data, this) : null) 42 | as T; 43 | } 44 | try { 45 | return _i2.Protocol().deserialize(data, t); 46 | } catch (_) {} 47 | return super.deserialize(data, t); 48 | } 49 | 50 | @override 51 | String? getClassNameForObject(Object data) { 52 | if (data is _i3.JsonRpc2Message) { 53 | return 'JsonRpc2Message'; 54 | } 55 | return super.getClassNameForObject(data); 56 | } 57 | 58 | @override 59 | dynamic deserializeByClassName(Map data) { 60 | if (data['className'] == 'JsonRpc2Message') { 61 | return deserialize<_i3.JsonRpc2Message>(data['data']); 62 | } 63 | return super.deserializeByClassName(data); 64 | } 65 | 66 | @override 67 | _i1.Table? getTableForType(Type t) { 68 | { 69 | var table = _i2.Protocol().getTableForType(t); 70 | if (table != null) { 71 | return table; 72 | } 73 | } 74 | return null; 75 | } 76 | 77 | @override 78 | List<_i2.TableDefinition> getTargetTableDefinitions() => 79 | targetTableDefinitions; 80 | 81 | @override 82 | String getModuleName() => 'serverpod_json_rpc_2'; 83 | } 84 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_client/lib/src/channels/endpoint_stream_channel.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:serverpod_client/serverpod_client.dart'; 4 | import 'package:stream_channel/stream_channel.dart'; 5 | 6 | /// An extensions for generic [EndpointRef]s that allows to access the endpoints 7 | /// websocket connection via a [StreamChannel]. 8 | /// 9 | /// This basically wraps serverpod's stream APIs into endpoint-bound stream 10 | /// channels. Most of it happens automatically, but the following should be 11 | /// considered: 12 | /// 1. The endpoint is **not** responsible for managing the underlying websocket 13 | /// connection. This is done by the [client]. Use 14 | /// [ServerpodClientShared.openStreamingConnection] to connect to the server 15 | /// *before* accessing the endpoints stream channel. Likewise, use 16 | /// [ServerpodClientShared.closeStreamingConnection] to close it once finished. 17 | /// 2. If any side closes the connection, the [StreamChannel.stream] will emit 18 | /// the done event and adding more messages to the[StreamChannel.sink] will have 19 | /// no effect. 20 | /// 3. Closing the [StreamChannel.sink] will also close the 21 | /// [StreamChannel.stream], but it will **not** close the websocket connection! 22 | /// This is because multiple endpoints could be using the same connection. If 23 | /// you need to close the connection, use 24 | /// 4. It is allowed to call [createStreamChannel] before 25 | /// [ServerpodClientShared.openStreamingConnection]. However, in that case you 26 | /// **must not** add any messages to the [StreamChannel.sink] before doing so. 27 | /// [ServerpodClientShared.closeStreamingConnection]. Please note that closing 28 | /// the *sink* will **not** notify the server at all. Further messages received 29 | /// from the server will be silently dropped. 30 | extension EndpointStreamChannel on EndpointRef { 31 | /// Creates a new [StreamChannel] for the endpoint. 32 | /// 33 | /// If a previous channel already exists it will be closed, meaning the 34 | /// [StreamChannel.stream] will emit the done event and adding more messages 35 | /// to the[StreamChannel.sink] will have no effect. 36 | StreamChannel createStreamChannel() { 37 | resetStream(); 38 | 39 | final controller = StreamChannelController( 40 | allowForeignErrors: false, 41 | ); 42 | unawaited(_setupController(controller)); 43 | return controller.foreign; 44 | } 45 | 46 | Future _setupController( 47 | StreamChannelController controller, 48 | ) async { 49 | final localStreamSub = controller.local.stream.listen( 50 | sendStreamMessage, 51 | onDone: resetStream, 52 | ); 53 | try { 54 | await stream.pipe(controller.local.sink); 55 | 56 | // ignore: avoid_catches_without_on_clauses 57 | } catch (e, s) { 58 | controller.local.sink.addError(e, s); 59 | await controller.local.sink.close(); 60 | } finally { 61 | await localStreamSub.cancel(); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /serverpod_json_rpc_2_server/lib/src/channels/endpoint_stream_channel.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:meta/meta.dart'; 4 | import 'package:serverpod/serverpod.dart'; 5 | import 'package:stream_channel/stream_channel.dart'; 6 | 7 | @immutable 8 | class _ChannelData { 9 | final StreamChannelController controller; 10 | final StreamSubscription localStreamSub; 11 | 12 | const _ChannelData({ 13 | required this.controller, 14 | required this.localStreamSub, 15 | }); 16 | 17 | Future close() => Future.wait([ 18 | controller.local.sink.close(), 19 | localStreamSub.cancel(), 20 | ]); 21 | } 22 | 23 | /// An [Endpoint] mixin that allows access to [StreamingSession]s via a 24 | /// [StreamChannel]. 25 | /// 26 | /// This basically wraps serverpod's stream APIs into session-bound stream 27 | /// channels. Most of it happens automatically, but the following should be 28 | /// considered: 29 | /// 1. [StreamChannel] life cycles are managed by serverpod. If a connection 30 | /// is closed, the [StreamChannel.stream] will emit the done event and adding 31 | /// more messages to the[StreamChannel.sink] will have no effect. 32 | /// 2. Closing the [StreamChannel.sink] will also close the 33 | /// [StreamChannel.stream], but it will **not** close the websocket connection! 34 | /// This is because multiple endpoints could be using the same connection. If 35 | /// you need to close the connection, use the [StreamingSession.webSocket] and 36 | /// close it directly. Please note that closing the *sink* will **not** notify 37 | /// the client at all. Further messages received from the client will be 38 | /// dropped. 39 | mixin EndpointStreamChannel on Endpoint { 40 | final _channels = {}; 41 | 42 | /// Returns the [StreamChannel] for the given [session]. 43 | /// 44 | /// Only returns a valid value if the client has previously opened a session 45 | /// (and thus [streamOpened] was called) and that session has been closed be 46 | /// neither the client nor the endpoint (via closing the sink). Otherwise 47 | /// `null` is returned. 48 | @nonVirtual 49 | StreamChannel? channelFor(StreamingSession session) => 50 | _channels[session]?.controller.foreign; 51 | 52 | @override 53 | @mustCallSuper 54 | Future streamOpened(StreamingSession session) async { 55 | final controller = StreamChannelController( 56 | allowForeignErrors: false, 57 | ); 58 | _channels[session] = _ChannelData( 59 | controller: controller, 60 | localStreamSub: controller.local.stream.listen( 61 | (event) => sendStreamMessage(session, event), 62 | onDone: () => _cleanup(session), 63 | ), 64 | ); 65 | } 66 | 67 | @override 68 | @mustCallSuper 69 | Future streamClosed(StreamingSession session) => _cleanup(session); 70 | 71 | @override 72 | @nonVirtual 73 | Future handleStreamMessage( 74 | StreamingSession session, 75 | SerializableEntity message, 76 | ) async { 77 | final channel = _channels[session]; 78 | if (channel != null) { 79 | channel.controller.local.sink.add(message); 80 | } else { 81 | session.log( 82 | 'Dropping received stream message, channel has already been closed!', 83 | level: LogLevel.debug, 84 | ); 85 | } 86 | } 87 | 88 | Future _cleanup(StreamingSession session) async => 89 | _channels.remove(session)?.close(); 90 | } 91 | --------------------------------------------------------------------------------