Skip to content

Commit 78c1822

Browse files
committed
Reduce REST traffic for server-side folders
1 parent 3ebf56c commit 78c1822

File tree

3 files changed

+48
-25
lines changed

3 files changed

+48
-25
lines changed

src/commands/project.ts

-10
Original file line numberDiff line numberDiff line change
@@ -680,11 +680,6 @@ export async function modifyProject(
680680
if (!args) return;
681681
const { node, api, project } = args;
682682

683-
// Technically a project is a "document", so tell the server that we're opening it
684-
await new StudioActions().fireProjectUserAction(api, project, OtherStudioAction.OpenedDocument).catch(() => {
685-
// Swallow error because showing it is more disruptive than using a potentially outdated project definition
686-
});
687-
688683
let items: ProjectItem[] = await api
689684
.actionQuery("SELECT Name, Type FROM %Studio.Project_ProjectItemsList(?,?) WHERE Type != 'GBL'", [project, "1"])
690685
.then((data) => data.result.content);
@@ -1149,11 +1144,6 @@ export async function modifyProjectMetadata(nodeOrUri: NodeBase | vscode.Uri | u
11491144
if (!args) return;
11501145
const { api, project } = args;
11511146

1152-
// Technically a project is a "document", so tell the server that we're opening it
1153-
await new StudioActions().fireProjectUserAction(api, project, OtherStudioAction.OpenedDocument).catch(() => {
1154-
// Swallow error because showing it is more disruptive than using a potentially outdated project definition
1155-
});
1156-
11571147
try {
11581148
const oldDesc: string = await api
11591149
.actionQuery("SELECT Description FROM %Studio.Project WHERE Name = ?", [project])

src/extension.ts

+26
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import {
5858
OtherStudioAction,
5959
contextSourceControlMenu,
6060
mainSourceControlMenu,
61+
StudioActions,
6162
} from "./commands/studio";
6263
import { addServerNamespaceToWorkspace, pickServerAndNamespace } from "./commands/addServerNamespaceToWorkspace";
6364
import { jumpToTagAndOffset, openErrorLocation } from "./commands/jumpToTagAndOffset";
@@ -153,6 +154,7 @@ import {
153154
} from "./utils/documentIndex";
154155
import { WorkspaceNode, NodeBase } from "./explorer/nodes";
155156
import { showPlanWebview } from "./commands/showPlanPanel";
157+
import { isfsConfig } from "./utils/FileProviderUtil";
156158

157159
const packageJson = vscode.extensions.getExtension(extensionId).packageJSON;
158160
const extensionVersion = packageJson.version;
@@ -708,6 +710,25 @@ async function systemModeWarning(wsFolders: readonly vscode.WorkspaceFolder[]):
708710
}
709711
}
710712

713+
/**
714+
* Fire the `OpenedDocument` UserAction for any workspace folders
715+
* that are showing the contents of a server-side project.
716+
* This must be done because technically a project is a "document".
717+
*/
718+
async function fireOpenProjectUserAction(wsFolders: readonly vscode.WorkspaceFolder[]): Promise<void> {
719+
if (!wsFolders || wsFolders.length == 0) return;
720+
for (const wsFolder of wsFolders) {
721+
if (notIsfs(wsFolder.uri)) return;
722+
const { project } = isfsConfig(wsFolder.uri);
723+
if (!project) return;
724+
const api = new AtelierAPI(wsFolder.uri);
725+
if (!api.active) return;
726+
new StudioActions().fireProjectUserAction(api, project, OtherStudioAction.OpenedDocument).catch(() => {
727+
// Swallow error because showing it is more disruptive than using a potentially outdated project definition
728+
});
729+
}
730+
}
731+
711732
/**
712733
* Set when clause context keys so the ObjectScript Explorer and
713734
* Projects Explorer views are correctly shown or hidden depending
@@ -941,6 +962,9 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
941962
// Warn about SystemMode
942963
systemModeWarning(vscode.workspace.workspaceFolders);
943964

965+
// Fire OpenedDocument UserAction for folders showing the contents of a server-side project
966+
fireOpenProjectUserAction(vscode.workspace.workspaceFolders);
967+
944968
iscIcon = vscode.Uri.joinPath(context.extensionUri, "images", "fileIcon.svg");
945969

946970
// Index documents in all local workspace folders
@@ -1531,6 +1555,8 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
15311555
for (const r of e.removed) removeIndexOfWorkspaceFolder(r);
15321556
// Show or hide explorer views as needed
15331557
setExplorerContextKeys();
1558+
// Fire OpenedDocument UserAction for added folders showing the contents of a server-side project
1559+
fireOpenProjectUserAction(e.added);
15341560
}),
15351561
vscode.commands.registerCommand("vscode-objectscript.importXMLFiles", importXMLFiles),
15361562
vscode.commands.registerCommand("vscode-objectscript.exportToXMLFile", exportDocumentsToXMLFile),

src/providers/FileSystemProvider/FileSystemProvider.ts

+22-15
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as path from "path";
22
import * as vscode from "vscode";
33
import { isText } from "istextorbinary";
44
import { AtelierAPI } from "../../api";
5-
import { fireOtherStudioAction, OtherStudioAction, StudioActions } from "../../commands/studio";
5+
import { fireOtherStudioAction, OtherStudioAction } from "../../commands/studio";
66
import { isfsConfig, projectContentsFromUri, studioOpenDialogFromURI } from "../../utils/FileProviderUtil";
77
import {
88
classNameRegex,
@@ -234,6 +234,9 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
234234
}
235235

236236
public async stat(uri: vscode.Uri): Promise<vscode.FileStat> {
237+
if (uri.path.includes(".vscode/") && !uri.path.endsWith("/settings.json")) {
238+
throw vscode.FileSystemError.NoPermissions("Only settings.json is allowed within the /.vscode directory");
239+
}
237240
let entryPromise: Promise<Entry>;
238241
let result: Entry;
239242
const redirectedUri = redirectDotvscodeRoot(uri);
@@ -284,19 +287,14 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
284287
}
285288

286289
public async readDirectory(uri: vscode.Uri): Promise<[string, vscode.FileType][]> {
287-
uri = redirectDotvscodeRoot(uri);
290+
if (uri.path.includes(".vscode/")) {
291+
throw vscode.FileSystemError.NoPermissions("Cannot read the /.vscode directory");
292+
}
288293
const parent = await this._lookupAsDirectory(uri);
289294
const api = new AtelierAPI(uri);
290295
if (!api.active) throw vscode.FileSystemError.Unavailable(uri);
291296
const { csp, project } = isfsConfig(uri);
292297
if (project) {
293-
if (["", "/"].includes(uri.path)) {
294-
// Technically a project is a "document", so tell the server that we're opening it
295-
await new StudioActions().fireProjectUserAction(api, project, OtherStudioAction.OpenedDocument).catch(() => {
296-
// Swallow error because showing it is more disruptive than using a potentially outdated project definition
297-
});
298-
}
299-
300298
// Get all items in the project
301299
return projectContentsFromUri(uri).then((entries) =>
302300
entries.map((entry) => {
@@ -405,7 +403,9 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
405403
}
406404

407405
public createDirectory(uri: vscode.Uri): void | Thenable<void> {
408-
uri = redirectDotvscodeRoot(uri);
406+
if (uri.path.includes(".vscode/")) {
407+
throw vscode.FileSystemError.NoPermissions("Cannot create a subdirectory of the /.vscode directory");
408+
}
409409
const basename = path.posix.basename(uri.path);
410410
const dirname = uri.with({ path: path.posix.dirname(uri.path) });
411411
return this._lookupAsDirectory(dirname).then((parent) => {
@@ -421,6 +421,9 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
421421
}
422422

423423
public async readFile(uri: vscode.Uri): Promise<Uint8Array> {
424+
if (uri.path.includes(".vscode/") && !uri.path.endsWith("/settings.json")) {
425+
throw vscode.FileSystemError.NoPermissions("Only settings.json is allowed within the /.vscode directory");
426+
}
424427
// Use _lookup() instead of _lookupAsFile() so we send
425428
// our cached mtime with the GET /doc request if we have it
426429
return this._lookup(uri, true).then((file: File) => {
@@ -439,6 +442,9 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
439442
overwrite: boolean;
440443
}
441444
): void | Thenable<void> {
445+
if (uri.path.includes(".vscode/") && !uri.path.endsWith("/settings.json")) {
446+
throw vscode.FileSystemError.NoPermissions("Only settings.json is allowed within the /.vscode directory");
447+
}
442448
uri = redirectDotvscodeRoot(uri);
443449
if (uri.path.startsWith("/.")) {
444450
throw vscode.FileSystemError.NoPermissions("dot-folders not supported by server");
@@ -606,6 +612,9 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
606612
}
607613

608614
public async delete(uri: vscode.Uri, options: { recursive: boolean }): Promise<void> {
615+
if (uri.path.includes(".vscode/") && !uri.path.endsWith("/settings.json")) {
616+
throw vscode.FileSystemError.NoPermissions("Only settings.json is allowed within the /.vscode directory");
617+
}
609618
uri = redirectDotvscodeRoot(uri);
610619
const { project } = isfsConfig(uri);
611620
const csp = isCSP(uri);
@@ -699,6 +708,9 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
699708
if (vscode.workspace.getWorkspaceFolder(oldUri) != vscode.workspace.getWorkspaceFolder(newUri)) {
700709
throw vscode.FileSystemError.NoPermissions("Cannot rename a file across workspace folders");
701710
}
711+
if (oldUri.path.includes(".vscode/") || newUri.path.includes(".vscode/")) {
712+
throw vscode.FileSystemError.NoPermissions("Cannot rename a file in the /.vscode directory");
713+
}
702714
// Check if the destination exists
703715
let newFileStat: vscode.FileStat;
704716
try {
@@ -864,11 +876,6 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
864876
// Fetch entry (a file or directory) from cache, else from server
865877
private async _lookup(uri: vscode.Uri, fillInPath?: boolean): Promise<Entry> {
866878
const api = new AtelierAPI(uri);
867-
if (uri.path === "/") {
868-
await api.serverInfo().catch((error) => {
869-
throw vscode.FileSystemError.Unavailable(stringifyError(error) || uri);
870-
});
871-
}
872879
const config = api.config;
873880
const rootName = `${config.username}@${config.host}:${config.port}${config.pathPrefix}/${config.ns.toUpperCase()}`;
874881
let entry: Entry = this.superRoot.entries.get(rootName);

0 commit comments

Comments
 (0)