blob: e9fc95d859b85d8d43737a17fe3ba4c2e51504c3 [file] [log] [blame]
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library channel;
import 'dart:convert';
import 'dart:io';
import 'package:analysis_server/src/protocol.dart';
/**
* The abstract class [ClientCommunicationChannel] defines the behavior of
* objects that allows an object to send [Request]s to [AnalysisServer] and to
* receive both [Response]s and [Notification]s.
*/
abstract class ClientCommunicationChannel {
/**
* Listen to the channel for responses and notifications.
* If a response is received, invoke the [onResponse] function.
* If a notification is received, invoke the [onNotification] function.
* If an error is encountered while trying to read from
* the socket, invoke the [onError] function. If the socket is closed by the
* client, invoke the [onDone] function.
*/
void listen(void onResponse(Response response),
void onNotification(Notification notification),
{void onError(), void onDone()});
/**
* Send the given [request] to the server.
*/
void sendRequest(Request request);
}
/**
* The abstract class [ServerCommunicationChannel] defines the behavior of
* objects that allow an [AnalysisServer] to receive [Request]s and to return
* both [Response]s and [Notification]s.
*/
abstract class ServerCommunicationChannel {
/**
* Listen to the channel for requests. If a request is received, invoke the
* [onRequest] function. If an error is encountered while trying to read from
* the socket, invoke the [onError] function. If the socket is closed by the
* client, invoke the [onDone] function.
*/
void listen(void onRequest(Request request), {void onError(), void onDone()});
/**
* Send the given [notification] to the client.
*/
void sendNotification(Notification notification);
/**
* Send the given [response] to the client.
*/
void sendResponse(Response response);
}
/**
* Instances of the class [WebSocketClientChannel] implement a
* [ClientCommunicationChannel] that uses a [WebSocket] to communicate with
* servers.
*/
class WebSocketClientChannel implements ClientCommunicationChannel {
/**
* The socket being wrapped.
*/
final WebSocket socket;
final JsonEncoder jsonEncoder = const JsonEncoder(null);
final JsonDecoder jsonDecoder = const JsonDecoder(null);
/**
* Initialize a newly create [WebSocket] wrapper to wrap the given [socket].
*/
WebSocketClientChannel(this.socket);
@override
void listen(void onResponse(Response response),
void onNotification(Notification notification),
{void onError(), void onDone()}) {
socket.listen((data) => _read(data, onResponse, onNotification),
onError: onError, onDone: onDone);
}
@override
void sendRequest(Request request) {
socket.add(jsonEncoder.convert(request.toJson()));
}
/**
* Read a request from the given [data] and use the given function to handle
* the request.
*/
void _read(Object data,
void onResponse(Response response),
void onNotification(Notification notification)) {
if (data is String) {
// Parse the string as a JSON descriptor
var json;
try {
json = jsonDecoder.convert(data);
if (json is! Map) {
return;
}
} catch (error) {
return;
}
// Process the resulting structure as a response or notification.
if (json[Notification.EVENT] != null) {
Notification notification = new Notification.fromJson(json);
if (notification != null) {
onNotification(notification);
}
} else {
Response response = new Response.fromJson(json);
if (response != null) {
onResponse(response);
}
}
}
}
}
/**
* Instances of the class [WebSocketServerChannel] implement a
* [ServerCommunicationChannel] that uses a [WebSocket] to communicate with
* clients.
*/
class WebSocketServerChannel implements ServerCommunicationChannel {
/**
* The socket being wrapped.
*/
final WebSocket socket;
final JsonEncoder jsonEncoder = const JsonEncoder(null);
/**
* Initialize a newly create [WebSocket] wrapper to wrap the given [socket].
*/
WebSocketServerChannel(this.socket);
@override
void listen(void onRequest(Request request), {void onError(), void onDone()}) {
socket.listen((data) => _readRequest(data, onRequest), onError: onError,
onDone: onDone);
}
@override
void sendNotification(Notification notification) {
socket.add(jsonEncoder.convert(notification.toJson()));
}
@override
void sendResponse(Response response) {
socket.add(jsonEncoder.convert(response.toJson()));
}
/**
* Read a request from the given [data] and use the given function to handle
* the request.
*/
void _readRequest(Object data, void onRequest(Request request)) {
if (data is List<int>) {
sendResponse(new Response.invalidRequestFormat());
return;
}
if (data is String) {
// Parse the string as a JSON descriptor and process the resulting
// structure as a request.
Request request = new Request.fromString(data);
if (request == null) {
sendResponse(new Response.invalidRequestFormat());
return;
}
onRequest(request);
}
}
}