Добавлен retry механизм для webservice аутентификации (race condition fix)
This commit is contained in:
@@ -293,13 +293,11 @@ function normalizeInputData($data) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Основная функция для создания документов
|
||||
function createDocumentsInCRM($filesArray, $userName = 'api') {
|
||||
global $adb, $current_user;
|
||||
// Функция для получения сессии webservice с retry
|
||||
function getWebserviceSession($userName, $maxRetries = 3) {
|
||||
global $adb;
|
||||
|
||||
writeLog('🚀 Начинаем создание документов...');
|
||||
|
||||
// 1. Получаем access key пользователя
|
||||
// Получаем access key пользователя
|
||||
$rs = $adb->pquery('SELECT id, accesskey FROM vtiger_users WHERE user_name=?', [$userName]);
|
||||
if (!$rs || $adb->num_rows($rs) == 0) {
|
||||
writeLog("❌ Пользователь $userName не найден");
|
||||
@@ -308,53 +306,93 @@ function createDocumentsInCRM($filesArray, $userName = 'api') {
|
||||
$userId = $adb->query_result($rs, 0, 'id');
|
||||
$accessKey = $adb->query_result($rs, 0, 'accesskey');
|
||||
|
||||
// 2. Получаем challenge token
|
||||
$endpointUrl = 'https://crm.clientright.ru/webservice.php';
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
|
||||
for ($attempt = 1; $attempt <= $maxRetries; $attempt++) {
|
||||
writeLog("🔐 Попытка аутентификации #{$attempt}...");
|
||||
|
||||
// Добавляем случайную задержку для избежания race condition
|
||||
if ($attempt > 1) {
|
||||
$delay = rand(100, 500) * 1000; // 100-500ms в микросекундах
|
||||
usleep($delay);
|
||||
writeLog("⏱️ Задержка " . ($delay / 1000) . "ms перед попыткой #{$attempt}");
|
||||
}
|
||||
|
||||
// getchallenge
|
||||
curl_setopt($ch, CURLOPT_URL, $endpointUrl . '?operation=getchallenge&username=' . urlencode($userName));
|
||||
curl_setopt($ch, CURLOPT_POST, 0);
|
||||
curl_setopt($ch, CURLOPT_HTTPGET, 1);
|
||||
$resp = curl_exec($ch);
|
||||
if ($resp === false) {
|
||||
writeLog('❌ CURL error (challenge): ' . curl_error($ch));
|
||||
continue;
|
||||
}
|
||||
|
||||
$resp = ltrim($resp, "\xEF\xBB\xBF\x00\x09\x0A\x0D\x20");
|
||||
$challenge = json_decode($resp, true);
|
||||
if (!$challenge || empty($challenge['result']['token'])) {
|
||||
writeLog("❌ Invalid challenge response (attempt #{$attempt}): " . substr($resp, 0, 100));
|
||||
continue;
|
||||
}
|
||||
$token = $challenge['result']['token'];
|
||||
|
||||
// login
|
||||
$key = md5($token . $accessKey);
|
||||
curl_setopt($ch, CURLOPT_URL, $endpointUrl);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, [
|
||||
'operation' => 'login',
|
||||
'username' => $userName,
|
||||
'accessKey' => $key,
|
||||
]);
|
||||
$resp = curl_exec($ch);
|
||||
if ($resp === false) {
|
||||
writeLog('❌ CURL error (login): ' . curl_error($ch));
|
||||
continue;
|
||||
}
|
||||
|
||||
$resp = ltrim($resp, "\xEF\xBB\xBF\x00\x09\x0A\x0D\x20");
|
||||
$login = json_decode($resp, true);
|
||||
if (!$login || empty($login['result']['sessionName'])) {
|
||||
writeLog("❌ Login failed (attempt #{$attempt}): " . substr($resp, 0, 100));
|
||||
continue;
|
||||
}
|
||||
|
||||
writeLog("✅ Аутентификация успешна с попытки #{$attempt}");
|
||||
return [
|
||||
'sessionId' => $login['result']['sessionName'],
|
||||
'userId' => $userId,
|
||||
'curl' => $ch
|
||||
];
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
return ['error' => 'Authentication failed after ' . $maxRetries . ' attempts'];
|
||||
}
|
||||
|
||||
// Основная функция для создания документов
|
||||
function createDocumentsInCRM($filesArray, $userName = 'api') {
|
||||
global $adb, $current_user;
|
||||
|
||||
writeLog('🚀 Начинаем создание документов...');
|
||||
|
||||
// Получаем сессию с retry логикой
|
||||
$session = getWebserviceSession($userName);
|
||||
if (isset($session['error'])) {
|
||||
return $session;
|
||||
}
|
||||
|
||||
$sessionId = $session['sessionId'];
|
||||
$userId = $session['userId'];
|
||||
$ch = $session['curl'];
|
||||
|
||||
$endpointUrl = 'https://crm.clientright.ru/webservice.php';
|
||||
|
||||
// getchallenge
|
||||
curl_setopt($ch, CURLOPT_URL, $endpointUrl . '?operation=getchallenge&username=' . urlencode($userName));
|
||||
$resp = curl_exec($ch);
|
||||
if ($resp === false) {
|
||||
writeLog('❌ CURL error: ' . curl_error($ch));
|
||||
return ['error' => 'Network error'];
|
||||
}
|
||||
|
||||
$resp = ltrim($resp, "\xEF\xBB\xBF\x00\x09\x0A\x0D\x20");
|
||||
$challenge = json_decode($resp, true);
|
||||
if (!$challenge || empty($challenge['result']['token'])) {
|
||||
writeLog('❌ Invalid challenge response: ' . substr($resp, 0, 100));
|
||||
return ['error' => 'Authentication failed'];
|
||||
}
|
||||
$token = $challenge['result']['token'];
|
||||
|
||||
// 3. Логинимся
|
||||
$key = md5($token . $accessKey);
|
||||
curl_setopt($ch, CURLOPT_URL, $endpointUrl);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, [
|
||||
'operation' => 'login',
|
||||
'username' => $userName,
|
||||
'accessKey' => $key,
|
||||
]);
|
||||
$resp = curl_exec($ch);
|
||||
if ($resp === false) {
|
||||
writeLog('❌ CURL error: ' . curl_error($ch));
|
||||
return ['error' => 'Network error'];
|
||||
}
|
||||
|
||||
$resp = ltrim($resp, "\xEF\xBB\xBF\x00\x09\x0A\x0D\x20");
|
||||
$login = json_decode($resp, true);
|
||||
if (!$login || empty($login['result']['sessionName'])) {
|
||||
writeLog('❌ Login failed: ' . substr($resp, 0, 100));
|
||||
return ['error' => 'Authentication failed'];
|
||||
}
|
||||
$sessionId = $login['result']['sessionName'];
|
||||
|
||||
// 4. Устанавливаем current_user для CRMEntity
|
||||
$current_user = new Users();
|
||||
$current_user->retrieveCurrentUserInfoFromFile((int)$userId);
|
||||
|
||||
Reference in New Issue
Block a user