Compare commits

...

6 Commits

Author SHA1 Message Date
root
0dbba014d8 Merge branch 'master' of https://git.fredericofalcao.com/git/ContinuousIntegrationScript 2025-06-19 14:28:49 +01:00
root
854e8d3e2e Merge branch 'master' of https://git.fredericofalcao.com/git/ContinuousIntegrationScript 2025-06-19 14:05:04 +01:00
root
3c169713cd fixed bug. 2025-06-12 11:34:04 +01:00
FredericoFalcao
6c2fbcfae5
Merge pull request #6 from FredericoFalcao/codex/add-javascript-support-with-npm
Add Node.js support
2025-06-12 13:30:19 +03:00
FredericoFalcao
8df222616d docs: remove duplicate JavaScript version entry 2025-06-12 12:26:17 +03:00
FredericoFalcao
ae0cfb98a6
v0.2 - release version 2025-06-12 11:49:40 +03:00
10 changed files with 200 additions and 19 deletions

4
.gitignore vendored
View File

@ -11,3 +11,7 @@ test_code.php
modules/ modules/
requirements.txt requirements.txt
package.json
package-lock.json
npm.sync
node_modules/

View File

@ -5,6 +5,8 @@ do
killall DbContinuousIntegrationWrapper.sh killall DbContinuousIntegrationWrapper.sh
/usr/bin/php composer.json.php > composer.json /usr/bin/php composer.json.php > composer.json
touch -t $(/usr/bin/mysql -se "SELECT DATE_FORMAT(LastUpdated, '%Y%m%d%H%i.%s') FROM SYS_PRD_BND.Composer ORDER BY LastUpdated DESC LIMIT 1") composer.json touch -t $(/usr/bin/mysql -se "SELECT DATE_FORMAT(LastUpdated, '%Y%m%d%H%i.%s') FROM SYS_PRD_BND.Composer ORDER BY LastUpdated DESC LIMIT 1") composer.json
/usr/bin/php package.json.php > package.json
touch -t $(/usr/bin/mysql -se "SELECT DATE_FORMAT(LastUpdated, '%Y%m%d%H%i.%s') FROM SYS_PRD_BND.Npm ORDER BY LastUpdated DESC LIMIT 1") package.json
make make
/usr/bin/php DbContinuousIntegration.php /usr/bin/php DbContinuousIntegration.php
sleep 10 sleep 10

View File

@ -1,12 +1,18 @@
#!/bin/bash #!/bin/bash
all: composer.sync requirements.sync npm.sync
composer.sync: composer.json composer.sync: composer.json
COMPOSER_ALLOW_SUPERUSER=1 composer update > $@ 2>&1 COMPOSER_ALLOW_SUPERUSER=1 composer update > $@ 2>&1
requirements.sync: requirements.txt requirements.sync: requirements.txt
pip install -r requirements.txt $@ pip install -r requirements.txt > $@ 2>&1
npm.sync: package.json
npm install > $@ 2>&1
install: install:
echo "Add this line to crontab -e" @echo "Add this line to crontab -e"
echo '@reboot /bin/bash /root/DbContinuousIntegration/DbContinuousIntegrationWrapper.sh 2> /dev/null > /dev/null &' @echo '@reboot /bin/bash /root/DbContinuousIntegration/DbContinuousIntegrationWrapper.sh 2> /dev/null > /dev/null &'
echo @echo
echo 'CREATE TABLE SYS_PRD_BND.Tables (Name, onUpdate_phpCode, onUpdate_pyCode, LastUpdated);' | sudo mysql @echo 'CREATE TABLE SYS_PRD_BND.Tables (Name, onUpdate_phpCode, onUpdate_pyCode, onUpdate_jsCode, LastUpdated);' | sudo mysql

View File

@ -4,11 +4,13 @@
### TO BE: ### TO BE:
v0.3 - has an "export" and "import" module that converts sql data into a "git repo" / folder with code v0.4 - has an "export" and "import" module that converts sql data into a "git repo" / folder with code
v0.2 - has a function called "sql_read_hidrate()" that gives the foreign keys hidrated
- (useful for trigger functions like telegram outbox that need data like recipients hidrated)
## AS IS: ## AS IS:
v0.3 - supports Javascript / ECMA Script, and npm package manager
v0.2 - has a function called "sql_read_hidrate()" that gives the foreign keys hidrated
- (useful for trigger functions like telegram outbox that need data like recipients hidrated)
v0.1 - works. v0.1 - works.

View File

@ -0,0 +1,8 @@
USE SYS_PRD_BND;
CREATE TABLE `Npm` (
`PackageName` varchar(255) NOT NULL,
`AliasName` varchar(255) DEFAULT NULL,
`VersionOrTag` varchar(25) DEFAULT NULL,
`LastUpdated` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
PRIMARY KEY (`PackageName`)
);

View File

