-
Notifications
You must be signed in to change notification settings - Fork 125
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Provide an example using an Isolate Worker Pool with Squadron (#361)
- Loading branch information
Showing
7 changed files
with
462 additions
and
0 deletions.
There are no files selected for viewing
164 changes: 164 additions & 0 deletions
164
example/bin/main_json_serializable_squadron_worker_pool.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
/// This example uses | ||
/// - https://github.com/google/json_serializable.dart | ||
/// - https://github.com/d-markey/squadron | ||
/// - https://github.com/d-markey/squadron_builder | ||
import 'dart:async' show FutureOr; | ||
import 'dart:convert' show jsonDecode; | ||
|
||
import 'package:chopper/chopper.dart'; | ||
import 'package:chopper_example/json_decode_service.dart'; | ||
import 'package:chopper_example/json_serializable.dart'; | ||
import 'package:http/testing.dart'; | ||
import 'package:squadron/squadron.dart'; | ||
import 'package:http/http.dart' as http; | ||
|
||
import 'main_json_serializable.dart' show authHeader; | ||
|
||
typedef JsonFactory<T> = T Function(Map<String, dynamic> json); | ||
|
||
/// This JsonConverter works with or without a WorkerPool | ||
class JsonSerializableWorkerPoolConverter extends JsonConverter { | ||
const JsonSerializableWorkerPoolConverter(this.factories, [this.workerPool]); | ||
|
||
final Map<Type, JsonFactory> factories; | ||
final JsonDecodeServiceWorkerPool? workerPool; | ||
|
||
T? _decodeMap<T>(Map<String, dynamic> values) { | ||
/// Get jsonFactory using Type parameters | ||
/// if not found or invalid, throw error or return null | ||
final jsonFactory = factories[T]; | ||
if (jsonFactory == null || jsonFactory is! JsonFactory<T>) { | ||
/// throw serializer not found error; | ||
return null; | ||
} | ||
|
||
return jsonFactory(values); | ||
} | ||
|
||
List<T> _decodeList<T>(Iterable values) => | ||
values.where((v) => v != null).map<T>((v) => _decode<T>(v)).toList(); | ||
|
||
dynamic _decode<T>(entity) { | ||
if (entity is Iterable) return _decodeList<T>(entity as List); | ||
|
||
if (entity is Map) return _decodeMap<T>(entity as Map<String, dynamic>); | ||
|
||
return entity; | ||
} | ||
|
||
@override | ||
FutureOr<Response<ResultType>> convertResponse<ResultType, Item>( | ||
Response response, | ||
) async { | ||
// use [JsonConverter] to decode json | ||
final jsonRes = await super.convertResponse(response); | ||
|
||
return jsonRes.copyWith<ResultType>(body: _decode<Item>(jsonRes.body)); | ||
} | ||
|
||
@override | ||
FutureOr<Response> convertError<ResultType, Item>(Response response) async { | ||
// use [JsonConverter] to decode json | ||
final jsonRes = await super.convertError(response); | ||
|
||
return jsonRes.copyWith<ResourceError>( | ||
body: ResourceError.fromJsonFactory(jsonRes.body), | ||
); | ||
} | ||
|
||
@override | ||
FutureOr<dynamic> tryDecodeJson(String data) async { | ||
try { | ||
// if there is a worker pool use it, otherwise run in the main thread | ||
return workerPool != null | ||
? await workerPool!.jsonDecode(data) | ||
: jsonDecode(data); | ||
} catch (error) { | ||
print(error); | ||
|
||
chopperLogger.warning(error); | ||
|
||
return data; | ||
} | ||
} | ||
} | ||
|
||
/// Simple client to have working example without remote server | ||
final client = MockClient((http.Request req) async { | ||
if (req.method == 'POST') { | ||
return http.Response('{"type":"Fatal","message":"fatal error"}', 500); | ||
} | ||
if (req.method == 'GET' && req.headers['test'] == 'list') { | ||
return http.Response('[{"id":"1","name":"Foo"}]', 200); | ||
} | ||
|
||
return http.Response('{"id":"1","name":"Foo"}', 200); | ||
}); | ||
|
||
/// inspired by https://github.com/d-markey/squadron_sample/blob/main/lib/main.dart | ||
void initSquadron(String id) { | ||
Squadron.setId(id); | ||
Squadron.setLogger(ConsoleSquadronLogger()); | ||
Squadron.logLevel = SquadronLogLevel.all; | ||
Squadron.debugMode = true; | ||
} | ||
|
||
Future<void> main() async { | ||
/// initialize Squadron before using it | ||
initSquadron('worker_pool_example'); | ||
|
||
final jsonDecodeServiceWorkerPool = JsonDecodeServiceWorkerPool( | ||
// Set whatever you want here | ||
concurrencySettings: ConcurrencySettings.oneCpuThread, | ||
); | ||
|
||
/// start the Worker Pool | ||
await jsonDecodeServiceWorkerPool.start(); | ||
|
||
final converter = JsonSerializableWorkerPoolConverter( | ||
{ | ||
Resource: Resource.fromJsonFactory, | ||
}, | ||
// make sure to provide the WorkerPool to the JsonConverter | ||
jsonDecodeServiceWorkerPool, | ||
); | ||
|
||
final chopper = ChopperClient( | ||
client: client, | ||
baseUrl: 'http://localhost:8000', | ||
// bind your object factories here | ||
converter: converter, | ||
errorConverter: converter, | ||
services: [ | ||
// the generated service | ||
MyService.create(), | ||
], | ||
/* ResponseInterceptorFunc | RequestInterceptorFunc | ResponseInterceptor | RequestInterceptor */ | ||
interceptors: [authHeader], | ||
); | ||
|
||
final myService = chopper.getService<MyService>(); | ||
|
||
/// All of the calls below will use jsonDecode in an Isolate worker | ||
final response1 = await myService.getResource('1'); | ||
print('response 1: ${response1.body}'); // undecoded String | ||
|
||
final response2 = await myService.getResources(); | ||
print('response 2: ${response2.body}'); // decoded list of Resources | ||
|
||
final response3 = await myService.getTypedResource(); | ||
print('response 3: ${response3.body}'); // decoded Resource | ||
|
||
final response4 = await myService.getMapResource('1'); | ||
print('response 4: ${response4.body}'); // undecoded Resource | ||
|
||
try { | ||
await myService.newResource(Resource('3', 'Super Name')); | ||
} on Response catch (error) { | ||
print(error.body); | ||
} | ||
|
||
/// stop the Worker Pool | ||
jsonDecodeServiceWorkerPool.stop(); | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/// This example uses https://github.com/d-markey/squadron_builder | ||
import 'dart:async'; | ||
import 'dart:convert' show json; | ||
|
||
import 'package:squadron/squadron.dart'; | ||
import 'package:squadron/squadron_annotations.dart'; | ||
|
||
import 'json_decode_service.activator.g.dart'; | ||
|
||
part 'json_decode_service.worker.g.dart'; | ||
|
||
@SquadronService( | ||
// disable web to keep the number of generated files low for this example | ||
web: false, | ||
) | ||
class JsonDecodeService extends WorkerService | ||
with $JsonDecodeServiceOperations { | ||
@SquadronMethod() | ||
Future<dynamic> jsonDecode(String source) async => json.decode(source); | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.