Archive: Namaste PHP AMQP framework v1.0 (2017-2020)

952 days continuous production uptime, 40k+ tp/s single node.
Original corpo Bitbucket history not included — clean archive commit.
This commit is contained in:
2026-04-05 09:49:30 -07:00
commit 373ebc8c93
1284 changed files with 409372 additions and 0 deletions

653
classes/gasStatic.class.inc Normal file
View File

@@ -0,0 +1,653 @@
<?php
/**
* This is the gasStatic class which is a collection of one-off functions that can be called from a broker or any
* instantiation class -- code herein is class-agnostic and storing one-off's here reduces the overhead of a full
* class instantiation to accomplish the same functionality.
*
* @author mike@givingassistant.org
* @version 1.0
*
* HISTORY:
* ========
* 06-09-17 mks original coding
* 08-28-17 mks CORE-494: removed buildMappedDataArray() -- method lives in the gasCache class
* 03-02-18 mks CORE-680: deprecated trace logging
* 07-30-18 mks CORE-774: PHP7.2 Exception handling
*
*/
class gasStatic
{
private static ?gasStatic $instance = null; // used to determine if already instantiated
private static string $res = 'STTK: '; // logging resource id
public static bool $debug; // debug state for diagnostic output
public static bool $available = false; // instantiation-check
private static ?array $errors; // local error stack
private static string $class; // name of the current class
private static ?gacErrorLogger $logger = null;
/**
* __construct() -- private function
*
* this is the constructor function for this singleton class. the constructor sets the class's member variables
* and calls any cache pre-loading that's required.
*
* Note that the public entry point is via the getInstance() method.
*
* @author mike@givingassistant.org
* @version 1.0
*
*
* HISTORY:
* ========
* 06-09-17 mks original coding
* 07-30-18 mks CORE-774: PHP7.2 Exception handling
*
*/
private function __construct()
{
global $eos;
static::$errors = null;
try {
static::$logger = new gacErrorLogger();
} catch (TypeError $t) {
echo getDateTime() . CON_ERROR . static::$res . $t->getMessage() . $eos;
static::$errors[] = $t->getMessage();
}
static::$class = __CLASS__;
static::$debug = (isset(gasConfig::$settings[STRING_DEBUG])) ? gasConfig::$settings[STRING_DEBUG] : false;
}
/**
* singleton() -- public static class
*
* method to instantiate the resourceManager singleton class
*
* note:
* -----
* it's the calling client's responsibility to check for the null return value in the member variable $instance.
*
* @author mike@givingassistant.org
* @version 1.0
*
* @return null
*
* HISTORY:
* ========
* 06-09-17 mks original coding
*
*/
public static function singleton()
{
if (static::$instance === null) {
$c = __CLASS__;
static::$instance = new $c();
}
return(static::$instance);
}
/**
* getInstance() -- public static method
*
* this is the singleton constructor entry point for the class. returns a resource pointer to the static or
* a null value if the instantiation failed.
*
* USAGE:
* ------
* $resourcePointer = pgsStatic::getInstance();
*
* @author mike@givingassistant.org
* @version 1.0
*
* @return mixed
*
* HISTORY:
* ========
* 06-09-17 mks original coding
*
*/
public static function getInstance()
{
if (static::$instance === null) {
$c = __CLASS__;
static::$instance = new $c();
}
return (static::$instance);
}
/**
* doingTime() -- public static method
*
* public static method that creates a timer (micro-time) value.
*
* _start is the input parameter (defaults to Boolean(false)) -- if this value is false, then the method will
* immediately return a generated timer value to the client.
*
* if _start is provided, then get a second timer value and derive the difference between the current and the
* start-time returning the total time calculated.
*
* USAGE:
* ------
* pgsStatic::getInstance()->doingTime($startValue);
*
* @author mike@givingassistant.org
* @version 1.0
*
* @param integer $_start
* @return float|int
*
* HISTORY:
* ========
* 06-09-17 mks original coding
*
*/
public static function doingTime(int $_start = 0)
{
if ($_start == 0) {
return (time() + microtime(true));
}
$end = time() + microtime(true);
return (round(floatval($end - floatval($_start)), NUMBER_FP_PRECISION));
}
/**
* publishSystemEvent() -- public method
*
* This method is invoked when we want to publish a system event to the (remote) admin service. The method requires
* a single input parameter: the data ball in array format which represents one, or more, broker event records.
*
* The method is responsible for ensuring the data ball is in the correct format (an array of records), and for
* building the payload that's published to the admin service.
*
* The method returns a false on processing error, or if the packet fails to send. A true return means that the
* payload was successfully submitted to the (remote) service. It does not indicate that the record was
* successfully processed and inserted into the collection as that part of the process is black-boxed behind RMQ.
*
* @author mike@givingassistant.org
* @version 1.0
*
* @param array $_data the record to be published remotely
* @param array $_meta the meta data for the sysEvent record to be published
* @param string $_og the original event guid
* @param array|null $_es call-by-reference parameter to contain the error stack
* @return bool
*
* HISTORY:
* ========
* 08-17-17 mks CORE-500: original coding
* 08-13-20 mks DB-168: method renamed, meta added to params, refactored, and moved to gasStatic class
*
*/
public static function publishSystemEvent(array $_data, array $_meta, string $_og = '', ?array $_es = null): bool
{
$bc = null;
// validate that the $_data payload is not empty
if (empty($_data)) {
$msg = ERROR_DATA_ARRAY_EMPTY . COLON . STRING_DATA;
$_es[] = $msg;
return false;
}
if (empty($_meta)) {
$msg = ERROR_DATA_ARRAY_EMPTY . COLON . STRING_META;
$_es[] = $msg;
return false;
}
// validate that we're getting an array of records ($_data[0] = record1, etc.)
if (key($_data) !== 0) {
$msg = ERROR_DATA_ARRAY_NOT_ARRAY . STRING_DATA;
$_es[] = $msg;
return false;
}
try {
// instantiate an AI broker client
$bc = static::fetchAIClient($_es);
if (is_null($bc)) return false;
if (!empty($_og) and validateGUID($_og)) $_meta[META_EVENT_GUID] = $_og;
$request = [
BROKER_REQUEST => BROKER_REQUEST_ADMIN_BROKER_EVENT,
BROKER_DATA => $_data,
BROKER_META_DATA => $_meta
];
$response = $bc->call(gzcompress(json_encode($request))); // rpc queue
if (is_object($bc)) $bc->__destruct();
unset($bc);
return ($response);
} catch (Throwable $t) {
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
@handleExceptionMessaging($hdr, $t->getMessage(), $_es);
if (is_object($bc)) $bc->__destruct();
unset($bc);
return false;
}
}
/**
* fetchAIClient() -- private method
*
* This method instantiates a new AdminIN broker client and assigns the object to the $aiClient property.
*
* The method checks to see if there's already an object attached before instantiating a new one.
*
* The method returns a BOOL value that indicates if the instantiation was successful or not.
*
*
* @param array|null $_es -- call-by-reference parameter containing the method's error stack output
* @return null|gacWorkQueueClient
*
* HISTORY:
* ========
* 08-17-17 mks CORE-500: original coding
* 09-10-20 mks DB-168: improved error handling, moved to static class, changed return type to obj
*
*@author mike@givingassistant.org
* @version 1.0
*
*/
private static function fetchAIClient(?array &$_es):?gacWorkQueueClient
{
$bc = null;
$foo = null;
$method = basename(__METHOD__);
try {
$bc = new gacWorkQueueClient($method . AT . __LINE__);
if (!$bc->status) {
$hdr = sprintf(INFO_LOC, $method, __LINE__);
$msg = ERROR_FAILED_TO_INSTANTIATE . RESOURCE_ADMIN_CLIENT;
$_es[] = $msg;
static::$logger->error($hdr . $msg);
if (is_object($bc)) $bc->__destruct();
unset($bc);
return null;
}
return $bc;
} catch (Throwable | TypeError $t) {
$hdr = sprintf(INFO_LOC, $method, __LINE__);
$_es[] = ERROR_THROWABLE_EXCEPTION;
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
if (is_object($bc)) $bc->__destruct();
unset($bc);
return null;
}
}
/**
* createATJob() -- public static method
*
* this is a private method providing a single point-of-access to the create-AT-Job function. the method requires
* the following input parameters:
*
* -- duration (in seconds) from "now" when the session will expire
* -- the systemEvent token that will be passed to the PHP script, invoked by AT(1)
* -- $_script - should be one of two values: used the session script for backward compatibility
*
* since this is an internal method, there's no error checking or parameter validation - this method will only
* execute if the admin service is local to the current instance.
*
* the function returns the AT output back to the calling client as a string or a null if the admin service is not
* local to the current instance or if an exception was raised during processing.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* @param int $_duration
* @param string $_sysEvToken
* @param string $_script
* @return null | string
*
* HISTORY:
* ========
* 08-13-20 mks DB-168: original coding
*
*/
public static function createATJob(int $_duration, string $_sysEvToken, string $_script = FILE_EOS):?string
{
if (gasConfig::$settings[ENV_ADMIN][CONFIG_IS_LOCAL]) {
$time = 'now + ' . floor($_duration / NUMBER_SECS_IN_MIN) . ' ' . STRING_SYS_MIN;
$job = '/usr/bin/php -f ' . dirname(__DIR__) . DIR_SCRIPTS . $_script . ' ' . $_sysEvToken;
return (gacATWrapper::cmd($job, $time));
} else {
try {
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
$msg = ERROR_REMOTE_NOT_ADMIN;
static::$logger->warn($hdr . $msg);
consoleLog(static::$res, CON_ERROR, $msg);
} catch (TypeError | Throwable $t) {
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
static::$logger->warn($hdr . $t->getMessage());
consoleLog(static::$res, CON_ERROR, $t->getMessage());
}
return null;
}
}
/**
* convertWebMigrationRequest() -- public static method
*
* This function is called from the migration broker when we receive a migration request from the webUI.
*
* There is one input parameter for this method:
*
* $_data -- the array passed from the broker which contains the event payload data
*
* The method returns an array -- this array will contain a new configuration matrix to temporarily replace
* gasConfig::$settings[CONFIG_MIGRATION].
*
* The method generates a copy of the migration XML data and then over-writes relevant fields with data received
* via the input parameters.
*
* No validation is performed as the web-app (./utilities/migrateData.php) does all the data validation prior
* to publishing the broker event request.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
*
* @param array $_data -- broker event payload data
* @return array -- returns a replacement migration configuration (data validated/tested in web-app!)
*
*
* HISTORY:
* ========
* 09-27-18 mks DB-43: initial coding
*
*/
public static function convertWebMigrationRequest(array $_data): array
{
$rd = null; // return data
$newMigCfg = gasConfig::$settings[CONFIG_MIGRATION]; // start with a copy of the current config
// first, set the schema
$schema = $_data[MIGRATION_SOURCE_SCHEMA];
// next, let's replace the common migration XML components that are required in an override-migration request
$newMigCfg[$schema][STRING_HOST] = $_data[STRING_HOST];
$newMigCfg[$schema][STRING_PORT] = $_data[STRING_PORT];
$newMigCfg[$schema][CONFIG_DATABASE] = $_data[CONFIG_DATABASE];
// next, if the optional components are set, bring them into the new config array
if (isset($_data[STRING_USER])) $newMigCfg[$schema][STRING_USER] = $_data[STRING_USER];
if (isset($_data[STRING_PASS])) $newMigCfg[$schema][STRING_PASS] = $_data[STRING_PASS];
// next, grab the mongo-specific components
if ($schema == CONFIG_SCHEMA_MONGO) {
$newMigCfg[$schema][STRING_AUTH_SRC] = $_data[STRING_AUTH_SRC];
$newMigCfg[$schema][CONFIG_DATABASE_MONGODB_REPLSET_NAME] = $_data[CONFIG_DATABASE_MONGODB_REPLSET_NAME];
$newMigCfg[$schema][CONFIG_DATABASE_MONGODB_REPLSET_DSN] = $_data[CONFIG_DATABASE_MONGODB_REPLSET_DSN];
}
return $newMigCfg;
}
/**
* loadValidTemplateNames() -- private method
*
* this method loads all of the file names that end with an ".inc" extension that currently reside in the
* framework's template directory.
*
* The file names are loaded into the indexed array and returned to the calling client.
*
* If we could not open the template directory, then the value for $validTemplates is set to null - which
* should be tested by the client on return.
*
* Additionally, if the template files could not be loaded, we generate both a diagnostics and a logging
* error message.
*
* There are no inputs to this method. The method returns an array of valid template names it sussed from the
* template directory, on success, or a null on failure.
*
* @author mike@givingassistant.com
* @version 1.0
*
* @return array|null
*
* HISTORY:
* ========
* 06-15-17 mks original coding
* 07-07-17 mks fixed error searching for .inc type files
* 07-30-18 mks CORE-775: PHP7.2 Exception Handling
* 09-13-18 mks DB-43: added option to strip "gat" prepend
* 06-11-20 mks ECI-164: can no longer strip the TLTI prefix from template classes
*
*/
public static function loadValidTemplateNames(): ?array
{
$validTemplates = null;
$tDir = __DIR__ . DIR_TEMPLATE;
if ($fh = opendir($tDir)) {
while (false !== ($file = readdir($fh))) {
if ($file != DOT and $file != DOTDOT and (substr($file, (strlen($file) - strlen(FILE_TYPE_INC))) == FILE_TYPE_INC)) {
$validTemplates[] = preg_replace("/" . FILE_TEMPLATE_EXT . "/", "", $file);
}
}
closedir($fh);
} else {
$msg = ERROR_READ_DIR . $tDir;
static::$logger->warn($msg);
}
return($validTemplates);
}
/**
* getTLTI() -- public static method
*
* This method was moved from gacFactory class to gasStatic class because the factory is not the only place where
* we need to derive a TLTI based on a meta-data payload - this method will also be called from every broker
* class when validating an incoming meta-data payload prior to the gacFactory instantiation.
*
* The method has the following input parameters:
*
* $_authToken -- this is the CLIENT_AUTH_TOKEN as received from the SMAX-request meta-data payload
* $_eventGUID -- as above, except META_EVENT_GUID
* $_payload -- call-by-reference parameter, will implicitly return the broker response payload
*
* We instantiate a read-broker client and, on success, build our query to fetch the TLTI from the SMAXAPI
* data table in appServer. We'll exec the request as a system-level request to bypass redundant validation
* checks speeding up the process.
*
* Next, we publish the request and consume the response -- if the event was successful, then we'll extract
* the tlti from the payload and explicitly return that value.
*
* In all other cases, the function returns a null value to indicate a processing error. It's the responsibility
* of the calling client to process the error which is why we implicitly return the response payload.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* @param string $_authToken
* @param string $_eventGUID
* @param array|null $_payload
* @return string|null
*
*
* HISTORY:
* ========
* 06-15-20 mks ECI-164: original coding as a tweaked-import from the gacFactory class
*
*/
public static function getTLTI(string $_authToken, string $_eventGUID, ?array &$_payload = null):?string
{
// instantiate a read-broker client to fetch the TLTI for the AUTH TOKEN
if (is_null($bc = static::getBC(BROKER_QUEUE_R, sprintf(INFO_LOC, basename(__FILE__), __LINE__)))) return null;
$query = [STRING_KEY => [OPERAND_NULL => [OPERATOR_EQ => [$_authToken]]]];
$request = [
BROKER_REQUEST => BROKER_REQUEST_FETCH,
BROKER_DATA => [
STRING_QUERY_DATA => $query,
STRING_RETURN_DATA => [CM_SMAX_TLTI]
],
BROKER_META_DATA => [
META_CLIENT => CLIENT_SYSTEM,
META_DO_CACHE => false,
META_TEMPLATE => TEMPLATE_CLASS_SMAXAPI,
META_EVENT_GUID => $_eventGUID
]
];
// publish the payload request and consume the Namaste response
$response = json_decode(gzuncompress($bc->call(gzcompress(json_encode($request)))), true);
if (is_object($bc)) $bc->__destruct();
unset($bc);
$_payload = $response;
if ($response[PAYLOAD_STATUS] and $response[PAYLOAD_STATE] != STATE_NOT_FOUND) {
if (isset($response[PAYLOAD_RESULTS][STRING_QUERY_RESULTS][0][SMAX_TLTI])) {
return $response[PAYLOAD_RESULTS][STRING_QUERY_RESULTS][0][SMAX_TLTI] . CHAR_T;
}
}
return null;
}
/**
* getBC() -- private static method
*
* This method was originally in the Factory class but was moved to the static class because of the broker calls
* to validateMetaData also requires deriving the TLTI based on the META_CLIENT setting.
*
* This method fetches a valid broker client connecting to the appServer read broker. Since the instantiation
* is exception wrapped, the call here is not.
*
* The method requires the following two input parameters:
*
* $_queue -- the name of the broker queue to instantiate
* $_loc -- the INFO_LOC string which is passed to rabbit so as to identify where the request originated
*
* The method returns a gacBrokerClient object or, in the case of an error raised during instantiation, a null.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* @param string $_queue
* @param string $_loc
* @return gacBrokerClient|null
*
*
* HISTORY:
* ========
* 06-15-20 mks ECI-164: original coding
*
*/
private static function getBC(string $_queue, string $_loc):?gacBrokerClient
{
$file = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
$bc = new gacBrokerClient($_queue, $_loc);
if (!$bc->status) {
// failed to instantiate a broker client
$hdr = sprintf(INFO_LOC, $file, __LINE__);
$msg = ERROR_BROKER_CLIENT_DECLARE . BROKER_QUEUE_R;
consoleLog(static::$res, CON_SYSTEM, $hdr . $msg);
static::$errors[] = $hdr . $msg;
if (is_object($bc)) $bc->__destruct();
unset($bc);
return null;
}
return $bc;
}
/**
* buildPDODBName() -- public static method
*
* This method requires a single argument to the function:
*
* $_env: should be either ENV_PRIME, ENV_SEGUNDO or any of the other valid env names
*
* The purpose of this function is to generate the database name during run time which is predicated on the
* current running environment and the current namaste service on which this is running.
*
* If an invalid or unsupported env is passed to the method, it will return a null. Otherwise, the method builds
* the db name and returns that to the calling client.
*
* @author mike@givingassistant.org
* @version 1.0
*
* @param string $_env
* @return string|null
*
* HISTORY:
* ========
* 08-20-19 mks DB-
*/
public static function buildPDODBName(string $_env): ?string
{
$dbConfig = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_PDO];
// if more env's are defined to support PDO, you will have to also define them here.
switch ($_env) {
case ENV_APPSERVER :
$namastePDO = $dbConfig[CONFIG_DATABASE_PDO_APPSERVER][CONFIG_DATABASE_PDO_MASTER][CONFIG_DATABASE_PDO_DB];
break;
case ENV_SEGUNDO :
$namastePDO = $dbConfig[CONFIG_DATABASE_PDO_SEGUNDO][CONFIG_DATABASE_PDO_MASTER][CONFIG_DATABASE_PDO_DB];
break;
default :
consoleLog(static::$res, CON_ERROR, sprintf(ERROR_RESOURCE_ENV_404, STRING_PDO, $_env));
return null;
break;
}
return gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV] . UDASH . $namastePDO;
}
/**
* getSysLogError() -- public static method
*
* This method requires one input parameter:
*
* $_error: integer value representing the namaste error
*
* Namaste errors are mapped as follows:
*
* Namaste Error Value Syslog Error
* ---------------------------------------
* DEBUG 2 LOG_DEBUG
* DATA 3 LOG_NOTICE
* INFO 4 LOG_INFO
* ERROR 5 LOG_ERROR
* WARN 6 LOG_CRIT
* FATAL 7 LOG_EMERG
*
* TRACE used to be Value = 1 but has since been deprecated.
* METRICS has a Value of 0.
* EVENT has a value of -1.
*
* We create a simple matrix with the Namaste values as keys and the sysLog values as values and then map the
* input value passed in $_error via the matrix. If not found, then we return a LOG_ERR syslog code. Otherwise,
* return the mapped integer value.
*
*
* @author mike@givingassistant.org
* @version 1.0
*
* @param int $_error
* @return int
*
* HISTORY:
* ========
* 09-26-19 mks DB-136: original coding
*
*/
public static function getSysLogError(int $_error): int
{
$matrix = [
2 => LOG_DEBUG,
3 => LOG_NOTICE,
4 => LOG_INFO,
5 => LOG_ERR,
6 => LOG_CRIT,
7 => LOG_EMERG
];
return (!array_key_exists($_error, $matrix)) ? LOG_ERR : $matrix[$_error];
}
}