Move event into IoSession
This commit is contained in:
parent
005c86340f
commit
d6c3a15ea6
4 changed files with 97 additions and 69 deletions
|
@ -320,7 +320,6 @@ namespace ts.server {
|
|||
pluginProbeLocations?: ReadonlyArray<string>;
|
||||
allowLocalPluginLoads?: boolean;
|
||||
typesMapLocation?: string;
|
||||
eventSender?: EventSender;
|
||||
}
|
||||
|
||||
type WatchFile = (host: ServerHost, file: string, cb: FileWatcherCallback, watchType: WatchType, project?: Project) => FileWatcher;
|
||||
|
@ -441,7 +440,7 @@ namespace ts.server {
|
|||
this.logger.info("No types map provided; using the default");
|
||||
}
|
||||
|
||||
this.typingsInstaller.attach(this, opts.eventSender);
|
||||
this.typingsInstaller.attach(this);
|
||||
|
||||
this.typingsCache = new TypingsCache(this.typingsInstaller);
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@ namespace ts.server {
|
|||
cancellationToken: ServerCancellationToken;
|
||||
canUseEvents: boolean;
|
||||
/**
|
||||
* If defined, specifies the socket used to send events to the client.
|
||||
* Otherwise, events are sent through the host.
|
||||
*/
|
||||
* If defined, specifies the socket used to send events to the client.
|
||||
* Otherwise, events are sent through the host.
|
||||
*/
|
||||
eventPort?: number;
|
||||
useSingleInferredProject: boolean;
|
||||
useInferredProjectPerProjectRoot: boolean;
|
||||
|
@ -248,7 +248,6 @@ namespace ts.server {
|
|||
private installer: NodeChildProcess;
|
||||
private installerPidReported = false;
|
||||
private projectService: ProjectService;
|
||||
private eventSender: EventSender | undefined;
|
||||
private activeRequestCount = 0;
|
||||
private requestQueue: QueuedOperation[] = [];
|
||||
private requestMap = createMap<QueuedOperation>(); // Maps operation ID to newest requestQueue entry with that ID
|
||||
|
@ -272,7 +271,11 @@ namespace ts.server {
|
|||
readonly globalTypingsCacheLocation: string,
|
||||
readonly typingSafeListLocation: string,
|
||||
readonly typesMapLocation: string,
|
||||
private readonly npmLocation: string | undefined) {
|
||||
private readonly npmLocation: string | undefined,
|
||||
/**
|
||||
* If undefined, event-related work will be suppressed.
|
||||
*/
|
||||
private eventSender: EventSender | undefined) {
|
||||
}
|
||||
|
||||
isKnownTypesPackageName(name: string): boolean {
|
||||
|
@ -311,16 +314,12 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
|
||||
attach(projectService: ProjectService, eventSender?: EventSender) {
|
||||
attach(projectService: ProjectService) {
|
||||
this.projectService = projectService;
|
||||
if (this.logger.hasLevel(LogLevel.requestTime)) {
|
||||
this.logger.info("Binding...");
|
||||
}
|
||||
|
||||
if (eventSender) {
|
||||
this.eventSender = eventSender;
|
||||
}
|
||||
|
||||
const args: string[] = [Arguments.GlobalCacheLocation, this.globalTypingsCacheLocation];
|
||||
if (this.telemetryEnabled) {
|
||||
args.push(Arguments.EnableTelemetry);
|
||||
|
@ -519,17 +518,15 @@ namespace ts.server {
|
|||
}
|
||||
}
|
||||
|
||||
class SocketEventSender implements EventSender {
|
||||
private host: ServerHost;
|
||||
private logger: Logger;
|
||||
private eventPort: number;
|
||||
class SocketEventSender extends DefaultMessageSender {
|
||||
private eventSocket: NodeSocket | undefined;
|
||||
private socketEventQueue: { body: any, eventName: string }[] | undefined;
|
||||
|
||||
constructor(host: ServerHost, logger: Logger, eventPort: number) {
|
||||
this.host = host;
|
||||
this.logger = logger;
|
||||
this.eventPort = eventPort;
|
||||
constructor(host: ServerHost,
|
||||
byteLength: (buf: string, encoding?: string) => number,
|
||||
logger: Logger,
|
||||
private eventPort: number) {
|
||||
super(host, byteLength, logger, /*canUseEvents*/ true);
|
||||
|
||||
const s = net.connect({ port: this.eventPort }, () => {
|
||||
this.eventSocket = s;
|
||||
|
@ -541,20 +538,20 @@ namespace ts.server {
|
|||
this.socketEventQueue = undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public event = <T>(body: T, eventName: string) => {
|
||||
if (!this.eventSocket) {
|
||||
if (this.logger.hasLevel(LogLevel.verbose)) {
|
||||
this.logger.info(`eventPort: event "${eventName}" queued, but socket not yet initialized`);
|
||||
this.event = <T>(body: T, eventName: string) => {
|
||||
if (!this.eventSocket) {
|
||||
if (this.logger.hasLevel(LogLevel.verbose)) {
|
||||
this.logger.info(`eventPort: event "${eventName}" queued, but socket not yet initialized`);
|
||||
}
|
||||
(this.socketEventQueue || (this.socketEventQueue = [])).push({ body, eventName });
|
||||
return;
|
||||
}
|
||||
(this.socketEventQueue || (this.socketEventQueue = [])).push({ body, eventName });
|
||||
return;
|
||||
}
|
||||
else {
|
||||
Debug.assert(this.socketEventQueue === undefined);
|
||||
this.writeToEventSocket(body, eventName);
|
||||
}
|
||||
else {
|
||||
Debug.assert(this.socketEventQueue === undefined);
|
||||
this.writeToEventSocket(body, eventName);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private writeToEventSocket(body: any, eventName: string): void {
|
||||
|
@ -566,15 +563,11 @@ namespace ts.server {
|
|||
constructor(options: IoSessionOptions) {
|
||||
const { host, eventPort, globalTypingsCacheLocation, typingSafeListLocation, typesMapLocation, npmLocation, canUseEvents } = options;
|
||||
|
||||
let event: Event;
|
||||
if (canUseEvents && eventPort) {
|
||||
const eventSender = new SocketEventSender(host, logger, eventPort);
|
||||
event = eventSender.event;
|
||||
}
|
||||
const messageSender = eventPort && canUseEvents ? new SocketEventSender(host, Buffer.byteLength, logger, eventPort) : new DefaultMessageSender(host, Buffer.byteLength, logger, canUseEvents);
|
||||
|
||||
const typingsInstaller = disableAutomaticTypingAcquisition
|
||||
? undefined
|
||||
: new NodeTypingsInstaller(telemetryEnabled, logger, host, globalTypingsCacheLocation, typingSafeListLocation, typesMapLocation, npmLocation);
|
||||
: new NodeTypingsInstaller(telemetryEnabled, logger, host, globalTypingsCacheLocation, typingSafeListLocation, typesMapLocation, npmLocation, canUseEvents ? messageSender : undefined);
|
||||
|
||||
super({
|
||||
host,
|
||||
|
@ -586,7 +579,7 @@ namespace ts.server {
|
|||
hrtime: process.hrtime,
|
||||
logger,
|
||||
canUseEvents,
|
||||
event,
|
||||
messageSender,
|
||||
globalPlugins: options.globalPlugins,
|
||||
pluginProbeLocations: options.pluginProbeLocations,
|
||||
allowLocalPluginLoads: options.allowLocalPluginLoads });
|
||||
|
|
|
@ -245,6 +245,58 @@ namespace ts.server {
|
|||
event: Event;
|
||||
}
|
||||
|
||||
export type Send = (msg: protocol.Message) => void;
|
||||
|
||||
export interface MessageSender extends EventSender {
|
||||
send: Send;
|
||||
event: Event;
|
||||
}
|
||||
|
||||
function defaultSend(
|
||||
host: ServerHost,
|
||||
byteLength: (buf: string, encoding?: string) => number,
|
||||
logger: Logger,
|
||||
canUseEvents: boolean,
|
||||
msg: protocol.Message) {
|
||||
if (msg.type === "event" && !canUseEvents) {
|
||||
if (logger.hasLevel(LogLevel.verbose)) {
|
||||
logger.info(`Session does not support events: ignored event: ${JSON.stringify(msg)}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
host.write(formatMessage(msg, logger, byteLength, host.newLine));
|
||||
}
|
||||
|
||||
function defaultEvent<T>(
|
||||
host: ServerHost,
|
||||
byteLength: (buf: string, encoding?: string) => number,
|
||||
logger: Logger,
|
||||
canUseEvents: boolean,
|
||||
body: T, eventName: string): void {
|
||||
const ev: protocol.Event = {
|
||||
seq: 0,
|
||||
type: "event",
|
||||
event: eventName,
|
||||
body
|
||||
};
|
||||
defaultSend(host, byteLength, logger, canUseEvents, ev);
|
||||
}
|
||||
|
||||
export class DefaultMessageSender implements MessageSender {
|
||||
constructor(protected host: ServerHost,
|
||||
protected byteLength: (buf: string, encoding?: string) => number,
|
||||
protected logger: Logger,
|
||||
protected canUseEvents: boolean) { }
|
||||
|
||||
public send = (msg: protocol.Message) => {
|
||||
defaultSend(this.host, this.byteLength, this.logger, this.canUseEvents, msg);
|
||||
}
|
||||
|
||||
public event = <T>(body: T, eventName: string) => {
|
||||
defaultEvent(this.host, this.byteLength, this.logger, this.canUseEvents, body, eventName);
|
||||
}
|
||||
}
|
||||
|
||||
export interface SessionOptions {
|
||||
host: ServerHost;
|
||||
cancellationToken: ServerCancellationToken;
|
||||
|
@ -259,10 +311,9 @@ namespace ts.server {
|
|||
*/
|
||||
canUseEvents: boolean;
|
||||
/**
|
||||
* An optional callback overriding the default behavior for sending events.
|
||||
* if set, `canUseEvents` and `eventPort` are ignored.
|
||||
* An optional callback overriding the default behavior for sending messages.
|
||||
*/
|
||||
event?: Event;
|
||||
messageSender?: MessageSender;
|
||||
eventHandler?: ProjectServiceEventHandler;
|
||||
throttleWaitMilliseconds?: number;
|
||||
|
||||
|
@ -271,9 +322,7 @@ namespace ts.server {
|
|||
allowLocalPluginLoads?: boolean;
|
||||
}
|
||||
|
||||
export class Session implements EventSender {
|
||||
public readonly event: Event;
|
||||
|
||||
export class Session implements MessageSender {
|
||||
private readonly gcTimer: GcTimer;
|
||||
protected projectService: ProjectService;
|
||||
private changeSeq = 0;
|
||||
|
@ -298,23 +347,13 @@ namespace ts.server {
|
|||
this.byteLength = opts.byteLength;
|
||||
this.hrtime = opts.hrtime;
|
||||
this.logger = opts.logger;
|
||||
this.canUseEvents = opts.canUseEvents || !!opts.event;
|
||||
this.canUseEvents = opts.canUseEvents;
|
||||
|
||||
const { throttleWaitMilliseconds } = opts;
|
||||
|
||||
if (opts.event) {
|
||||
this.event = opts.event;
|
||||
}
|
||||
else {
|
||||
this.event = function <T>(body: T, eventName: string): void {
|
||||
const ev: protocol.Event = {
|
||||
seq: 0,
|
||||
type: "event",
|
||||
event: eventName,
|
||||
body
|
||||
};
|
||||
this.send(ev);
|
||||
};
|
||||
if (opts.messageSender) {
|
||||
this.send = opts.messageSender.send;
|
||||
this.event = opts.messageSender.event;
|
||||
}
|
||||
|
||||
this.eventHandler = this.canUseEvents
|
||||
|
@ -340,8 +379,7 @@ namespace ts.server {
|
|||
eventHandler: this.eventHandler,
|
||||
globalPlugins: opts.globalPlugins,
|
||||
pluginProbeLocations: opts.pluginProbeLocations,
|
||||
allowLocalPluginLoads: opts.allowLocalPluginLoads,
|
||||
eventSender: this
|
||||
allowLocalPluginLoads: opts.allowLocalPluginLoads
|
||||
};
|
||||
this.projectService = new ProjectService(settings);
|
||||
this.gcTimer = new GcTimer(this.host, /*delay*/ 7000, this.logger);
|
||||
|
@ -413,13 +451,11 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
public send(msg: protocol.Message) {
|
||||
if (msg.type === "event" && !this.canUseEvents) {
|
||||
if (this.logger.hasLevel(LogLevel.verbose)) {
|
||||
this.logger.info(`Session does not support events: ignored event: ${JSON.stringify(msg)}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.host.write(formatMessage(msg, this.logger, this.byteLength, this.host.newLine));
|
||||
defaultSend(this.host, this.byteLength, this.logger, this.canUseEvents, msg);
|
||||
}
|
||||
|
||||
public event<T>(body: T, eventName: string): void {
|
||||
defaultEvent(this.host, this.byteLength, this.logger, this.canUseEvents, body, eventName);
|
||||
}
|
||||
|
||||
// For backwards-compatibility only.
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace ts.server {
|
|||
isKnownTypesPackageName(name: string): boolean;
|
||||
installPackage(options: InstallPackageOptionsWithProjectRootPath): Promise<ApplyCodeActionCommandResult>;
|
||||
enqueueInstallTypingsRequest(p: Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray<string>): void;
|
||||
attach(projectService: ProjectService, eventSender?: EventSender): void;
|
||||
attach(projectService: ProjectService): void;
|
||||
onProjectClosed(p: Project): void;
|
||||
readonly globalTypingsCacheLocation: string;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue