@qooxdoo/framework 7.0.0-beta.3 → 7.0.0-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -0
- package/Manifest.json +1 -1
- package/README.md +9 -3
- package/lib/compiler/compile-info.json +60 -58
- package/lib/compiler/index.js +3242 -1883
- package/lib/resource/qx/tool/cli/templates/skeleton/mobile/source/theme/custom/css/custom.css.map +1 -1
- package/lib/resource/qx/tool/loadsass.js +6 -4
- package/lib/resource/qx/tool/schema/compile-1-0-0.json +6 -11
- package/package.json +17 -3
- package/source/class/qx/Bootstrap.js +22 -1
- package/source/class/qx/bom/Blocker.js +2 -1
- package/source/class/qx/core/Environment.js +3 -12
- package/source/class/qx/core/MProperty.js +1 -1
- package/source/class/qx/dev/unit/Sinon.js +1 -1
- package/source/class/qx/io/__init__.js +5 -3
- package/source/class/qx/io/exception/Cancel.js +34 -0
- package/source/class/qx/io/exception/Exception.js +38 -0
- package/source/class/qx/io/exception/Protocol.js +26 -0
- package/source/class/qx/io/exception/Transport.js +39 -0
- package/source/class/qx/io/exception/__init__.js +4 -0
- package/source/class/qx/io/graphql/Client.js +112 -0
- package/source/class/qx/io/graphql/__init__.js +9 -0
- package/source/class/qx/io/graphql/protocol/Message.js +65 -0
- package/source/class/qx/io/graphql/protocol/Request.js +95 -0
- package/source/class/qx/io/graphql/protocol/Response.js +61 -0
- package/source/class/qx/io/graphql/protocol/__init__.js +6 -0
- package/source/class/qx/io/jsonrpc/Client.js +323 -0
- package/source/class/qx/io/jsonrpc/__init__.js +15 -0
- package/source/class/qx/io/jsonrpc/protocol/Batch.js +97 -0
- package/source/class/qx/io/jsonrpc/protocol/Error.js +63 -0
- package/source/class/qx/io/jsonrpc/protocol/Message.js +48 -0
- package/source/class/qx/io/jsonrpc/protocol/Notification.js +45 -0
- package/source/class/qx/io/jsonrpc/protocol/Parser.js +81 -0
- package/source/class/qx/io/jsonrpc/protocol/Request.js +93 -0
- package/source/class/qx/io/jsonrpc/protocol/Result.js +48 -0
- package/source/class/qx/io/jsonrpc/protocol/__init__.js +5 -0
- package/source/class/qx/io/request/authentication/Bearer.js +52 -0
- package/source/class/qx/io/transport/AbstractClient.js +100 -0
- package/source/class/qx/io/transport/AbstractTransport.js +41 -0
- package/source/class/qx/io/transport/Fetch.js +95 -0
- package/source/class/qx/io/transport/ITransport.js +40 -0
- package/source/class/qx/io/transport/PostMessage.js +55 -0
- package/source/class/qx/io/transport/Websocket.js +97 -0
- package/source/class/qx/io/transport/Xhr.js +139 -0
- package/source/class/qx/io/transport/__init__.js +18 -0
- package/source/class/qx/test/core/Assert.js +1 -1
- package/source/class/qx/test/core/Environment.js +0 -3
- package/source/class/qx/test/io/MAssert.js +46 -0
- package/source/class/qx/test/io/graphql/Client.js +169 -0
- package/source/class/qx/test/io/graphql/ClientFetch.js +34 -0
- package/source/class/qx/test/io/graphql/Request.js +42 -0
- package/source/class/qx/test/io/jsonrpc/Client.js +267 -0
- package/source/class/qx/test/io/jsonrpc/Protocol.js +80 -0
- package/source/class/qx/test/io/transport/PostMessage.js +56 -0
- package/source/class/qx/test/io/transport/Websocket.js +63 -0
- package/source/class/qx/test/ui/embed/Iframe.js +1 -1
- package/source/class/qx/test/util/DateFormat.js +45 -6
- package/source/class/qx/tool/cli/Cli.js +1 -0
- package/source/class/qx/tool/cli/commands/Compile.js +13 -3
- package/source/class/qx/tool/cli/commands/Es6ify.js +93 -0
- package/source/class/qx/tool/cli/commands/package/Install.js +1 -1
- package/source/class/qx/tool/cli/commands/package/Publish.js +14 -0
- package/source/class/qx/tool/compiler/ClassFile.js +67 -27
- package/source/class/qx/tool/compiler/Es6ify.js +368 -0
- package/source/class/qx/tool/compiler/makers/AppMaker.js +2 -1
- package/source/class/qx/tool/compiler/targets/Target.js +57 -47
- package/source/class/qx/tool/compiler/targets/meta/AbstractJavascriptMeta.js +25 -18
- package/source/class/qx/tool/compiler/targets/meta/BootJs.js +16 -16
- package/source/class/qx/tool/compiler/targets/meta/PolyfillJs.js +11 -3
- package/source/class/qx/tool/compiler/targets/meta/Uglify.js +10 -10
- package/source/class/qx/ui/core/Widget.js +70 -0
- package/source/class/qx/ui/decoration/MLinearBackgroundGradient.js +2 -1
- package/source/class/qx/ui/form/ComboBox.js +8 -3
- package/source/class/qx/ui/form/DateField.js +16 -1
- package/source/class/qx/ui/form/MenuButton.js +8 -4
- package/source/class/qx/ui/form/SelectBox.js +8 -3
- package/source/class/qx/ui/menu/AbstractButton.js +12 -8
- package/source/class/qx/ui/menu/Menu.js +18 -8
- package/source/class/qx/ui/table/pane/Model.js +10 -4
- package/source/class/qx/ui/window/Window.js +8 -0
- package/source/class/qx/util/format/DateFormat.js +44 -17
- package/source/resource/qx/tool/loadsass.js +6 -4
- package/source/resource/qx/tool/schema/compile-1-0-0.json +6 -11
- package/source/translation/hr.po +297 -0
- package/lib/resource/qx/static/blank.gif +0 -0
- package/source/class/qx/io/remote/Exchange.js +0 -1063
- package/source/class/qx/io/remote/Request.js +0 -1021
- package/source/class/qx/io/remote/RequestQueue.js +0 -521
- package/source/class/qx/io/remote/Response.js +0 -137
- package/source/class/qx/io/remote/Rpc.js +0 -1075
- package/source/class/qx/io/remote/RpcError.js +0 -198
- package/source/class/qx/io/remote/__init__.js +0 -88
- package/source/class/qx/io/remote/transport/Abstract.js +0 -513
- package/source/class/qx/io/remote/transport/Iframe.js +0 -652
- package/source/class/qx/io/remote/transport/Script.js +0 -475
- package/source/class/qx/io/remote/transport/XmlHttp.js +0 -1019
- package/source/class/qx/io/remote/transport/__init__.js +0 -3
- package/source/class/qx/test/io/remote/AbstractRequest.js +0 -150
- package/source/class/qx/test/io/remote/RequestIframe.js +0 -105
- package/source/class/qx/test/io/remote/RequestXhr.js +0 -151
- package/source/class/qx/test/io/remote/Rpc.js +0 -205
- package/source/class/qx/test/io/remote/__init__.js +0 -4
- package/source/class/qx/test/io/remote/transport/Iframe.js +0 -67
- package/source/class/qx/test/io/remote/transport/XmlHttp.js +0 -133
- package/source/class/qx/test/io/remote/transport/__init__.js +0 -4
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/* ************************************************************************
|
|
2
|
+
|
|
3
|
+
qooxdoo - the new era of web development
|
|
4
|
+
|
|
5
|
+
http://qooxdoo.org
|
|
6
|
+
|
|
7
|
+
Copyright:
|
|
8
|
+
2020 Christian Boulanger
|
|
9
|
+
|
|
10
|
+
License:
|
|
11
|
+
MIT: https://opensource.org/licenses/MIT
|
|
12
|
+
See the LICENSE file in the project's top-level directory for details.
|
|
13
|
+
|
|
14
|
+
Authors:
|
|
15
|
+
* Christian Boulanger (cboulanger)
|
|
16
|
+
|
|
17
|
+
************************************************************************ */
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* An Object modelling a GraphQL request based on the GraphQL language
|
|
21
|
+
* (see http://spec.graphql.org/draft/#sec-Language) usually sent as JSON via
|
|
22
|
+
* a HTTP request (https://graphql.org/learn/serving-over-http)
|
|
23
|
+
* @experimental The API might change. Feedback is appreciated.
|
|
24
|
+
*/
|
|
25
|
+
qx.Class.define("qx.io.graphql.protocol.Request",{
|
|
26
|
+
extend: qx.io.graphql.protocol.Message,
|
|
27
|
+
properties: {
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* An optional field that only needs to be provided if multiple operations are present in the query
|
|
31
|
+
*/
|
|
32
|
+
operationName: {
|
|
33
|
+
check:"String",
|
|
34
|
+
nullable: true,
|
|
35
|
+
event: "changeOperationName"
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The query as a string which will be parsed and executed on the server
|
|
40
|
+
*/
|
|
41
|
+
query : {
|
|
42
|
+
check: "String",
|
|
43
|
+
nullable: false,
|
|
44
|
+
init: "",
|
|
45
|
+
event: "changeQuery"
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A qooxdoo object that maps variable names to variable values
|
|
50
|
+
*/
|
|
51
|
+
variables : {
|
|
52
|
+
check: "qx.core.Object",
|
|
53
|
+
nullable: true,
|
|
54
|
+
event: "changeVariables",
|
|
55
|
+
transform: "_transformVariables",
|
|
56
|
+
validate: "_validateVariables"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
members: {
|
|
61
|
+
// overriden
|
|
62
|
+
toString() {
|
|
63
|
+
return qx.lang.Json.stringify(this.toObject(), this._jsonReplacer);
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
_jsonReplacer: function(key, value) {
|
|
67
|
+
if (key === "variables" || key === "operationName") {
|
|
68
|
+
return value !== null ? value : undefined;
|
|
69
|
+
}
|
|
70
|
+
// everything else is returned as it is
|
|
71
|
+
return value;
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Transforms the variables object to a qooxdoo model. Called automaticaly
|
|
77
|
+
* when the variables property is set.
|
|
78
|
+
*/
|
|
79
|
+
_transformVariables: function(val) {
|
|
80
|
+
let model = null;
|
|
81
|
+
if (![null, undefined].includes(val)) {
|
|
82
|
+
model = qx.data.marshal.Json.createModel(val);
|
|
83
|
+
}
|
|
84
|
+
return model;
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
_validateVariables: function(val) {
|
|
88
|
+
if (!qx.lang.Type.isObject(val) && (val !== null)) {
|
|
89
|
+
throw new qx.core.ValidationError(
|
|
90
|
+
"Validation Error: " + val + " is not an object or null."
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/* ************************************************************************
|
|
2
|
+
|
|
3
|
+
qooxdoo - the new era of web development
|
|
4
|
+
|
|
5
|
+
http://qooxdoo.org
|
|
6
|
+
|
|
7
|
+
Copyright:
|
|
8
|
+
2020 Christian Boulanger
|
|
9
|
+
|
|
10
|
+
License:
|
|
11
|
+
MIT: https://opensource.org/licenses/MIT
|
|
12
|
+
See the LICENSE file in the project's top-level directory for details.
|
|
13
|
+
|
|
14
|
+
Authors:
|
|
15
|
+
* Christian Boulanger (cboulanger)
|
|
16
|
+
|
|
17
|
+
************************************************************************ */
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* An Object modelling a GraphQL response (see http://spec.graphql.org/draft/#sec-Response-Format)
|
|
21
|
+
* @experimental The API might change. Feedback is appreciated.
|
|
22
|
+
*/
|
|
23
|
+
qx.Class.define("qx.io.graphql.protocol.Response",{
|
|
24
|
+
extend: qx.io.graphql.protocol.Message,
|
|
25
|
+
|
|
26
|
+
properties: {
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* "The data entry in the response will be the result of the execution
|
|
30
|
+
* of the requested operation. If the operation was a query, this
|
|
31
|
+
* output will be an object of the schema’s query root type; if the
|
|
32
|
+
* operation was a mutation, this output will be an object of the
|
|
33
|
+
* schema’s mutation root type. If an error was encountered before
|
|
34
|
+
* execution begins, the data entry should not be present in the result.
|
|
35
|
+
* If an error was encountered during the execution that prevented
|
|
36
|
+
* a valid response, the data entry in the response should be null"
|
|
37
|
+
*/
|
|
38
|
+
data : {
|
|
39
|
+
check: "Object",
|
|
40
|
+
nullable: true,
|
|
41
|
+
init: null
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* "The errors entry in the response is a non‐empty list of errors,
|
|
46
|
+
* where each error is a map. If no errors were encountered during
|
|
47
|
+
* the requested operation, the errors entry should not be present in
|
|
48
|
+
* the result. If the data entry in the response is not present, the
|
|
49
|
+
* errors entry in the response must not be empty. It must contain
|
|
50
|
+
* at least one error. The errors it contains should indicate why no
|
|
51
|
+
* data was able to be returned. If the data entry in the response is
|
|
52
|
+
* present (including if it is the value null), the errors entry in the
|
|
53
|
+
* response may contain any errors that occurred during execution. If
|
|
54
|
+
* errors occurred during execution, it should contain those errors."
|
|
55
|
+
*/
|
|
56
|
+
errors : {
|
|
57
|
+
check: value => qx.lang.Type.isArray(value) && value.length && value.every(item => Boolean(item.message)),
|
|
58
|
+
nullable: true
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
});
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
/* ************************************************************************
|
|
2
|
+
|
|
3
|
+
qooxdoo - the new era of web development
|
|
4
|
+
|
|
5
|
+
http://qooxdoo.org
|
|
6
|
+
|
|
7
|
+
Copyright:
|
|
8
|
+
2020 Christian Boulanger
|
|
9
|
+
|
|
10
|
+
License:
|
|
11
|
+
MIT: https://opensource.org/licenses/MIT
|
|
12
|
+
See the LICENSE file in the project's top-level directory for details.
|
|
13
|
+
|
|
14
|
+
Authors:
|
|
15
|
+
* Christian Boulanger (cboulanger)
|
|
16
|
+
|
|
17
|
+
************************************************************************ */
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* This class provides a JSON-RPC client object with auto-configuration of the
|
|
21
|
+
* transport used (based on the URI passed).
|
|
22
|
+
*/
|
|
23
|
+
qx.Class.define("qx.io.jsonrpc.Client",
|
|
24
|
+
{
|
|
25
|
+
extend : qx.io.transport.AbstractClient,
|
|
26
|
+
|
|
27
|
+
statics: {
|
|
28
|
+
// statics are not inherited from parent class
|
|
29
|
+
registerTransport : qx.io.transport.AbstractClient.registerTransport
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
events : {
|
|
33
|
+
/**
|
|
34
|
+
* Event fired before a request message is sent to the server.
|
|
35
|
+
* Event data is the {@link qx.io.jsonrpc.protocol.Message} to
|
|
36
|
+
* be sent. This also allows listeners to configure the transport
|
|
37
|
+
* object beforehand.
|
|
38
|
+
*/
|
|
39
|
+
"outgoingRequest": "qx.event.type.Data",
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Event fired when a request results in an error. Event data is an instance of
|
|
43
|
+
* {@link qx.io.exception.Transport}, {@link qx.io.exception.Protocol},
|
|
44
|
+
* or {@link qx.io.exception.Cancel}.
|
|
45
|
+
* Event fired when a message is received from the endpoint. Event data
|
|
46
|
+
* is an UTF-8 encoded string
|
|
47
|
+
*/
|
|
48
|
+
"error" : "qx.event.type.Data",
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Event fired when a peer-originated JSON-RPC message has been
|
|
52
|
+
* received from the peer endpoint. Event data is an instance of {@link
|
|
53
|
+
* qx.io.jsonrpc.message.Batch}, {@link qx.io.jsonrpc.message.Request}
|
|
54
|
+
* or {@link qx.io.jsonrpc.protocol.Notification}.
|
|
55
|
+
*/
|
|
56
|
+
"incomingRequest" : "qx.event.type.Data"
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @param {qx.io.transport.ITransport|String} transportOrUri
|
|
61
|
+
* Transport object, which must implement {@link qx.io.transport.ITransport}
|
|
62
|
+
* or a string URI, which will trigger auto-detection of transport, as long as an
|
|
63
|
+
* appropriate transport has been registered with the static `registerTransport()` function.
|
|
64
|
+
* @param {String?} methodPrefix
|
|
65
|
+
* Optional service name which will be prepended to the method
|
|
66
|
+
* @param {qx.io.jsonrpc.protocol.Parser?} parser
|
|
67
|
+
* Optional parser object, which needs to be an instance of a subclass of {@link qx.io.jsonrpc.protocol.Parser}
|
|
68
|
+
*/
|
|
69
|
+
construct : function(transportOrUri, methodPrefix, parser) {
|
|
70
|
+
this.base(arguments);
|
|
71
|
+
this.selectTransport(transportOrUri);
|
|
72
|
+
// listen for incoming messages
|
|
73
|
+
this.getTransport().addListener("message", evt => this.handleIncoming(evt.getData()));
|
|
74
|
+
if (!methodPrefix) {
|
|
75
|
+
methodPrefix = "";
|
|
76
|
+
}
|
|
77
|
+
this.setMethodPrefix(methodPrefix);
|
|
78
|
+
if (!parser) {
|
|
79
|
+
parser = new qx.io.jsonrpc.protocol.Parser();
|
|
80
|
+
}
|
|
81
|
+
this.setParser(parser);
|
|
82
|
+
this.__requests = [];
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
properties :
|
|
86
|
+
{
|
|
87
|
+
/**
|
|
88
|
+
* An optional string which is prepended to the method name by the {@link #sendRequest}
|
|
89
|
+
* and {@link #sendNotification} methods
|
|
90
|
+
*/
|
|
91
|
+
methodPrefix :
|
|
92
|
+
{
|
|
93
|
+
check : "String",
|
|
94
|
+
nullable : true
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The parser object, which must be a subclass of {@link qx.io.jsonrpc.protocol.Parser}
|
|
99
|
+
*/
|
|
100
|
+
parser: {
|
|
101
|
+
check : "qx.io.jsonrpc.protocol.Parser"
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
members :
|
|
106
|
+
{
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* A cache of the requests which have been sent out and are still pending
|
|
110
|
+
*/
|
|
111
|
+
__requests : null,
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* If a service name has been configured, prepend it to the method name,
|
|
115
|
+
* unless it has already been prefixed
|
|
116
|
+
* @param {String} method
|
|
117
|
+
* @return {String}
|
|
118
|
+
* @private
|
|
119
|
+
*/
|
|
120
|
+
_prependMethodPrefix(method) {
|
|
121
|
+
qx.core.Assert.assertString(method);
|
|
122
|
+
let methodPrefix = this.getMethodPrefix();
|
|
123
|
+
if (methodPrefix && !method.startsWith(methodPrefix)) {
|
|
124
|
+
return `${methodPrefix}${method}`;
|
|
125
|
+
}
|
|
126
|
+
return method;
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Fires "error" event and throws the error after informing pending requests
|
|
131
|
+
* about the error.
|
|
132
|
+
* @param exception
|
|
133
|
+
* @private
|
|
134
|
+
*/
|
|
135
|
+
_throwTransportException(exception) {
|
|
136
|
+
this.fireDataEvent("error", exception);
|
|
137
|
+
this.__requests.forEach(request => {
|
|
138
|
+
if (request instanceof qx.io.jsonrpc.protocol.Request) {
|
|
139
|
+
request.handleTransportException(exception);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
throw exception;
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Send the given JSON-RPC message object using the configured transport
|
|
147
|
+
*
|
|
148
|
+
* @param {qx.io.jsonrpc.protocol.Message|qx.io.jsonrpc.protocol.Batch} message
|
|
149
|
+
* @return {qx.Promise} Promise that resolves (with no data)
|
|
150
|
+
* when the message has been successfully sent out, and rejects
|
|
151
|
+
* when there is an error or a cancellation up to that point.
|
|
152
|
+
*/
|
|
153
|
+
async send(message) {
|
|
154
|
+
if (!(message instanceof qx.io.jsonrpc.protocol.Message || message instanceof qx.io.jsonrpc.protocol.Batch)) {
|
|
155
|
+
throw new Error("Argument must be instanceof qx.io.jsonrpc.protocol.Message or qx.io.jsonrpc.protocol.Batch");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// filter by type
|
|
159
|
+
let messages = message instanceof qx.io.jsonrpc.protocol.Batch ? message.getBatch().toArray() : [message];
|
|
160
|
+
let requests = messages.filter(message => message instanceof qx.io.jsonrpc.protocol.Request);
|
|
161
|
+
|
|
162
|
+
// store requests
|
|
163
|
+
requests.forEach(request => {
|
|
164
|
+
let id = request.getId();
|
|
165
|
+
if (this.__requests[id] !== undefined) {
|
|
166
|
+
throw new qx.io.exception.Transport(`Request ID ${id} is already in use`, qx.io.exception.Transport.INVALID_ID, {request: message.toObject()});
|
|
167
|
+
}
|
|
168
|
+
this.__requests[id] = request;
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// inform listeners
|
|
172
|
+
this.fireDataEvent("outgoingRequest", message);
|
|
173
|
+
|
|
174
|
+
// debugging
|
|
175
|
+
if (qx.core.Environment.get("qx.io.jsonrpc.debug")) {
|
|
176
|
+
this.debug(">>> Outgoing json-rpc message: " + message);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// send it async, using transport-specific implementation
|
|
180
|
+
return this.getTransport().send(message.toString());
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Sends a single JSON-RPC request. If a method prefix name has been configured,
|
|
185
|
+
* it will be prepended to the method name.
|
|
186
|
+
* @param {String} method
|
|
187
|
+
* @param {Array|Object?} params
|
|
188
|
+
* @return {qx.Promise} Promise that resolves with the result to that request,
|
|
189
|
+
* and rejects with an exception in the {@link qx.io.jsonrpc.exception} namespace.
|
|
190
|
+
*/
|
|
191
|
+
async sendRequest(method, params) {
|
|
192
|
+
const request = new qx.io.jsonrpc.protocol.Request(this._prependMethodPrefix(method), params);
|
|
193
|
+
await this.send(request);
|
|
194
|
+
return await request.getPromise();
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Sends a single JSON-RPC notification. Will use the method prefix
|
|
199
|
+
* @param {String} method
|
|
200
|
+
* @param {Array|Object?} params
|
|
201
|
+
* @return {qx.Promise} Promise that resolves immediately, (i.e. when the
|
|
202
|
+
* notification has been sent out (which is synchronous)
|
|
203
|
+
*/
|
|
204
|
+
async sendNotification(method, params) {
|
|
205
|
+
const notification = new qx.io.jsonrpc.protocol.Notification(this._prependMethodPrefix(method), params);
|
|
206
|
+
await this.send(notification);
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Send the given message batch. Will use the method prefix.
|
|
211
|
+
* @param {qx.io.jsonrpc.protocol.Batch} batch
|
|
212
|
+
* @return {qx.Promise} Promise that resolves with an array of the responses
|
|
213
|
+
* to all requests in the batch, or rejects with any error that occurs.
|
|
214
|
+
*/
|
|
215
|
+
async sendBatch(batch) {
|
|
216
|
+
qx.core.Assert.assertInstance(batch, qx.io.jsonrpc.protocol.Batch);
|
|
217
|
+
if (this.getMethodPrefix()) {
|
|
218
|
+
batch.getBatch().forEach(message => message.setMethod(this._prependMethodPrefix(message.getMethod())));
|
|
219
|
+
}
|
|
220
|
+
await this.send(batch);
|
|
221
|
+
return await qx.Promise.all(batch.getPromises());
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Receives and handles an incoming JSON-RPC compliant message data
|
|
226
|
+
* @param {String} json JSON data
|
|
227
|
+
*/
|
|
228
|
+
handleIncoming(json) {
|
|
229
|
+
if (qx.core.Environment.get("qx.io.jsonrpc.debug")) {
|
|
230
|
+
this.debug("<<< Incoming json-rpc message: " + json);
|
|
231
|
+
}
|
|
232
|
+
let message;
|
|
233
|
+
try {
|
|
234
|
+
message = this.getParser().parse(json);
|
|
235
|
+
// act on each message
|
|
236
|
+
this.handleMessage(message);
|
|
237
|
+
} catch (e) {
|
|
238
|
+
this._throwTransportException(e);
|
|
239
|
+
} finally {
|
|
240
|
+
// cleanup
|
|
241
|
+
if (message instanceof qx.io.jsonrpc.protocol.Batch) {
|
|
242
|
+
message.getBatch().forEach(msg => this._cleanup(msg));
|
|
243
|
+
} else if (message instanceof qx.io.jsonrpc.protocol.Message) {
|
|
244
|
+
this._cleanup(message);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Clean up after a message has been received
|
|
251
|
+
* @param {qx.io.jsonrpc.protocol.Message} message
|
|
252
|
+
* @private
|
|
253
|
+
*/
|
|
254
|
+
_cleanup(message) {
|
|
255
|
+
message.dispose();
|
|
256
|
+
},
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Handle an incoming message or batch of messages
|
|
260
|
+
* @param {qx.io.jsonrpc.protocol.Message|qx.io.jsonrpc.protocol.Batch} message Message or Batch
|
|
261
|
+
*/
|
|
262
|
+
handleMessage(message) {
|
|
263
|
+
// handle batches
|
|
264
|
+
if (message instanceof qx.io.jsonrpc.protocol.Batch) {
|
|
265
|
+
message.getBatch().forEach(msg => this.handleMessage(msg));
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
// handle individual message
|
|
269
|
+
qx.core.Assert.assertInstance(message, qx.io.jsonrpc.protocol.Message);
|
|
270
|
+
let request;
|
|
271
|
+
let id;
|
|
272
|
+
if (message instanceof qx.io.jsonrpc.protocol.Result || message instanceof qx.io.jsonrpc.protocol.Error) {
|
|
273
|
+
// handle results and errors, which are responses to sent requests
|
|
274
|
+
id = message.getId();
|
|
275
|
+
request = this.__requests[id];
|
|
276
|
+
if (request === undefined) {
|
|
277
|
+
// no request with this id exists
|
|
278
|
+
throw new qx.io.exception.Transport(
|
|
279
|
+
`Invalid jsonrpc response data: Unknown id ${id}.`,
|
|
280
|
+
qx.io.exception.Transport.UNKNOWN_ID,
|
|
281
|
+
message.toObject()
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
if (request === true) {
|
|
285
|
+
// the request has already been responded to
|
|
286
|
+
throw new qx.io.exception.Transport(
|
|
287
|
+
`Invalid jsonrpc response data: multiple responses with same id ${id}.`,
|
|
288
|
+
qx.io.exception.Transport.DUPLICATE_ID,
|
|
289
|
+
message.toObject()
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
// handle the different message types
|
|
294
|
+
if (message instanceof qx.io.jsonrpc.protocol.Result) {
|
|
295
|
+
// resolve the individual promise
|
|
296
|
+
request.getPromise().resolve(message.getResult());
|
|
297
|
+
} else if (message instanceof qx.io.jsonrpc.protocol.Error) {
|
|
298
|
+
|
|
299
|
+
let error = message.getError();
|
|
300
|
+
let ex = new qx.io.exception.Protocol(
|
|
301
|
+
error.message,
|
|
302
|
+
error.code,
|
|
303
|
+
message.toObject()
|
|
304
|
+
);
|
|
305
|
+
// inform listeners
|
|
306
|
+
this.fireDataEvent("error", ex);
|
|
307
|
+
// reject the individual promise
|
|
308
|
+
request.getPromise().reject(ex);
|
|
309
|
+
} else if (message instanceof qx.io.jsonrpc.protocol.Request || message instanceof qx.io.jsonrpc.protocol.Notification) {
|
|
310
|
+
// handle peer-originated requests and notifications
|
|
311
|
+
this.fireDataEvent("incomingRequest", message);
|
|
312
|
+
} else {
|
|
313
|
+
throw new Error("Unhandled message:" + message.toString());
|
|
314
|
+
}
|
|
315
|
+
// mark request as handled (and remove reference so it can be gc'ed)
|
|
316
|
+
this.__requests[id] = true;
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
|
|
320
|
+
environment: {
|
|
321
|
+
"qx.io.jsonrpc.debug" : false
|
|
322
|
+
}
|
|
323
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <p>This namespace provides an API implementing the <a
|
|
3
|
+
* href="https://www.jsonrpc.org/specification">JSON Remote
|
|
4
|
+
* Procedure Call (JSON-RPC) version 2 specification</a></p>
|
|
5
|
+
*
|
|
6
|
+
* <p>JSON-RPC v2 is transport-agnostic. We provide a high-level
|
|
7
|
+
* API interface (qx.io.jsonrpc.Client), a transport interface
|
|
8
|
+
* (qx.io.transport.ITransport) and an HTTP transport implementation.
|
|
9
|
+
* Other transports based on websockets or other mechanisms can be added later.</p>
|
|
10
|
+
*
|
|
11
|
+
* <p>Please refer to
|
|
12
|
+
* <a href="https://github.com/qooxdoo/incubator.qx.io.jsonrpc/blob/master/readme.md#usage">
|
|
13
|
+
* the documentation on GitHub
|
|
14
|
+
* </a></p>
|
|
15
|
+
*/
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/* ************************************************************************
|
|
2
|
+
|
|
3
|
+
qooxdoo - the new era of web development
|
|
4
|
+
|
|
5
|
+
http://qooxdoo.org
|
|
6
|
+
|
|
7
|
+
Copyright:
|
|
8
|
+
2020 Christian Boulanger
|
|
9
|
+
|
|
10
|
+
License:
|
|
11
|
+
MIT: https://opensource.org/licenses/MIT
|
|
12
|
+
See the LICENSE file in the project's top-level directory for details.
|
|
13
|
+
|
|
14
|
+
Authors:
|
|
15
|
+
* Christian Boulanger (cboulanger)
|
|
16
|
+
|
|
17
|
+
************************************************************************ */
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* An object representing a JSON-RPC v2.0 batch message object. You can add
|
|
21
|
+
* one or more of the following message objects to the batch:
|
|
22
|
+
* - {@link qx.io.jsonrpc.protocol.Request}
|
|
23
|
+
* - {@link qx.io.jsonrpc.protocol.Notification}
|
|
24
|
+
* - {@link qx.io.jsonrpc.protocol.Result}
|
|
25
|
+
* - {@link qx.io.jsonrpc.protocol.Error}
|
|
26
|
+
* @see https://www.jsonrpc.org/specification#batch
|
|
27
|
+
*/
|
|
28
|
+
qx.Class.define("qx.io.jsonrpc.protocol.Batch",{
|
|
29
|
+
extend: qx.core.Object,
|
|
30
|
+
properties: {
|
|
31
|
+
batch : {
|
|
32
|
+
check: "qx.data.Array"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
construct() {
|
|
36
|
+
this.base(arguments);
|
|
37
|
+
this.setBatch(new qx.data.Array());
|
|
38
|
+
},
|
|
39
|
+
members: {
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Adds a request or notification to the batch
|
|
43
|
+
* @param {qx.io.jsonrpc.protocol.Message} message
|
|
44
|
+
* @return {qx.io.jsonrpc.protocol.Batch}
|
|
45
|
+
*/
|
|
46
|
+
add(message) {
|
|
47
|
+
qx.core.Assert.assertInstance(message, qx.io.jsonrpc.protocol.Message);
|
|
48
|
+
this.getBatch().push(message);
|
|
49
|
+
// return the instance for chaining
|
|
50
|
+
return this;
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Adds a request to the batch
|
|
55
|
+
* @param method
|
|
56
|
+
* @param params
|
|
57
|
+
*/
|
|
58
|
+
addRequest(method,params) {
|
|
59
|
+
this.add(new qx.io.jsonrpc.protocol.Request(method, params));
|
|
60
|
+
return this;
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Adds a notification to the batch
|
|
65
|
+
* @param method
|
|
66
|
+
* @param params
|
|
67
|
+
*/
|
|
68
|
+
addNotification(method,params) {
|
|
69
|
+
this.add(new qx.io.jsonrpc.protocol.Notification(method, params));
|
|
70
|
+
return this;
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Returns an array of the promises of the requests in the batch
|
|
75
|
+
* @return {qx.Promise[]}
|
|
76
|
+
*/
|
|
77
|
+
getPromises() {
|
|
78
|
+
return this.getBatch().map(message => message.getPromise());
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Returns the message as a native object
|
|
83
|
+
* @return {*}
|
|
84
|
+
*/
|
|
85
|
+
toObject() {
|
|
86
|
+
return this.getBatch().toArray().map(message => message.toObject());
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Returns the message as a JSON string
|
|
91
|
+
* @return {String}
|
|
92
|
+
*/
|
|
93
|
+
toString() {
|
|
94
|
+
return JSON.stringify(this.getBatch().toArray().map(message => message.toObject()));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/* ************************************************************************
|
|
2
|
+
|
|
3
|
+
qooxdoo - the new era of web development
|
|
4
|
+
|
|
5
|
+
http://qooxdoo.org
|
|
6
|
+
|
|
7
|
+
Copyright:
|
|
8
|
+
2020 Christian Boulanger
|
|
9
|
+
|
|
10
|
+
License:
|
|
11
|
+
MIT: https://opensource.org/licenses/MIT
|
|
12
|
+
See the LICENSE file in the project's top-level directory for details.
|
|
13
|
+
|
|
14
|
+
Authors:
|
|
15
|
+
* Christian Boulanger (cboulanger)
|
|
16
|
+
|
|
17
|
+
************************************************************************ */
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A JSON-RPC v2.0 error message object, which is a response to a {@link qx.io.jsonrpc.protocol.Request},
|
|
21
|
+
* indicating a failure during the processing of the request on the server.
|
|
22
|
+
* @see https://www.jsonrpc.org/specification#error_object
|
|
23
|
+
*/
|
|
24
|
+
qx.Class.define("qx.io.jsonrpc.protocol.Error",{
|
|
25
|
+
extend: qx.io.jsonrpc.protocol.Message,
|
|
26
|
+
properties: {
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The integer id of the request
|
|
30
|
+
* @var {Number}
|
|
31
|
+
*/
|
|
32
|
+
id : {
|
|
33
|
+
check: value => qx.lang.Type.isNumber(value) && parseInt(value, 10) === value
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The error object
|
|
38
|
+
* @var {Object}
|
|
39
|
+
*/
|
|
40
|
+
error : {
|
|
41
|
+
check : value => qx.lang.Type.isObject(value) && "code" in value && "message" in value
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
/**
|
|
45
|
+
* The response messsage constructor
|
|
46
|
+
* @param {Number} id^
|
|
47
|
+
* @param {Number} code
|
|
48
|
+
* @param {String} message
|
|
49
|
+
* @param {*?} data
|
|
50
|
+
*/
|
|
51
|
+
construct(id, code, message, data) {
|
|
52
|
+
this.base(arguments);
|
|
53
|
+
this.setId(id);
|
|
54
|
+
if (!qx.lang.Type.isNumber(code) || parseInt(code, 10) !== code ) {
|
|
55
|
+
throw new Error("Code must be an integer");
|
|
56
|
+
}
|
|
57
|
+
let errorObj = {code, message};
|
|
58
|
+
if (data) {
|
|
59
|
+
errorObj.data = data;
|
|
60
|
+
}
|
|
61
|
+
this.setError(errorObj);
|
|
62
|
+
}
|
|
63
|
+
});
|