Compare commits

...

17 commits

Author SHA1 Message Date
Thomas Hii
06080c879a Updated Changelog 2024-05-21 23:51:17 +08:00
Thomas Hii
2247aae302 Updated 2024-05-21 23:38:44 +08:00
Thomas Hii
a0db187d75 Updated 2024-05-21 23:16:31 +08:00
Thomas
2decae0c3d
Merge pull request #6 from dart-backend/feature/dart3.3-support
Updated to min dart sdk 3.3
2024-05-21 23:09:26 +08:00
Thomas Hii
685419eea6 Updated to min dart sdk 3.3 2024-05-21 23:08:07 +08:00
thomashii@dukefirehawk.com
d466f2e776 Added comments 2023-12-12 10:30:48 +08:00
Thomas
42ca54ec0f
Merge pull request #5 from dart-backend/feature/upgrade_deps
Feature/upgrade deps
2023-12-12 10:24:40 +08:00
thomashii@dukefirehawk.com
8ee0fc607d Merge branch 'main' into feature/upgrade_deps 2023-12-12 10:23:31 +08:00
thomashii@dukefirehawk.com
58f63f0315 Updated to use lints 3.0.0 2023-12-12 10:10:10 +08:00
thomashii@dukefirehawk.com
dfccf23629 Updated pub_sub 2023-12-12 09:30:25 +08:00
thomashii@dukefirehawk.com
b6c1ba243a Updated lints 2023-11-16 23:52:43 +08:00
thomashii@dukefirehawk.com
0aee2f64da Updated lints 2023-11-16 23:44:09 +08:00
thomashii@dukefirehawk.com
f4a7b46cbc Upgraded library 2023-09-23 11:02:18 +08:00
thomashii
08bb59f51f Updated range_header 2023-06-24 13:28:42 +08:00
thomashii
6740e55356 Updated range_header 2023-06-24 13:24:24 +08:00
Thomas Hii
819e030a32
Merge pull request #4 from dart-backend/feature/v8
Updated body_parser
2023-05-26 23:07:40 +08:00
Thomas Hii
4e320b1e44
Merge pull request #3 from dart-backend/feature/v8
Feature/v8
2023-05-16 00:05:41 +08:00
71 changed files with 499 additions and 274 deletions

1
.gitignore vendored
View file

@ -27,3 +27,4 @@ doc/api/
!.vscode/launch.json
!.vscode/extensions.json
.metals/
.DS_Store

View file

@ -1,5 +1,16 @@
# Change Log
## 5.3.0
* Require Dart >= 3.3
* Updated `belatuk_http_server` to 4.4.0
* Updated `lints` to 4.0.0
## 5.2.0
* Updated `lints` to 3.0.0
* Updated `belatuk_http_server` to 4.2.0
## 5.1.0
* Updated `belatuk_http_server` to 4.1.1

View file

