136 lines
3.2 KiB
TypeScript
136 lines
3.2 KiB
TypeScript
import { Disposable } from "@hediet/std/disposable";
|
|
import { debugVisualizerUIContract } from "@hediet/debug-visualizer-vscode-shared";
|
|
import { ConsoleRpcLogger, RequestHandlingError } from "@hediet/typed-json-rpc";
|
|
import { EvaluationWatcher, DataSource } from "./DataSource/DataSource";
|
|
import { WebSocketStream } from "@hediet/typed-json-rpc-websocket";
|
|
import { observable, autorun } from "mobx";
|
|
import { Server } from "./Server";
|
|
import * as open from "open";
|
|
import chromeLauncher = require("chrome-launcher");
|
|
import { Config } from "./Config";
|
|
|
|
export class ConnectionHandler {
|
|
public readonly dispose = Disposable.fn();
|
|
@observable
|
|
private watcher: EvaluationWatcher | undefined = undefined;
|
|
|
|
constructor(
|
|
dataSource: DataSource,
|
|
stream: WebSocketStream,
|
|
server: Server,
|
|
config: Config,
|
|
serverSecret: string
|
|
) {
|
|
let authenticated = false;
|
|
|
|
function throwIfNotAuthenticated() {
|
|
if (!authenticated) {
|
|
throw new RequestHandlingError("Not authenticated");
|
|
}
|
|
}
|
|
|
|
const {
|
|
client,
|
|
channel,
|
|
} = debugVisualizerUIContract.registerServerToStream(
|
|
stream,
|
|
new ConsoleRpcLogger(),
|
|
{
|
|
authenticate: async ({ secret }, { newErr }) => {
|
|
if (secret !== serverSecret) {
|
|
return newErr({ errorMessage: "Invalid Secret" });
|
|
} else {
|
|
authenticated = true;
|
|
}
|
|
},
|
|
refresh: async () => {
|
|
throwIfNotAuthenticated();
|
|
|
|
if (this.watcher) {
|
|
this.watcher.refresh();
|
|
}
|
|
},
|
|
setExpression: async ({ newExpression }) => {
|
|
throwIfNotAuthenticated();
|
|
|
|
let oldPreferredDataExtractor: EvaluationWatcher["preferredDataExtractor"];
|
|
if (this.watcher) {
|
|
oldPreferredDataExtractor = this.watcher
|
|
.preferredDataExtractor;
|
|
this.dispose.untrack(this.watcher).dispose();
|
|
}
|
|
this.watcher = this.dispose.track(
|
|
dataSource.createEvaluationWatcher(newExpression, {
|
|
preferredDataExtractor: oldPreferredDataExtractor,
|
|
})
|
|
);
|
|
},
|
|
openInBrowser: async ({}) => {
|
|
throwIfNotAuthenticated();
|
|
|
|
const url = server.getIndexUrl({
|
|
expression: this.watcher
|
|
? this.watcher.expression
|
|
: undefined,
|
|
});
|
|
|
|
let opened = false;
|
|
if (config.useChromeKioskMode()) {
|
|
opened = await launchChrome(url);
|
|
}
|
|
if (!opened) {
|
|
open(url);
|
|
}
|
|
},
|
|
setPreferredDataExtractor: async ({ dataExtractorId }) => {
|
|
throwIfNotAuthenticated();
|
|
|
|
if (this.watcher) {
|
|
this.watcher.setPreferredDataExtractor(dataExtractorId);
|
|
}
|
|
},
|
|
getCompletions: async ({ text, column }) => {
|
|
throwIfNotAuthenticated();
|
|
|
|
const completions = await dataSource.getCompletions(
|
|
text,
|
|
column
|
|
);
|
|
return {
|
|
completions,
|
|
};
|
|
},
|
|
}
|
|
);
|
|
|
|
this.dispose.track(
|
|
Disposable.create(
|
|
autorun(() => {
|
|
if (this.watcher) {
|
|
client.updateState({
|
|
newState: this.watcher.state,
|
|
});
|
|
}
|
|
})
|
|
)
|
|
);
|
|
|
|
stream.onClosed.then(() => {
|
|
this.dispose();
|
|
});
|
|
}
|
|
}
|
|
|
|
async function launchChrome(url: string): Promise<boolean> {
|
|
try {
|
|
const _chrome = await chromeLauncher.launch({
|
|
startingUrl: url,
|
|
// `--window-size=${width},${height}`
|
|
chromeFlags: ["--app=" + url],
|
|
});
|
|
return true;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|