Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Project Name

This project provides an interactive development environment with a focus on real-time file exploration and management within a playground. It includes a backend server for handling socket connections and file operations, and a frontend for displaying and interacting with the file system.

## Features

- **Real-time File Explorer**: Browse and manage project files within a containerized environment.
- **File Content Editing**: Read and write file content directly from the frontend.
- **Playground Management**: Create and manage isolated development playgrounds.

## Getting Started

### Prerequisites

- Node.js (v14 or higher)
- Docker and Docker Compose

### Installation

1. **Clone the repository**:

```bash
git clone <repository-url>
cd project-name
```

2. **Install backend dependencies**:

```bash
cd server
npm install
```

3. **Install frontend dependencies**:

```bash
cd ../frontend
npm install
```

### Running the Application

1. **Start the backend server**:

```bash
cd server
npm start
```

2. **Start the frontend development server**:

```bash
cd ../frontend
npm start
```

3. Open your browser and navigate to `http://localhost:3000` (or the port specified by your frontend).

## Architecture Overview

The application consists of two main parts:

- **`server/`**: Node.js backend handling API requests, WebSocket communication, and orchestration of playground containers. It establishes a socket connection to a `file_server` running inside each playground container to proxy file system requests.
- **`frontend/`**: React application providing the user interface, including the code editor and file explorer. It communicates with the backend via WebSockets to send file system requests and receive updates.

## Key Components

- **File Explorer Listener (`server/src/socket/events/onFileExplorer.ts`)**: Manages the socket connection between the main server and the `file_server` within a playground container, relaying file system events.
- **File Explorer Frontend Component (`frontend/src/modules/playground/components/Explorer/FileExplorer.tsx`)**: Renders the directory tree and handles user interactions (e.g., opening files, requesting directory updates).
- **Source Code Context (`frontend/src/modules/playground/utils/SourceCodeContext/SourceCodeContext.tsx`)**: Manages the state of open files, active file, and whether the file explorer is connected, providing an interface for components to interact with file data.
- **File Server (`server/playground_images/vite-react/proxy_container/file_server/src/server.ts`)**: A service running inside the playground container responsible for file system operations (read, write, directory listing).

## API Endpoints (relevant for playground management)

- `/api/playground/create`: Creates and starts a new playground instance.
- `/api/playgrounds`: Lists active playgrounds.

See `server/src/routes/playground.route.ts` for details.
118 changes: 118 additions & 0 deletions docs/api/file-management.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# File Management API

This document describes the WebSocket-based API for interacting with the file system within a playground environment. These operations are facilitated by the File Explorer system.

All file system requests from the frontend are proxied through the main backend server to a dedicated `file_server` running inside the target playground container.

## WebSocket Events for File Management

### `file_server_request` (Client to Server)

This event is emitted by the frontend client to request a file system operation. The server then forwards this request to the `file_server` within the specific playground.

**Structure:**

`socket.emit('file_server_request', '<operation_name>', ...<arguments>);`

**Operations:**

#### `get_directory`

Requests the directory listing (tree structure) of a specified path.

- **Arguments:**
- `path` (string): The path to the directory to list (e.g., `'/'`, `'/src'`).

- **Example Frontend Usage:**
```typescript
socket.emit('file_server_request', 'get_directory', '/');
```

- **Backend (File Server) Handling:**
```typescript
// server/playground_images/vite-react/proxy_container/file_server/src/server.ts
io.on('connection', (socket) => {
socket.on('get_directory', (directoryPath) => {
const directoryTree = getDirectoryTree(directoryPath);
emitSocket('file_server_response', { type: 'directory_tree', data: directoryTree });
});
});
```

#### `get_file_content`

Requests the content of a specific file.

- **Arguments:**
- `path` (string): The path to the file (e.g., `'/src/App.tsx'`).

- **Example Frontend Usage:**
```typescript
socket.emit('file_server_request', 'get_file_content', '/src/index.js');
```

- **Backend (File Server) Handling:**
```typescript
// server/playground_images/vite-react/proxy_container/file_server/src/server.ts
socket.on('get_file_content', (filePath) => {
const fileData = getFileContent(filePath);
emitSocket('file_server_response', { type: 'file_content', data: fileData });
});
```

#### `write_file_content`

