blob: 9ae6be634b05f0c95e43c5a867306327eae235bc [file]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of bindings;
abstract class Client {
core.MojoMessagePipeEndpoint _endpoint;
core.MojoEventStream _eventStream;
List _sendQueue;
Map<int, Completer> _completerMap;
bool _isOpen = false;
int _nextId = 0;
void handleResponse(ServiceMessage reader);
Client(core.MojoMessagePipeEndpoint endpoint) :
_sendQueue = [],
_completerMap = {},
_endpoint = endpoint,
_eventStream = new core.MojoEventStream(endpoint.handle);
Client.fromHandle(int handle) {
_sendQueue = [];
_completerMap = {};
_endpoint =
new core.MojoMessagePipeEndpoint(new core.MojoHandle(handle));
_eventStream = new core.MojoHandle(_endpoint.handle);
}
void _doRead() {
// Query how many bytes are available.
var result = _endpoint.query();
assert(result.status.isOk || result.status.isResourceExhausted);
// Read the data.
var bytes = new ByteData(result.bytesRead);
var handles = new List<core.MojoHandle>(result.handlesRead);
result = _endpoint.read(bytes, result.bytesRead, handles);
assert(result.status.isOk || result.status.isResourceExhausted);
var message = new ServiceMessage.fromMessage(new Message(bytes, handles));
handleResponse(message);
}
void _doWrite() {
if (_sendQueue.length > 0) {
List messageCompleter = _sendQueue.removeAt(0);
ServiceMessage message = messageCompleter[0];
Completer completer = messageCompleter[1];
_endpoint.write(message.buffer,
message.buffer.lengthInBytes,
message.handles);
if (!_endpoint.status.isOk) {
throw "message pipe write failed";
}
if (completer != null) {
if (!message.header.hasRequestId) {
throw "Message has a completer, but does not expect a response";
}
int requestId = message.header.requestId;
if (_completerMap[requestId] != null) {
throw "Request Id $requestId is already in use.";
}
_completerMap[requestId] = completer;
}
}
}
void open() {
_eventStream.listen((List<int> event) {
var signalsWatched = new core.MojoHandleSignals(event[0]);
var signalsReceived = new core.MojoHandleSignals(event[1]);
if (signalsReceived.isPeerClosed) {
close();
return;
}
if (signalsReceived.isReadable) {
_doRead();
}
if (signalsReceived.isWritable) {
_doWrite();
}
if (_sendQueue.length == 0) {
var withoutWritable = signalsWatched - core.MojoHandleSignals.WRITABLE;
_eventStream.enableSignals(withoutWritable);
} else {
_eventStream.enableSignals(signalsWatched);
}
});
_isOpen = true;
}
void close() {
if (_isOpen) {
_eventStream.close();
_eventStream = null;
_isOpen = false;
}
}
void enqueueMessage(Struct message, int name) {
var header = new MessageHeader(name);
var serviceMessage = message.serializeWithHeader(header);
_sendQueue.add([serviceMessage, null]);
if (_sendQueue.length == 1) {
_eventStream.enableAllEvents();
}
}
int _getNextId() {
return _nextId++;
}
Future enqueueMessageWithRequestId(
Struct message, int name, int id, int flags) {
if (id == -1) {
id = _getNextId();
}
var header = new MessageHeader.withRequestId(name, flags, id);
var serviceMessage = message.serializeWithHeader(header);
var completer = new Completer();
_sendQueue.add([serviceMessage, completer]);
if (_sendQueue.length == 1) {
_eventStream.enableAllEvents();
} else {
_eventStream.enableReadEvents();
}
return completer.future;
}
// Need a getter for this for access in subclasses.
Map<int, Completer> get completerMap => _completerMap;
bool get isOpen => _isOpen;
}