@ -21,16 +21,14 @@ This is the request body parser powering the [Angel3 framework](https://pub.dev/
### About
I needed something like Express.js's `body-parser` module, so I made it here. It fully supports JSON requests. x-www-form-urlencoded fully supported, as well as query strings. You can also include arrays in your query, in the same way you would for a PHP application. Full file upload support will also be present by the production 1.0.0 release.
A benefit of this is that primitive types are automatically deserialized correctly. As in, if you have a `hello=1.5` request, then `body['hello']` will equal `1.5` and not `'1.5'`. A very semantic difference, yes, but it relieves stress in my head.
This package is similar to Express.js's `body-parser` module. It fully supports JSON, x-www-form-urlencoded as well as query strings requests. You can also include arrays in your query, in the same way you would for a PHP application. A benefit of this is that primitive types are automatically deserialized correctly. As in, if you have a `hello=1.5` request, then `body['hello']` will equal `1.5` and not `'1.5'`.
### Installation
To install Body Parser for your Dart project, simply add body_parser to your pub dependencies.
dependencies:
belatuk_body_parser: ^5.1.0
belatuk_body_parser: ^5.2.0
### Usage

View file

@ -1,14 +1,14 @@
name: belatuk_body_parser
version: 5.1.0
version: 5.3.0
description: Parse request bodies and query strings in Dart. Supports JSON, URL-encoded, and multi-part bodies.
homepage: https://github.com/dart-backend/belatuk-common-utilities/tree/main/packages/body_parser
environment:
sdk: '>=3.0.0 <4.0.0'
sdk: '>=3.3.0 <4.0.0'
dependencies:
http_parser: ^4.0.0
belatuk_http_server: ^4.1.0
belatuk_http_server: ^4.4.0
mime: ^1.0.0
dev_dependencies:
http: ^1.0.0
test: ^1.24.0
lints: ^2.1.0
lints: ^4.0.0

View file

@ -1,5 +1,14 @@
# Change Log
## 5.2.0
* Require Dart >= 3.3
* Updated `lints` to 4.0.0
## 5.1.0
* Updated `lints` to 3.0.0
## 5.0.0
* Require Dart >= 3.0

View file

@ -14,7 +14,7 @@ In your `pubspec.yaml`:
```yaml
dependencies:
belatuk_code_buffer: ^5.0.0
belatuk_code_buffer: ^5.1.0
```
## Usage

View file

@ -1,12 +1,12 @@
name: belatuk_code_buffer
version: 5.0.0
version: 5.2.0
description: An advanced StringBuffer geared toward generating code, and source maps.
homepage: https://github.com/dart-backend/belatuk-common-utilities/tree/main/packages/code_buffer
environment:
sdk: '>=3.0.0 <4.0.0'
sdk: '>=3.3.0 <4.0.0'
dependencies:
charcode: ^1.2.0
source_span: ^1.8.1
dev_dependencies:
test: ^1.24.0
lints: ^2.0.0
lints: ^4.0.0

View file

@ -1,5 +1,15 @@
# Change Log
## 5.2.0
* Require Dart >= 3.3
* Updated `lints` to 4.0.0
## 5.1.0
* Updated `lints` to 3.0.0
* Fixed lints warnings
## 5.0.0
* Require Dart >= 3.0

View file

@ -9,8 +9,7 @@
Packrat parser combinators that support static typing, generics, file spans, memoization, and more.
**RECOMMENDED:**
Check `example/` for examples.
The examples contain examples of using:
Check `example/` for examples. The examples contain examples of using:
* Generic typing
* Reading `FileSpan` from `ParseResult`

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
class _Advance<T> extends Parser<T> {
final Parser<T> parser;

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
/// Matches any one of the given [parsers].
///

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
class _Cache<T> extends Parser<T> {
final Map<int, ParseResult<T>> _cache = {};

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
class _Cast<T, U extends T> extends Parser<U> {
final Parser<T> parser;

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
/// Expects to parse a sequence of [parsers].
///

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
class _Check<T> extends Parser<T> {
final Parser<T> parser;

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
class _Compare<T> extends ListParser<T> {
final ListParser<T> parser;

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
class _FoldErrors<T> extends Parser<T> {
final Parser<T> parser;

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
class _Index<T> extends Parser<T> {
final ListParser<T> parser;

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
/// Matches any one of the given [parsers].
///

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
class _Map<T, U> extends Parser<U> {
final Parser<T> parser;

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
/// Expects to match a given [pattern]. If it is not matched, you can provide a custom [errorMessage].
Parser<T> match<T>(Pattern pattern,

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
class _MaxDepth<T> extends Parser<T> {
final Parser<T> parser;

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
class _Negate<T> extends Parser<T> {
final Parser<T> parser;

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
class _Opt<T> extends Parser<T> {
final Parser<T> parser;

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
/*
/// Handles left recursion in a grammar using the Pratt algorithm.

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
class _Reduce<T> extends Parser<T> {
final ListParser<T> parser;

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
Reference<T> reference<T>() => Reference<T>._();

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
class _Repeat<T> extends ListParser<T> {
final Parser<T> parser;

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
class _Safe<T> extends Parser<T> {
final Parser<T> parser;

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
class _ToList<T> extends ListParser<T> {
final Parser<T> parser;

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
/// A typed parser that parses a sequence of 2 values of different types.
Parser<Tuple2<A, B>> tuple2<A, B>(Parser<A> a, Parser<B> b) {

View file

@ -1,4 +1,4 @@
part of lex.src.combinator;
part of 'combinator.dart';
class _Value<T> extends Parser<T> {
final Parser<T> parser;

View file

@ -1,9 +1,9 @@
name: belatuk_combinator
version: 5.0.0
version: 5.2.0
description: Packrat parser combinators that support static typing, generics, file spans, memoization, and more.
homepage: https://github.com/dart-backend/belatuk-common-utilities/tree/main/packages/combinator
environment:
sdk: '>=3.0.0 <4.0.0'
sdk: '>=3.3.0 <4.0.0'
dependencies:
belatuk_code_buffer: ^5.0.0
matcher: ^0.12.10
@ -12,4 +12,4 @@ dependencies:
tuple: ^2.0.0
dev_dependencies:
test: ^1.24.0
lints: ^2.0.0
lints: ^4.0.0

View file

@ -1,5 +1,14 @@
# Change Log
## 5.2.0
* Require Dart >= 3.3
* Updated `lints` to 4.0.0
## 5.1.0
* Updated `lints` to 3.0.0
## 5.0.0
* Require Dart >= 3.0

View file

@ -8,17 +8,13 @@
This package builds HTML AST's and renders them to HTML. It can be used as an internal DSL, i.e. for a templating engine.
## Requirements
* Dart SDK: 3.0.x or later
## Installation
In your `pubspec.yaml`:
```yaml
dependencies:
belatuk_html_builder: ^5.0.0
belatuk_html_builder: ^5.1.0
```
## Usage

View file

@ -54,7 +54,8 @@ class SelfClosingNode extends Node {
@override
List<Node> get children => List<Node>.unmodifiable([]);
SelfClosingNode(tagName, [Map<String, dynamic> attributes = const {}])
// ignore: use_super_parameters
SelfClosingNode(String tagName, [Map<String, dynamic> attributes = const {}])
: super._selfClosing(tagName, attributes);
}

View file

@ -1,12 +1,12 @@
name: belatuk_html_builder
version: 5.0.0
version: 5.2.0
description: Build HTML AST's and render them to HTML. This can be used as an internal DSL, i.e. for a templating engine.
homepage: https://github.com/dart-backend/belatuk-common-utilities/tree/main/packages/html_builder
environment:
sdk: '>=3.0.0 <4.0.0'
sdk: '>=3.3.0 <4.0.0'
dependencies:
collection: ^1.17.0
dev_dependencies:
html: ^0.15.0
test: ^1.24.0
lints: ^2.0.0
lints: ^4.0.0

View file

@ -1,5 +1,15 @@
# Change Log
## 7.2.0
* Require Dart >= 3.3
* Updated `lints` to 4.0.0
## 7.1.0
* Updated `lints` to 3.0.0
* Fixed lints warnings
## 7.0.0
* Require Dart >= 3.0

View file

@ -11,8 +11,10 @@ The ***new and improved*** definitive solution for JSON in Dart. It supports syn
## Installation
```yaml
dependencies:
belatuk_json_serializer: ^7.0.0
belatuk_json_serializer: ^7.1.0
```
## Usage

View file

@ -1,4 +1,4 @@
part of belatuk_json_serializer;
part of '../belatuk_json_serializer.dart';
/// Deserializes a JSON string into a Dart datum.
///

View file

@ -1,4 +1,4 @@
part of belatuk_json_serializer;
part of '../belatuk_json_serializer.dart';
/// Serializes any arbitrary Dart datum to JSON. Supports schema validation.
String serialize(value) {

View file

@ -1,4 +1,4 @@
part of belatuk_json_serializer;
part of '../belatuk_json_serializer.dart';
bool _isPrimitive(value) {
return value is num || value is bool || value is String || value == null;

View file

@ -1,4 +1,4 @@
part of belatuk_json_serializer;
part of '../belatuk_json_serializer.dart';
/// Thrown when schema validation fails.
class JsonValidationError implements Exception {

View file

@ -1,12 +1,12 @@
name: belatuk_json_serializer
version: 7.0.0
version: 7.2.0
description: Easy JSON to Object serialization and deserialization in Dart.
homepage: https://github.com/dart-backend/belatuk-common-utilities/tree/main/packages/json_serializer
environment:
sdk: '>=3.0.0 <4.0.0'
sdk: '>=3.3.0 <4.0.0'
dependencies:
logging: ^1.0.1
dev_dependencies:
stack_trace: ^1.10.0
test: ^1.24.0
lints: ^2.0.0
lints: ^4.0.0

View file

@ -1,5 +1,14 @@
# Change Log
## 5.2.0
* Require Dart >= 3.3
* Updated `lints` to 4.0.0
## 5.1.0
* Updated `lints` to 3.0.0
## 5.0.0
* Require Dart >= 3.0

View file

@ -7,8 +7,7 @@
**Replacement of `package:merge_map` with breaking changes to support NNBD.**
Combine multiple Maps into one. Equivalent to
[Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
in JS.
[Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) in JS.
## Example

View file

@ -1,9 +1,9 @@
name: belatuk_merge_map
version: 5.0.0
version: 5.2.0
description: Combine multiple Maps into one. Equivalent to Object.assign in JS.
homepage: https://github.com/dart-backend/belatuk-common-utilities/tree/main/packages/merge_map
environment:
sdk: '>=3.0.0 <4.0.0'
sdk: '>=3.3.0 <4.0.0'
dev_dependencies:
test: ^1.24.0
lints: ^2.0.0
lints: ^4.0.0

View file

@ -1,5 +1,14 @@
# Change Log
## 6.2.0
* Require Dart >= 3.3
* Updated `lints` to 4.0.0
## 6.1.0
* Updated `lints` to 3.0.0
## 6.0.0
* Require Dart >= 3.0

View file

@ -15,7 +15,7 @@ In your `pubspec.yaml`:
```yaml
dependencies:
belatuk_pretty_logging: ^6.0.0
belatuk_pretty_logging: ^6.1.0
```
## Usage

View file

@ -1,12 +1,12 @@
name: belatuk_pretty_logging
version: 6.0.0
version: 6.2.0
description: Standalone helper for colorful logging output, using pkg:io AnsiCode.
homepage: https://github.com/dart-backend/belatuk-common-utilities/tree/main/packages/pretty_logging
environment:
sdk: '>=3.0.0 <4.0.0'
sdk: '>=3.3.0 <4.0.0'
dependencies:
io: ^1.0.0
logging: ^1.0.1
dev_dependencies:
test: ^1.24.0
lints: ^2.0.0
lints: ^4.0.0

View file

@ -1,5 +1,19 @@
# Change Log
## 6.3.0
* Require Dart >= 3.3
* Updated `lints` to 4.0.0
## 6.2.0
* Updated `lints` to 3.0.0
* Refactored encode/decode message handling into `MessageHandler`
## 6.1.0
* Updated `uuid` to 4.0.0
## 6.0.0
* Require Dart >= 3.0

View file

@ -14,7 +14,7 @@ Add `belatuk_pub_sub` as a dependency in your `pubspec.yaml` file:
```yaml
dependencies:
belatuk_pub_sub: ^6.0.0
belatuk_pub_sub: ^6.2.0
```
Then, be sure to run `dart pub get` in your terminal.
@ -22,17 +22,13 @@ Then, be sure to run `dart pub get` in your terminal.
## Usage
`belatuk_pub_sub` is your typical pub/sub API. However, `belatuk_pub_sub` enforces authentication of every
request. It is very possible that `belatuk_pub_sub` will run on both servers and in the browser,
or on a platform belatuk_pub_sublike Flutter. Thus, there are provisions available to limit
access.
request. It is very possible that `belatuk_pub_sub` will run on both server and in the browser,
or on a platform like Flutter.
**Be careful to not leak any `belatuk_pub_sub` client ID's if operating over a network.**
If you do, you risk malicious users injecting events into your application, which
could ultimately spell *disaster*.
If you do, you run the risk of malicious users injecting events into your application.
A `belatuk_pub_sub` server can operate across multiple *adapters*, which take care of interfacing data over different
media. For example, a single server can handle pub/sub between multiple Isolates and TCP Sockets, as well as
WebSockets, simultaneously.
A `belatuk_pub_sub` server can operate across multiple *adapters*, which take care of interfacing data over different media. For example, a single server can handle pub/sub between multiple Isolates and TCP Sockets, as well as WebSockets, simultaneously.
```dart
import 'package:belatuk_pub_sub/belatuk_pub_sub.dart' as pub_sub;
@ -52,13 +48,7 @@ main() async {
### Trusted Clients
You can use `package:belatuk_pub_sub` without explicitly registering
clients, *if and only if* those clients come from trusted sources.
Clients via `Isolate` are always trusted.
Clients via `package:json_rpc_2` must be explicitly marked
as trusted (i.e. using an IP whitelist mechanism):
You can use `package:belatuk_pub_sub` without explicitly registering clients, *if and only if* those clients come from trusted sources. Clients via `Isolate` are always trusted. Clients via `package:json_rpc_2` must be explicitly marked as trusted (i.e. using an IP whitelist mechanism):
```dart
JsonRpc2Adapter(..., isTrusted: false);
@ -70,9 +60,7 @@ pub_sub.IsolateClient(null);
### Access Control
The ID's of all *untrusted* clients who will connect to the server must be known at start-up time.
You may not register new clients after the server has started. This is mostly a security consideration;
if it is impossible to register new clients, then malicious users cannot grant themselves additional
privileges within the system.
You may not register new clients after the server has started. This is mostly a security consideration, to make it impossible to register new clients, thus preventing malicious users from granting themselves additional privileges within the system.
```dart
import 'package:belatuk_pub_sub/belatuk_pub_sub.dart' as pub_sub;
@ -96,10 +84,7 @@ void main() async {
### Isolates
If you are just running multiple instances of a server,
use `package:belatuk_pub_sub/isolate.dart`.
You'll need one isolate to be the master. Typically this is the first isolate you create.
If you are just running multiple instances of a server, use `package:belatuk_pub_sub/isolate.dart`. You'll need one isolate to be the master. Typically this is the first isolate you create.
```dart
import 'dart:io';
@ -157,9 +142,7 @@ Check out `test/json_rpc_2_test.dart` for an example of serving `belatuk_pub_sub
## Protocol
`belatuk_pub_sub` is built upon a simple RPC, and this package includes
an implementation that runs via `SendPort`s and `ReceivePort`s, as
well as one that runs on any `StreamChannel<String>`.
`belatuk_pub_sub` is built upon a simple RPC, and this package includes an implementation that runs via `SendPort`s and `ReceivePort`s, as well as one that runs on any `StreamChannel<String>`.
Data sent over the wire looks like the following:
@ -219,14 +202,11 @@ In the case of Isolate clients/servers, events will be simply sent as Lists:
['<event-name>', value]
```
Clients can send the following (3) methods:
Clients can send with the following 3 methods:
* `subscribe` (`event_name`:string): Subscribe to an event.
* `unsubscribe` (`subscription_id`:string): Unsubscribe from an event you previously subscribed to.
* `publish` (`event_name`:string, `value`:any): Publish an event to all other clients who are subscribed.
The client and server in `package:belatuk_pub_sub/isolate.dart` must make extra
provisions to keep track of client ID's. Since `SendPort`s and `ReceivePort`s
do not have any sort of guaranteed-unique ID's, new clients must send their
`SendPort` to the server before sending any requests. The server then responds
The client and server in `package:belatuk_pub_sub/isolate.dart` must make extra provisions to keep track of client ID's. Since `SendPort`s and `ReceivePort`s do not have any sort of guaranteed-unique ID's, new clients must send their `SendPort` to the server before sending any requests. The server then responds
with an `id` that must be used to identify a `SendPort` to send a response to.

View file

@ -1,19 +1,20 @@
import 'dart:io';
import 'dart:isolate';
import 'package:belatuk_pub_sub/isolate.dart' as pub_sub;
import 'package:belatuk_pub_sub/belatuk_pub_sub.dart' as pub_sub;
import 'package:belatuk_pub_sub/isolate.dart';
import 'package:belatuk_pub_sub/belatuk_pub_sub.dart';
void main() async {
// Easily bring up a server.
var adapter = pub_sub.IsolateAdapter();
var server = pub_sub.Server([adapter]);
var adapter = IsolateAdapter();
var server = Server([adapter]);
// You then need to create a client that will connect to the adapter.
// Every untrusted client in your application should be pre-registered.
//
// In the case of Isolates, however, those are always implicitly trusted.
print("Register Client");
for (var i = 0; i < Platform.numberOfProcessors - 1; i++) {
server.registerClient(pub_sub.ClientInfo('client$i'));
server.registerClient(ClientInfo('client$i'));
}
// Start the server.
@ -22,6 +23,7 @@ void main() async {
// Next, let's start isolates that interact with the server.
//
// Fortunately, we can send SendPorts over Isolates, so this is no hassle.
print("Create Isolate");
for (var i = 0; i < Platform.numberOfProcessors - 1; i++) {
await Isolate.spawn(isolateMain, [i, adapter.receivePort.sendPort]);
}
@ -32,7 +34,7 @@ void main() async {
void isolateMain(List args) {
// Isolates are always trusted, so technically we don't need to pass a client iD.
var client = pub_sub.IsolateClient('client${args[0]}', args[1] as SendPort);
var client = IsolateClient('client${args[0]}', args[1] as SendPort);
// The client will connect automatically. In the meantime, we can start subscribing to events.
client.subscribe('user::logged_in').then((sub) {

View file

@ -2,7 +2,9 @@ import 'dart:async';
import 'dart:collection';
import 'dart:isolate';
import 'package:uuid/uuid.dart';
import '../../belatuk_pub_sub.dart';
import '../protocol/protocol.dart';
import 'shared.dart';
/// A [Client] implementation that communicates via [SendPort]s and [ReceivePort]s.
class IsolateClient extends Client {
@ -29,33 +31,39 @@ class IsolateClient extends Client {
IsolateClient(String? clientId, this.serverSendPort) {
_clientId = clientId;
receivePort.listen((data) {
if (data is Map && data['request_id'] is String) {
var requestId = data['request_id'] as String?;
var c = _requests.remove(requestId);
if (data is Map<String, Object?>) {
var (status, id, requestId, result, errorMessage) =
MessageHandler().decodeResponseMessage(data);
if (c != null && !c.isCompleted) {
if (data['status'] is! bool) {
c.completeError(
FormatException('The server sent an invalid response.'));
} else if (!(data['status'] as bool)) {
c.completeError(PubSubException(data['error_message']?.toString() ??
'The server sent a failure response, but did not provide an error message.'));
} else if (data['result'] is! Map) {
c.completeError(FormatException(
'The server sent a success response, but did not include a result.'));
} else {
c.complete(data['result'] as Map?);
if (requestId != null) {
//var requestId = data['request_id'] as String?;
var c = _requests.remove(requestId);
if (c != null && !c.isCompleted) {
//if (data['status'] is! bool) {
// c.completeError(
// FormatException('The server sent an invalid response.'));
//} else if (!(data['status'] as bool)) {
if (!status) {
c.completeError(PubSubException(errorMessage ??
'The server sent a failure response, but did not provide an error message.'));
} else if (result is! Map) {
c.completeError(FormatException(
'The server sent a success response, but did not include a result.'));
} else {
c.complete(result);
}
}
}
} else if (data is Map && data['id'] is String && _id == null) {
_id = data['id'] as String?;
} else if (id != null && _id == null) {
_id = id;
for (var c in _onConnect) {
if (!c.isCompleted) c.complete(_id);
}
for (var c in _onConnect) {
if (!c.isCompleted) c.complete(_id);
}
_onConnect.clear();
} else if (data is List && data.length == 2 && data[0] is String) {
_onConnect.clear();
}
} else if (data is List) {
var eventName = data[0] as String;
var event = data[1];
for (var s in _subscriptions.where((s) => s.eventName == eventName)) {
@ -82,18 +90,13 @@ class IsolateClient extends Client {
var c = Completer<Map>();
var requestId = _uuid.v4();
_requests[requestId] = c;
serverSendPort.send({
'id': _id,
'request_id': requestId,
'method': 'publish',
'params': {
'client_id': clientId,
'event_name': eventName,
'value': value
}
});
serverSendPort.send(MessageHandler().encodePublishRequestMessage(
_id, requestId, clientId, eventName, value));
return c.future.then((result) {
_clientId = result['client_id'] as String?;
var (_, clientId) = MessageHandler()
.decodePublishResponseMessage(result as Map<String, Object?>);
_clientId = clientId;
});
});
}
@ -104,16 +107,14 @@ class IsolateClient extends Client {
var c = Completer<Map>();
var requestId = _uuid.v4();
_requests[requestId] = c;
serverSendPort.send({
'id': _id,
'request_id': requestId,
'method': 'subscribe',
'params': {'client_id': clientId, 'event_name': eventName}
});
serverSendPort.send(MessageHandler().encodeSubscriptionRequestMessage(
_id, requestId, clientId, eventName));
return c.future.then<ClientSubscription>((result) {
_clientId = result['client_id'] as String?;
var s = _IsolateClientSubscription(
eventName, result['subscription_id'] as String?, this);
var (subcriptionId, clientId) = MessageHandler()
.decodeSubscriptionResponseMessage(result as Map<String, Object?>);
_clientId = clientId;
var s = _IsolateClientSubscription(eventName, subcriptionId, this);
_subscriptions.add(s);
return s;
});
@ -171,14 +172,11 @@ class _IsolateClientSubscription extends ClientSubscription {
var c = Completer<Map>();
var requestId = client._uuid.v4();
client._requests[requestId] = c;
client.serverSendPort.send({
'id': client._id,
'request_id': requestId,
'method': 'unsubscribe',
'params': {'client_id': client.clientId, 'subscription_id': id}
});
client.serverSendPort.send(MessageHandler()
.encodeUnsubscriptionRequestMessage(
client._id, requestId, client.clientId, id));
return c.future.then((_) {
return c.future.then((result) {
_close();
});
});

View file

@ -1,7 +1,8 @@
import 'dart:async';
import 'dart:isolate';
import 'package:uuid/uuid.dart';
import '../../belatuk_pub_sub.dart';
import '../protocol/protocol.dart';
import 'shared.dart';
/// A [Adapter] implementation that communicates via [SendPort]s and [ReceivePort]s.
class IsolateAdapter extends Adapter {
@ -42,81 +43,50 @@ class IsolateAdapter extends Adapter {
if (data is SendPort) {
var id = _uuid.v4();
_clients[id] = data;
data.send({'status': true, 'id': id});
} else if (data is Map &&
data['id'] is String &&
data['request_id'] is String &&
data['method'] is String &&
data['params'] is Map) {
var id = data['id'] as String?,
requestId = data['request_id'] as String?,
method = data['method'] as String?;
var params = data['params'] as Map?;
var sp = _clients[id!];
data.send(MessageHandler().encodeSendPortResponseMessage(id));
} else if (data is Map<String, Object?>) {
var (id, method, requestId, params) =
MessageHandler().decodeRequestMessage(data);
var (clientId, eventName, subscriptionId, value) =
MessageHandler().decodeRequestParams(params);
var sp = _clients[id];
if (sp == null) {
// There's nobody to respond to, so don't send anything to anyone. Oops.
} else if (method == 'publish') {
if (_isValidClientId(params!['client_id']) &&
params['event_name'] is String &&
params.containsKey('value')) {
var clientId = params['client_id'] as String?,
eventName = params['event_name'] as String?;
var value = params['value'];
var rq = _IsolatePublishRequestImpl(
requestId, clientId, eventName, value, sp);
_onPublish.add(rq);
} else {
sp.send({
'status': false,
'request_id': requestId,
'error_message': 'Expected client_id, event_name, and value.'
});
// There's nobody to respond to, so don't send anything to anyone
return;
}
if (method == 'publish') {
if (eventName == null || value == null) {
sp.send(MessageHandler().encodePublishResponseError(requestId));
}
var rq = _IsolatePublishRequestImpl(
requestId, clientId, eventName, value, sp);
_onPublish.add(rq);
} else if (method == 'subscribe') {
if (_isValidClientId(params!['client_id']) &&
params['event_name'] is String) {
var clientId = params['client_id'] as String?,
eventName = params['event_name'] as String?;
var rq = _IsolateSubscriptionRequestImpl(
clientId, eventName, sp, requestId, _uuid);
_onSubscribe.add(rq);
} else {
sp.send({
'status': false,
'request_id': requestId,
'error_message': 'Expected client_id, and event_name.'
});
if (eventName == null) {
sp.send(
MessageHandler().encodeSubscriptionResponseError(requestId));
}
var rq = _IsolateSubscriptionRequestImpl(
clientId, eventName, sp, requestId, _uuid);
_onSubscribe.add(rq);
} else if (method == 'unsubscribe') {
if (_isValidClientId(params!['client_id']) &&
params['subscription_id'] is String) {
var clientId = params['client_id'] as String?,
subscriptionId = params['subscription_id'] as String?;
var rq = _IsolateUnsubscriptionRequestImpl(
clientId, subscriptionId, sp, requestId);
_onUnsubscribe.add(rq);
} else {
sp.send({
'status': false,
'request_id': requestId,
'error_message': 'Expected client_id, and subscription_id.'
});
if (subscriptionId == null) {
sp.send(
MessageHandler().encodeUnsubscriptionResponseError(requestId));
}
var rq = _IsolateUnsubscriptionRequestImpl(
clientId, subscriptionId, sp, requestId);
_onUnsubscribe.add(rq);
} else {
sp.send({
'status': false,
'request_id': requestId,
'error_message':
'Unrecognized method "$method". Or, you omitted id, request_id, method, or params.'
});
sp.send(MessageHandler()
.encodeUnknownMethodResponseError(requestId, method));
}
}
});
}
bool _isValidClientId(id) => id == null || id is String;
@override
bool isTrustedPublishRequest(PublishRequest request) {
// Isolate clients are considered trusted, because they are
@ -138,7 +108,7 @@ class _IsolatePublishRequestImpl extends PublishRequest {
final String? eventName;
@override
final dynamic value;
final Object? value;
final SendPort sendPort;
@ -148,24 +118,15 @@ class _IsolatePublishRequestImpl extends PublishRequest {
this.requestId, this.clientId, this.eventName, this.value, this.sendPort);
@override
void accept(PublishResponse response) {
sendPort.send({
'status': true,
'request_id': requestId,
'result': {
'listeners': response.listeners,
'client_id': response.clientId
}
});
void reject(String errorMessage) {
sendPort.send(MessageHandler()
.encodePublishResponseError(requestId, errorMessage: errorMessage));
}
@override
void reject(String errorMessage) {
sendPort.send({
'status': false,
'request_id': requestId,
'error_message': errorMessage
});
void accept(PublishResponse response) {
sendPort.send(MessageHandler().encodePublishResponseMessage2(
requestId, response.listeners, response.clientId));
}
}
@ -187,21 +148,15 @@ class _IsolateSubscriptionRequestImpl extends SubscriptionRequest {
@override
void reject(String errorMessage) {
sendPort.send({
'status': false,
'request_id': requestId,
'error_message': errorMessage
});
sendPort.send(MessageHandler().encodeSubscriptionResponseError(requestId,
errorMessage: errorMessage));
}
@override
FutureOr<Subscription> accept(String? clientId) {
var id = _uuid.v4();
sendPort.send({
'status': true,
'request_id': requestId,
'result': {'subscription_id': id, 'client_id': clientId}
});
sendPort.send(MessageHandler()
.encodeSubscriptionResponseMessage(requestId, id, clientId));
return _IsolateSubscriptionImpl(clientId, id, eventName, sendPort);
}
}
@ -239,15 +194,13 @@ class _IsolateUnsubscriptionRequestImpl extends UnsubscriptionRequest {
@override
void reject(String errorMessage) {
sendPort.send({
'status': false,
'request_id': requestId,
'error_message': errorMessage
});
sendPort.send(MessageHandler().encodeUnsubscriptionResponseError(requestId,
errorMessage: errorMessage));
}
@override
void accept() {
sendPort.send({'status': true, 'request_id': requestId, 'result': {}});
sendPort
.send(MessageHandler().encodeUnsubscriptionResponseMessage(requestId));
}
}

View file

@ -0,0 +1,183 @@
/// A message handler class that handles the encoding/decoding of messages send
/// between isolate [Client] and [Server].
class MessageHandler {
static const _requestId = 'request_id';
static const _method = 'method';
static const _clientId = 'client_id';
static const _eventName = 'event_name';
static const _subscriptionId = 'subscription_id';
static const _errorMessage = 'error_message';
static const _value = 'value';
static const _id = 'id';
static const _params = 'params';
static const _status = 'status';
static const _result = 'result';
static const _listeners = 'listeners';
static const _publishErrorMsg = 'Expected client_id, event_name, and value';
static const _subscribeErrorMsg = 'Expected client_id, and event_name';
static const _unsubscribeErrorMsg = 'Expected client_id, and subscription_id';
const MessageHandler();
Map<String, dynamic> encodePublishResponseError(String? requestId,
{String errorMessage = _publishErrorMsg}) {
return _encodeResponseError(requestId, errorMessage);
}
Map<String, dynamic> encodeSubscriptionResponseError(String? requestId,
{String errorMessage = _subscribeErrorMsg}) {
return _encodeResponseError(requestId, errorMessage);
}
Map<String, dynamic> encodeUnsubscriptionResponseError(String? requestId,
{String errorMessage = _unsubscribeErrorMsg}) {
return _encodeResponseError(requestId, errorMessage);
}
Map<String, dynamic> encodeUnknownMethodResponseError(
String? requestId, String method) {
var unknownMethodErrorMsg =
'Unrecognized method "$method" or you have omitted id, request_id, method, or params';
return _encodeResponseError(requestId, unknownMethodErrorMsg);
}
Map<String, dynamic> _encodeResponseError(String? requestId, String message) {
return {
_status: false,
_requestId: requestId ?? '',
_errorMessage: message
};
}
Map<String, dynamic> encodeEventMessage(String? requestId, Object message) {
return {_status: true, _requestId: requestId ?? '', _result: message};
}
Map<String, dynamic> encodeSubscriptionResponseMessage(
String? requestId, String? subscriptionId, String? clientId) {
return {
_status: true,
_requestId: requestId ?? '',
_result: {_subscriptionId: subscriptionId, _clientId: clientId}
};
}
(String?, String?) decodeSubscriptionResponseMessage(
Map<String, Object?> message) {
var subscriptionId = message[_subscriptionId] as String?;
var clientId = message[_clientId] as String?;
return (subscriptionId, clientId);
}
Map<String, dynamic> encodeUnsubscriptionResponseMessage(String? requestId) {
return {_status: true, _requestId: requestId, _result: {}};
}
(bool, String?, Object?, String?) decodeUnsubscriptionResponseMessage(
Map<String, Object?> message) {
var status = message[_status] as bool? ?? false;
var requestId = message[_requestId] as String?;
var result = message[_result];
var errorMessage = message[_errorMessage] as String?;
return (status, requestId, result, errorMessage);
}
Map<String, Object?> encodePublishResponseMessage2(
String? requestId, int listeners, String? clientId) {
return {
_status: true,
_requestId: requestId,
_result: {_listeners: listeners, _clientId: clientId}
};
}
(int, String?) decodePublishResponseMessage(Map<String, Object?> message) {
var listeners = message[_listeners] as int;
var clientId = message[_clientId] as String?;
return (listeners, clientId);
}
Map<String, Object?> encodePublishResponseMessage(String? id,
String? requestId, String? clientId, String? eventName, Object? value) {
return {
_id: id,
_requestId: requestId,
_method: 'publish',
_params: {_clientId: clientId, _eventName: eventName, _value: value}
};
}
Map<String, dynamic> encodeResponseMessage(
String? requestId, Object message) {
return {_status: true, _requestId: requestId ?? '', _result: message};
}
(bool, String?, String?, Object?, String?) decodeResponseMessage(
Map<String, Object?> message) {
var id = message[_id] as String?;
var status = message[_status] as bool? ?? false;
var requestId = message[_requestId] as String?;
var result = message[_result];
var errorMessage = message[_errorMessage] as String?;
return (status, id, requestId, result, errorMessage);
}
(String, String, String, Map<String, Object?>) decodeRequestMessage(
Map<String, Object?> message) {
var id = message[_id] as String? ?? '';
var method = message[_method] as String? ?? '';
var requestId = message[_requestId] as String? ?? '';
var params = message[_params] as Map<String, Object?>? ?? {};
return (id, method, requestId, params);
}
Map<String, Object?> encodeSubscriptionRequestMessage(
String? id, String? requestId, String? clientId, String? eventName) {
return {
_id: id,
_requestId: requestId,
_method: 'subscribe',
_params: {_clientId: clientId, _eventName: eventName}
};
}
Map<String, Object?> encodeUnsubscriptionRequestMessage(
String? id, String? requestId, String? clientId, String? subscriptionId) {
return {
_id: id,
_requestId: requestId,
_method: 'unsubscribe',
_params: {_clientId: clientId, _subscriptionId: subscriptionId}
};
}
Map<String, Object?> encodePublishRequestMessage(String? id,
String? requestId, String? clientId, String? eventName, Object? value) {
return {
_id: id,
_requestId: requestId,
_method: 'publish',
_params: {_clientId: clientId, _eventName: eventName, _value: value}
};
}
(String?, String?, String?, Object?) decodeRequestParams(
Map<String, Object?> params) {
var clientId = params[_clientId] as String?;
var eventName = params[_eventName] as String?;
var value = params[_value];
var subscriptionId = params[_subscriptionId] as String?;
return (clientId, eventName, subscriptionId, value);
}
Map<String, Object> encodeSendPortResponseMessage(String id) {
return {_status: true, _id: id};
}
}

View file

@ -7,7 +7,7 @@ abstract class PublishRequest {
String? get eventName;
/// The value to be published as an event.
dynamic get value;
Object? get value;
/// Accept the request, with a response.
void accept(PublishResponse response);

View file

@ -1,14 +1,14 @@
name: belatuk_pub_sub
version: 6.0.0
version: 6.3.0
description: Keep application instances in sync with a simple pub/sub API.
homepage: https://github.com/dart-backend/belatuk-common-utilities/tree/main/packages/pub_sub
environment:
sdk: '>=3.0.0 <4.0.0'
sdk: '>=3.3.0 <4.0.0'
dependencies:
json_rpc_2: ^3.0.0
stream_channel: ^2.1.0
uuid: ^3.0.4
uuid: ^4.0.0
collection: ^1.17.0
dev_dependencies:
lints: ^2.0.0
test: ^1.24.0
lints: ^4.0.0

View file

@ -157,7 +157,7 @@ class _SocketStreamChannel extends StreamChannelMixin<List<int>> {
Stream<List<int>> get stream => socket;
}
class _SocketSink extends StreamSink<List<int>> {
class _SocketSink implements StreamSink<List<int>> {
final Socket socket;
_SocketSink(this.socket);

View file

@ -1,8 +1,22 @@
# Change Log
## 6.3.0
* Require Dart >= 3.3
* Updated `lints` to 4.0.0
## 6.2.0
* Updated `lints` to 3.0.0
## 6.1.0
* Updated `file` to 7.0.0
## 6.0.0
* Require Dart >= 3.0
* Updated all dependencies to latest
## 6.0.0-beta.1

View file

@ -14,7 +14,7 @@ In your `pubspec.yaml`:
```yaml
dependencies:
belatuk_range_header: ^6.0.0
belatuk_range_header: ^6.2.0
```
## Usage

View file

@ -1,9 +1,9 @@
name: belatuk_range_header
version: 6.0.0
version: 6.3.0
description: Range header parser for Dart. Beyond parsing, a stream transformer is included.
homepage: https://github.com/dart-backend/belatuk-common-utilities/tree/main/packages/range_header
environment:
sdk: '>=3.0.0 <4.0.0'
sdk: '>=3.3.0 <4.0.0'
dependencies:
async: ^2.11.0
charcode: ^1.3.0
@ -11,8 +11,8 @@ dependencies:
source_span: ^1.10.0
string_scanner: ^1.2.0
dev_dependencies:
file: ^6.1.0
file: ^7.0.0
http_parser: ^4.0.0
logging: ^1.0.1
test: ^1.24.0
lints: ^2.0.0
lints: ^4.0.0

View file

@ -1,5 +1,15 @@
# Change Log
## 5.2.0
* Require Dart >= 3.3
* Updated `lints` to 4.0.0
## 5.1.0
* Updated `lints` to 3.0.0
* Fixed lints warnings
## 5.0.0
* Require Dart >= 3.0

View file

@ -30,8 +30,7 @@ foo.value = 'baz'; // Also throws a StateError - Once a variable is locked, it c
## Visibility
Variables are *public* by default, but can also be marked as *private* or *protected*. This can be helpful if you are trying
to determine which symbols should be exported from a library or class.
Variables are *public* by default, but can also be marked as *private* or *protected*. This can be helpful if you are trying to determine which symbols should be exported from a library or class.
```dart
myVariable.visibility = Visibility.protected;

View file

@ -1,4 +1,4 @@
part of symbol_table;
part of 'symbol_table.dart';
/// Holds a symbol, the value of which may change or be marked immutable.
class Variable<T> {

View file

@ -1,4 +1,4 @@
part of symbol_table;
part of 'symbol_table.dart';
/// Represents the visibility of a symbol.
///

View file

@ -1,11 +1,11 @@
name: belatuk_symbol_table
version: 5.0.0
version: 5.2.0
description: A generic symbol table implementation in Dart, with support for scopes and constants.
homepage: https://github.com/dart-backend/belatuk-common-utilities/tree/main/packages/symbol_table
environment:
sdk: '>=3.0.0 <4.0.0'
sdk: '>=3.3.0 <4.0.0'
dependencies:
collection: ^1.17.0
dev_dependencies:
test: ^1.24.0
lints: ^2.0.0
lints: ^4.0.0

View file

@ -1,5 +1,14 @@
# Change Log
## 5.2.0
* Require Dart >= 3.3
* Updated `lints` to 4.0.0
## 5.1.0
* Updated `lints` to 3.0.0
## 5.0.0
* Require Dart >= 3.0

View file

@ -1,9 +1,9 @@
name: user_agent_analyzer
version: 5.0.0
version: 5.2.0
description: A library to identify the type of devices and web browsers based on User-Agent string.
homepage: https://github.com/dart-backend/belatuk-common-utilities/tree/main/packages/user_agent
environment:
sdk: '>=3.0.0 <4.0.0'
sdk: '>=3.3.0 <4.0.0'
dev_dependencies:
test: ^1.24.0
lints: ^2.0.0
lints: ^4.0.0

View file

@ -1,6 +1,6 @@
name: belatuk_common_utilities_workspace
environment:
sdk: '>=2.18.0 <4.0.0'
sdk: '>=3.3.0 <4.0.0'
dev_dependencies:
melos: ^3.0.0
melos: ^6.0.0