mirror of
https://gitee.com/infiniflow/ragflow.git
synced 2025-12-06 15:29:03 +08:00
Refa: improve usability of Node.js/JavaScript code executor (#8979)
### What problem does this PR solve? Improve usability of Node.js/JavaScript code executor. ### Type of change - [x] Refactoring --------- Co-authored-by: Kevin Hu <kevinhu.sh@gmail.com> Co-authored-by: writinwaters <93570324+writinwaters@users.noreply.github.com>
This commit is contained in:
@@ -213,6 +213,42 @@ To add Node.js dependencies:
|
||||
|
||||
---
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
### 🐍 A Python example
|
||||
|
||||
```python
|
||||
def main(arg1: str, arg2: str) -> str:
|
||||
return f"result: {arg1 + arg2}"
|
||||
```
|
||||
|
||||
### 🟨 JavaScript examples
|
||||
|
||||
A simple sync function
|
||||
|
||||
```javascript
|
||||
function main({arg1, arg2}) {
|
||||
return arg1+arg2
|
||||
}
|
||||
```
|
||||
|
||||
Async funcion with aioxs
|
||||
|
||||
```javascript
|
||||
const axios = require('axios');
|
||||
async function main() {
|
||||
try {
|
||||
const response = await axios.get('https://github.com/infiniflow/ragflow');
|
||||
return 'Body:' + response.data;
|
||||
} catch (error) {
|
||||
return 'Error:' + error.message;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 FAQ
|
||||
|
||||
### ❓Sandbox Not Working?
|
||||
|
||||
@@ -15,24 +15,29 @@
|
||||
#
|
||||
import base64
|
||||
|
||||
from core.container import _CONTAINER_EXECUTION_SEMAPHORES
|
||||
from core.logger import logger
|
||||
from fastapi import Request
|
||||
from models.enums import ResultStatus
|
||||
from models.enums import ResultStatus, SupportLanguage
|
||||
from models.schemas import CodeExecutionRequest, CodeExecutionResult
|
||||
from services.execution import execute_code
|
||||
from services.limiter import limiter
|
||||
from services.security import analyze_code_security
|
||||
from core.container import _CONTAINER_EXECUTION_SEMAPHORES
|
||||
|
||||
|
||||
async def healthz_handler():
|
||||
return {"status": "ok"}
|
||||
|
||||
|
||||
@limiter.limit("5/second")
|
||||
async def run_code_handler(req: CodeExecutionRequest, request: Request):
|
||||
logger.info("🟢 Received /run request")
|
||||
|
||||
async with _CONTAINER_EXECUTION_SEMAPHORES[req.language]:
|
||||
code = base64.b64decode(req.code_b64).decode("utf-8")
|
||||
if req.language == SupportLanguage.NODEJS:
|
||||
code += "\n\nmodule.exports = { main };"
|
||||
req.code_b64 = base64.b64encode(code.encode("utf-8")).decode("utf-8")
|
||||
is_safe, issues = analyze_code_security(code, language=req.language)
|
||||
if not is_safe:
|
||||
issue_details = "\n".join([f"Line {lineno}: {issue}" for issue, lineno in issues])
|
||||
|
||||
@@ -21,3 +21,4 @@ router = APIRouter()
|
||||
|
||||
router.get("/healthz")(healthz_handler)
|
||||
router.post("/run")(run_code_handler)
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ from core.logger import logger
|
||||
|
||||
_CONTAINER_QUEUES: dict[SupportLanguage, Queue] = {}
|
||||
_CONTAINER_LOCK: asyncio.Lock = asyncio.Lock()
|
||||
_CONTAINER_EXECUTION_SEMAPHORES:dict[SupportLanguage,asyncio.Semaphore] = {}
|
||||
_CONTAINER_EXECUTION_SEMAPHORES: dict[SupportLanguage, asyncio.Semaphore] = {}
|
||||
|
||||
|
||||
async def init_containers(size: int) -> tuple[int, int]:
|
||||
|
||||
@@ -82,20 +82,40 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const args = JSON.parse(process.argv[2]);
|
||||
|
||||
const mainPath = path.join(__dirname, 'main.js');
|
||||
|
||||
function isPromise(value) {
|
||||
return Boolean(value && typeof value.then === 'function');
|
||||
}
|
||||
|
||||
if (fs.existsSync(mainPath)) {
|
||||
const { main } = require(mainPath);
|
||||
const mod = require(mainPath);
|
||||
const main = typeof mod === 'function' ? mod : mod.main;
|
||||
|
||||
if (typeof main !== 'function') {
|
||||
console.error('Error: main is not a function');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (typeof args === 'object' && args !== null) {
|
||||
main(args).then(result => {
|
||||
try {
|
||||
const result = main(args);
|
||||
if (isPromise(result)) {
|
||||
result.then(output => {
|
||||
if (output !== null) {
|
||||
console.log(output);
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('Error in async main function:', err);
|
||||
});
|
||||
} else {
|
||||
if (result !== null) {
|
||||
console.log(result);
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('Error in main function:', err);
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error when executing main:', err);
|
||||
}
|
||||
} else {
|
||||
console.error('Error: args is not a valid object:', args);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user