2 /* --------------------------------------------------------------------------------------------
3 * Copyright (c) Microsoft Corporation. All rights reserved.
4 * Licensed under the MIT License. See License.txt in the project root for license information.
5 * ------------------------------------------------------------------------------------------ */
6 Object.defineProperty(exports, "__esModule", { value: true });
7 exports.createMessageConnection = exports.ConnectionOptions = exports.CancellationStrategy = exports.CancellationSenderStrategy = exports.CancellationReceiverStrategy = exports.ConnectionStrategy = exports.ConnectionError = exports.ConnectionErrors = exports.LogTraceNotification = exports.SetTraceNotification = exports.TraceFormat = exports.Trace = exports.NullLogger = exports.ProgressType = void 0;
8 const ral_1 = require("./ral");
9 const Is = require("./is");
10 const messages_1 = require("./messages");
11 const linkedMap_1 = require("./linkedMap");
12 const events_1 = require("./events");
13 const cancellation_1 = require("./cancellation");
14 var CancelNotification;
15 (function (CancelNotification) {
16 CancelNotification.type = new messages_1.NotificationType('$/cancelRequest');
17 })(CancelNotification || (CancelNotification = {}));
18 var ProgressNotification;
19 (function (ProgressNotification) {
20 ProgressNotification.type = new messages_1.NotificationType('$/progress');
21 })(ProgressNotification || (ProgressNotification = {}));
26 exports.ProgressType = ProgressType;
27 var StarRequestHandler;
28 (function (StarRequestHandler) {
30 return Is.func(value);
32 StarRequestHandler.is = is;
33 })(StarRequestHandler || (StarRequestHandler = {}));
34 exports.NullLogger = Object.freeze({
42 Trace[Trace["Off"] = 0] = "Off";
43 Trace[Trace["Messages"] = 1] = "Messages";
44 Trace[Trace["Verbose"] = 2] = "Verbose";
45 })(Trace = exports.Trace || (exports.Trace = {}));
47 function fromString(value) {
48 if (!Is.string(value)) {
51 value = value.toLowerCase();
56 return Trace.Messages;
63 Trace.fromString = fromString;
64 function toString(value) {
76 Trace.toString = toString;
77 })(Trace = exports.Trace || (exports.Trace = {}));
79 (function (TraceFormat) {
80 TraceFormat["Text"] = "text";
81 TraceFormat["JSON"] = "json";
82 })(TraceFormat = exports.TraceFormat || (exports.TraceFormat = {}));
83 (function (TraceFormat) {
84 function fromString(value) {
85 value = value.toLowerCase();
86 if (value === 'json') {
87 return TraceFormat.JSON;
90 return TraceFormat.Text;
93 TraceFormat.fromString = fromString;
94 })(TraceFormat = exports.TraceFormat || (exports.TraceFormat = {}));
95 var SetTraceNotification;
96 (function (SetTraceNotification) {
97 SetTraceNotification.type = new messages_1.NotificationType('$/setTrace');
98 })(SetTraceNotification = exports.SetTraceNotification || (exports.SetTraceNotification = {}));
99 var LogTraceNotification;
100 (function (LogTraceNotification) {
101 LogTraceNotification.type = new messages_1.NotificationType('$/logTrace');
102 })(LogTraceNotification = exports.LogTraceNotification || (exports.LogTraceNotification = {}));
103 var ConnectionErrors;
104 (function (ConnectionErrors) {
106 * The connection is closed.
108 ConnectionErrors[ConnectionErrors["Closed"] = 1] = "Closed";
110 * The connection got disposed.
112 ConnectionErrors[ConnectionErrors["Disposed"] = 2] = "Disposed";
114 * The connection is already in listening mode.
116 ConnectionErrors[ConnectionErrors["AlreadyListening"] = 3] = "AlreadyListening";
117 })(ConnectionErrors = exports.ConnectionErrors || (exports.ConnectionErrors = {}));
118 class ConnectionError extends Error {
119 constructor(code, message) {
122 Object.setPrototypeOf(this, ConnectionError.prototype);
125 exports.ConnectionError = ConnectionError;
126 var ConnectionStrategy;
127 (function (ConnectionStrategy) {
129 const candidate = value;
130 return candidate && Is.func(candidate.cancelUndispatched);
132 ConnectionStrategy.is = is;
133 })(ConnectionStrategy = exports.ConnectionStrategy || (exports.ConnectionStrategy = {}));
134 var CancellationReceiverStrategy;
135 (function (CancellationReceiverStrategy) {
136 CancellationReceiverStrategy.Message = Object.freeze({
137 createCancellationTokenSource(_) {
138 return new cancellation_1.CancellationTokenSource();
142 const candidate = value;
143 return candidate && Is.func(candidate.createCancellationTokenSource);
145 CancellationReceiverStrategy.is = is;
146 })(CancellationReceiverStrategy = exports.CancellationReceiverStrategy || (exports.CancellationReceiverStrategy = {}));
147 var CancellationSenderStrategy;
148 (function (CancellationSenderStrategy) {
149 CancellationSenderStrategy.Message = Object.freeze({
150 sendCancellation(conn, id) {
151 conn.sendNotification(CancelNotification.type, { id });
156 const candidate = value;
157 return candidate && Is.func(candidate.sendCancellation) && Is.func(candidate.cleanup);
159 CancellationSenderStrategy.is = is;
160 })(CancellationSenderStrategy = exports.CancellationSenderStrategy || (exports.CancellationSenderStrategy = {}));
161 var CancellationStrategy;
162 (function (CancellationStrategy) {
163 CancellationStrategy.Message = Object.freeze({
164 receiver: CancellationReceiverStrategy.Message,
165 sender: CancellationSenderStrategy.Message
168 const candidate = value;
169 return candidate && CancellationReceiverStrategy.is(candidate.receiver) && CancellationSenderStrategy.is(candidate.sender);
171 CancellationStrategy.is = is;
172 })(CancellationStrategy = exports.CancellationStrategy || (exports.CancellationStrategy = {}));
173 var ConnectionOptions;
174 (function (ConnectionOptions) {
176 const candidate = value;
177 return candidate && (CancellationStrategy.is(candidate.cancellationStrategy) || ConnectionStrategy.is(candidate.connectionStrategy));
179 ConnectionOptions.is = is;
180 })(ConnectionOptions = exports.ConnectionOptions || (exports.ConnectionOptions = {}));
182 (function (ConnectionState) {
183 ConnectionState[ConnectionState["New"] = 1] = "New";
184 ConnectionState[ConnectionState["Listening"] = 2] = "Listening";
185 ConnectionState[ConnectionState["Closed"] = 3] = "Closed";
186 ConnectionState[ConnectionState["Disposed"] = 4] = "Disposed";
187 })(ConnectionState || (ConnectionState = {}));
188 function createMessageConnection(messageReader, messageWriter, _logger, options) {
189 const logger = _logger !== undefined ? _logger : exports.NullLogger;
190 let sequenceNumber = 0;
191 let notificationSquenceNumber = 0;
192 let unknownResponseSquenceNumber = 0;
193 const version = '2.0';
194 let starRequestHandler = undefined;
195 const requestHandlers = Object.create(null);
196 let starNotificationHandler = undefined;
197 const notificationHandlers = Object.create(null);
198 const progressHandlers = new Map();
200 let messageQueue = new linkedMap_1.LinkedMap();
201 let responsePromises = Object.create(null);
202 let requestTokens = Object.create(null);
203 let trace = Trace.Off;
204 let traceFormat = TraceFormat.Text;
206 let state = ConnectionState.New;
207 const errorEmitter = new events_1.Emitter();
208 const closeEmitter = new events_1.Emitter();
209 const unhandledNotificationEmitter = new events_1.Emitter();
210 const unhandledProgressEmitter = new events_1.Emitter();
211 const disposeEmitter = new events_1.Emitter();
212 const cancellationStrategy = (options && options.cancellationStrategy) ? options.cancellationStrategy : CancellationStrategy.Message;
213 function createRequestQueueKey(id) {
215 throw new Error(`Can't send requests with id null since the response can't be correlated.`);
217 return 'req-' + id.toString();
219 function createResponseQueueKey(id) {
221 return 'res-unknown-' + (++unknownResponseSquenceNumber).toString();
224 return 'res-' + id.toString();
227 function createNotificationQueueKey() {
228 return 'not-' + (++notificationSquenceNumber).toString();
230 function addMessageToQueue(queue, message) {
231 if (messages_1.isRequestMessage(message)) {
232 queue.set(createRequestQueueKey(message.id), message);
234 else if (messages_1.isResponseMessage(message)) {
235 queue.set(createResponseQueueKey(message.id), message);
238 queue.set(createNotificationQueueKey(), message);
241 function cancelUndispatched(_message) {
244 function isListening() {
245 return state === ConnectionState.Listening;
247 function isClosed() {
248 return state === ConnectionState.Closed;
250 function isDisposed() {
251 return state === ConnectionState.Disposed;
253 function closeHandler() {
254 if (state === ConnectionState.New || state === ConnectionState.Listening) {
255 state = ConnectionState.Closed;
256 closeEmitter.fire(undefined);
258 // If the connection is disposed don't sent close events.
260 function readErrorHandler(error) {
261 errorEmitter.fire([error, undefined, undefined]);
263 function writeErrorHandler(data) {
264 errorEmitter.fire(data);
266 messageReader.onClose(closeHandler);
267 messageReader.onError(readErrorHandler);
268 messageWriter.onClose(closeHandler);
269 messageWriter.onError(writeErrorHandler);
270 function triggerMessageQueue() {
271 if (timer || messageQueue.size === 0) {
274 timer = ral_1.default().timer.setImmediate(() => {
276 processMessageQueue();
279 function processMessageQueue() {
280 if (messageQueue.size === 0) {
283 const message = messageQueue.shift();
285 if (messages_1.isRequestMessage(message)) {
286 handleRequest(message);
288 else if (messages_1.isNotificationMessage(message)) {
289 handleNotification(message);
291 else if (messages_1.isResponseMessage(message)) {
292 handleResponse(message);
295 handleInvalidMessage(message);
299 triggerMessageQueue();
302 const callback = (message) => {
304 // We have received a cancellation message. Check if the message is still in the queue
305 // and cancel it if allowed to do so.
306 if (messages_1.isNotificationMessage(message) && message.method === CancelNotification.type.method) {
307 const key = createRequestQueueKey(message.params.id);
308 const toCancel = messageQueue.get(key);
309 if (messages_1.isRequestMessage(toCancel)) {
310 const strategy = options === null || options === void 0 ? void 0 : options.connectionStrategy;
311 const response = (strategy && strategy.cancelUndispatched) ? strategy.cancelUndispatched(toCancel, cancelUndispatched) : cancelUndispatched(toCancel);
312 if (response && (response.error !== undefined || response.result !== undefined)) {
313 messageQueue.delete(key);
314 response.id = toCancel.id;
315 traceSendingResponse(response, message.method, Date.now());
316 messageWriter.write(response);
321 addMessageToQueue(messageQueue, message);
324 triggerMessageQueue();
327 function handleRequest(requestMessage) {
329 // we return here silently since we fired an event when the
330 // connection got disposed.
333 function reply(resultOrError, method, startTime) {
336 id: requestMessage.id
338 if (resultOrError instanceof messages_1.ResponseError) {
339 message.error = resultOrError.toJson();
342 message.result = resultOrError === undefined ? null : resultOrError;
344 traceSendingResponse(message, method, startTime);
345 messageWriter.write(message);
347 function replyError(error, method, startTime) {
350 id: requestMessage.id,
351 error: error.toJson()
353 traceSendingResponse(message, method, startTime);
354 messageWriter.write(message);
356 function replySuccess(result, method, startTime) {
357 // The JSON RPC defines that a response must either have a result or an error
358 // So we can't treat undefined as a valid response result.
359 if (result === undefined) {
364 id: requestMessage.id,
367 traceSendingResponse(message, method, startTime);
368 messageWriter.write(message);
370 traceReceivedRequest(requestMessage);
371 const element = requestHandlers[requestMessage.method];
376 requestHandler = element.handler;
378 const startTime = Date.now();
379 if (requestHandler || starRequestHandler) {
380 const tokenKey = String(requestMessage.id);
381 const cancellationSource = cancellationStrategy.receiver.createCancellationTokenSource(tokenKey);
382 requestTokens[tokenKey] = cancellationSource;
385 if (requestHandler) {
386 if (requestMessage.params === undefined) {
387 if (type !== undefined && type.numberOfParams !== 0) {
388 replyError(new messages_1.ResponseError(messages_1.ErrorCodes.InvalidParams, `Request ${requestMessage.method} defines ${type.numberOfParams} params but recevied none.`), requestMessage.method, startTime);
391 handlerResult = requestHandler(cancellationSource.token);
393 else if (Array.isArray(requestMessage.params)) {
394 if (type !== undefined && type.parameterStructures === messages_1.ParameterStructures.byName) {
395 replyError(new messages_1.ResponseError(messages_1.ErrorCodes.InvalidParams, `Request ${requestMessage.method} defines parameters by name but received parameters by position`), requestMessage.method, startTime);
398 handlerResult = requestHandler(...requestMessage.params, cancellationSource.token);
401 if (type !== undefined && type.parameterStructures === messages_1.ParameterStructures.byPosition) {
402 replyError(new messages_1.ResponseError(messages_1.ErrorCodes.InvalidParams, `Request ${requestMessage.method} defines parameters by position but received parameters by name`), requestMessage.method, startTime);
405 handlerResult = requestHandler(requestMessage.params, cancellationSource.token);
408 else if (starRequestHandler) {
409 handlerResult = starRequestHandler(requestMessage.method, requestMessage.params, cancellationSource.token);
411 const promise = handlerResult;
412 if (!handlerResult) {
413 delete requestTokens[tokenKey];
414 replySuccess(handlerResult, requestMessage.method, startTime);
416 else if (promise.then) {
417 promise.then((resultOrError) => {
418 delete requestTokens[tokenKey];
419 reply(resultOrError, requestMessage.method, startTime);
421 delete requestTokens[tokenKey];
422 if (error instanceof messages_1.ResponseError) {
423 replyError(error, requestMessage.method, startTime);
425 else if (error && Is.string(error.message)) {
426 replyError(new messages_1.ResponseError(messages_1.ErrorCodes.InternalError, `Request ${requestMessage.method} failed with message: ${error.message}`), requestMessage.method, startTime);
429 replyError(new messages_1.ResponseError(messages_1.ErrorCodes.InternalError, `Request ${requestMessage.method} failed unexpectedly without providing any details.`), requestMessage.method, startTime);
434 delete requestTokens[tokenKey];
435 reply(handlerResult, requestMessage.method, startTime);
439 delete requestTokens[tokenKey];
440 if (error instanceof messages_1.ResponseError) {
441 reply(error, requestMessage.method, startTime);
443 else if (error && Is.string(error.message)) {
444 replyError(new messages_1.ResponseError(messages_1.ErrorCodes.InternalError, `Request ${requestMessage.method} failed with message: ${error.message}`), requestMessage.method, startTime);
447 replyError(new messages_1.ResponseError(messages_1.ErrorCodes.InternalError, `Request ${requestMessage.method} failed unexpectedly without providing any details.`), requestMessage.method, startTime);
452 replyError(new messages_1.ResponseError(messages_1.ErrorCodes.MethodNotFound, `Unhandled method ${requestMessage.method}`), requestMessage.method, startTime);
455 function handleResponse(responseMessage) {
457 // See handle request.
460 if (responseMessage.id === null) {
461 if (responseMessage.error) {
462 logger.error(`Received response message without id: Error is: \n${JSON.stringify(responseMessage.error, undefined, 4)}`);
465 logger.error(`Received response message without id. No further error information provided.`);
469 const key = String(responseMessage.id);
470 const responsePromise = responsePromises[key];
471 traceReceivedResponse(responseMessage, responsePromise);
472 if (responsePromise) {
473 delete responsePromises[key];
475 if (responseMessage.error) {
476 const error = responseMessage.error;
477 responsePromise.reject(new messages_1.ResponseError(error.code, error.message, error.data));
479 else if (responseMessage.result !== undefined) {
480 responsePromise.resolve(responseMessage.result);
483 throw new Error('Should never happen.');
488 logger.error(`Response handler '${responsePromise.method}' failed with message: ${error.message}`);
491 logger.error(`Response handler '${responsePromise.method}' failed unexpectedly.`);
497 function handleNotification(message) {
499 // See handle request.
502 let type = undefined;
503 let notificationHandler;
504 if (message.method === CancelNotification.type.method) {
505 notificationHandler = (params) => {
506 const id = params.id;
507 const source = requestTokens[String(id)];
514 const element = notificationHandlers[message.method];
516 notificationHandler = element.handler;
520 if (notificationHandler || starNotificationHandler) {
522 traceReceivedNotification(message);
523 if (notificationHandler) {
524 if (message.params === undefined) {
525 if (type !== undefined) {
526 if (type.numberOfParams !== 0 && type.parameterStructures !== messages_1.ParameterStructures.byName) {
527 logger.error(`Notification ${message.method} defines ${type.numberOfParams} params but recevied none.`);
530 notificationHandler();
532 else if (Array.isArray(message.params)) {
533 if (type !== undefined) {
534 if (type.parameterStructures === messages_1.ParameterStructures.byName) {
535 logger.error(`Notification ${message.method} defines parameters by name but received parameters by position`);
537 if (type.numberOfParams !== message.params.length) {
538 logger.error(`Notification ${message.method} defines ${type.numberOfParams} params but received ${message.params.length} argumennts`);
541 notificationHandler(...message.params);
544 if (type !== undefined && type.parameterStructures === messages_1.ParameterStructures.byPosition) {
545 logger.error(`Notification ${message.method} defines parameters by position but received parameters by name`);
547 notificationHandler(message.params);
550 else if (starNotificationHandler) {
551 starNotificationHandler(message.method, message.params);
556 logger.error(`Notification handler '${message.method}' failed with message: ${error.message}`);
559 logger.error(`Notification handler '${message.method}' failed unexpectedly.`);
564 unhandledNotificationEmitter.fire(message);
567 function handleInvalidMessage(message) {
569 logger.error('Received empty message.');
572 logger.error(`Received message which is neither a response nor a notification message:\n${JSON.stringify(message, null, 4)}`);
573 // Test whether we find an id to reject the promise
574 const responseMessage = message;
575 if (Is.string(responseMessage.id) || Is.number(responseMessage.id)) {
576 const key = String(responseMessage.id);
577 const responseHandler = responsePromises[key];
578 if (responseHandler) {
579 responseHandler.reject(new Error('The received response has neither a result nor an error property.'));
583 function traceSendingRequest(message) {
584 if (trace === Trace.Off || !tracer) {
587 if (traceFormat === TraceFormat.Text) {
588 let data = undefined;
589 if (trace === Trace.Verbose && message.params) {
590 data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`;
592 tracer.log(`Sending request '${message.method} - (${message.id})'.`, data);
595 logLSPMessage('send-request', message);
598 function traceSendingNotification(message) {
599 if (trace === Trace.Off || !tracer) {
602 if (traceFormat === TraceFormat.Text) {
603 let data = undefined;
604 if (trace === Trace.Verbose) {
605 if (message.params) {
606 data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`;
609 data = 'No parameters provided.\n\n';
612 tracer.log(`Sending notification '${message.method}'.`, data);
615 logLSPMessage('send-notification', message);
618 function traceSendingResponse(message, method, startTime) {
619 if (trace === Trace.Off || !tracer) {
622 if (traceFormat === TraceFormat.Text) {
623 let data = undefined;
624 if (trace === Trace.Verbose) {
625 if (message.error && message.error.data) {
626 data = `Error data: ${JSON.stringify(message.error.data, null, 4)}\n\n`;
629 if (message.result) {
630 data = `Result: ${JSON.stringify(message.result, null, 4)}\n\n`;
632 else if (message.error === undefined) {
633 data = 'No result returned.\n\n';
637 tracer.log(`Sending response '${method} - (${message.id})'. Processing request took ${Date.now() - startTime}ms`, data);
640 logLSPMessage('send-response', message);
643 function traceReceivedRequest(message) {
644 if (trace === Trace.Off || !tracer) {
647 if (traceFormat === TraceFormat.Text) {
648 let data = undefined;
649 if (trace === Trace.Verbose && message.params) {
650 data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`;
652 tracer.log(`Received request '${message.method} - (${message.id})'.`, data);
655 logLSPMessage('receive-request', message);
658 function traceReceivedNotification(message) {
659 if (trace === Trace.Off || !tracer || message.method === LogTraceNotification.type.method) {
662 if (traceFormat === TraceFormat.Text) {
663 let data = undefined;
664 if (trace === Trace.Verbose) {
665 if (message.params) {
666 data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`;
669 data = 'No parameters provided.\n\n';
672 tracer.log(`Received notification '${message.method}'.`, data);
675 logLSPMessage('receive-notification', message);
678 function traceReceivedResponse(message, responsePromise) {
679 if (trace === Trace.Off || !tracer) {
682 if (traceFormat === TraceFormat.Text) {
683 let data = undefined;
684 if (trace === Trace.Verbose) {
685 if (message.error && message.error.data) {
686 data = `Error data: ${JSON.stringify(message.error.data, null, 4)}\n\n`;
689 if (message.result) {
690 data = `Result: ${JSON.stringify(message.result, null, 4)}\n\n`;
692 else if (message.error === undefined) {
693 data = 'No result returned.\n\n';
697 if (responsePromise) {
698 const error = message.error ? ` Request failed: ${message.error.message} (${message.error.code}).` : '';
699 tracer.log(`Received response '${responsePromise.method} - (${message.id})' in ${Date.now() - responsePromise.timerStart}ms.${error}`, data);
702 tracer.log(`Received response ${message.id} without active response promise.`, data);
706 logLSPMessage('receive-response', message);
709 function logLSPMessage(type, message) {
710 if (!tracer || trace === Trace.Off) {
717 timestamp: Date.now()
719 tracer.log(lspMessage);
721 function throwIfClosedOrDisposed() {
723 throw new ConnectionError(ConnectionErrors.Closed, 'Connection is closed.');
726 throw new ConnectionError(ConnectionErrors.Disposed, 'Connection is disposed.');
729 function throwIfListening() {
731 throw new ConnectionError(ConnectionErrors.AlreadyListening, 'Connection is already listening');
734 function throwIfNotListening() {
735 if (!isListening()) {
736 throw new Error('Call listen() first.');
739 function undefinedToNull(param) {
740 if (param === undefined) {
747 function nullToUndefined(param) {
748 if (param === null) {
755 function isNamedParam(param) {
756 return param !== undefined && param !== null && !Array.isArray(param) && typeof param === 'object';
758 function computeSingleParam(parameterStructures, param) {
759 switch (parameterStructures) {
760 case messages_1.ParameterStructures.auto:
761 if (isNamedParam(param)) {
762 return nullToUndefined(param);
765 return [undefinedToNull(param)];
768 case messages_1.ParameterStructures.byName:
769 if (!isNamedParam(param)) {
770 throw new Error(`Recevied parameters by name but param is not an object literal.`);
772 return nullToUndefined(param);
773 case messages_1.ParameterStructures.byPosition:
774 return [undefinedToNull(param)];
776 throw new Error(`Unknown parameter structure ${parameterStructures.toString()}`);
779 function computeMessageParams(type, params) {
781 const numberOfParams = type.numberOfParams;
782 switch (numberOfParams) {
787 result = computeSingleParam(type.parameterStructures, params[0]);
791 for (let i = 0; i < params.length && i < numberOfParams; i++) {
792 result.push(undefinedToNull(params[i]));
794 if (params.length < numberOfParams) {
795 for (let i = params.length; i < numberOfParams; i++) {
804 sendNotification: (type, ...args) => {
805 throwIfClosedOrDisposed();
808 if (Is.string(type)) {
810 const first = args[0];
812 let parameterStructures = messages_1.ParameterStructures.auto;
813 if (messages_1.ParameterStructures.is(first)) {
815 parameterStructures = first;
817 let paramEnd = args.length;
818 const numberOfParams = paramEnd - paramStart;
819 switch (numberOfParams) {
821 messageParams = undefined;
824 messageParams = computeSingleParam(parameterStructures, args[paramStart]);
827 if (parameterStructures === messages_1.ParameterStructures.byName) {
828 throw new Error(`Recevied ${numberOfParams} parameters for 'by Name' notification parameter structure.`);
830 messageParams = args.slice(paramStart, paramEnd).map(value => undefinedToNull(value));
836 method = type.method;
837 messageParams = computeMessageParams(type, params);
839 const notificationMessage = {
842 params: messageParams
844 traceSendingNotification(notificationMessage);
845 messageWriter.write(notificationMessage);
847 onNotification: (type, handler) => {
848 throwIfClosedOrDisposed();
851 starNotificationHandler = type;
854 if (Is.string(type)) {
856 notificationHandlers[type] = { type: undefined, handler };
859 method = type.method;
860 notificationHandlers[type.method] = { type, handler };
865 if (method !== undefined) {
866 delete notificationHandlers[method];
869 starNotificationHandler = undefined;
874 onProgress: (_type, token, handler) => {
875 if (progressHandlers.has(token)) {
876 throw new Error(`Progress handler for token ${token} already registered`);
878 progressHandlers.set(token, handler);
881 progressHandlers.delete(token);
885 sendProgress: (_type, token, value) => {
886 connection.sendNotification(ProgressNotification.type, { token, value });
888 onUnhandledProgress: unhandledProgressEmitter.event,
889 sendRequest: (type, ...args) => {
890 throwIfClosedOrDisposed();
891 throwIfNotListening();
894 let token = undefined;
895 if (Is.string(type)) {
897 const first = args[0];
898 const last = args[args.length - 1];
900 let parameterStructures = messages_1.ParameterStructures.auto;
901 if (messages_1.ParameterStructures.is(first)) {
903 parameterStructures = first;
905 let paramEnd = args.length;
906 if (cancellation_1.CancellationToken.is(last)) {
907 paramEnd = paramEnd - 1;
910 const numberOfParams = paramEnd - paramStart;
911 switch (numberOfParams) {
913 messageParams = undefined;
916 messageParams = computeSingleParam(parameterStructures, args[paramStart]);
919 if (parameterStructures === messages_1.ParameterStructures.byName) {
920 throw new Error(`Recevied ${numberOfParams} parameters for 'by Name' request parameter structure.`);
922 messageParams = args.slice(paramStart, paramEnd).map(value => undefinedToNull(value));
928 method = type.method;
929 messageParams = computeMessageParams(type, params);
930 const numberOfParams = type.numberOfParams;
931 token = cancellation_1.CancellationToken.is(params[numberOfParams]) ? params[numberOfParams] : undefined;
933 const id = sequenceNumber++;
936 disposable = token.onCancellationRequested(() => {
937 cancellationStrategy.sender.sendCancellation(connection, id);
940 const result = new Promise((resolve, reject) => {
941 const requestMessage = {
945 params: messageParams
947 const resolveWithCleanup = (r) => {
949 cancellationStrategy.sender.cleanup(id);
950 disposable === null || disposable === void 0 ? void 0 : disposable.dispose();
952 const rejectWithCleanup = (r) => {
954 cancellationStrategy.sender.cleanup(id);
955 disposable === null || disposable === void 0 ? void 0 : disposable.dispose();
957 let responsePromise = { method: method, timerStart: Date.now(), resolve: resolveWithCleanup, reject: rejectWithCleanup };
958 traceSendingRequest(requestMessage);
960 messageWriter.write(requestMessage);
963 // Writing the message failed. So we need to reject the promise.
964 responsePromise.reject(new messages_1.ResponseError(messages_1.ErrorCodes.MessageWriteError, e.message ? e.message : 'Unknown reason'));
965 responsePromise = null;
967 if (responsePromise) {
968 responsePromises[String(id)] = responsePromise;
973 onRequest: (type, handler) => {
974 throwIfClosedOrDisposed();
976 if (StarRequestHandler.is(type)) {
978 starRequestHandler = type;
980 else if (Is.string(type)) {
982 if (handler !== undefined) {
984 requestHandlers[type] = { handler: handler, type: undefined };
988 if (handler !== undefined) {
989 method = type.method;
990 requestHandlers[type.method] = { type, handler };
995 if (method === null) {
998 if (method !== undefined) {
999 delete requestHandlers[method];
1002 starRequestHandler = undefined;
1007 trace: (_value, _tracer, sendNotificationOrTraceOptions) => {
1008 let _sendNotification = false;
1009 let _traceFormat = TraceFormat.Text;
1010 if (sendNotificationOrTraceOptions !== undefined) {
1011 if (Is.boolean(sendNotificationOrTraceOptions)) {
1012 _sendNotification = sendNotificationOrTraceOptions;
1015 _sendNotification = sendNotificationOrTraceOptions.sendNotification || false;
1016 _traceFormat = sendNotificationOrTraceOptions.traceFormat || TraceFormat.Text;
1020 traceFormat = _traceFormat;
1021 if (trace === Trace.Off) {
1027 if (_sendNotification && !isClosed() && !isDisposed()) {
1028 connection.sendNotification(SetTraceNotification.type, { value: Trace.toString(_value) });
1031 onError: errorEmitter.event,
1032 onClose: closeEmitter.event,
1033 onUnhandledNotification: unhandledNotificationEmitter.event,
1034 onDispose: disposeEmitter.event,
1036 messageWriter.end();
1042 state = ConnectionState.Disposed;
1043 disposeEmitter.fire(undefined);
1044 const error = new Error('Connection got disposed.');
1045 Object.keys(responsePromises).forEach((key) => {
1046 responsePromises[key].reject(error);
1048 responsePromises = Object.create(null);
1049 requestTokens = Object.create(null);
1050 messageQueue = new linkedMap_1.LinkedMap();
1051 // Test for backwards compatibility
1052 if (Is.func(messageWriter.dispose)) {
1053 messageWriter.dispose();
1055 if (Is.func(messageReader.dispose)) {
1056 messageReader.dispose();
1060 throwIfClosedOrDisposed();
1062 state = ConnectionState.Listening;
1063 messageReader.listen(callback);
1066 // eslint-disable-next-line no-console
1067 ral_1.default().console.log('inspect');
1070 connection.onNotification(LogTraceNotification.type, (params) => {
1071 if (trace === Trace.Off || !tracer) {
1074 tracer.log(params.message, trace === Trace.Verbose ? params.verbose : undefined);
1076 connection.onNotification(ProgressNotification.type, (params) => {
1077 const handler = progressHandlers.get(params.token);
1079 handler(params.value);
1082 unhandledProgressEmitter.fire(params);
1087 exports.createMessageConnection = createMessageConnection;
1088 //# sourceMappingURL=connection.js.map