summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkonpeki622 <512054675@qq.com>2022-03-11 17:35:28 +0800
committerJens Geyer <Jens-G@users.noreply.github.com>2022-03-13 18:59:54 +0100
commitbbea728aaa9f72bb3b58a1c5448b4e917eaf5796 (patch)
treeb98f1cd252f2da5301313d3617ab9c5240ee1f73
parent8ef4ed1b2a0b28f27d35516cfb56a16c2583de0c (diff)
downloadthrift-bbea728aaa9f72bb3b58a1c5448b4e917eaf5796.tar.gz
feat: support creating connection on OpenHarmonyOS
-rw-r--r--lib/nodejs/lib/thrift/browser.js4
-rw-r--r--lib/nodejs/lib/thrift/ohos_connection.js261
2 files changed, 265 insertions, 0 deletions
diff --git a/lib/nodejs/lib/thrift/browser.js b/lib/nodejs/lib/thrift/browser.js
index 0b06f0f13..e217704d6 100644
--- a/lib/nodejs/lib/thrift/browser.js
+++ b/lib/nodejs/lib/thrift/browser.js
@@ -28,6 +28,10 @@ exports.XHRConnection = xhrConnection.XHRConnection;
exports.createXHRConnection = xhrConnection.createXHRConnection;
exports.createXHRClient = xhrConnection.createXHRClient;
+var ohosConnection = require('./ohos_connection');
+exports.OhosConnection = ohosConnection.OhosConnection;
+exports.createOhosConnection = ohosConnection.createOhosConnection;
+exports.createOhosClient = ohosConnection.createOhosClient;
exports.Int64 = require('node-int64');
exports.Q = require('q');
diff --git a/lib/nodejs/lib/thrift/ohos_connection.js b/lib/nodejs/lib/thrift/ohos_connection.js
new file mode 100644
index 000000000..95bf12279
--- /dev/null
+++ b/lib/nodejs/lib/thrift/ohos_connection.js
@@ -0,0 +1,261 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+var util = require('util');
+var EventEmitter = require('events').EventEmitter;
+var thrift = require('./thrift');
+
+var TBufferedTransport = require('./buffered_transport');
+var TBinaryProtocol = require('./binary_protocol');
+var InputBufferUnderrunError = require('./input_buffer_underrun_error');
+
+var createClient = require('./create_client');
+
+/**
+ * @class
+ * @name ConnectOptions
+ * @property {string} transport - The Thrift layered transport to use (TBufferedTransport, etc).
+ * @property {string} protocol - The Thrift serialization protocol to use (TBinaryProtocol, etc.).
+ * @property {string} path - The URL path to POST to (e.g. "/", "/mySvc", "/thrift/quoteSvc", etc.).
+ * @property {object} header - A standard Node.js header hash, an object hash containing key/value
+ * pairs where the key is the header name string and the value is the header value string.
+ * @property {object} requestOptions - Options passed on to http request. Details:
+ * https://developer.harmonyos.com/en/docs/documentation/doc-references/js-apis-net-http-0000001168304341#section12262183471518
+ * @example
+ * //Use a connection that requires ssl/tls, closes the connection after each request,
+ * // uses the buffered transport layer, uses the JSON protocol and directs RPC traffic
+ * // to https://thrift.example.com:9090/hello
+ * import http from '@ohos.net.http' // HTTP module of OpenHarmonyOS
+ * var thrift = require('thrift');
+ * var options = {
+ * transport: thrift.TBufferedTransport,
+ * protocol: thrift.TJSONProtocol,
+ * path: "/hello",
+ * headers: {"Connection": "close"}
+ * };
+ * // With OpenHarmonyOS HTTP module, HTTPS is supported by default. To support HTTP, See:
+ * // https://developer.harmonyos.com/en/docs/documentation/doc-references/js-apis-net-http-0000001168304341#EN-US_TOPIC_0000001171944450__s56d19203690d4782bfc74069abb6bd71
+ * var con = thrift.createOhosConnection(http.createHttp, "thrift.example.com", 9090, options);
+ * var client = thrift.createOhosClient(myService, connection);
+ * client.myServiceFunction();
+ */
+
+/**
+ * Initializes a Thrift HttpConnection instance (use createHttpConnection() rather than
+ * instantiating directly).
+ * @constructor
+ * @param {ConnectOptions} options - The configuration options to use.
+ * @throws {error} Exceptions other than InputBufferUnderrunError are rethrown
+ * @event {error} The "error" event is fired when a Node.js error event occurs during
+ * request or response processing, in which case the node error is passed on. An "error"
+ * event may also be fired when the connection can not map a response back to the
+ * appropriate client (an internal error), generating a TApplicationException.
+ * @classdesc OhosConnection objects provide Thrift end point transport
+ * semantics implemented over the OpenHarmonyOS http.request() method.
+ * @see {@link createOhosConnection}
+ */
+var OhosConnection = exports.OhosConnection = function(options) {
+ //Initialize the emitter base object
+ EventEmitter.call(this);
+
+ //Set configuration
+ var self = this;
+ this.options = options || {};
+ this.host = this.options.host;
+ this.port = this.options.port;
+ this.path = this.options.path || '/';
+ //OpenHarmonyOS needs URL for initiating an HTTP request.
+ this.url =
+ this.port === 80
+ ? this.host.replace(/\/$/, '') + this.path
+ : this.host.replace(/\/$/, '') + ':' + this.port + this.path;
+ this.transport = this.options.transport || TBufferedTransport;
+ this.protocol = this.options.protocol || TBinaryProtocol;
+ //Inherit method from OpenHarmonyOS HTTP module
+ this.createHttp = this.options.createHttp;
+
+ //Prepare HTTP request options
+ this.requestOptions = {
+ method: 'POST',
+ header: this.options.header || {},
+ readTimeout: this.options.readTimeout || 60000,
+ connectTimeout: this.options.connectTimeout || 60000
+ };
+ for (var attrname in this.options.requestOptions) {
+ this.requestOptions[attrname] = this.options.requestOptions[attrname];
+ }
+ /*jshint -W069 */
+ if (!this.requestOptions.header['Connection']) {
+ this.requestOptions.header['Connection'] = 'keep-alive';
+ }
+ /*jshint +W069 */
+
+ //The sequence map is used to map seqIDs back to the
+ // calling client in multiplexed scenarios
+ this.seqId2Service = {};
+
+ function decodeCallback(transport_with_data) {
+ var proto = new self.protocol(transport_with_data);
+ try {
+ while (true) {
+ var header = proto.readMessageBegin();
+ var dummy_seqid = header.rseqid * -1;
+ var client = self.client;
+ //The Multiplexed Protocol stores a hash of seqid to service names
+ // in seqId2Service. If the SeqId is found in the hash we need to
+ // lookup the appropriate client for this call.
+ // The client var is a single client object when not multiplexing,
+ // when using multiplexing it is a service name keyed hash of client
+ // objects.
+ //NOTE: The 2 way interdependencies between protocols, transports,
+ // connections and clients in the Node.js implementation are irregular
+ // and make the implementation difficult to extend and maintain. We
+ // should bring this stuff inline with typical thrift I/O stack
+ // operation soon.
+ // --ra
+ var service_name = self.seqId2Service[header.rseqid];
+ if (service_name) {
+ client = self.client[service_name];
+ delete self.seqId2Service[header.rseqid];
+ }
+ /*jshint -W083 */
+ client._reqs[dummy_seqid] = function(err, success){
+ transport_with_data.commitPosition();
+ var clientCallback = client._reqs[header.rseqid];
+ delete client._reqs[header.rseqid];
+ if (clientCallback) {
+ process.nextTick(function() {
+ clientCallback(err, success);
+ });
+ }
+ };
+ /*jshint +W083 */
+ if(client['recv_' + header.fname]) {
+ client['recv_' + header.fname](proto, header.mtype, dummy_seqid);
+ } else {
+ delete client._reqs[dummy_seqid];
+ self.emit("error",
+ new thrift.TApplicationException(
+ thrift.TApplicationExceptionType.WRONG_METHOD_NAME,
+ "Received a response to an unknown RPC function"));
+ }
+ }
+ }
+ catch (e) {
+ if (e instanceof InputBufferUnderrunError) {
+ transport_with_data.rollbackPosition();
+ } else {
+ self.emit('error', e);
+ }
+ }
+ }
+
+
+ //Response handler
+ //////////////////////////////////////////////////
+ this.responseCallback = function(error, response) {
+ //Response will be a struct like:
+ // https://developer.harmonyos.com/en/docs/documentation/doc-references/js-apis-net-http-0000001168304341#section15920192914312
+ var data = [];
+ var dataLen = 0;
+
+ if (error) {
+ self.emit('error', error);
+ return;
+ }
+
+ if (!response || response.responseCode !== 200) {
+ self.emit('error', new THTTPException(response));
+ }
+
+ // With OpenHarmonyOS running in a Browser (e.g. Browserify), chunk
+ // will be a string or an ArrayBuffer.
+ if (
+ typeof response.result == 'string' ||
+ Object.prototype.toString.call(response.result) == '[object Uint8Array]'
+ ) {
+ // Wrap ArrayBuffer/string in a Buffer so data[i].copy will work
+ data.push(Buffer.from(response.result));
+ }
+ dataLen += response.result.length;
+
+ var buf = Buffer.alloc(dataLen);
+ for (var i = 0, len = data.length, pos = 0; i < len; i++) {
+ data[i].copy(buf, pos);
+ pos += data[i].length;
+ }
+ //Get the receiver function for the transport and
+ // call it with the buffer
+ self.transport.receiver(decodeCallback)(buf);
+ };
+
+ /**
+ * Writes Thrift message data to the connection
+ * @param {Buffer} data - A Node.js Buffer containing the data to write
+ * @returns {void} No return value.
+ * @event {error} the "error" event is raised upon request failure passing the
+ * Node.js error object to the listener.
+ */
+ this.write = function(data) {
+ //To initiate multiple HTTP requests, we must create an HttpRequest object
+ // for each HTTP request
+ var http = self.createHttp();
+ var opts = self.requestOptions;
+ opts.header["Content-length"] = data.length;
+ if (!opts.header["Content-Type"])
+ opts.header["Content-Type"] = "application/x-thrift";
+ // extraData not support array data currently
+ opts.extraData = data.toString();
+ http.request(self.url, opts, self.responseCallback);
+ };
+};
+util.inherits(OhosConnection, EventEmitter);
+
+/**
+ * Creates a new OhosConnection object, used by Thrift clients to connect
+ * to Thrift HTTP based servers.
+ * @param {Function} createHttp - OpenHarmonyOS method to initiate or destroy an HTTP request.
+ * @param {string} host - The host name or IP to connect to.
+ * @param {number} port - The TCP port to connect to.
+ * @param {ConnectOptions} options - The configuration options to use.
+ * @returns {OhosConnection} The connection object.
+ * @see {@link ConnectOptions}
+ */
+exports.createOhosConnection = function(createHttp, host, port, options) {
+ options.createHttp = createHttp;
+ options.host = host;
+ options.port = port || 80;
+ return new OhosConnection(options);
+};
+
+exports.createOhosClient = createClient;
+
+function THTTPException(response) {
+ thrift.TApplicationException.call(this);
+ if (Error.captureStackTrace !== undefined) {
+ Error.captureStackTrace(this, this.constructor);
+ }
+
+ this.name = this.constructor.name;
+ this.responseCode = response.responseCode;
+ this.response = response;
+ this.type = thrift.TApplicationExceptionType.PROTOCOL_ERROR;
+ this.message =
+ 'Received a response with a bad HTTP status code: ' + response.responseCode;
+}
+util.inherits(THTTPException, thrift.TApplicationException);