11import { RunCodeDto , RunCodeResponse } from 'src/sandbox/dto/create-sandbox.dto' ;
22import IsolatedVM , { ExternalCopy , Isolate , Reference } from 'isolated-vm' ;
3-
3+ import { mkdtemp , writeFile } from 'fs/promises' ;
4+ import { tmpdir } from 'os' ;
5+ import { join } from 'path' ;
6+ import { rmSync } from 'fs' ;
47import { countToken } from './jsFn/tiktoken' ;
58import { timeDelay } from './jsFn/delay' ;
69import { strToBase64 } from './jsFn/str2Base64' ;
@@ -9,7 +12,7 @@ import { createHmac } from './jsFn/crypto';
912import { spawn } from 'child_process' ;
1013import { pythonScript } from './constants' ;
1114const CustomLogStr = 'CUSTOM_LOG' ;
12-
15+ const PythonScriptFileName = 'main.py' ;
1316export const runJsSandbox = async ( {
1417 code,
1518 variables = { }
@@ -112,15 +115,16 @@ export const runPythonSandbox = async ({
112115 code,
113116 variables = { }
114117} : RunCodeDto ) : Promise < RunCodeResponse > => {
118+ const tempDir = await mkdtemp ( join ( tmpdir ( ) , 'python_script_tmp_' ) ) ;
115119 const mainCallCode = `
116- data = ${ JSON . stringify ( { code, variables } ) }
120+ data = ${ JSON . stringify ( { code, variables, tempDir } ) }
117121res = run_pythonCode(data)
118122print(json.dumps(res))
119123` ;
120124
121125 const fullCode = [ pythonScript , mainCallCode ] . filter ( Boolean ) . join ( '\n' ) ;
122-
123- const pythonProcess = spawn ( 'python3' , [ '-u' , '-c' , fullCode ] ) ;
126+ const { path : tempFilePath , cleanup } = await createTempFile ( tempDir , fullCode ) ;
127+ const pythonProcess = spawn ( 'python3' , [ '-u' , tempFilePath ] ) ;
124128
125129 const stdoutChunks : string [ ] = [ ] ;
126130 const stderrChunks : string [ ] = [ ] ;
@@ -137,7 +141,9 @@ print(json.dumps(res))
137141 }
138142 } ) ;
139143 } ) ;
140- const stdout = await stdoutPromise ;
144+ const stdout = await stdoutPromise . finally ( ( ) => {
145+ cleanup ( ) ;
146+ } ) ;
141147
142148 try {
143149 const parsedOutput = JSON . parse ( stdout ) ;
@@ -146,11 +152,35 @@ print(json.dumps(res))
146152 }
147153 return { codeReturn : parsedOutput , log : '' } ;
148154 } catch ( err ) {
149- if ( stdout . includes ( 'malformed node or string on line 1' ) ) {
155+ if (
156+ stdout . includes ( 'malformed node or string on line 1' ) ||
157+ stdout . includes ( 'invalid syntax (<unknown>, line 1)' )
158+ ) {
150159 return Promise . reject ( `The result should be a parsable variable, such as a list. ${ stdout } ` ) ;
151160 } else if ( stdout . includes ( 'Unexpected end of JSON input' ) ) {
152161 return Promise . reject ( `Not allowed print or ${ stdout } ` ) ;
153162 }
154163 return Promise . reject ( `Run failed: ${ err } ` ) ;
155164 }
156165} ;
166+
167+ // write full code into a tmp file
168+ async function createTempFile ( tempFileDirPath : string , context : string ) {
169+ const tempFilePath = join ( tempFileDirPath , PythonScriptFileName ) ;
170+
171+ try {
172+ await writeFile ( tempFilePath , context ) ;
173+ return {
174+ path : tempFilePath ,
175+ cleanup : ( ) => {
176+ rmSync ( tempFilePath ) ;
177+ rmSync ( tempFileDirPath , {
178+ recursive : true ,
179+ force : true
180+ } ) ;
181+ }
182+ } ;
183+ } catch ( err ) {
184+ return Promise . reject ( `write file err: ${ err } ` ) ;
185+ }
186+ }
0 commit comments