@ -3,6 +3,7 @@ CREATE TABLE `Tables` (
`Name` varchar(255) NOT NULL, `Name` varchar(255) NOT NULL,
`onUpdate_phpCode` text DEFAULT NULL, `onUpdate_phpCode` text DEFAULT NULL,
`onUpdate_pyCode` text DEFAULT NULL, `onUpdate_pyCode` text DEFAULT NULL,
`onUpdate_jsCode` text DEFAULT NULL,
`LastError` text DEFAULT NULL, `LastError` text DEFAULT NULL,
`LastUpdated` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), `LastUpdated` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
PRIMARY KEY (`Name`) PRIMARY KEY (`Name`)

29
package.json.php Normal file
View File

@ -0,0 +1,29 @@
<?php
$dsn = "mysql:unix_socket=/var/run/mysqld/mysqld.sock;dbname=SYS_PRD_BND;charset=utf8mb4";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];
try {
$pdo = new PDO($dsn, "root", "", $options);
$stmt = $pdo->query("SELECT PackageName, VersionOrTag FROM Npm ORDER BY PackageName");
$dependencies = [];
foreach ($stmt as $row) {
$ver = $row['VersionOrTag'];
$dependencies[$row['PackageName']] = $ver ?: '*';
}
$packageJson = [
'type' => 'module',
'dependencies' => (object)$dependencies,
];
file_put_contents('php://stdout', json_encode($packageJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
file_put_contents('php://stderr', "✅ package.json generated successfully.\n");
} catch (PDOException $e) {
file_put_contents('php://stderr', "❌ Database error: " . $e->getMessage() . "\n");
}

View File

@ -0,0 +1,32 @@
<?php
/**
* Generates JavaScript code for sandbox execution based on provided trigger code and row data.
*
* @param string $functionName The name of the JavaScript function to generate.
* @param string $jsCode The JavaScript code to embed within the generated function.
* @param array $row The row data to pass to the generated function.
*
* @return string The complete JavaScript code ready for sandbox execution.
*/
function generateJSTriggerCode($functionName, $jsCode, $row) {
$constants = getJSConstantsDefinition();
$supportFunctions = getJavascriptSupportFunctionsDefinition();
$requires = getNodeRequires();
$rowJson = json_encode($row, JSON_UNESCAPED_SLASHES);
$indentedCode = implode("\n", array_map(fn($l) => ' ' . $l, explode("\n", $jsCode)));
$javascript = <<<JS
$requires
$constants
$supportFunctions
function $functionName(data, error) {
$indentedCode
}
let data = $rowJson;
let error = null;
$functionName(data, error);
console.log(JSON.stringify(data));
JS;
return $javascript;
}

View File

@ -6,7 +6,7 @@
* Overview: * Overview:
* This PHP script automates database updates by processing rows marked for action in various tables. * This PHP script automates database updates by processing rows marked for action in various tables.
* It dynamically executes predefined functions based on table-specific instructions stored in the database. * It dynamically executes predefined functions based on table-specific instructions stored in the database.
* Functions are executed in either PHP or Python environments depending on configuration. * Functions are executed in PHP, Python, or JavaScript environments depending on configuration.
* *
* How It Works: * How It Works:
* 1. The script queries the `SYS_PRD_BND.Tables` table to determine which tables require processing. * 1. The script queries the `SYS_PRD_BND.Tables` table to determine which tables require processing.
@ -19,8 +19,8 @@
* *
* Tables and Their Purpose: * Tables and Their Purpose:
* - SYS_PRD_BND.Tables: * - SYS_PRD_BND.Tables:
* Defines active tables and their respective PHP or Python trigger codes. * Defines active tables and their respective PHP, Python, or JavaScript trigger codes.
* Columns: Name, onUpdate_phpCode, onUpdate_pyCode, LastUpdated, LastError * Columns: Name, onUpdate_phpCode, onUpdate_pyCode, onUpdate_jsCode, LastUpdated, LastError
* *
* - SYS_PRD_BND.Constants: * - SYS_PRD_BND.Constants:
* Holds constants that are injected into the PHP environment during execution. * Holds constants that are injected into the PHP environment during execution.
@ -34,6 +34,10 @@
* Lists external Python libraries imported into Python trigger execution. * Lists external Python libraries imported into Python trigger execution.
* Columns: LibName, AliasName * Columns: LibName, AliasName
* *
* - SYS_PRD_BND.Npm:
* Lists external Node modules imported into JavaScript trigger execution.
* Columns: PackageName, AliasName, VersionOrTag
*
* Dynamic Tables: * Dynamic Tables:
* - Application-specific tables, each must include at least: * - Application-specific tables, each must include at least:
* - LastUpdated (timestamp for tracking) * - LastUpdated (timestamp for tracking)
@ -68,7 +72,7 @@ foreach(scandir(__DIR__) as $filename) if (substr($filename,-8) == ".inc.php") r
*/ */
function processAllTheActiveTables() { function processAllTheActiveTables() {
echo "Scanning all the tables that need updating...\n"; echo "Scanning all the tables that need updating...\n";
$activeTables = sql("SELECT Name, onUpdate_phpCode, onUpdate_pyCode, LastUpdated FROM SYS_PRD_BND.Tables"); $activeTables = sql("SELECT Name, onUpdate_phpCode, onUpdate_pyCode, onUpdate_jsCode, LastUpdated FROM SYS_PRD_BND.Tables");
foreach ($activeTables as $activeTable) { foreach ($activeTables as $activeTable) {
processActiveTable($activeTable); processActiveTable($activeTable);
@ -118,6 +122,10 @@ function processTableRow($activeTable, $unprocessedRow) {
if (!empty($activeTable['onUpdate_pyCode'])) { if (!empty($activeTable['onUpdate_pyCode'])) {
runPythonCodeTrigger($functionName, $activeTable, $unprocessedRow); runPythonCodeTrigger($functionName, $activeTable, $unprocessedRow);
} }
if (!empty($activeTable['onUpdate_jsCode'])) {
runJavascriptCodeTrigger($functionName, $activeTable, $unprocessedRow);
}
} }
/** /**
@ -156,6 +164,17 @@ function runPythonCodeTrigger($functionName, $activeTable, $row) {
handleTriggerExecutionResult($result, $stdout, $stderr, $row, $activeTable); handleTriggerExecutionResult($result, $stdout, $stderr, $row, $activeTable);
} }
/**
* Executes database-level dynamic JavaScript trigger code.
*/
function runJavascriptCodeTrigger($functionName, $activeTable, $row) {
echo "Running JavaScript Code trigger...\n";
$jsCode = generateJSTriggerCode($functionName, $activeTable['onUpdate_jsCode'], $row);
$result = runSandboxedJavascript($jsCode, $stdout, $stderr);
handleTriggerExecutionResult($result, $stdout, $stderr, $row, $activeTable);
}
/** /**
* Helper functions implementations. * Helper functions implementations.
*/ */
@ -216,6 +235,43 @@ function getPythonImports() {
} }
return $imports; return $imports;
} }
function getNodeRequires() {
$requires = "";
foreach (sql("SELECT PackageName, AliasName FROM SYS_PRD_BND.Npm") as $module) {
$alias = !empty($module['AliasName']) ? $module['AliasName'] : basename($module['PackageName']);
$alias = preg_replace('/[^A-Za-z0-9_]/', '_', $alias);
$requires .= "const $alias = require('{$module['PackageName']}');\n";
}
return $requires;
}
function getJSConstantsDefinition() {
$constants = "";
foreach (sql("SELECT Name, Type, Value FROM SYS_PRD_BND.Constants") as $const) {
switch ($const['Type']) {
case 'String':
$val = '`' . str_replace('`', '\\`', $const['Value']) . '`';
break;
case 'Json':
$val = json_encode(json_decode($const['Value'], true));
break;
default:
$val = $const['Value'];
}
$constants .= "const {$const['Name']} = {$val};\n";
}
return $constants;
}
function getJavascriptSupportFunctionsDefinition() {
$functions = "";
foreach (sql("SELECT Name, InputArgs_json, JavascriptCode FROM SYS_PRD_BND.SupportFunctions WHERE JavascriptCode IS NOT NULL") as $f) {
$args = implode(', ', array_keys(json_decode($f['InputArgs_json'], true)));
$functions .= "function {$f['Name']}($args) {\n{$f['JavascriptCode']}\n}\n";
}
return $functions;
}
function greenText($string) { $green = "\033[0;32m"; $reset = "\033[0m"; return $green . $string . $reset ; } function greenText($string) { $green = "\033[0;32m"; $reset = "\033[0m"; return $green . $string . $reset ; }
function blueText($string) { $green = "\033[0;34m"; $reset = "\033[0m"; return $green . $string . $reset ; } function blueText($string) { $green = "\033[0;34m"; $reset = "\033[0m"; return $green . $string . $reset ; }
function redText($string) { $green = "\033[0;31m"; $reset = "\033[0m"; return $green . $string . $reset ; } function redText($string) { $green = "\033[0;31m"; $reset = "\033[0m"; return $green . $string . $reset ; }

View File

@ -0,0 +1,41 @@
<?php
/**
* Runs dynamically generated JavaScript code in a sandboxed environment using Node.js.
*
* @param string $code The JavaScript code to execute.
* @param string &$stdout Captured standard output from the execution.
* @param string &$stderr Captured standard error from the execution.
*
* @return int Exit code of the executed script (0 means success).
*/
function runSandboxedJavascript($code, &$stdout = null, &$stderr = null) {
$tempFile = tempnam(sys_get_temp_dir(), 'sandboxed_') . '.js';
file_put_contents($tempFile, $code);
$command = "/usr/bin/node " . escapeshellarg($tempFile);
$descriptorspec = [
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
];
$process = proc_open($command, $descriptorspec, $pipes);
if (!is_resource($process)) {
unlink($tempFile);
throw new Exception('Failed to execute sandboxed JavaScript code.');
}
$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
$exitCode = proc_close($process);
unlink($tempFile);
return $exitCode;
}