Writes new content to a specific file (or creates it if it doesn't exist).

- **Arguments:**
- `path` (string): The path to the file.
- `content` (string): The new content to write to the file.

- **Example Frontend Usage:**
```typescript
const newContent = 'console.log("Hello, playground!");';
socket.emit('file_server_request', 'write_file_content', '/src/main.js', newContent);
```

- **Backend (File Server) Handling:**
```typescript
// server/playground_images/vite-react/proxy_container/file_server/src/server.ts
socket.on('write_file_content', (filePath, content) => {
const result = writeToFile(filePath, content);
emitSocket('file_server_response', { type: 'write_file_result', data: result });
});
```

### `file_server` (Server to Client)

This event is emitted by the main backend server to send responses or updates from the `file_server` in the playground back to the frontend client.

**Structure:**

`socket.on('file_server', (data) => { ... });`

**Data Payload (examples):**

- **Connection Status:**
```json
{ "connected": true }
```
Sent when the `FileExplorerListener` successfully connects to the playground's `file_server`.

- **Directory Tree Update:**
```json
{ "type": "directory_tree", "data": { /* JSON tree structure */ } }
```
Response to a `get_directory` request.

- **File Content:**
```json
{ "type": "file_content", "data": { "path": "/src/App.tsx", "content": "...", "fileExists": true } }
```
Response to a `get_file_content` request.

- **Write File Result:**
```json
{ "type": "write_file_result", "data": { "success": true, "path": "/src/main.js" } }
```
Response to a `write_file_content` request.
126 changes: 126 additions & 0 deletions docs/guides/file-explorer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# File Explorer Guide

This guide explains the architecture and functionality of the file explorer component, detailing how it enables real-time file system interaction within the development playgrounds.

## Overview

The file explorer is a core feature that allows users to browse directories, open files, and manage content directly from the frontend. It operates by establishing a dedicated WebSocket connection for file system events, proxying requests between the frontend and a `file_server` running inside each playground container.

## Architecture

Interaction with the file system involves several components:

1. **Frontend (`frontend/src/modules/playground/components/Explorer/FileExplorer.tsx`)**:
- Displays the directory tree.
- Sends `file_server_request` events to the main backend server for operations like `get_directory`, `get_file_content`, and `write_file_content`.
- Listens for `file_server` events from the backend to update its state (e.g., directory tree, file content).

2. **Main Backend Server (`server/src/socket/events/onFileExplorer.ts`)**:
- Contains the `FileExplorerListener` class, which is responsible for managing the connection to the `file_server` in the playground.
- Receives `file_server_request` events from the frontend and forwards them to the respective `file_server` in the playground container via its own WebSocket connection.
- Relays `file_server_response` events from the playground's `file_server` back to the frontend.

```typescript
class FileExplorerListener {
clientSocket: Socket;
fileServerSocket: ClientSocket;

directoryServicePort: any;
playgroundId: any;

constructor(clientSocket, directoryServicePort, playgroundId) {
this.clientSocket = clientSocket;
this.directoryServicePort = directoryServicePort;
this.playgroundId = playgroundId;
}

connectFileExplorerSocket() {
this.fileServerSocket = connect(`http://host.docker.internal:${this.directoryServicePort}`);
this.fileServerSocket.on('connect', () => {
this.clientSocket.emit('file_server', { connected: true });
});
}

init() {
this.connectFileExplorerSocket();
this.clientSocket.on('file_server_request', (event, ...args) => {
this.fileServerSocket.emit(event, ...args);
});
this.fileServerSocket.on('file_server_response', (data) => {
this.clientSocket.emit('file_server', data);
});
}
}
```

3. **File Server within Playground Container (`server/playground_images/vite-react/proxy_container/file_server/src/server.ts`)**:
- A dedicated service running inside each playground container.
- Handles actual file system operations (reading files, writing files, listing directories using the `tree` command).
- Emits `file_server_response` events back to the main backend server with the results of its operations.

```typescript
const getFileContent = (path) => {
const fileExists = existsSync(path);
if (fileExists) {
try {
const content = readFileSync(path, 'utf-8');
return { path, content: content, fileExists: true };
} catch (error) {}
}
return { path, content: '', fileExists: false };
};

const writeToFile = (path, content) => {
try {
writeFileSync(path, content, 'utf-8');
return { success: true, path };
} catch (error) {
return { success: false, path, error: error.message };
}
};
```

## Frontend Interaction Examples

### Connecting to the File Explorer

The `FileExplorer` component uses the `useSocketContext` and `useCodeFilesContext` to manage its connection status and file data.

```typescript
const FileExplorer = () => {
const { socket } = useSocketContext();
const {
addFile,
setActiveFile,
updateFile,
files: codeFiles,
activeFile,
setExplorerConnected,
} = useCodeFilesContext();

// ... useEffect for socket event listeners
};
```

### Requesting Directory Content

To get the content of a directory, the frontend emits a `file_server_request` event:

```typescript
const getDirectory = (path: string) => {
socket.emit('file_server_request', 'get_directory', path);
};
```

### Updating File Content

When a user edits a file, the `updateFileData` function (from `SourceCodeContext`) propagates the change:

```typescript
const updateFileData = (path: string, content: string) => {
if (!socket || !socket.connected) {
return;
}
socket.emit('file_server_request', 'write_file_content', path, content);
};
```