http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/Makefile.am ---------------------------------------------------------------------- diff --git a/lib/Makefile.am b/lib/Makefile.am index 5066a00..44bb9ff 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -65,6 +65,10 @@ if WITH_PHP SUBDIRS += php endif +if WITH_DART +SUBDIRS += dart +endif + if WITH_GO SUBDIRS += go endif @@ -88,6 +92,7 @@ EXTRA_DIST = \ as3 \ cocoa \ d \ + dart \ delphi \ haxe \ javame \
http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/LICENSE_HEADER ---------------------------------------------------------------------- diff --git a/lib/dart/LICENSE_HEADER b/lib/dart/LICENSE_HEADER new file mode 100644 index 0000000..4eacb64 --- /dev/null +++ b/lib/dart/LICENSE_HEADER @@ -0,0 +1,16 @@ +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. http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/Makefile.am ---------------------------------------------------------------------- diff --git a/lib/dart/Makefile.am b/lib/dart/Makefile.am new file mode 100644 index 0000000..6dfff40 --- /dev/null +++ b/lib/dart/Makefile.am @@ -0,0 +1,26 @@ +# +# 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. +# + +all-local: + $(DARTPUB) get + +clean-local: + $(RM) -r .pub + +check-local: all http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/README.md ---------------------------------------------------------------------- diff --git a/lib/dart/README.md b/lib/dart/README.md new file mode 100644 index 0000000..2be168b --- /dev/null +++ b/lib/dart/README.md @@ -0,0 +1,26 @@ +Thrift Dart Library + +License +======= + +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. + +Using Thrift with Dart +==================== + +Dart 1.12.0 or newer is required http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/coding_standards.md ---------------------------------------------------------------------- diff --git a/lib/dart/coding_standards.md b/lib/dart/coding_standards.md new file mode 100644 index 0000000..62f6003 --- /dev/null +++ b/lib/dart/coding_standards.md @@ -0,0 +1,6 @@ +# Dart Coding Standards + +### Please follow: + * [Thrift General Coding Standards](/doc/coding_standards.md) + * [Use dartfmt](https://www.dartlang.org/tools/dartfmt/) and follow the + [Dart Style Guide](https://www.dartlang.org/articles/style-guide/) http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/browser/t_web_socket.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/browser/t_web_socket.dart b/lib/dart/lib/src/browser/t_web_socket.dart new file mode 100644 index 0000000..dfcee83 --- /dev/null +++ b/lib/dart/lib/src/browser/t_web_socket.dart @@ -0,0 +1,130 @@ +/// 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. + +library thrift.src.browser; + +import 'dart:async'; +import 'dart:html' show CloseEvent; +import 'dart:html' show Event; +import 'dart:html' show MessageEvent; +import 'dart:html' show WebSocket; +import 'dart:typed_data' show Uint8List; + +import 'package:crypto/crypto.dart' show CryptoUtils; +import 'package:thrift/thrift.dart'; + +/// A [TSocket] backed by a [WebSocket] from dart:html +class TWebSocket implements TSocket { + final Uri url; + + final StreamController<TSocketState> _onStateController; + Stream<TSocketState> get onState => _onStateController.stream; + + final StreamController<Object> _onErrorController; + Stream<Object> get onError => _onErrorController.stream; + + final StreamController<Uint8List> _onMessageController; + Stream<Uint8List> get onMessage => _onMessageController.stream; + + final List<Uint8List> _requests = []; + + TWebSocket(this.url) + : _onStateController = new StreamController.broadcast(), + _onErrorController = new StreamController.broadcast(), + _onMessageController = new StreamController.broadcast() { + if (url == null || !url.hasAuthority || !url.hasPort) { + throw new ArgumentError('Invalid url'); + } + } + + WebSocket _socket; + + bool get isOpen => _socket != null && _socket.readyState == WebSocket.OPEN; + + bool get isClosed => + _socket == null || _socket.readyState == WebSocket.CLOSED; + + Future open() { + if (!isClosed) { + throw new TTransportError( + TTransportErrorType.ALREADY_OPEN, 'Socket already connected'); + } + + _socket = new WebSocket(url.toString()); + _socket.onError.listen(_onError); + _socket.onOpen.listen(_onOpen); + _socket.onClose.listen(_onClose); + _socket.onMessage.listen(_onMessage); + + return _socket.onOpen.first; + } + + Future close() { + if (_socket != null) { + _socket.close(); + return _socket.onClose.first; + } else { + return new Future.value(); + } + } + + void send(Uint8List data) { + _requests.add(data); + _sendRequests(); + } + + void _sendRequests() { + while (isOpen && _requests.isNotEmpty) { + Uint8List data = _requests.removeAt(0); + _socket.sendString(CryptoUtils.bytesToBase64(data)); + } + } + + void _onOpen(Event event) { + _onStateController.add(TSocketState.OPEN); + _sendRequests(); + } + + void _onClose(CloseEvent event) { + _socket = null; + + if (_requests.isNotEmpty) { + _onErrorController + .add(new StateError('Socket was closed with pending requests')); + } + _requests.clear(); + + _onStateController.add(TSocketState.CLOSED); + } + + void _onMessage(MessageEvent message) { + try { + Uint8List data = + new Uint8List.fromList(CryptoUtils.base64StringToBytes(message.data)); + _onMessageController.add(data); + } on FormatException catch (_) { + var error = new TProtocolError(TProtocolErrorType.INVALID_DATA, + "Expected a Base 64 encoded string."); + _onErrorController.add(error); + } + } + + void _onError(Event event) { + close(); + _onErrorController.add(event.toString()); + } +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/console/t_tcp_socket.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/console/t_tcp_socket.dart b/lib/dart/lib/src/console/t_tcp_socket.dart new file mode 100644 index 0000000..b714803 --- /dev/null +++ b/lib/dart/lib/src/console/t_tcp_socket.dart @@ -0,0 +1,81 @@ +/// 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. + +library thrift.src.console.t_tcp_socket; + +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data' show Uint8List; + +import 'package:thrift/thrift.dart'; + +/// A [TSocket] backed by a [Socket] from dart:io +class TTcpSocket implements TSocket { + final StreamController<TSocketState> _onStateController; + Stream<TSocketState> get onState => _onStateController.stream; + + final StreamController<Object> _onErrorController; + Stream<Object> get onError => _onErrorController.stream; + + final StreamController<Uint8List> _onMessageController; + Stream<Uint8List> get onMessage => _onMessageController.stream; + + TTcpSocket(Socket socket) + : _onStateController = new StreamController.broadcast(), + _onErrorController = new StreamController.broadcast(), + _onMessageController = new StreamController.broadcast() { + if (socket == null) { + throw new ArgumentError.notNull('socket'); + } + + _socket = socket; + _socket.listen(_onMessage, onError: _onError, onDone: close); + } + + Socket _socket; + + bool get isOpen => _socket != null; + + bool get isClosed => _socket == null; + + Future open() async { + _onStateController.add(TSocketState.OPEN); + } + + Future close() async { + if (_socket != null) { + await _socket.close(); + _socket = null; + } + + _onStateController.add(TSocketState.CLOSED); + } + + void send(Uint8List data) { + _socket.add(data); + } + + void _onMessage(List<int> message) { + Uint8List data = new Uint8List.fromList(message); + _onMessageController.add(data); + } + + void _onError(Object error) { + close(); + _onErrorController.add('$error'); + } +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/console/t_web_socket.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/console/t_web_socket.dart b/lib/dart/lib/src/console/t_web_socket.dart new file mode 100644 index 0000000..5a549be --- /dev/null +++ b/lib/dart/lib/src/console/t_web_socket.dart @@ -0,0 +1,89 @@ +/// 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. + +library thrift.src.console.t_web_socket; + +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data' show Uint8List; + +import 'package:crypto/crypto.dart' show CryptoUtils; +import 'package:thrift/thrift.dart'; + +/// A [TSocket] backed by a [WebSocket] from dart:io +class TWebSocket implements TSocket { + final StreamController<TSocketState> _onStateController; + Stream<TSocketState> get onState => _onStateController.stream; + + final StreamController<Object> _onErrorController; + Stream<Object> get onError => _onErrorController.stream; + + final StreamController<Uint8List> _onMessageController; + Stream<Uint8List> get onMessage => _onMessageController.stream; + + TWebSocket(WebSocket socket) + : _onStateController = new StreamController.broadcast(), + _onErrorController = new StreamController.broadcast(), + _onMessageController = new StreamController.broadcast() { + if (socket == null) { + throw new ArgumentError.notNull('socket'); + } + + _socket = socket; + _socket.listen(_onMessage, onError: _onError, onDone: close); + } + + WebSocket _socket; + + bool get isOpen => _socket != null; + + bool get isClosed => _socket == null; + + Future open() async { + _onStateController.add(TSocketState.OPEN); + } + + Future close() async { + if (_socket != null) { + await _socket.close(); + _socket = null; + } + + _onStateController.add(TSocketState.CLOSED); + } + + void send(Uint8List data) { + _socket.add(CryptoUtils.bytesToBase64(data)); + } + + void _onMessage(String message) { + try { + Uint8List data = + new Uint8List.fromList(CryptoUtils.base64StringToBytes(message)); + _onMessageController.add(data); + } on FormatException catch (_) { + var error = new TProtocolError(TProtocolErrorType.INVALID_DATA, + "Expected a Base 64 encoded string."); + _onErrorController.add(error); + } + } + + void _onError(Object error) { + close(); + _onErrorController.add('$error'); + } +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/protocol/t_binary_protocol.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/protocol/t_binary_protocol.dart b/lib/dart/lib/src/protocol/t_binary_protocol.dart new file mode 100644 index 0000000..f73223c --- /dev/null +++ b/lib/dart/lib/src/protocol/t_binary_protocol.dart @@ -0,0 +1,276 @@ +/// 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. + +part of thrift; + +class TBinaryProtocolFactory implements TProtocolFactory<TBinaryProtocol> { + TBinaryProtocolFactory({this.strictRead: false, this.strictWrite: true}); + + final bool strictRead; + final bool strictWrite; + + TBinaryProtocol getProtocol(TTransport transport) { + return new TBinaryProtocol(transport, + strictRead: strictRead, strictWrite: strictWrite); + } +} + +/// Binary protocol implementation for Thrift. +/// +/// Adapted from the C# version. +class TBinaryProtocol extends TProtocol { + static const int VERSION_MASK = 0xffff0000; + static const int VERSION_1 = 0x80010000; + + static const Utf8Codec _utf8Codec = const Utf8Codec(); + + final bool strictRead; + final bool strictWrite; + + TBinaryProtocol(TTransport transport, + {this.strictRead: false, this.strictWrite: true}) + : super(transport); + + /// write + void writeMessageBegin(TMessage message) { + if (strictWrite) { + int version = VERSION_1 | message.type; + writeI32(version); + writeString(message.name); + writeI32(message.seqid); + } else { + writeString(message.name); + writeByte(message.type); + writeI32(message.seqid); + } + } + + void writeMessageEnd() {} + + void writeStructBegin(TStruct struct) {} + + void writeStructEnd() {} + + void writeFieldBegin(TField field) { + writeByte(field.type); + writeI16(field.id); + } + + void writeFieldEnd() {} + + void writeFieldStop() { + writeByte(TType.STOP); + } + + void writeMapBegin(TMap map) { + writeByte(map.keyType); + writeByte(map.valueType); + writeI32(map.length); + } + + void writeMapEnd() {} + + void writeListBegin(TList list) { + writeByte(list.elementType); + writeI32(list.length); + } + + void writeListEnd() {} + + void writeSetBegin(TSet set) { + writeByte(set.elementType); + writeI32(set.length); + } + + void writeSetEnd() {} + + void writeBool(bool b) { + if (b == null) b = false; + writeByte(b ? 1 : 0); + } + + final ByteData _byteOut = new ByteData(1); + void writeByte(int byte) { + if (byte == null) byte = 0; + _byteOut.setUint8(0, byte); + transport.write(_byteOut.buffer.asUint8List(), 0, 1); + } + + final ByteData _i16Out = new ByteData(2); + void writeI16(int i16) { + if (i16 == null) i16 = 0; + _i16Out.setInt16(0, i16); + transport.write(_i16Out.buffer.asUint8List(), 0, 2); + } + + final ByteData _i32Out = new ByteData(4); + void writeI32(int i32) { + if (i32 == null) i32 = 0; + _i32Out.setInt32(0, i32); + transport.write(_i32Out.buffer.asUint8List(), 0, 4); + } + + final ByteData _i64Out = new ByteData(8); + void writeI64(int i64) { + if (i64 == null) i64 = 0; + _i64Out.setInt64(0, i64); + transport.write(_i64Out.buffer.asUint8List(), 0, 8); + } + + void writeString(String s) { + var bytes = s != null ? _utf8Codec.encode(s) : new Uint8List.fromList([]); + writeI32(bytes.length); + transport.write(bytes, 0, bytes.length); + } + + final ByteData _doubleOut = new ByteData(8); + void writeDouble(double d) { + if (d == null) d = 0.0; + _doubleOut.setFloat64(0, d); + transport.write(_doubleOut.buffer.asUint8List(), 0, 8); + } + + void writeBinary(Uint8List bytes) { + var length = bytes.length; + writeI32(length); + transport.write(bytes, 0, length); + } + + /// read + TMessage readMessageBegin() { + String name; + int type; + int seqid; + + int size = readI32(); + if (size < 0) { + int version = size & VERSION_MASK; + if (version != VERSION_1) { + throw new TProtocolError(TProtocolErrorType.BAD_VERSION, + "Bad version in readMessageBegin: $version"); + } + type = size & 0x000000ff; + name = readString(); + seqid = readI32(); + } else { + if (strictRead) { + throw new TProtocolError(TProtocolErrorType.BAD_VERSION, + "Missing version in readMessageBegin"); + } + name = _readString(size); + type = readByte(); + seqid = readI32(); + } + return new TMessage(name, type, seqid); + } + + void readMessageEnd() {} + + TStruct readStructBegin() { + return new TStruct(); + } + + void readStructEnd() {} + + TField readFieldBegin() { + String name = ""; + int type = readByte(); + int id = type != TType.STOP ? readI16() : 0; + + return new TField(name, type, id); + } + + void readFieldEnd() {} + + TMap readMapBegin() { + int keyType = readByte(); + int valueType = readByte(); + int length = readI32(); + + return new TMap(keyType, valueType, length); + } + + void readMapEnd() {} + + TList readListBegin() { + int elementType = readByte(); + int length = readI32(); + + return new TList(elementType, length); + } + + void readListEnd() {} + + TSet readSetBegin() { + int elementType = readByte(); + int length = readI32(); + + return new TSet(elementType, length); + } + + void readSetEnd() {} + + bool readBool() => readByte() == 1; + + final Uint8List _byteIn = new Uint8List(1); + int readByte() { + transport.readAll(_byteIn, 0, 1); + return _byteIn.buffer.asByteData().getUint8(0); + } + + final Uint8List _i16In = new Uint8List(2); + int readI16() { + transport.readAll(_i16In, 0, 2); + return _i16In.buffer.asByteData().getInt16(0); + } + + final Uint8List _i32In = new Uint8List(4); + int readI32() { + transport.readAll(_i32In, 0, 4); + return _i32In.buffer.asByteData().getInt32(0); + } + + final Uint8List _i64In = new Uint8List(8); + int readI64() { + transport.readAll(_i64In, 0, 8); + return _i64In.buffer.asByteData().getInt64(0); + } + + final Uint8List _doubleIn = new Uint8List(8); + double readDouble() { + transport.readAll(_doubleIn, 0, 8); + return _doubleIn.buffer.asByteData().getFloat64(0); + } + + String readString() { + int size = readI32(); + return _readString(size); + } + + String _readString(int size) { + Uint8List stringIn = new Uint8List(size); + transport.readAll(stringIn, 0, size); + return _utf8Codec.decode(stringIn); + } + + Uint8List readBinary() { + int length = readI32(); + Uint8List binaryIn = new Uint8List(length); + transport.readAll(binaryIn, 0, length); + return binaryIn; + } +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/protocol/t_field.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/protocol/t_field.dart b/lib/dart/lib/src/protocol/t_field.dart new file mode 100644 index 0000000..444b4e5 --- /dev/null +++ b/lib/dart/lib/src/protocol/t_field.dart @@ -0,0 +1,26 @@ +/// 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. + +part of thrift; + +class TField { + final String name; + final int type; + final int id; + + TField(this.name, this.type, this.id); +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/protocol/t_json_protocol.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/protocol/t_json_protocol.dart b/lib/dart/lib/src/protocol/t_json_protocol.dart new file mode 100644 index 0000000..4fa6499 --- /dev/null +++ b/lib/dart/lib/src/protocol/t_json_protocol.dart @@ -0,0 +1,754 @@ +/// 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. + +part of thrift; + +class TJsonProtocolFactory implements TProtocolFactory<TJsonProtocol> { + TJsonProtocol getProtocol(TTransport transport) { + return new TJsonProtocol(transport); + } +} + +/// JSON protocol implementation for Thrift. +/// +/// Adapted from the C# version. +class TJsonProtocol extends TProtocol { + static const int VERSION_1 = 1; + + static const Utf8Codec utf8Codec = const Utf8Codec(); + + _BaseContext _context; + _BaseContext _rootContext; + _LookaheadReader _reader; + + final List<_BaseContext> _contextStack = []; + final Uint8List _tempBuffer = new Uint8List(4); + + TJsonProtocol(TTransport transport) : super(transport) { + _rootContext = new _BaseContext(this); + _reader = new _LookaheadReader(this); + } + + void _pushContext(_BaseContext c) { + _contextStack.add(c); + _context = c; + } + + void _popContext() { + _contextStack.removeLast(); + _context = _contextStack.isEmpty ? _rootContext : _contextStack.last; + } + + void _resetContext() { + _contextStack.clear(); + _context = _rootContext; + } + + /// Read a byte that must match [char]; otherwise throw a [TProtocolError]. + void _readJsonSyntaxChar(int charByte) { + int byte = _reader.read(); + if (byte != charByte) { + throw new TProtocolError(TProtocolErrorType.INVALID_DATA, + "Expected character ${new String.fromCharCode(charByte)} but found: ${new String.fromCharCode(byte)}"); + } + } + + int _hexVal(int byte) { + if (byte >= _Constants.HEX_0_BYTES[0] && + byte <= _Constants.HEX_9_BYTES[0]) { + return byte - _Constants.HEX_0_BYTES[0]; + } else if (byte >= _Constants.HEX_A_BYTES[0] && + byte <= _Constants.HEX_F_BYTES[0]) { + byte += 10; + return byte - _Constants.HEX_A_BYTES[0]; + } else { + throw new TProtocolError( + TProtocolErrorType.INVALID_DATA, "Expected hex character"); + } + } + + int _hexChar(int byte) => byte.toRadixString(16).codeUnitAt(0); + + /// write + + /// Write the [bytes] as JSON characters, escaping as needed. + void _writeJsonString(Uint8List bytes) { + _context.write(); + transport.writeAll(_Constants.QUOTE_BYTES); + + int length = bytes.length; + for (int i = 0; i < length; i++) { + int byte = bytes[i]; + if ((byte & 0x00FF) >= 0x30) { + if (byte == _Constants.BACKSLASH_BYTES[0]) { + transport.writeAll(_Constants.BACKSLASH_BYTES); + transport.writeAll(_Constants.BACKSLASH_BYTES); + } else { + transport.write(bytes, i, 1); + } + } else { + _tempBuffer[0] = _Constants.JSON_CHAR_TABLE[byte]; + if (_tempBuffer[0] == 1) { + transport.write(bytes, i, 1); + } else if (_tempBuffer[0] > 1) { + transport.writeAll(_Constants.BACKSLASH_BYTES); + transport.write(_tempBuffer, 0, 1); + } else { + transport.writeAll(_Constants.ESCSEQ_BYTES); + _tempBuffer[0] = _hexChar(byte >> 4); + _tempBuffer[1] = _hexChar(byte); + transport.write(_tempBuffer, 0, 2); + } + } + } + + transport.writeAll(_Constants.QUOTE_BYTES); + } + + void _writeJsonInteger(int i) { + if (i == null) i = 0; + + _context.write(); + String str = i.toString(); + + if (_context.escapeNumbers) { + transport.writeAll(_Constants.QUOTE_BYTES); + } + transport.writeAll(utf8Codec.encode(str)); + if (_context.escapeNumbers) { + transport.writeAll(_Constants.QUOTE_BYTES); + } + } + + void _writeJsonDouble(double d) { + if (d == null) d = 0.0; + + _context.write(); + String str = d.toString(); + bool escapeNumbers = d.isNaN || d.isInfinite || _context.escapeNumbers; + + if (escapeNumbers) { + transport.writeAll(_Constants.QUOTE_BYTES); + } + transport.writeAll(utf8Codec.encode(str)); + if (escapeNumbers) { + transport.writeAll(_Constants.QUOTE_BYTES); + } + } + + void _writeJsonBase64(Uint8List bytes) { + _context.write(); + transport.writeAll(_Constants.QUOTE_BYTES); + + String base64 = CryptoUtils.bytesToBase64(bytes); + transport.writeAll(utf8Codec.encode(base64)); + + transport.writeAll(_Constants.QUOTE_BYTES); + } + + void _writeJsonObjectStart() { + _context.write(); + transport.writeAll(_Constants.LBRACE_BYTES); + _pushContext(new _PairContext(this)); + } + + void _writeJsonObjectEnd() { + _popContext(); + transport.writeAll(_Constants.RBRACE_BYTES); + } + + void _writeJsonArrayStart() { + _context.write(); + transport.writeAll(_Constants.LBRACKET_BYTES); + _pushContext(new _ListContext(this)); + } + + void _writeJsonArrayEnd() { + _popContext(); + transport.writeAll(_Constants.RBRACKET_BYTES); + } + + void writeMessageBegin(TMessage message) { + _resetContext(); + + _writeJsonArrayStart(); + _writeJsonInteger(VERSION_1); + + _writeJsonString(utf8Codec.encode(message.name)); + _writeJsonInteger(message.type); + _writeJsonInteger(message.seqid); + } + + void writeMessageEnd() { + _writeJsonArrayEnd(); + } + + void writeStructBegin(TStruct struct) { + _writeJsonObjectStart(); + } + + void writeStructEnd() { + _writeJsonObjectEnd(); + } + + void writeFieldBegin(TField field) { + _writeJsonInteger(field.id); + _writeJsonObjectStart(); + _writeJsonString(_Constants.getTypeNameBytesForTypeId(field.type)); + } + + void writeFieldEnd() { + _writeJsonObjectEnd(); + } + + void writeFieldStop() {} + + void writeMapBegin(TMap map) { + _writeJsonArrayStart(); + _writeJsonString(_Constants.getTypeNameBytesForTypeId(map.keyType)); + _writeJsonString(_Constants.getTypeNameBytesForTypeId(map.valueType)); + _writeJsonInteger(map.length); + _writeJsonObjectStart(); + } + + void writeMapEnd() { + _writeJsonObjectEnd(); + _writeJsonArrayEnd(); + } + + void writeListBegin(TList list) { + _writeJsonArrayStart(); + _writeJsonString(_Constants.getTypeNameBytesForTypeId(list.elementType)); + _writeJsonInteger(list.length); + } + + void writeListEnd() { + _writeJsonArrayEnd(); + } + + void writeSetBegin(TSet set) { + _writeJsonArrayStart(); + _writeJsonString(_Constants.getTypeNameBytesForTypeId(set.elementType)); + _writeJsonInteger(set.length); + } + + void writeSetEnd() { + _writeJsonArrayEnd(); + } + + void writeBool(bool b) { + if (b == null) b = false; + _writeJsonInteger(b ? 1 : 0); + } + + void writeByte(int b) { + _writeJsonInteger(b); + } + + void writeI16(int i16) { + _writeJsonInteger(i16); + } + + void writeI32(int i32) { + _writeJsonInteger(i32); + } + + void writeI64(int i64) { + _writeJsonInteger(i64); + } + + void writeDouble(double d) { + _writeJsonDouble(d); + } + + void writeString(String s) { + var bytes = s != null ? utf8Codec.encode(s) : new Uint8List.fromList([]); + _writeJsonString(bytes); + } + + void writeBinary(Uint8List bytes) { + _writeJsonBase64(bytes); + } + + /// read + + Uint8List _readJsonString({bool skipContext: false}) { + List<int> bytes = []; + + if (!skipContext) { + _context.read(); + } + + _readJsonSyntaxChar(_Constants.QUOTE_BYTES[0]); + while (true) { + int byte = _reader.read(); + if (byte == _Constants.QUOTE_BYTES[0]) { + break; + } + + // escaped? + if (byte != _Constants.ESCSEQ_BYTES[0]) { + bytes.add(byte); + continue; + } + + byte = _reader.read(); + + // distinguish between \u00XX and control chars like \n + if (byte != _Constants.ESCSEQ_BYTES[1]) { + String char = new String.fromCharCode(byte); + int offset = _Constants.ESCAPE_CHARS.indexOf(char); + if (offset == -1) { + throw new TProtocolError( + TProtocolErrorType.INVALID_DATA, "Expected control char"); + } + byte = _Constants.ESCAPE_CHAR_VALS.codeUnitAt(offset); + bytes.add(byte); + continue; + } + + // it's \u00XX + _readJsonSyntaxChar(_Constants.HEX_0_BYTES[0]); + _readJsonSyntaxChar(_Constants.HEX_0_BYTES[0]); + transport.readAll(_tempBuffer, 0, 2); + byte = _hexVal(_tempBuffer[0]) << 4 + _hexVal(_tempBuffer[1]); + bytes.add(byte); + } + + return new Uint8List.fromList(bytes); + } + + String _readJsonNumericChars() { + StringBuffer buffer = new StringBuffer(); + while (true) { + if (!_Constants.isJsonNumeric(_reader.peek())) { + break; + } + buffer.write(new String.fromCharCode(_reader.read())); + } + return buffer.toString(); + } + + int _readJsonInteger() { + _context.read(); + + if (_context.escapeNumbers) { + _readJsonSyntaxChar(_Constants.QUOTE_BYTES[0]); + } + String str = _readJsonNumericChars(); + if (_context.escapeNumbers) { + _readJsonSyntaxChar(_Constants.QUOTE_BYTES[0]); + } + + try { + return int.parse(str); + } on FormatException catch (_) { + throw new TProtocolError(TProtocolErrorType.INVALID_DATA, + "Bad data encounted in numeric data"); + } + } + + double _readJsonDouble() { + _context.read(); + + if (_reader.peek() == _Constants.QUOTE_BYTES[0]) { + Uint8List bytes = _readJsonString(skipContext: true); + double d = double.parse(utf8Codec.decode(bytes), (_) { + throw new TProtocolError(TProtocolErrorType.INVALID_DATA, + "Bad data encounted in numeric data"); + }); + if (!_context.escapeNumbers && !d.isNaN && !d.isInfinite) { + throw new TProtocolError(TProtocolErrorType.INVALID_DATA, + "Numeric data unexpectedly quoted"); + } + return d; + } else { + if (_context.escapeNumbers) { + // This will throw - we should have had a quote if escapeNumbers == true + _readJsonSyntaxChar(_Constants.QUOTE_BYTES[0]); + } + return double.parse(_readJsonNumericChars(), (_) { + throw new TProtocolError(TProtocolErrorType.INVALID_DATA, + "Bad data encounted in numeric data"); + }); + } + } + + Uint8List _readJsonBase64() { + // convert UTF-8 bytes of a Base 64 encoded string to binary bytes + Uint8List base64Bytes = _readJsonString(); + String base64 = utf8Codec.decode(base64Bytes); + + return new Uint8List.fromList(CryptoUtils.base64StringToBytes(base64)); + } + + void _readJsonObjectStart() { + _context.read(); + _readJsonSyntaxChar(_Constants.LBRACE_BYTES[0]); + _pushContext(new _PairContext(this)); + } + + void _readJsonObjectEnd() { + _readJsonSyntaxChar(_Constants.RBRACE_BYTES[0]); + _popContext(); + } + + void _readJsonArrayStart() { + _context.read(); + _readJsonSyntaxChar(_Constants.LBRACKET_BYTES[0]); + _pushContext(new _ListContext(this)); + } + + void _readJsonArrayEnd() { + _readJsonSyntaxChar(_Constants.RBRACKET_BYTES[0]); + _popContext(); + } + + TMessage readMessageBegin() { + _resetContext(); + + _readJsonArrayStart(); + if (_readJsonInteger() != VERSION_1) { + throw new TProtocolError( + TProtocolErrorType.BAD_VERSION, "Message contained bad version."); + } + + Uint8List buffer = _readJsonString(); + String name = utf8Codec.decode(buffer); + int type = _readJsonInteger(); + int seqid = _readJsonInteger(); + + return new TMessage(name, type, seqid); + } + + void readMessageEnd() { + _readJsonArrayEnd(); + } + + TStruct readStructBegin() { + _readJsonObjectStart(); + return new TStruct(); + } + + void readStructEnd() { + _readJsonObjectEnd(); + } + + TField readFieldBegin() { + String name = ""; + int type = TType.STOP; + int id = 0; + + if (_reader.peek() != _Constants.RBRACE_BYTES[0]) { + id = _readJsonInteger(); + _readJsonObjectStart(); + type = _Constants.getTypeIdForTypeName(_readJsonString()); + } + + return new TField(name, type, id); + } + + void readFieldEnd() { + _readJsonObjectEnd(); + } + + TMap readMapBegin() { + _readJsonArrayStart(); + int keyType = _Constants.getTypeIdForTypeName(_readJsonString()); + int valueType = _Constants.getTypeIdForTypeName(_readJsonString()); + int length = _readJsonInteger(); + _readJsonObjectStart(); + + return new TMap(keyType, valueType, length); + } + + void readMapEnd() { + _readJsonObjectEnd(); + _readJsonArrayEnd(); + } + + TList readListBegin() { + _readJsonArrayStart(); + int elementType = _Constants.getTypeIdForTypeName(_readJsonString()); + int length = _readJsonInteger(); + + return new TList(elementType, length); + } + + void readListEnd() { + _readJsonArrayEnd(); + } + + TSet readSetBegin() { + _readJsonArrayStart(); + int elementType = _Constants.getTypeIdForTypeName(_readJsonString()); + int length = _readJsonInteger(); + + return new TSet(elementType, length); + } + + void readSetEnd() { + _readJsonArrayEnd(); + } + + bool readBool() { + return _readJsonInteger() == 0 ? false : true; + } + + int readByte() { + return _readJsonInteger(); + } + + int readI16() { + return _readJsonInteger(); + } + + int readI32() { + return _readJsonInteger(); + } + + int readI64() { + return _readJsonInteger(); + } + + double readDouble() { + return _readJsonDouble(); + } + + String readString() { + return utf8Codec.decode(_readJsonString()); + } + + Uint8List readBinary() { + return new Uint8List.fromList(_readJsonBase64()); + } +} + +class _Constants { + static const utf8codec = const Utf8Codec(); + + static final Uint8List HEX_0_BYTES = new Uint8List.fromList('0'.codeUnits); + static final Uint8List HEX_9_BYTES = new Uint8List.fromList('9'.codeUnits); + static final Uint8List HEX_A_BYTES = new Uint8List.fromList('a'.codeUnits); + static final Uint8List HEX_F_BYTES = new Uint8List.fromList('f'.codeUnits); + static final Uint8List COMMA_BYTES = new Uint8List.fromList(','.codeUnits); + static final Uint8List COLON_BYTES = new Uint8List.fromList(':'.codeUnits); + static final Uint8List LBRACE_BYTES = new Uint8List.fromList('{'.codeUnits); + static final Uint8List RBRACE_BYTES = new Uint8List.fromList('}'.codeUnits); + static final Uint8List LBRACKET_BYTES = new Uint8List.fromList('['.codeUnits); + static final Uint8List RBRACKET_BYTES = new Uint8List.fromList(']'.codeUnits); + static final Uint8List QUOTE_BYTES = new Uint8List.fromList('"'.codeUnits); + static final Uint8List BACKSLASH_BYTES = + new Uint8List.fromList(r'\'.codeUnits); + + static final ESCSEQ_BYTES = new Uint8List.fromList(r'\u00'.codeUnits); + + static final Uint8List JSON_CHAR_TABLE = new Uint8List.fromList([ + 0, 0, 0, 0, 0, 0, 0, 0, // 8 bytes + 'b'.codeUnitAt(0), 't'.codeUnitAt(0), 'n'.codeUnitAt(0), 0, // 4 bytes + 'f'.codeUnitAt(0), 'r'.codeUnitAt(0), 0, 0, // 4 bytes + 0, 0, 0, 0, 0, 0, 0, 0, // 8 bytes + 0, 0, 0, 0, 0, 0, 0, 0, // 8 bytes + 1, 1, '"'.codeUnitAt(0), 1, 1, 1, 1, 1, // 8 bytes + 1, 1, 1, 1, 1, 1, 1, 1 // 8 bytes + ]); + + static const String ESCAPE_CHARS = r'"\/bfnrt'; + static const String ESCAPE_CHAR_VALS = '"\\/\b\f\n\r\t'; + + static const String NAME_BOOL = 'tf'; + static const String NAME_BYTE = 'i8'; + static const String NAME_I16 = 'i16'; + static const String NAME_I32 = 'i32'; + static const String NAME_I64 = 'i64'; + static const String NAME_DOUBLE = 'dbl'; + static const String NAME_STRUCT = 'rec'; + static const String NAME_STRING = 'str'; + static const String NAME_MAP = 'map'; + static const String NAME_LIST = 'lst'; + static const String NAME_SET = 'set'; + + static final Map<int, Uint8List> _TYPE_ID_TO_NAME_BYTES = + new Map.unmodifiable({ + TType.BOOL: new Uint8List.fromList(NAME_BOOL.codeUnits), + TType.BYTE: new Uint8List.fromList(NAME_BYTE.codeUnits), + TType.I16: new Uint8List.fromList(NAME_I16.codeUnits), + TType.I32: new Uint8List.fromList(NAME_I32.codeUnits), + TType.I64: new Uint8List.fromList(NAME_I64.codeUnits), + TType.DOUBLE: new Uint8List.fromList(NAME_DOUBLE.codeUnits), + TType.STRING: new Uint8List.fromList(NAME_STRING.codeUnits), + TType.STRUCT: new Uint8List.fromList(NAME_STRUCT.codeUnits), + TType.MAP: new Uint8List.fromList(NAME_MAP.codeUnits), + TType.SET: new Uint8List.fromList(NAME_SET.codeUnits), + TType.LIST: new Uint8List.fromList(NAME_LIST.codeUnits) + }); + + static Uint8List getTypeNameBytesForTypeId(int typeId) { + if (!_TYPE_ID_TO_NAME_BYTES.containsKey(typeId)) { + throw new TProtocolError( + TProtocolErrorType.NOT_IMPLEMENTED, "Unrecognized type"); + } + + return _TYPE_ID_TO_NAME_BYTES[typeId]; + } + + static final Map<String, int> _NAME_TO_TYPE_ID = new Map.unmodifiable({ + NAME_BOOL: TType.BOOL, + NAME_BYTE: TType.BYTE, + NAME_I16: TType.I16, + NAME_I32: TType.I32, + NAME_I64: TType.I64, + NAME_DOUBLE: TType.DOUBLE, + NAME_STRING: TType.STRING, + NAME_STRUCT: TType.STRUCT, + NAME_MAP: TType.MAP, + NAME_SET: TType.SET, + NAME_LIST: TType.LIST + }); + + static int getTypeIdForTypeName(Uint8List bytes) { + String name = utf8codec.decode(bytes); + if (!_NAME_TO_TYPE_ID.containsKey(name)) { + throw new TProtocolError( + TProtocolErrorType.NOT_IMPLEMENTED, "Unrecognized type"); + } + + return _NAME_TO_TYPE_ID[name]; + } + + static final Set<int> _JSON_NUMERICS = new Set.from([ + '+'.codeUnitAt(0), + '-'.codeUnitAt(0), + '.'.codeUnitAt(0), + '0'.codeUnitAt(0), + '1'.codeUnitAt(0), + '2'.codeUnitAt(0), + '3'.codeUnitAt(0), + '4'.codeUnitAt(0), + '5'.codeUnitAt(0), + '6'.codeUnitAt(0), + '7'.codeUnitAt(0), + '8'.codeUnitAt(0), + '9'.codeUnitAt(0), + 'E'.codeUnitAt(0), + 'e'.codeUnitAt(0) + ]); + + static bool isJsonNumeric(int byte) { + return _JSON_NUMERICS.contains(byte); + } +} + +class _LookaheadReader { + final TJsonProtocol protocol; + + _LookaheadReader(this.protocol); + + bool _hasData = false; + final Uint8List _data = new Uint8List(1); + + int read() { + if (_hasData) { + _hasData = false; + } else { + protocol.transport.readAll(_data, 0, 1); + } + + return _data[0]; + } + + int peek() { + if (!_hasData) { + protocol.transport.readAll(_data, 0, 1); + } + _hasData = true; + + return _data[0]; + } +} + +class _BaseContext { + final TJsonProtocol protocol; + + _BaseContext(this.protocol); + + void write() {} + + void read() {} + + bool get escapeNumbers => false; + + String toString() => 'BaseContext'; +} + +class _ListContext extends _BaseContext { + _ListContext(TJsonProtocol protocol) : super(protocol); + + bool _first = true; + + void write() { + if (_first) { + _first = false; + } else { + protocol.transport.writeAll(_Constants.COMMA_BYTES); + } + } + + void read() { + if (_first) { + _first = false; + } else { + protocol._readJsonSyntaxChar(_Constants.COMMA_BYTES[0]); + } + } + + String toString() => 'ListContext'; +} + +class _PairContext extends _BaseContext { + _PairContext(TJsonProtocol protocol) : super(protocol); + + bool _first = true; + bool _colon = true; + + Uint8List get symbolBytes => + _colon ? _Constants.COLON_BYTES : _Constants.COMMA_BYTES; + + void write() { + if (_first) { + _first = false; + _colon = true; + } else { + protocol.transport.writeAll(symbolBytes); + _colon = !_colon; + } + } + + void read() { + if (_first) { + _first = false; + _colon = true; + } else { + protocol._readJsonSyntaxChar(symbolBytes[0]); + _colon = !_colon; + } + } + + bool get escapeNumbers => _colon; + + String toString() => 'PairContext'; +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/protocol/t_list.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/protocol/t_list.dart b/lib/dart/lib/src/protocol/t_list.dart new file mode 100644 index 0000000..49f4673 --- /dev/null +++ b/lib/dart/lib/src/protocol/t_list.dart @@ -0,0 +1,25 @@ +/// 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. + +part of thrift; + +class TList { + final int elementType; + final int length; + + TList(this.elementType, this.length); +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/protocol/t_map.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/protocol/t_map.dart b/lib/dart/lib/src/protocol/t_map.dart new file mode 100644 index 0000000..efdf681 --- /dev/null +++ b/lib/dart/lib/src/protocol/t_map.dart @@ -0,0 +1,26 @@ +/// 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. + +part of thrift; + +class TMap { + final int keyType; + final int valueType; + final int length; + + TMap(this.keyType, this.valueType, this.length); +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/protocol/t_message.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/protocol/t_message.dart b/lib/dart/lib/src/protocol/t_message.dart new file mode 100644 index 0000000..cc7b886 --- /dev/null +++ b/lib/dart/lib/src/protocol/t_message.dart @@ -0,0 +1,35 @@ +/// 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. + +part of thrift; + +class TMessageType { + static const int CALL = 1; + static const int REPLY = 2; + static const int EXCEPTION = 3; + static const int ONEWAY = 4; +} + +class TMessage { + final String name; + final int type; + final int seqid; + + TMessage(this.name, this.type, this.seqid); + + String toString() => "<TMessage name: '$name' type: $type seqid: $seqid>"; +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/protocol/t_multiplexed_protocol.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/protocol/t_multiplexed_protocol.dart b/lib/dart/lib/src/protocol/t_multiplexed_protocol.dart new file mode 100644 index 0000000..078a6d7 --- /dev/null +++ b/lib/dart/lib/src/protocol/t_multiplexed_protocol.dart @@ -0,0 +1,43 @@ +/// 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. + +part of thrift; + +/// Adapted from the C# version. +class TMultiplexedProtocol extends TProtocolDecorator { + static const SEPARATOR = ':'; + + final String _serviceName; + + TMultiplexedProtocol(TProtocol protocol, String serviceName) + : _serviceName = serviceName, + super(protocol) { + if (serviceName == null) { + throw new ArgumentError.notNull("serviceName"); + } + } + + void writeMessageBegin(TMessage message) { + if (message.type == TMessageType.CALL || + message.type == TMessageType.ONEWAY) { + String name = _serviceName + SEPARATOR + message.name; + message = new TMessage(name, message.type, message.seqid); + } + + super.writeMessageBegin(message); + } +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/protocol/t_protocol.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/protocol/t_protocol.dart b/lib/dart/lib/src/protocol/t_protocol.dart new file mode 100644 index 0000000..f49c032 --- /dev/null +++ b/lib/dart/lib/src/protocol/t_protocol.dart @@ -0,0 +1,95 @@ +/// 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. + +part of thrift; + +abstract class TProtocol { + final TTransport transport; + + TProtocol(this.transport); + + /// Write + void writeMessageBegin(TMessage message); + void writeMessageEnd(); + + void writeStructBegin(TStruct struct); + void writeStructEnd(); + + void writeFieldBegin(TField field); + void writeFieldEnd(); + void writeFieldStop(); + + void writeMapBegin(TMap map); + void writeMapEnd(); + + void writeListBegin(TList list); + void writeListEnd(); + + void writeSetBegin(TSet set); + void writeSetEnd(); + + void writeBool(bool b); + + void writeByte(int b); + + void writeI16(int i16); + + void writeI32(int i32); + + void writeI64(int i64); + + void writeDouble(double d); + + void writeString(String str); + + void writeBinary(Uint8List bytes); + + /// Read + TMessage readMessageBegin(); + void readMessageEnd(); + + TStruct readStructBegin(); + void readStructEnd(); + + TField readFieldBegin(); + void readFieldEnd(); + + TMap readMapBegin(); + void readMapEnd(); + + TList readListBegin(); + void readListEnd(); + + TSet readSetBegin(); + void readSetEnd(); + + bool readBool(); + + int readByte(); + + int readI16(); + + int readI32(); + + int readI64(); + + double readDouble(); + + String readString(); + + Uint8List readBinary(); +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/protocol/t_protocol_decorator.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/protocol/t_protocol_decorator.dart b/lib/dart/lib/src/protocol/t_protocol_decorator.dart new file mode 100644 index 0000000..9cd02f6 --- /dev/null +++ b/lib/dart/lib/src/protocol/t_protocol_decorator.dart @@ -0,0 +1,150 @@ +/// 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. + +part of thrift; + +/// Forward all operations to the wrapped protocol. Used as a base class. +/// +/// Adapted from the C# version. +class TProtocolDecorator extends TProtocol { + final TProtocol _protocol; + + TProtocolDecorator(TProtocol protocol) + : _protocol = protocol, + super(protocol.transport); + + /// Write + + void writeMessageBegin(TMessage message) { + _protocol.writeMessageBegin(message); + } + + void writeMessageEnd() { + _protocol.writeMessageEnd(); + } + + void writeStructBegin(TStruct struct) { + _protocol.writeStructBegin(struct); + } + + void writeStructEnd() { + _protocol.writeStructEnd(); + } + + void writeFieldBegin(TField field) { + _protocol.writeFieldBegin(field); + } + + void writeFieldEnd() { + _protocol.writeFieldEnd(); + } + + void writeFieldStop() { + _protocol.writeFieldStop(); + } + + void writeMapBegin(TMap map) { + _protocol.writeMapBegin(map); + } + + void writeMapEnd() { + _protocol.writeMapEnd(); + } + + void writeListBegin(TList list) { + _protocol.writeListBegin(list); + } + + void writeListEnd() { + _protocol.writeListEnd(); + } + + void writeSetBegin(TSet set) { + _protocol.writeSetBegin(set); + } + + void writeSetEnd() { + _protocol.writeSetEnd(); + } + + void writeBool(bool b) { + _protocol.writeBool(b); + } + + void writeByte(int b) { + _protocol.writeByte(b); + } + + void writeI16(int i16) { + _protocol.writeI16(i16); + } + + void writeI32(int i32) { + _protocol.writeI32(i32); + } + + void writeI64(int i64) { + _protocol.writeI64(i64); + } + + void writeDouble(double d) { + _protocol.writeDouble(d); + } + + void writeString(String str) { + _protocol.writeString(str); + } + + void writeBinary(Uint8List bytes) { + _protocol.writeBinary(bytes); + } + + /// Read + TMessage readMessageBegin() => _protocol.readMessageBegin(); + void readMessageEnd() => _protocol.readMessageEnd(); + + TStruct readStructBegin() => _protocol.readStructBegin(); + void readStructEnd() => _protocol.readStructEnd(); + + TField readFieldBegin() => _protocol.readFieldBegin(); + void readFieldEnd() => _protocol.readFieldEnd(); + + TMap readMapBegin() => _protocol.readMapBegin(); + void readMapEnd() => _protocol.readMapEnd(); + + TList readListBegin() => _protocol.readListBegin(); + void readListEnd() => _protocol.readListEnd(); + + TSet readSetBegin() => _protocol.readSetBegin(); + void readSetEnd() => _protocol.readSetEnd(); + + bool readBool() => _protocol.readBool(); + + int readByte() => _protocol.readByte(); + + int readI16() => _protocol.readI16(); + + int readI32() => _protocol.readI32(); + + int readI64() => _protocol.readI64(); + + double readDouble() => _protocol.readDouble(); + + String readString() => _protocol.readString(); + + Uint8List readBinary() => _protocol.readBinary(); +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/protocol/t_protocol_error.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/protocol/t_protocol_error.dart b/lib/dart/lib/src/protocol/t_protocol_error.dart new file mode 100644 index 0000000..456baeb --- /dev/null +++ b/lib/dart/lib/src/protocol/t_protocol_error.dart @@ -0,0 +1,33 @@ +/// 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. + +part of thrift; + +class TProtocolErrorType { + static const int UNKNOWN = 0; + static const int INVALID_DATA = 1; + static const int NEGATIVE_SIZE = 2; + static const int SIZE_LIMIT = 3; + static const int BAD_VERSION = 4; + static const int NOT_IMPLEMENTED = 5; + static const int DEPTH_LIMIT = 6; +} + +class TProtocolError extends TError { + TProtocolError([int type = TProtocolErrorType.UNKNOWN, String message = ""]) + : super(type, message); +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/protocol/t_protocol_factory.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/protocol/t_protocol_factory.dart b/lib/dart/lib/src/protocol/t_protocol_factory.dart new file mode 100644 index 0000000..922c6cb --- /dev/null +++ b/lib/dart/lib/src/protocol/t_protocol_factory.dart @@ -0,0 +1,22 @@ +/// 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. + +part of thrift; + +abstract class TProtocolFactory<T extends TProtocol> { + T getProtocol(TTransport transport); +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/protocol/t_protocol_util.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/protocol/t_protocol_util.dart b/lib/dart/lib/src/protocol/t_protocol_util.dart new file mode 100644 index 0000000..ad20068 --- /dev/null +++ b/lib/dart/lib/src/protocol/t_protocol_util.dart @@ -0,0 +1,107 @@ +/// 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. + +part of thrift; + +class TProtocolUtil { + // equal to JavaScript Number.MAX_SAFE_INTEGER, 2^53 - 1 + static const int defaultRecursionLimit = 9007199254740991; + + static int maxRecursionLimit = defaultRecursionLimit; + + static skip(TProtocol prot, int type) { + _skip(prot, type, maxRecursionLimit); + } + + static _skip(TProtocol prot, int type, int recursionLimit) { + if (recursionLimit <= 0) { + throw new TProtocolError( + TProtocolErrorType.DEPTH_LIMIT, "Depth limit exceeded"); + } + + switch (type) { + case TType.BOOL: + prot.readBool(); + break; + + case TType.BYTE: + prot.readByte(); + break; + + case TType.I16: + prot.readI16(); + break; + + case TType.I32: + prot.readI32(); + break; + + case TType.I64: + prot.readI64(); + break; + + case TType.DOUBLE: + prot.readDouble(); + break; + + case TType.STRING: + prot.readBinary(); + break; + + case TType.STRUCT: + prot.readStructBegin(); + while (true) { + TField field = prot.readFieldBegin(); + if (field.type == TType.STOP) { + break; + } + _skip(prot, field.type, recursionLimit - 1); + prot.readFieldEnd(); + } + prot.readStructEnd(); + break; + + case TType.MAP: + TMap map = prot.readMapBegin(); + for (int i = 0; i < map.length; i++) { + _skip(prot, map.keyType, recursionLimit - 1); + _skip(prot, map.valueType, recursionLimit - 1); + } + prot.readMapEnd(); + break; + + case TType.SET: + TSet set = prot.readSetBegin(); + for (int i = 0; i < set.length; i++) { + _skip(prot, set.elementType, recursionLimit - 1); + } + prot.readSetEnd(); + break; + + case TType.LIST: + TList list = prot.readListBegin(); + for (int i = 0; i < list.length; i++) { + _skip(prot, list.elementType, recursionLimit - 1); + } + prot.readListEnd(); + break; + + default: + break; + } + } +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/protocol/t_set.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/protocol/t_set.dart b/lib/dart/lib/src/protocol/t_set.dart new file mode 100644 index 0000000..b342537 --- /dev/null +++ b/lib/dart/lib/src/protocol/t_set.dart @@ -0,0 +1,25 @@ +/// 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. + +part of thrift; + +class TSet { + final int elementType; + final int length; + + TSet(this.elementType, this.length); +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/protocol/t_struct.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/protocol/t_struct.dart b/lib/dart/lib/src/protocol/t_struct.dart new file mode 100644 index 0000000..0303f63 --- /dev/null +++ b/lib/dart/lib/src/protocol/t_struct.dart @@ -0,0 +1,24 @@ +/// 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. + +part of thrift; + +class TStruct { + final String name; + + TStruct([this.name = ""]); +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/protocol/t_type.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/protocol/t_type.dart b/lib/dart/lib/src/protocol/t_type.dart new file mode 100644 index 0000000..3919d96 --- /dev/null +++ b/lib/dart/lib/src/protocol/t_type.dart @@ -0,0 +1,34 @@ +/// 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. + +part of thrift; + +class TType { + static const int STOP = 0; + static const int VOID = 1; + static const int BOOL = 2; + static const int BYTE = 3; + static const int DOUBLE = 4; + static const int I16 = 6; + static const int I32 = 8; + static const int I64 = 10; + static const int STRING = 11; + static const int STRUCT = 12; + static const int MAP = 13; + static const int SET = 14; + static const int LIST = 15; +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/t_application_error.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/t_application_error.dart b/lib/dart/lib/src/t_application_error.dart new file mode 100644 index 0000000..6f8abd4 --- /dev/null +++ b/lib/dart/lib/src/t_application_error.dart @@ -0,0 +1,104 @@ +/// 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. + +part of thrift; + +class TApplicationErrorType { + static const int UNKNOWN = 0; + static const int UNKNOWN_METHOD = 1; + static const int INVALID_MESSAGE_TYPE = 2; + static const int WRONG_METHOD_NAME = 3; + static const int BAD_SEQUENCE_ID = 4; + static const int MISSING_RESULT = 5; + static const int INTERNAL_ERROR = 6; + static const int PROTOCOL_ERROR = 7; + static const int INVALID_TRANSFORM = 8; + static const int INVALID_PROTOCOL = 9; + static const int UNSUPPORTED_CLIENT_TYPE = 10; +} + +class TApplicationError extends TError { + static final TStruct _struct = new TStruct("TApplicationError"); + static const int MESSAGE = 1; + static final TField _messageField = + new TField("message", TType.STRING, MESSAGE); + static const int TYPE = 2; + static final TField _typeField = new TField("type", TType.I32, TYPE); + + TApplicationError( + [int type = TApplicationErrorType.UNKNOWN, String message = ""]) + : super(type, message); + + static TApplicationError read(TProtocol iprot) { + TField field; + + String message = null; + int type = TApplicationErrorType.UNKNOWN; + + iprot.readStructBegin(); + while (true) { + field = iprot.readFieldBegin(); + + if (field.type == TType.STOP) { + break; + } + + switch (field.id) { + case MESSAGE: + if (field.type == TType.STRING) { + message = iprot.readString(); + } else { + TProtocolUtil.skip(iprot, field.type); + } + break; + + case TYPE: + if (field.type == TType.I32) { + type = iprot.readI32(); + } else { + TProtocolUtil.skip(iprot, field.type); + } + break; + + default: + TProtocolUtil.skip(iprot, field.type); + break; + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + + return new TApplicationError(type, message); + } + + write(TProtocol oprot) { + oprot.writeStructBegin(_struct); + + if (message != null && !message.isEmpty) { + oprot.writeFieldBegin(_messageField); + oprot.writeString(message); + oprot.writeFieldEnd(); + } + + oprot.writeFieldBegin(_typeField); + oprot.writeI32(type); + oprot.writeFieldEnd(); + + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/t_base.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/t_base.dart b/lib/dart/lib/src/t_base.dart new file mode 100644 index 0000000..d5571b6 --- /dev/null +++ b/lib/dart/lib/src/t_base.dart @@ -0,0 +1,37 @@ +/// 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. + +part of thrift; + +abstract class TBase { + /// Reads the TObject from the given input protocol. + void read(TProtocol iprot); + + /// Writes the objects out to the [oprot] protocol. + void write(TProtocol oprot); + + /// Check if a field is currently set or unset, using the [fieldId]. + bool isSet(int fieldId); + + /// Get a field's value by [fieldId]. Primitive types will be wrapped in the + /// appropriate "boxed" types. + getFieldValue(int fieldId); + + /// Set a field's value by [fieldId]. Primitive types must be "boxed" in the + /// appropriate object wrapper type. + setFieldValue(int fieldId, Object value); +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/t_error.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/t_error.dart b/lib/dart/lib/src/t_error.dart new file mode 100644 index 0000000..93ab732 --- /dev/null +++ b/lib/dart/lib/src/t_error.dart @@ -0,0 +1,27 @@ +/// 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. + +part of thrift; + +class TError extends Error { + final String message; + final int type; + + TError(this.type, this.message); + + String toString() => "<TError type: $type message: '$message'>"; +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/t_processor.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/t_processor.dart b/lib/dart/lib/src/t_processor.dart new file mode 100644 index 0000000..dcf20fb --- /dev/null +++ b/lib/dart/lib/src/t_processor.dart @@ -0,0 +1,24 @@ +/// 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. + +part of thrift; + +/// A processor is a generic object which operates upon an input stream and +/// writes to some output stream. +abstract class TProcessor { + bool process(TProtocol input, TProtocol output); +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/transport/t_buffered_transport.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/transport/t_buffered_transport.dart b/lib/dart/lib/src/transport/t_buffered_transport.dart new file mode 100644 index 0000000..1d44c62 --- /dev/null +++ b/lib/dart/lib/src/transport/t_buffered_transport.dart @@ -0,0 +1,98 @@ +/// 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. + +part of thrift; + +/// Buffered implementation of [TTransport]. +class TBufferedTransport extends TTransport { + final List<int> _writeBuffer = []; + Iterator<int> _readIterator; + + Uint8List _consumeWriteBuffer() { + Uint8List buffer = new Uint8List.fromList(_writeBuffer); + _writeBuffer.clear(); + return buffer; + } + + void _setReadBuffer(Uint8List readBuffer) { + _readIterator = readBuffer != null ? readBuffer.iterator : null; + } + + void _reset({bool isOpen: false}) { + _isOpen = isOpen; + _writeBuffer.clear(); + _readIterator = null; + } + + bool get hasReadData => _readIterator != null; + + bool _isOpen; + bool get isOpen => _isOpen; + + Future open() async { + _reset(isOpen: true); + } + + Future close() async { + _reset(isOpen: false); + } + + int read(Uint8List buffer, int offset, int length) { + if (buffer == null) { + throw new ArgumentError.notNull("buffer"); + } + + if (offset + length > buffer.length) { + throw new ArgumentError("The range exceeds the buffer length"); + } + + if (_readIterator == null || length <= 0) { + return 0; + } + + int i = 0; + while (i < length && _readIterator.moveNext()) { + buffer[offset + i] = _readIterator.current; + i++; + } + + // cleanup iterator when we've reached the end + if (_readIterator.current == null) { + _readIterator = null; + } + + return i; + } + + void write(Uint8List buffer, int offset, int length) { + if (buffer == null) { + throw new ArgumentError.notNull("buffer"); + } + + if (offset + length > buffer.length) { + throw new ArgumentError("The range exceeds the buffer length"); + } + + _writeBuffer.addAll(buffer.sublist(offset, offset + length)); + } + + Future flush() { + _readIterator = _consumeWriteBuffer().iterator; + + return new Future.value(); + } +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/transport/t_framed_transport.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/transport/t_framed_transport.dart b/lib/dart/lib/src/transport/t_framed_transport.dart new file mode 100644 index 0000000..baf8f32 --- /dev/null +++ b/lib/dart/lib/src/transport/t_framed_transport.dart @@ -0,0 +1,83 @@ +/// 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. + +part of thrift; + +/// Framed [TTransport]. +/// +/// Adapted from the Java Framed transport. +class TFramedTransport extends TBufferedTransport { + static const int headerByteCount = 4; + + final TTransport _transport; + + final Uint8List headerBytes = new Uint8List(headerByteCount); + + TFramedTransport(TTransport transport) : _transport = transport { + if (transport == null) { + throw new ArgumentError.notNull("transport"); + } + } + + bool get isOpen => _transport.isOpen; + + Future open() { + _reset(isOpen: true); + return _transport.open(); + } + + Future close() { + _reset(isOpen: false); + return _transport.close(); + } + + int read(Uint8List buffer, int offset, int length) { + if (hasReadData) { + int got = super.read(buffer, offset, length); + if (got > 0) return got; + } + + _readFrame(); + + return super.read(buffer, offset, length); + } + + void _readFrame() { + _transport.readAll(headerBytes, 0, headerByteCount); + int size = headerBytes.buffer.asByteData().getUint32(0); + + if (size < 0) { + throw new TTransportError( + TTransportErrorType.UNKNOWN, "Read a negative frame size: $size"); + } + + Uint8List buffer = new Uint8List(size); + _transport.readAll(buffer, 0, size); + _setReadBuffer(buffer); + } + + Future flush() { + Uint8List buffer = _consumeWriteBuffer(); + int length = buffer.length; + + headerBytes.buffer.asByteData().setUint32(0, length); + _transport.write(headerBytes, 0, headerByteCount); + _transport.write(buffer, 0, length); + + return _transport.flush(); + } +} http://git-wip-us.apache.org/repos/asf/thrift/blob/932c4700/lib/dart/lib/src/transport/t_http_transport.dart ---------------------------------------------------------------------- diff --git a/lib/dart/lib/src/transport/t_http_transport.dart b/lib/dart/lib/src/transport/t_http_transport.dart new file mode 100644 index 0000000..0e99a1d --- /dev/null +++ b/lib/dart/lib/src/transport/t_http_transport.dart @@ -0,0 +1,100 @@ +/// 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. + +part of thrift; + +/// HTTP implementation of [TTransport]. +/// +/// For example: +/// +/// var transport = new THttpClientTransport(new BrowserClient(), +/// new THttpConfig(url, {'X-My-Custom-Header': 'my value'})); +/// var protocol = new TJsonProtocol(transport); +/// var client = new MyThriftServiceClient(protocol); +/// var result = client.myMethod(); +/// +/// Adapted from the JS XHR HTTP transport. +class THttpClientTransport extends TBufferedTransport { + final Client httpClient; + final THttpConfig config; + + THttpClientTransport(this.httpClient, this.config) { + if (httpClient == null) { + throw new ArgumentError.notNull("httpClient"); + } + } + + Future close() async { + _reset(isOpen: false); + httpClient.close(); + } + + Future flush() { + var requestBody = CryptoUtils.bytesToBase64(_consumeWriteBuffer()); + + // Use a sync completer to ensure that the buffer can be read immediately + // after the read buffer is set, and avoid a race condition where another + // response could overwrite the read buffer. + var completer = new Completer.sync(); + + httpClient + .post(config.url, headers: config.headers, body: requestBody) + .then((response) { + Uint8List data; + try { + data = new Uint8List.fromList( + CryptoUtils.base64StringToBytes(response.body)); + } on FormatException catch (_) { + throw new TProtocolError(TProtocolErrorType.INVALID_DATA, + "Expected a Base 64 encoded string."); + } + + _setReadBuffer(data); + completer.complete(); + }); + + return completer.future; + } +} + +class THttpConfig { + final Uri url; + + Map<String, String> _headers; + get headers => _headers; + + THttpConfig(this.url, Map<String, String> headers) { + if (url == null || !url.hasAuthority) { + throw new ArgumentError("Invalid url"); + } + + _initHeaders(headers); + } + + void _initHeaders(Map<String, String> initial) { + var h = {}; + + if (initial != null) { + h.addAll(initial); + } + + h['Content-Type'] = 'application/x-thrift'; + h['Accept'] = 'application/x-thrift'; + + _headers = new Map.unmodifiable(h); + } +}
