mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +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
|
## 📋 FAQ
|
||||||
|
|
||||||
### ❓Sandbox Not Working?
|
### ❓Sandbox Not Working?
|
||||||
|
|||||||
@ -15,24 +15,29 @@
|
|||||||
#
|
#
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
|
from core.container import _CONTAINER_EXECUTION_SEMAPHORES
|
||||||
from core.logger import logger
|
from core.logger import logger
|
||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
from models.enums import ResultStatus
|
from models.enums import ResultStatus, SupportLanguage
|
||||||
from models.schemas import CodeExecutionRequest, CodeExecutionResult
|
from models.schemas import CodeExecutionRequest, CodeExecutionResult
|
||||||
from services.execution import execute_code
|
from services.execution import execute_code
|
||||||
from services.limiter import limiter
|
from services.limiter import limiter
|
||||||
from services.security import analyze_code_security
|
from services.security import analyze_code_security
|
||||||
from core.container import _CONTAINER_EXECUTION_SEMAPHORES
|
|
||||||
|
|
||||||
async def healthz_handler():
|
async def healthz_handler():
|
||||||
return {"status": "ok"}
|
return {"status": "ok"}
|
||||||
|
|
||||||
|
|
||||||
@limiter.limit("5/second")
|
@limiter.limit("5/second")
|
||||||
async def run_code_handler(req: CodeExecutionRequest, request: Request):
|
async def run_code_handler(req: CodeExecutionRequest, request: Request):
|
||||||
logger.info("🟢 Received /run request")
|
logger.info("🟢 Received /run request")
|
||||||
|
|
||||||
async with _CONTAINER_EXECUTION_SEMAPHORES[req.language]:
|
async with _CONTAINER_EXECUTION_SEMAPHORES[req.language]:
|
||||||
code = base64.b64decode(req.code_b64).decode("utf-8")
|
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)
|
is_safe, issues = analyze_code_security(code, language=req.language)
|
||||||
if not is_safe:
|
if not is_safe:
|
||||||
issue_details = "\n".join([f"Line {lineno}: {issue}" for issue, lineno in issues])
|
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.get("/healthz")(healthz_handler)
|
||||||
router.post("/run")(run_code_handler)
|
router.post("/run")(run_code_handler)
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@ from core.logger import logger
|
|||||||
|
|
||||||
_CONTAINER_QUEUES: dict[SupportLanguage, Queue] = {}
|
_CONTAINER_QUEUES: dict[SupportLanguage, Queue] = {}
|
||||||
_CONTAINER_LOCK: asyncio.Lock = asyncio.Lock()
|
_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]:
|
async def init_containers(size: int) -> tuple[int, int]:
|
||||||
|
|||||||
@ -82,20 +82,40 @@ const fs = require('fs');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const args = JSON.parse(process.argv[2]);
|
const args = JSON.parse(process.argv[2]);
|
||||||
|
|
||||||
const mainPath = path.join(__dirname, 'main.js');
|
const mainPath = path.join(__dirname, 'main.js');
|
||||||
|
|
||||||
|
function isPromise(value) {
|
||||||
|
return Boolean(value && typeof value.then === 'function');
|
||||||
|
}
|
||||||
|
|
||||||
if (fs.existsSync(mainPath)) {
|
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) {
|
if (typeof args === 'object' && args !== null) {
|
||||||
main(args).then(result => {
|
try {
|
||||||
if (result !== null) {
|
const result = main(args);
|
||||||
console.log(result);
|
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 => {
|
} catch (err) {
|
||||||
console.error('Error in main function:', err);
|
console.error('Error when executing main:', err);
|
||||||
});
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error('Error: args is not a valid object:', args);
|
console.error('Error: args is not a valid object:', args);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user