File manager - Edit - /var/www/payraty/helpdesk/vendor/itsgoingd/clockwork/Clockwork/Storage/RedisStorage.php
Back
<?php namespace Clockwork\Storage; use Clockwork\Request\Request; use Redis; use RedisCluster; class RedisStorage extends Storage { // List of Request keys that need to be serialized before they can be stored in database protected $needsSerialization = [ 'headers', 'getData', 'postData', 'requestData', 'sessionData', 'authenticatedUser', 'cookies', 'middleware', 'databaseQueries', 'cacheQueries', 'modelsActions', 'modelsRetrieved', 'modelsCreated', 'modelsUpdated', 'modelsDeleted', 'redisCommands', 'queueJobs', 'timelineData', 'log', 'events', 'routes', 'notifications', 'emailsData', 'viewsData', 'userData', 'subrequests', 'xdebug', 'commandArguments', 'commandArgumentsDefaults', 'commandOptions', 'commandOptionsDefaults', 'jobPayload', 'jobOptions', 'testAsserts', 'parent', 'clientMetrics', 'webVitals' ]; // Redis client instance protected $redis; // Metadata expiration time in minutes protected $expiration; // Metedata keys prefix protected $prefix; public function __construct($connection, $expiration = null, $prefix = 'clockwork') { $this->redis = is_array($connection) ? $this->createClient($connection) : $connection; $this->prefix = $this->isCluster($connection) ? "{{$prefix}}" : $prefix; $this->expiration = $expiration === null ? 60 * 24 * 7 : $expiration; } protected function isCluster($connection) { return $connection instanceof RedisCluster || is_array($connection) && isset($connection[0]) && is_array($connection[0]); } protected function createClient($connection) { return $this->isCluster($connection) ? $this->createRedisClusterClient($connection) : $this->createRedisClient($connection); } protected function createRedisClient($connection) { $redis = new Redis(); $redis->connect($connection['host'], $connection['port']); $redis->auth(array_filter([ 'user' => isset($connection['username']) ? $connection['username'] : null, 'pass' => isset($connection['password']) ? $connection['password'] : null ])); $redis->select($connection['database']); return $redis; } protected function createRedisClusterClient($connection) { return new RedisCluster(null, array_map(function ($hostConfig) { $host = "{$hostConfig['host']}:{$hostConfig['port']}"; $query = array_filter([ 'database' => $hostConfig['database'], 'password' => $hostConfig['password'] ]); if (count($query) > 0) { $host .= '?' . http_build_query($query, '', '&', PHP_QUERY_RFC3986); } return $host; }, $connection)); } // Returns all requests public function all(Search $search = null) { if ($search->isNotEmpty()) { return $this->search($search); } return $this->loadRequests($this->redis->zRange($this->prefix('requests'), 0, -1)); } // Return a single request by id public function find($id) { return $this->loadRequest($id); } // Return the latest request public function latest(Search $search = null) { if ($search->isNotEmpty()) { return $this->search('previous', $search, -1, 1); } $requests = $this->loadRequests($this->redis->zRange($this->prefix('requests'), -1, -1)); return reset($requests); } // Return requests received before specified id, optionally limited to specified count public function previous($id, $count = null, Search $search = null) { $requestIndex = $this->redis->zRank($this->prefix('requests'), $id) - 1; if ($requestIndex < 0) return []; if ($search->isNotEmpty()) { return $this->search('previous', $search, $requestIndex, $count); } $startIndex = $count === null ? 0 : max($requestIndex - $count, 0); return $this->loadRequests($this->redis->zRange($this->prefix('requests'), $startIndex, $requestIndex)); } // Return requests received after specified id, optionally limited to specified count public function next($id, $count = null, Search $search = null) { $requestIndex = $this->redis->zRank($this->prefix('requests'), $id); $indexLength = $this->redis->zCard($this->prefix('requests')); if ($requestIndex + 1 == $indexLength) return []; if ($search->isNotEmpty()) { return $this->search('next', $search, $requestIndex + 1, $count); } $endIndex = $count === null ? -1 : min($requestIndex + $count, $indexLength); return $this->loadRequests($this->redis->zRange($this->prefix('requests'), $requestIndex + 1, $endIndex)); } // Store request public function store(Request $request) { $data = $request->toArray(); foreach ($this->needsSerialization as $key) { $data[$key] = @json_encode($data[$key], \JSON_PARTIAL_OUTPUT_ON_ERROR); } $this->redis->multi(); $this->redis->zAdd($this->prefix('requests'), $data['time'], $data['id']); $this->redis->hMSet($this->prefix($data['id']), $data); if ($this->expiration) $this->redis->expire($this->prefix($data['id']), $this->expiration * 60); $this->redis->exec(); $this->cleanup(); } // Update existing request public function update(Request $request) { $data = $request->toArray(); foreach ($this->needsSerialization as $key) { $data[$key] = @json_encode($data[$key], \JSON_PARTIAL_OUTPUT_ON_ERROR); } $this->redis->multi(); $this->redis->hMSet($this->prefix($data['id']), $data); if ($this->expiration) $this->redis->expire($this->prefix($data['id']), $this->expiration * 60); $this->redis->exec(); $this->cleanup(); } // Cleanup old requests public function cleanup() { if ($this->expiration === false) return; $this->redis->zRemRangeByScore($this->prefix('requests'), 0, time() - ($this->expiration * 60)); } // Search for requests based on the requests sorted set protected function search($direction, Search $search = null, $requestIndex = null, $count = null) { if ($requestIndex) { $ids = $direction == 'previous' ? $this->redis->zRange($this->prefix('requests'), 0, $requestIndex) : $this->redis->zRange($this->prefix('requests'), $requestIndex, -1); } else { $ids = $this->redis->zRange($this->prefix('requests'), 0, -1); } if ($direction == 'previous') $ids = array_reverse($ids); $keys = array_map(function ($id) { return $this->prefix($id); }, $ids); $args = array_map( function ($value) { return implode(',', $value); }, [ $search->type, $search->uri, $search->name, $search->controller, $search->method, $search->status, $search->time, array_map(function ($value) { return $value[0] . strtotime(substr($value, 1)); }, $search->received) ] ); $results = $this->redis->eval(static::SEARCH_SCRIPT, array_merge($keys, $args, [ $count ]), count($keys)); if ($direction == 'previous') $results = array_reverse($results); return $this->resultsToRequests($results); } // Prefix a key with the configured prefix protected function prefix($key) { return "{$this->prefix}:$key"; } // Load a single request by id from Redis protected function loadRequest($id) { if (! $id) return; return $this->dataToRequest($this->redis->hGetAll($this->prefix($id))); } // Load multiple requests by ids from Redis protected function loadRequests($ids) { return array_filter(array_map(function ($id) { return $this->loadRequest($id); }, $ids)); } // Returns a Request instance from a single Redis record protected function dataToRequest($data) { if (! $data) return; foreach ($this->needsSerialization as $key) { $data[$key] = json_decode($data[$key], true); } return new Request($data); } // Retusna Requests instances from search results protected function resultsToRequests($results) { return array_map(function ($result) { return $this->dataToRequest(array_combine(array_column(array_chunk($result, 2), 0), array_column(array_chunk($result, 2), 1))); }, $results); } const SEARCH_SCRIPT = <<<'SCRIPT' #!lua flags=no-writes local function splitInput(input) if not input then return {} end local result = {} for token in string.gmatch(input, "[^,]+") do table.insert(result, token) end return result end local function mergeArrays(a, b) local merged = {} for _, value in ipairs(a) do table.insert(merged, value) end for _, value in ipairs(b) do table.insert(merged, value) end return merged end local function isEmpty (array) for _, value in ipairs(array) do if value ~= '' then return false end end return true end local function checkStringCondition (request, fields, inputs, exact) if isEmpty(inputs) then return true end for _, field in ipairs(fields) do local value = request[field] for _, input in ipairs(inputs) do if (not exact and string.find(string.lower(value), string.lower(input))) then return true end if (exact and string.lower(value) == string.lower(input)) then return true end end end return false end local function checkNumberCondition (request, fields, inputs) if isEmpty(inputs) then return true end for _, field in ipairs(fields) do local value = tonumber(request[field]) for _, input in ipairs(inputs) do if value == tonumber(input) then return true end local lowerLimit = tonumber(string.match(input, '^>(%d+%.?%d*)$')) if lowerLimit and value > lowerLimit then return true end local upperLimit = tonumber(string.match(input, '^<(%d+%.?%d*)$')) if upperLimit and value < upperLimit then return true end local rangeStart, rangeEnd = string.match(input, '^(%d+%.?%d*)-(%d+%.?%d*)$') if rangeStart and rangeEnd and tonumber(rangeStart) < value and value < tonumber(rangeEnd) then return true end end end return false end local results = {} local input = { type = splitInput(ARGV[1]), uri = splitInput(ARGV[2]), name = splitInput(ARGV[3]), controller = splitInput(ARGV[4]), method = splitInput(ARGV[5]), status = splitInput(ARGV[6]), time = splitInput(ARGV[7]), received = splitInput(ARGV[8]) } local limit = tonumber(ARGV[9]) local requestIds = KEYS for _, requestId in ipairs(requestIds) do local requestData = redis.call('hgetall', requestId) local request = {} for i = 1, #requestData, 2 do request[requestData[i]] = requestData[i + 1] end if ( checkStringCondition(request, {'type'}, input['type']) and checkStringCondition(request, {'uri', 'commandName', 'jobName', 'testName'}, mergeArrays(input['uri'], input['name'])) and checkStringCondition(request, {'controller'}, input['controller']) and checkStringCondition(request, {'method'}, input['method'], true) and checkNumberCondition(request, {'responseStatus', 'commandExitCode', 'jobStatus', 'testStatus'}, input['status']) and checkNumberCondition(request, {'responseDuration'}, input['time']) and checkNumberCondition(request, {'time'}, input['received']) ) then table.insert(results, requestData) end if (limit ~= nil and #results >= limit) then return results end end return results SCRIPT; }
| ver. 1.4 |
Github
|
.
| PHP 8.3.30 | Generation time: 0 |
proxy
|
phpinfo
|
Settings