Skip to content

Commit 54d2fb9

Browse files
committed
fix(web): support Piston synchronous code execution
1 parent 3e4ce3d commit 54d2fb9

File tree

3 files changed

+77
-6
lines changed

3 files changed

+77
-6
lines changed

README.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,23 @@ Available on iOS and Android with the same powerful features and encryption.
9999
- 🔄 **Resizable Code Blocks** - Drag to adjust editor height for optimal viewing
100100
- 🌙 **Theme Toggle** - Switch between light and dark Monaco editor themes
101101
- 💾 **Persistent Results** - Code output is automatically saved with your notes
102-
- 🔒 **Secure Sandboxed Execution** - Code runs in isolated environments via Judge0 API
102+
- 🔒 **Secure Sandboxed Execution** - Code runs in isolated environments via Piston API on EC2
103103
- 📋 **Error Handling** - Clear error messages and compilation details for debugging
104104

105+
### 📊 Diagram Support
106+
107+
![Create Diagram Demo](https://github.com/typelets/typelets-app/blob/main/assets/diagram-demo.gif)
108+
109+
Create beautiful diagrams with Mermaid and PlantUML support:
110+
111+
- 📐 **Mermaid Diagrams** - Flowcharts, sequence diagrams, class diagrams, state diagrams, ER diagrams, and more
112+
- 🎨 **PlantUML Support** - UML diagrams, architecture diagrams, and technical drawings
113+
- 🚀 **Quick Create** - Use the "New Diagram" button or slash command `/diagram`
114+
- 👁️ **Live Preview** - See your diagram update in real-time as you type
115+
- 📋 **Diagram Templates** - Start with pre-built templates for common diagram types
116+
- 💾 **Auto-Save** - Diagrams are automatically saved with your notes
117+
- 🔄 **Instant Conversion** - Convert existing notes to diagram notes with one click
118+
105119
## 🔒 Security First
106120

107121
Typelets uses industry-standard encryption:
@@ -175,7 +189,7 @@ VITE_APP_VERSION=0.5.0
175189

176190
**Code Execution Setup:**
177191
- Code execution is handled securely by your backend API
178-
- The backend proxy manages Judge0 API integration
192+
- The backend uses Piston API running on EC2 for isolated code execution
179193
- No client-side API keys required for security
180194

181195
### Development Proxy
@@ -405,7 +419,7 @@ typelets/
405419
- **Styling:** Tailwind CSS v4
406420
- **Editor:** TipTap with code highlighting
407421
- **Code Editor:** Monaco Editor (VS Code engine)
408-
- **Code Execution:** Judge0 API for 15+ programming languages
422+
- **Code Execution:** Piston API (self-hosted on EC2) for 15+ programming languages
409423
- **Authentication:** Clerk
410424
- **UI Components:** Radix UI
411425
- **Encryption:** Web Crypto API with AES-256-GCM

assets/diagram-demo.gif

1.62 MB
Loading

src/services/codeExecutionService.ts

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,67 @@ class CodeExecutionService {
169169
}
170170

171171
const submissionResult = await response.json();
172+
173+
// Check if this is a synchronous response (Piston) with immediate results
174+
// Piston returns stdout, stderr, status all in the initial response
175+
if (submissionResult.stdout !== undefined || submissionResult.stderr !== undefined) {
176+
// Synchronous execution (Piston) - results are already available
177+
const statusId = submissionResult.status?.id || 3;
178+
const statusDescription = submissionResult.status?.description || 'Accepted';
179+
180+
if (onStatusUpdate) {
181+
onStatusUpdate({ id: statusId, description: statusDescription });
182+
}
183+
184+
// Piston returns plain text (not base64), but check just in case
185+
const stdout = this.decodeBase64(submissionResult.stdout) || submissionResult.stdout || '';
186+
const stderr = this.decodeBase64(submissionResult.stderr) || submissionResult.stderr || '';
187+
const compileOutput = this.decodeBase64(submissionResult.compile_output) || submissionResult.compile_output || '';
188+
189+
if (statusId === 3) {
190+
return {
191+
output: stdout,
192+
error: undefined,
193+
executionTime: parseFloat(submissionResult.time || '0') || Date.now() - startTime,
194+
language,
195+
status: {
196+
id: statusId,
197+
description: statusDescription,
198+
},
199+
};
200+
} else {
201+
let errorMessage = statusDescription;
202+
203+
if (stderr) {
204+
const stderrContent = stderr.trim();
205+
if (stderrContent) {
206+
errorMessage += `\n\nDetails:\n${stderrContent}`;
207+
}
208+
} else if (compileOutput) {
209+
const compileOutputContent = compileOutput.trim();
210+
if (compileOutputContent) {
211+
errorMessage += `\n\nCompilation details:\n${compileOutputContent}`;
212+
}
213+
}
214+
215+
return {
216+
output: stdout || '',
217+
error: errorMessage,
218+
executionTime: parseFloat(submissionResult.time || '0') || Date.now() - startTime,
219+
language,
220+
status: {
221+
id: statusId,
222+
description: statusDescription,
223+
},
224+
};
225+
}
226+
}
227+
228+
// Asynchronous execution (Judge0) - need to poll for results
172229
const submissionToken = submissionResult.token;
173230

174231
if (!submissionToken) {
175-
throw new Error('No submission token returned from Judge0');
232+
throw new Error('No submission token returned from execution service');
176233
}
177234

178235
return await this.pollForResult(
@@ -243,7 +300,7 @@ class CodeExecutionService {
243300
}
244301

245302
if (statusId && statusId !== 1 && statusId !== 2) {
246-
// Decode base64 encoded output from Judge0
303+
// Decode base64 encoded output (Judge0 uses base64 encoding)
247304
const stdout = this.decodeBase64(result.stdout);
248305
const stderr = this.decodeBase64(result.stderr);
249306
const compileOutput = this.decodeBase64(result.compile_output);
@@ -307,7 +364,7 @@ class CodeExecutionService {
307364

308365
return {
309366
output: '',
310-
error: 'Execution timeout - Judge0 took too long to process',
367+
error: 'Execution timeout - code execution took too long to process',
311368
executionTime: Date.now() - startTime,
312369
language,
313370
status: {

0 commit comments

Comments
 (0)