Skip to content

Commit 889e7d3

Browse files
committed
Create a package that implements a JSON-RPC 2.0 server.
[email protected] BUG=17492 Review URL: https://codereview.chromium.org//205533005 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@34223 260f80e4-7a28-3924-810f-c04153c831b5
1 parent eae510d commit 889e7d3

14 files changed

+1526
-0
lines changed

pkg/json_rpc_2/LICENSE

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Copyright 2014, the Dart project authors. All rights reserved.
2+
Redistribution and use in source and binary forms, with or without
3+
modification, are permitted provided that the following conditions are
4+
met:
5+
6+
* Redistributions of source code must retain the above copyright
7+
notice, this list of conditions and the following disclaimer.
8+
* Redistributions in binary form must reproduce the above
9+
copyright notice, this list of conditions and the following
10+
disclaimer in the documentation and/or other materials provided
11+
with the distribution.
12+
* Neither the name of Google Inc. nor the names of its
13+
contributors may be used to endorse or promote products derived
14+
from this software without specific prior written permission.
15+
16+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

pkg/json_rpc_2/README.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
A library that implements the [JSON-RPC 2.0 spec][spec].
2+
3+
[spec]: http://www.jsonrpc.org/specification
4+
5+
## Server
6+
7+
A JSON-RPC 2.0 server exposes a set of methods that can be called by clients.
8+
These methods can be registered using `Server.registerMethod`:
9+
10+
```dart
11+
import "package:json_rpc_2/json_rpc_2.dart" as json_rpc;
12+
13+
var server = new json_rpc.Server();
14+
15+
// Any string may be used as a method name. JSON-RPC 2.0 methods are
16+
// case-sensitive.
17+
var i = 0;
18+
server.registerMethod("count", () {
19+
// Just return the value to be sent as a response to the client. This can be
20+
// anything JSON-serializable, or a Future that completes to something
21+
// JSON-serializable.
22+
return i++;
23+
});
24+
25+
// Methods can take parameters. They're presented as a [Parameters] object which
26+
// makes it easy to validate that the expected parameters exist.
27+
server.registerMethod("echo", (params) {
28+
// If the request doesn't have a "message" parameter, this will automatically
29+
// send a response notifying the client that the request was invalid.
30+
return params.getNamed("message");
31+
});
32+
33+
// [Parameters] has methods for verifying argument types.
34+
server.registerMethod("subtract", (params) {
35+
// If "minuend" or "subtrahend" aren't numbers, this will reject the request.
36+
return params.getNum("minuend") - params.getNum("subtrahend");
37+
});
38+
39+
// [Parameters] also supports optional arguments.
40+
server.registerMethod("sort", (params) {
41+
var list = params.getList("list");
42+
list.sort();
43+
if (params.getBool("descending", orElse: () => false)) {
44+
return params.list.reversed;
45+
} else {
46+
return params.list;
47+
}
48+
});
49+
50+
// A method can send an error response by throwing a `json_rpc.RpcException`.
51+
// Any positive number may be used as an application-defined error code.
52+
const DIVIDE_BY_ZERO = 1;
53+
server.registerMethod("divide", (params) {
54+
var divisor = params.getNum("divisor");
55+
if (divisor == 0) {
56+
throw new json_rpc.RpcException(DIVIDE_BY_ZERO, "Cannot divide by zero.");
57+
}
58+
59+
return params.getNum("dividend") / divisor;
60+
});
61+
```
62+
63+
Once you've registered your methods, you can handle requests with
64+
`Server.parseRequest`:
65+
66+
```dart
67+
import 'dart:io';
68+
69+
WebSocket.connect('ws://localhost:4321').then((socket) {
70+
socket.listen((message) {
71+
server.parseRequest(message).then((response) {
72+
if (response != null) socket.add(response);
73+
});
74+
});
75+
});
76+
```
77+
78+
If you're communicating with objects that haven't been serialized to a string,
79+
you can also call `Server.handleRequest` directly:
80+
81+
```dart
82+
import 'dart:isolate';
83+
84+
var receive = new ReceivePort();
85+
Isolate.spawnUri('path/to/client.dart', [], receive.sendPort).then((_) {
86+
receive.listen((message) {
87+
server.handleRequest(message['request']).then((response) {
88+
if (response != null) message['respond'].send(response);
89+
});
90+
});
91+
})
92+
```
93+
94+
## Client
95+
96+
Currently this package does not contain an implementation of a JSON-RPC 2.0
97+
client.
98+

