Skip to content

Commit 162bc74

Browse files
authored
Merge pull request #15 from appwrite/shift-workdir
chore: shift workDir to be instance based
2 parents c74d5c0 + dfb3e88 commit 162bc74

File tree

6 files changed

+40
-73
lines changed

6 files changed

+40
-73
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@appwrite.io/synapse",
3-
"version": "0.4.3",
3+
"version": "0.4.4",
44
"description": "Operating system gateway for remote serverless environments",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

src/services/filesystem.ts

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,31 @@ export type FileOperationResult = {
2424

2525
export class Filesystem {
2626
private synapse: Synapse;
27+
private workDir: string;
2728
private folderWatchers: Map<string, fsSync.FSWatcher> = new Map();
2829

2930
/**
3031
* Creates a new Filesystem instance
3132
* @param synapse - The Synapse instance to use
3233
*/
33-
constructor(synapse: Synapse) {
34+
constructor(synapse: Synapse, workDir?: string) {
3435
this.synapse = synapse;
3536
this.synapse.setFilesystem(this);
37+
this.workDir = workDir ?? process.cwd();
3638
}
3739

3840
private log(message: string): void {
3941
const timestamp = new Date().toISOString();
4042
console.log(`[Filesystem][${timestamp}] ${message}`);
4143
}
4244

45+
private resolvePath(inputPath: string): string {
46+
if (path.isAbsolute(inputPath)) {
47+
return inputPath;
48+
}
49+
return path.join(this.workDir, inputPath);
50+
}
51+
4352
/**
4453
* Creates a new file at the specified path with optional content.
4554
* Fails if the file already exists.
@@ -52,7 +61,7 @@ export class Filesystem {
5261
filePath: string,
5362
content: string = "",
5463
): Promise<FileOperationResult> {
55-
const fullPath = path.join(this.synapse.workDir, filePath);
64+
const fullPath = this.resolvePath(filePath);
5665

5766
try {
5867
await fs.access(fullPath, fsConstants.F_OK);
@@ -111,7 +120,7 @@ export class Filesystem {
111120
*/
112121
async getFile(filePath: string): Promise<FileOperationResult> {
113122
try {
114-
const fullPath = path.join(this.synapse.workDir, filePath);
123+
const fullPath = this.resolvePath(filePath);
115124

116125
const data = await fs.readFile(fullPath, "utf-8");
117126

@@ -140,7 +149,7 @@ export class Filesystem {
140149
): Promise<FileOperationResult> {
141150
try {
142151
this.log(`Updating file at path: ${filePath}`);
143-
const fullPath = path.join(this.synapse.workDir, filePath);
152+
const fullPath = this.resolvePath(filePath);
144153
const dirPath = path.dirname(filePath);
145154

146155
await this.createFolder(dirPath);
@@ -170,7 +179,7 @@ export class Filesystem {
170179
content: string,
171180
): Promise<FileOperationResult> {
172181
try {
173-
const fullPath = path.join(this.synapse.workDir, filePath);
182+
const fullPath = this.resolvePath(filePath);
174183
await fs.appendFile(fullPath, content);
175184
return { success: true };
176185
} catch (error) {
@@ -197,8 +206,8 @@ export class Filesystem {
197206
): Promise<FileOperationResult> {
198207
try {
199208
this.log(`Moving file from ${oldPath} to ${newPath}`);
200-
const fullOldPath = path.join(this.synapse.workDir, oldPath);
201-
const fullNewPath = path.join(this.synapse.workDir, newPath);
209+
const fullOldPath = this.resolvePath(oldPath);
210+
const fullNewPath = this.resolvePath(newPath);
202211

203212
await fs.rename(fullOldPath, fullNewPath);
204213

@@ -223,7 +232,7 @@ export class Filesystem {
223232
async deleteFile(filePath: string): Promise<FileOperationResult> {
224233
try {
225234
this.log(`Deleting file at path: ${filePath}`);
226-
const fullPath = path.join(this.synapse.workDir, filePath);
235+
const fullPath = this.resolvePath(filePath);
227236

228237
await fs.unlink(fullPath);
229238

@@ -246,13 +255,13 @@ export class Filesystem {
246255
* @throws Error if directory creation fails
247256
*/
248257
async createFolder(dirPath: string): Promise<FileOperationResult> {
258+
const fullPath = this.resolvePath(dirPath);
259+
249260
if (dirPath === "." || dirPath === "" || dirPath === "/") {
250261
// Skip creation for root or relative '.' path
251262
return { success: true };
252263
}
253264

254-
const fullPath = path.join(this.synapse.workDir, dirPath);
255-
256265
try {
257266
await fs.mkdir(fullPath, { recursive: true });
258267

@@ -279,7 +288,7 @@ export class Filesystem {
279288
async getFolder(dirPath: string): Promise<FileItemResult> {
280289
try {
281290
this.log(`Reading directory at path: ${dirPath}`);
282-
const fullPath = path.join(this.synapse.workDir, dirPath);
291+
const fullPath = this.resolvePath(dirPath);
283292

284293
const items = await fs.readdir(fullPath, { withFileTypes: true });
285294
const data: FileItem[] = items.map((item) => ({
@@ -312,7 +321,7 @@ export class Filesystem {
312321
): Promise<FileOperationResult> {
313322
try {
314323
this.log(`Renaming folder at ${dirPath} to ${name}`);
315-
const fullPath = path.join(this.synapse.workDir, dirPath);
324+
const fullPath = this.resolvePath(dirPath);
316325

317326
const dir = path.dirname(fullPath);
318327
const newPath = path.join(dir, name);
@@ -344,8 +353,8 @@ export class Filesystem {
344353
): Promise<FileOperationResult> {
345354
try {
346355
this.log(`Moving folder from ${oldPath} to ${newPath}`);
347-
const fullOldPath = path.join(this.synapse.workDir, oldPath);
348-
const fullNewPath = path.join(this.synapse.workDir, newPath);
356+
const fullOldPath = this.resolvePath(oldPath);
357+
const fullNewPath = this.resolvePath(newPath);
349358

350359
await fs.rename(fullOldPath, fullNewPath);
351360

@@ -370,7 +379,7 @@ export class Filesystem {
370379
async deleteFolder(dirPath: string): Promise<FileOperationResult> {
371380
try {
372381
this.log(`Deleting folder at path: ${dirPath}`);
373-
const fullPath = path.join(this.synapse.workDir, dirPath);
382+
const fullPath = this.resolvePath(dirPath);
374383

375384
await fs.rm(fullPath, { recursive: true });
376385

@@ -393,15 +402,15 @@ export class Filesystem {
393402
watchWorkDir(
394403
onChange: (result: { path: string; content: string | null }) => void,
395404
): void {
396-
const fullPath = path.join(this.synapse.workDir);
405+
const fullPath = this.resolvePath(this.workDir);
397406
if (this.folderWatchers.has(fullPath)) {
398407
return;
399408
}
400409

401410
// Read and parse .gitignore from the root of the workspace
402411
let ig: ReturnType<typeof ignore> | null = null;
403412
try {
404-
const gitignorePath = path.join(this.synapse.workDir, ".gitignore");
413+
const gitignorePath = this.resolvePath(".gitignore");
405414
const gitignoreContent = fsSync.existsSync(gitignorePath)
406415
? fsSync.readFileSync(gitignorePath, "utf-8")
407416
: "";
@@ -422,7 +431,7 @@ export class Filesystem {
422431
return; // ignore this change
423432
}
424433
const changedPath = path.join("/", filename); // relative to workDir
425-
const absPath = path.join(this.synapse.workDir, filename);
434+
const absPath = path.join(this.workDir, filename);
426435

427436
try {
428437
const stat = await fs.lstat(absPath);
@@ -447,7 +456,7 @@ export class Filesystem {
447456
* Stops watching a directory for changes.
448457
*/
449458
unwatchWorkDir(): void {
450-
const fullPath = path.join(this.synapse.workDir);
459+
const fullPath = this.resolvePath(this.workDir);
451460
const watcher = this.folderWatchers.get(fullPath);
452461
if (watcher) {
453462
watcher.close();

src/services/git.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ export type GitOperationResult = {
1111

1212
export class Git {
1313
private synapse: Synapse;
14+
private workDir: string;
1415

1516
/**
1617
* Creates a new Git instance
1718
* @param synapse - The Synapse instance to use
1819
*/
19-
constructor(synapse: Synapse) {
20+
constructor(synapse: Synapse, workDir?: string) {
2021
this.synapse = synapse;
22+
this.workDir = workDir ?? process.cwd();
2123
}
2224

2325
private isErrnoException(error: unknown): error is NodeJS.ErrnoException {
@@ -26,7 +28,7 @@ export class Git {
2628

2729
private async execute(args: string[]): Promise<GitOperationResult> {
2830
return new Promise((resolve) => {
29-
const git = spawn("git", args, { cwd: this.synapse.workDir });
31+
const git = spawn("git", args, { cwd: this.workDir });
3032
let output = "";
3133
let errorOutput = "";
3234

@@ -60,7 +62,7 @@ export class Git {
6062

6163
private async isGitRepository(): Promise<boolean> {
6264
try {
63-
const gitDir = path.join(this.synapse.workDir, ".git");
65+
const gitDir = path.join(this.workDir, ".git");
6466
return fs.existsSync(gitDir) && fs.statSync(gitDir).isDirectory();
6567
} catch (error: unknown) {
6668
if (this.isErrnoException(error)) {
@@ -86,7 +88,7 @@ export class Git {
8688

8789
// Check if we have write permissions in the current directory
8890
try {
89-
await fs.promises.access(this.synapse.workDir, fs.constants.W_OK);
91+
await fs.promises.access(this.workDir, fs.constants.W_OK);
9092
} catch (error: unknown) {
9193
if (this.isErrnoException(error)) {
9294
return {

src/services/terminal.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export type TerminalOptions = {
66
shell: string;
77
cols?: number;
88
rows?: number;
9+
workDir?: string;
910
};
1011

1112
export class Terminal {
@@ -27,6 +28,7 @@ export class Terminal {
2728
shell: os.platform() === "win32" ? "powershell.exe" : "bash",
2829
cols: 80,
2930
rows: 24,
31+
workDir: process.cwd(),
3032
},
3133
) {
3234
this.synapse = synapse;
@@ -37,7 +39,7 @@ export class Terminal {
3739
name: "xterm-color",
3840
cols: terminalOptions.cols,
3941
rows: terminalOptions.rows,
40-
cwd: this.synapse.workDir,
42+
cwd: terminalOptions.workDir,
4143
env: process.env,
4244
});
4345

src/synapse.ts

Lines changed: 1 addition & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import fs from "fs";
21
import { IncomingMessage } from "http";
32
import { Socket } from "net";
43
import WebSocket, { WebSocketServer } from "ws";
@@ -52,23 +51,12 @@ class Synapse {
5251
private host: string;
5352
private port: number;
5453

55-
public workDir: string;
56-
5754
private serverConnectionListener: ServerConnectionCallback = () => {};
5855

59-
constructor(
60-
host: string = "localhost",
61-
port: number = 3000,
62-
workDir: string = process.cwd(),
63-
) {
56+
constructor(host: string = "localhost", port: number = 3000) {
6457
this.host = host;
6558
this.port = port;
6659

67-
if (!fs.existsSync(workDir)) {
68-
fs.mkdirSync(workDir, { recursive: true });
69-
}
70-
this.workDir = workDir;
71-
7260
this.wss = new WebSocketServer({ noServer: true });
7361
this.wss.on("connection", (ws: WebSocket, req: IncomingMessage) => {
7462
const connectionId = this.generateConnectionId();
@@ -202,40 +190,6 @@ class Synapse {
202190
this.filesystem = filesystem;
203191
}
204192

205-
/**
206-
* Sets the working directory for the Synapse instance
207-
* @param workDir - The path to the working directory
208-
* @returns void
209-
*/
210-
updateWorkDir(workDir: string): { success: boolean; data: string } {
211-
if (!fs.existsSync(workDir)) {
212-
try {
213-
fs.mkdirSync(workDir, { recursive: true });
214-
} catch (error) {
215-
const errorMessage =
216-
error instanceof Error
217-
? error.message
218-
: "Unknown error creating directory";
219-
this.log(`Failed to create work directory: ${errorMessage}`);
220-
return {
221-
success: false,
222-
data: `Failed to create work directory: ${errorMessage}`,
223-
};
224-
}
225-
}
226-
227-
this.workDir = workDir;
228-
this.terminals.forEach((terminal) => {
229-
if (terminal.isTerminalAlive()) {
230-
terminal.updateWorkDir(workDir);
231-
}
232-
});
233-
return {
234-
success: true,
235-
data: "Work directory updated successfully",
236-
};
237-
}
238-
239193
/**
240194
* Establishes a WebSocket connection to the specified URL
241195
* @param path - The WebSocket endpoint path (e.g. '/' or '/terminal')

tests/services/filesystem.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ describe("Filesystem", () => {
2727
setFilesystem: jest.fn(),
2828
} as unknown as Synapse);
2929

30-
filesystem = new Filesystem(mockSynapse);
30+
filesystem = new Filesystem(mockSynapse, "/test");
3131
jest.clearAllMocks();
3232
});
3333

0 commit comments

Comments
 (0)