All Apache Thrift tutorials require that you have:
Generated the tutorial.thrift and shared.thrift files:
thrift -r --gen dart tutorial.thrift
Followed all prerequisites listed below.
TBD
import 'dart:html'; import 'package:thrift/thrift.dart'; import 'package:thrift/thrift_browser.dart'; import 'package:shared/shared.dart'; import 'package:tutorial/tutorial.dart'; /// Adapted from the AS3 tutorial void main() { new CalculatorUI(querySelector('#output')).start(); } class CalculatorUI { final DivElement output; CalculatorUI(this.output); TTransport _transport; Calculator _calculatorClient; void start() { _buildInterface(); _initConnection(); } void _validate() { if (!_transport.isOpen) { window.alert("The transport is not open!"); } } void _initConnection() { _transport = new TAsyncClientSocketTransport( new TWebSocket(Uri.parse('ws://127.0.0.1:9090/ws')), new TMessageReader(new TBinaryProtocolFactory())); TProtocol protocol = new TBinaryProtocol(_transport); _transport.open(); _calculatorClient = new CalculatorClient(protocol); } void _buildInterface() { output.children.forEach((e) { e.remove(); }); _buildPingComponent(); _buildAddComponent(); _buildCalculatorComponent(); _buildGetStructComponent(); } void _buildPingComponent() { output.append(new HeadingElement.h3()..text = "Ping"); ButtonElement pingButton = new ButtonElement() ..text = "PING" ..onClick.listen(_onPingClick); output.append(pingButton); } void _onPingClick(MouseEvent e) { _validate(); _calculatorClient.ping(); } void _buildAddComponent() { output.append(new HeadingElement.h3()..text = "Add"); InputElement num1 = new InputElement() ..id = "add1" ..type = "number" ..style.fontSize = "14px" ..style.width = "50px"; output.append(num1); SpanElement op = new SpanElement() ..text = "+" ..style.fontSize = "14px" ..style.marginLeft = "10px"; output.append(op); InputElement num2 = new InputElement() ..id = "add2" ..type = "number" ..style.fontSize = "14px" ..style.width = "50px" ..style.marginLeft = "10px"; output.append(num2); ButtonElement addButton = new ButtonElement() ..text = "=" ..style.fontSize = "14px" ..style.marginLeft = "10px" ..onClick.listen(_onAddClick); output.append(addButton); SpanElement result = new SpanElement() ..id = "addResult" ..style.fontSize = "14px" ..style.marginLeft = "10px"; output.append(result); } void _onAddClick(MouseEvent e) { _validate(); InputElement num1 = querySelector("#add1"); InputElement num2 = querySelector("#add2"); SpanElement result = querySelector("#addResult"); _calculatorClient .add(int.parse(num1.value), int.parse(num2.value)) .then((int n) { result.text = "$n"; }); } void _buildCalculatorComponent() { output.append(new HeadingElement.h3()..text = "Calculator"); InputElement num1 = new InputElement() ..id = "calc1" ..type = "number" ..style.fontSize = "14px" ..style.width = "50px"; output.append(num1); SelectElement op = new SelectElement() ..id = "calcOp" ..multiple = false ..selectedIndex = 0 ..style.fontSize = "16px" ..style.marginLeft = "10px" ..style.width = "50px"; OptionElement addOp = new OptionElement() ..text = "+" ..value = Operation.ADD.toString(); op.add(addOp, 0); OptionElement subtractOp = new OptionElement() ..text = "-" ..value = Operation.SUBTRACT.toString(); op.add(subtractOp, 1); OptionElement multiplyOp = new OptionElement() ..text = "*" ..value = Operation.MULTIPLY.toString(); op.add(multiplyOp, 2); OptionElement divideOp = new OptionElement() ..text = "/" ..value = Operation.DIVIDE.toString(); op.add(divideOp, 3); output.append(op); InputElement num2 = new InputElement() ..id = "calc2" ..type = "number" ..style.fontSize = "14px" ..style.width = "50px" ..style.marginLeft = "10px"; output.append(num2); ButtonElement calcButton = new ButtonElement() ..text = "=" ..style.fontSize = "14px" ..style.marginLeft = "10px" ..onClick.listen(_onCalcClick); output.append(calcButton); SpanElement result = new SpanElement() ..id = "calcResult" ..style.fontSize = "14px" ..style.marginLeft = "10px"; output.append(result); output.append(new BRElement()); output.append(new BRElement()); LabelElement logIdLabel = new LabelElement() ..text = "Log ID:" ..style.fontSize = "14px"; output.append(logIdLabel); InputElement logId = new InputElement() ..id = "logId" ..type = "number" ..value = "1" ..style.fontSize = "14px" ..style.width = "50px" ..style.marginLeft = "10px"; output.append(logId); LabelElement commentLabel = new LabelElement() ..text = "Comment:" ..style.fontSize = "14px" ..style.marginLeft = "10px"; output.append(commentLabel); InputElement comment = new InputElement() ..id = "comment" ..style.fontSize = "14px" ..style.width = "100px" ..style.marginLeft = "10px"; output.append(comment); } void _onCalcClick(MouseEvent e) { _validate(); InputElement num1 = querySelector("#calc1"); InputElement num2 = querySelector("#calc2"); SelectElement op = querySelector("#calcOp"); SpanElement result = querySelector("#calcResult"); InputElement logId = querySelector("#logId"); InputElement comment = querySelector("#comment"); int logIdValue = int.parse(logId.value); logId.value = (logIdValue + 1).toString(); Work work = new Work(); work.num1 = int.parse(num1.value); work.num2 = int.parse(num2.value); work.op = int.parse(op.options[op.selectedIndex].value); work.comment = comment.value; _calculatorClient.calculate(logIdValue, work).then((int n) { result.text = "$n"; }); } void _buildGetStructComponent() { output.append(new HeadingElement.h3()..text = "Get Struct"); LabelElement logIdLabel = new LabelElement() ..text = "Struct Key:" ..style.fontSize = "14px"; output.append(logIdLabel); InputElement logId = new InputElement() ..id = "structKey" ..type = "number" ..value = "1" ..style.fontSize = "14px" ..style.width = "50px" ..style.marginLeft = "10px"; output.append(logId); ButtonElement getStructButton = new ButtonElement() ..text = "GET" ..style.fontSize = "14px" ..style.marginLeft = "10px" ..onClick.listen(_onGetStructClick); output.append(getStructButton); output.append(new BRElement()); output.append(new BRElement()); TextAreaElement result = new TextAreaElement() ..id = "getStructResult" ..style.fontSize = "14px" ..style.width = "300px" ..style.height = "50px" ..style.marginLeft = "10px"; output.append(result); } void _onGetStructClick(MouseEvent e) { _validate(); InputElement structKey = querySelector("#structKey"); TextAreaElement result = querySelector("#getStructResult"); _calculatorClient .getStruct(int.parse(structKey.value)) .then((SharedStruct s) { result.text = "${s.toString()}"; }); } }
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Thrift Tutorial</title> <link rel="stylesheet" href="styles.css"> <script async src="client.dart.js"></script> </head> <body> <div id="output"></div> </body> </html>
import 'dart:async'; import 'dart:io'; import 'package:args/args.dart'; import 'package:logging/logging.dart'; import 'package:thrift/thrift.dart'; import 'package:thrift/thrift_console.dart'; import 'package:tutorial/tutorial.dart'; import 'package:shared/shared.dart'; TProtocol _protocol; TProcessor _processor; WebSocket _webSocket; main(List<String> args) { Logger.root.level = Level.ALL; Logger.root.onRecord.listen((LogRecord rec) { print('${rec.level.name}: ${rec.time}: ${rec.message}'); }); var parser = new ArgParser(); parser.addOption('port', defaultsTo: '9090', help: 'The port to listen on'); parser.addOption('type', defaultsTo: 'ws', allowed: ['ws', 'tcp'], help: 'The type of socket', allowedHelp: {'ws': 'WebSocket', 'tcp': 'TCP Socket'}); ArgResults results; try { results = parser.parse(args); } catch (e) { results = null; } if (results == null) { print(parser.usage); exit(0); } int port = int.parse(results['port']); String socketType = results['type']; if (socketType == 'tcp') { _runTcpServer(port); } else if (socketType == 'ws') { _runWebSocketServer(port); } } Future _runWebSocketServer(int port) async { var httpServer = await HttpServer.bind('127.0.0.1', port); print('listening for WebSocket connections on $port'); httpServer.listen((HttpRequest request) async { if (request.uri.path == '/ws') { _webSocket = await WebSocketTransformer.upgrade(request); await _initProcessor(new TWebSocket(_webSocket)); } else { print('Invalid path: ${request.uri.path}'); } }); } Future _runTcpServer(int port) async { var serverSocket = await ServerSocket.bind('127.0.0.1', port); print('listening for TCP connections on $port'); Socket socket = await serverSocket.first; await _initProcessor(new TTcpSocket(socket)); } Future _initProcessor(TSocket socket) async { TServerSocketTransport transport = new TServerSocketTransport(socket); transport.onIncomingMessage.listen(_processMessage); _processor = new CalculatorProcessor(new CalculatorServer()); _protocol = new TBinaryProtocol(transport); await _protocol.transport.open(); print('connected'); } Future _processMessage(_) async { _processor.process(_protocol, _protocol); } class CalculatorServer implements Calculator { final Map<int, SharedStruct> _log = {}; Future ping() async { print('ping()'); } Future<int> add(int num1, int num2) async { print('add($num1, $num2)'); return num1 + num2; } Future<int> calculate(int logid, Work work) async { print('calulate($logid, ${work.toString()})'); int val; switch (work.op) { case Operation.ADD: val = work.num1 + work.num2; break; case Operation.SUBTRACT: val = work.num1 - work.num2; break; case Operation.MULTIPLY: val = work.num1 * work.num2; break; case Operation.DIVIDE: if (work.num2 == 0) { var x = new InvalidOperation(); x.whatOp = work.op; x.why = 'Cannot divide by 0'; throw x; } val = (work.num1 / work.num2).floor(); break; } var log = new SharedStruct(); log.key = logid; log.value = '$val "${work.comment}"'; this._log[logid] = log; return val; } Future zip() async { print('zip()'); } Future<SharedStruct> getStruct(int key) async { print('getStruct($key)'); return _log[key]; } }
TBD