pkg/json_rpc_2/lib/error_code.dart

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// Error codes defined in the [JSON-RPC 2.0 specificiation][spec].
6+
///
7+
/// These codes are generally used for protocol-level communication. Most of
8+
/// them shouldn't be used by the application. Those that should have
9+
/// convenience constructors in [RpcException].
10+
///
11+
/// [spec]: http://www.jsonrpc.org/specification#error_object
12+
library json_rpc_2.error_code;
13+
14+
/// An error code indicating that invalid JSON was received by the server.
15+
const PARSE_ERROR = -32700;
16+
17+
/// An error code indicating that the request JSON was invalid according to the
18+
/// JSON-RPC 2.0 spec.
19+
const INVALID_REQUEST = -32600;
20+
21+
/// An error code indicating that the requested method does not exist or is
22+
/// unavailable.
23+
const METHOD_NOT_FOUND = -32601;
24+
25+
/// An error code indicating that the request paramaters are invalid for the
26+
/// requested method.
27+
const INVALID_PARAMS = -32602;
28+
29+
/// An internal JSON-RPC error.
30+
const INTERNAL_ERROR = -32603;
31+
32+
/// An unexpected error occurred on the server.
33+
///
34+
/// The spec reserves the range from -32000 to -32099 for implementation-defined
35+
/// server exceptions, but for now we only use one of those values.
36+
const SERVER_ERROR = -32000;

pkg/json_rpc_2/lib/json_rpc_2.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
library json_rpc_2;
6+
7+
export 'src/exception.dart';
8+
export 'src/parameters.dart';
9+
export 'src/server.dart';

pkg/json_rpc_2/lib/src/exception.dart

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
library json_rpc_2.exception;
6+
7+
import '../error_code.dart' as error_code;
8+
9+
/// An exception from a JSON-RPC server that can be translated into an error
10+
/// response.
11+
class RpcException implements Exception {
12+
/// The error code.
13+
///
14+
/// All non-negative error codes are available for use by application
15+
/// developers.
16+
final int code;
17+
18+
/// The error message.
19+
///
20+
/// This should be limited to a concise single sentence. Further information
21+
/// should be supplied via [data].
22+
final String message;
23+
24+
/// Extra application-defined information about the error.
25+
///
26+
/// This must be a JSON-serializable object. If it's a [Map] without a
27+
/// `"request"` key, a copy of the request that caused the error will
28+
/// automatically be injected.
29+
final data;
30+
31+
RpcException(this.code, this.message, {this.data});
32+
33+
/// An exception indicating that the method named [methodName] was not found.
34+
///
35+
/// This should usually be used only by fallback handlers.
36+
RpcException.methodNotFound(String methodName)
37+
: this(error_code.METHOD_NOT_FOUND, 'Unknown method "$methodName".');
38+
39+
/// An exception indicating that the parameters for the requested method were
40+
/// invalid.
41+
///
42+
/// Methods can use this to reject requests with invalid parameters.
43+
RpcException.invalidParams(String message)
44+
: this(error_code.INVALID_PARAMS, message);
45+
46+
/// Converts this exception into a JSON-serializable object that's a valid
47+
/// JSON-RPC 2.0 error response.
48+
serialize(request) {
49+
var modifiedData;
50+
if (data is Map && !data.containsKey('request')) {
51+
modifiedData = new Map.from(data);
52+
modifiedData['request'] = request;
53+
} else if (data == null) {
54+
modifiedData = {'request': request};
55+
}
56+
57+
var id = request is Map ? request['id'] : null;
58+
if (id is! String && id is! num) id = null;
59+
return {
60+
'jsonrpc': '2.0',
61+
'error': {'code': code, 'message': message, 'data': modifiedData},
62+
'id': id
63+
};
64+
}
65+
}

0 commit comments

Comments
 (0)