All Apache Thrift tutorials require that you have:
thrift -r --gen dart tutorial.thrift
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