mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-05 01:25:38 -05:00
Merge from vscode 1eb87b0e9ce9886afeaecec22b31abd0d9b7939f (#7282)
* Merge from vscode 1eb87b0e9ce9886afeaecec22b31abd0d9b7939f * fix various icon issues * fix preview features
This commit is contained in:
@@ -8,6 +8,9 @@ import { ISocket } from 'vs/base/parts/ipc/common/ipc.net';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { RemoteAuthorityResolverError, RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
|
||||
export interface IWebSocketFactory {
|
||||
create(url: string): IWebSocket;
|
||||
@@ -23,27 +26,34 @@ export interface IWebSocket {
|
||||
close(): void;
|
||||
}
|
||||
|
||||
class BrowserWebSocket implements IWebSocket {
|
||||
class BrowserWebSocket extends Disposable implements IWebSocket {
|
||||
|
||||
private readonly _onData = new Emitter<ArrayBuffer>();
|
||||
public readonly onData = this._onData.event;
|
||||
|
||||
public readonly onOpen: Event<void>;
|
||||
public readonly onClose: Event<void>;
|
||||
public readonly onError: Event<any>;
|
||||
|
||||
private readonly _onClose = this._register(new Emitter<void>());
|
||||
public readonly onClose = this._onClose.event;
|
||||
|
||||
private readonly _onError = this._register(new Emitter<any>());
|
||||
public readonly onError = this._onError.event;
|
||||
|
||||
private readonly _socket: WebSocket;
|
||||
private readonly _fileReader: FileReader;
|
||||
private readonly _queue: Blob[];
|
||||
private _isReading: boolean;
|
||||
private _isClosed: boolean;
|
||||
|
||||
private readonly _socketMessageListener: (ev: MessageEvent) => void;
|
||||
|
||||
constructor(socket: WebSocket) {
|
||||
super();
|
||||
this._socket = socket;
|
||||
this._fileReader = new FileReader();
|
||||
this._queue = [];
|
||||
this._isReading = false;
|
||||
this._isClosed = false;
|
||||
|
||||
this._fileReader.onload = (event) => {
|
||||
this._isReading = false;
|
||||
@@ -71,17 +81,79 @@ class BrowserWebSocket implements IWebSocket {
|
||||
this._socket.addEventListener('message', this._socketMessageListener);
|
||||
|
||||
this.onOpen = Event.fromDOMEventEmitter(this._socket, 'open');
|
||||
this.onClose = Event.fromDOMEventEmitter(this._socket, 'close');
|
||||
this.onError = Event.fromDOMEventEmitter(this._socket, 'error');
|
||||
|
||||
// WebSockets emit error events that do not contain any real information
|
||||
// Our only chance of getting to the root cause of an error is to
|
||||
// listen to the close event which gives out some real information:
|
||||
// - https://www.w3.org/TR/websockets/#closeevent
|
||||
// - https://tools.ietf.org/html/rfc6455#section-11.7
|
||||
//
|
||||
// But the error event is emitted before the close event, so we therefore
|
||||
// delay the error event processing in the hope of receiving a close event
|
||||
// with more information
|
||||
|
||||
let pendingErrorEvent: any | null = null;
|
||||
|
||||
const sendPendingErrorNow = () => {
|
||||
const err = pendingErrorEvent;
|
||||
pendingErrorEvent = null;
|
||||
this._onError.fire(err);
|
||||
};
|
||||
|
||||
const errorRunner = this._register(new RunOnceScheduler(sendPendingErrorNow, 0));
|
||||
|
||||
const sendErrorSoon = (err: any) => {
|
||||
errorRunner.cancel();
|
||||
pendingErrorEvent = err;
|
||||
errorRunner.schedule();
|
||||
};
|
||||
|
||||
const sendErrorNow = (err: any) => {
|
||||
errorRunner.cancel();
|
||||
pendingErrorEvent = err;
|
||||
sendPendingErrorNow();
|
||||
};
|
||||
|
||||
this._register(dom.addDisposableListener(this._socket, 'close', (e: CloseEvent) => {
|
||||
this._isClosed = true;
|
||||
|
||||
if (pendingErrorEvent) {
|
||||
if (!window.navigator.onLine) {
|
||||
// The browser is offline => this is a temporary error which might resolve itself
|
||||
sendErrorNow(new RemoteAuthorityResolverError('Browser is offline', RemoteAuthorityResolverErrorCode.TemporarilyNotAvailable, e));
|
||||
} else {
|
||||
// An error event is pending
|
||||
// The browser appears to be online...
|
||||
if (!e.wasClean) {
|
||||
// Let's be optimistic and hope that perhaps the server could not be reached or something
|
||||
sendErrorNow(new RemoteAuthorityResolverError(e.reason || `WebSocket close with status code ${e.code}`, RemoteAuthorityResolverErrorCode.TemporarilyNotAvailable, e));
|
||||
} else {
|
||||
// this was a clean close => send existing error
|
||||
errorRunner.cancel();
|
||||
sendPendingErrorNow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._onClose.fire();
|
||||
}));
|
||||
|
||||
this._register(dom.addDisposableListener(this._socket, 'error', sendErrorSoon));
|
||||
}
|
||||
|
||||
send(data: ArrayBuffer | ArrayBufferView): void {
|
||||
if (this._isClosed) {
|
||||
// Refuse to write data to closed WebSocket...
|
||||
return;
|
||||
}
|
||||
this._socket.send(data);
|
||||
}
|
||||
|
||||
close(): void {
|
||||
this._isClosed = true;
|
||||
this._socket.close();
|
||||
this._socket.removeEventListener('message', this._socketMessageListener);
|
||||
this.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user