Работа с переменными проекта в ZennoPoster

⚠️ Переменные должны быть созданы заранее

  • Все переменные должны быть созданы в ProjectMaker до выполнения кода
  • Попытка доступа к несуществующей переменной вызовет исключение
  • API IZennoPosterProjectModel позволяет только читать и изменять существующие локальные переменные, но НЕ создавать новые

⚠️ Тип данных переменных

  • Все переменные в ZennoPoster имеют тип string
  • При работе с числами, булевыми значениями и другими типами необходимо выполнять конвертацию

📋 ОСНОВЫ РАБОТЫ С ЛОКАЛЬНЫМИ ПЕРЕМЕННЫМИ

Получение значения переменной

// Базовое получение значения (переменная должна существовать!)
string userName = project.Variables["UserName"].Value;
string email = project.Variables["Email"].Value;
 
// Проверка на пустое значение (если переменная существует)
if (string.IsNullOrEmpty(email)) {
    project.SendWarningToLog("Переменная Email пуста", false);
}

Установка значения переменной

// Установка строкового значения
project.Variables["UserName"].Value = "ivan_petrov";
 
// Установка числа - конвертация в string
int age = 25;
project.Variables["Age"].Value = age.ToString();
 
// Установка булевого значения - конвертация в string
bool isLoggedIn = true;
project.Variables["IsLoggedIn"].Value = isLoggedIn.ToString();
 
// Установка текущей даты и времени
project.Variables["CurrentDateTime"].Value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
 
// Универсальный код
var someObject = object;
project.Variables["object"].Value = $"{someObject}";
 
 

🔢 РАБОТА С ЧИСЛОВЫМИ ДАННЫМИ

Конвертация из string в числовые типы

// Получение числового значения из переменной
string countStr = project.Variables["Count"].Value;
int count = int.Parse(countStr);
count++;
project.Variables["Count"].Value = count.ToString();
 
// Работа с double
string priceStr = project.Variables["Price"].Value;
double price = double.Parse(priceStr);
price *= 1.2; // Увеличиваем цену на 20%
project.Variables["Price"].Value = price.ToString("F2"); // Форматируем до 2 знаков после запятой

Арифметические операции

// Инкремент счетчика
string attemptStr = project.Variables["Attempts"].Value;
int attempts = int.Parse(attemptStr);
attempts++;
project.Variables["Attempts"].Value = attempts.ToString();
 
// Вычисление суммы
string sum1Str = project.Variables["Sum1"].Value;
string sum2Str = project.Variables["Sum2"].Value;
int sum1 = int.Parse(sum1Str);
int sum2 = int.Parse(sum2Str);
int total = sum1 + sum2;
project.Variables["TotalSum"].Value = total.ToString();

🔤 РАБОТА СО СТРОКОВЫМИ ДАННЫМИ

Конкатенация строк

// Простая конкатенация
string firstName = project.Variables["FirstName"].Value;
string lastName = project.Variables["LastName"].Value;
project.Variables["FullName"].Value = firstName + " " + lastName;
 
// Форматирование строки
string template = project.Variables["MessageTemplate"].Value;
string userName = project.Variables["UserName"].Value;
project.Variables["PersonalMessage"].Value = template.Replace("{username}", userName);

Обработка текста

// Удаление лишних пробелов
string rawText = project.Variables["RawInput"].Value;
project.Variables["CleanInput"].Value = rawText.Trim();
 
// Изменение регистра
string email = project.Variables["Email"].Value;
project.Variables["EmailLower"].Value = email.ToLower();
 
// Проверка на содержание подстроки
string url = project.Variables["CurrentUrl"].Value;
if (url.Contains("success")) {
    project.Variables["IsSuccess"].Value = "True";
} else {
    project.Variables["IsSuccess"].Value = "False";
}

🔀 РАБОТА С БУЛЕВЫМИ ЗНАЧЕНИЯМИ

Установка и проверка булевых переменных

// Установка булевого значения
project.Variables["IsProcessed"].Value = "True";
project.Variables["HasErrors"].Value = "False";
 
// Проверка булевого значения
string isLoggedInStr = project.Variables["IsLoggedIn"].Value;
bool isLoggedIn = isLoggedInStr == "True";
 
if (isLoggedIn) {
    // Пользователь авторизован
    project.Variables["LastLoginTime"].Value = DateTime.Now.ToString();
} else {
    // Необходима авторизация
    project.Variables["LoginRequired"].Value = "True";
}
 
// Переключение булевого значения
string currentState = project.Variables["FeatureEnabled"].Value;
bool isEnabled = currentState == "True";
project.Variables["FeatureEnabled"].Value = (!isEnabled).ToString();

📅 РАБОТА С ДАТОЙ И ВРЕМЕНЕМ

Установка даты и времени

// Текущая дата и время
project.Variables["CurrentDateTime"].Value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
 
// Только дата
project.Variables["CurrentDate"].Value = DateTime.Now.ToString("yyyy-MM-dd");
 
// Только время
project.Variables["CurrentTime"].Value = DateTime.Now.ToString("HH:mm:ss");
 
// Дата в различных форматах
project.Variables["DateRus"].Value = DateTime.Now.ToString("dd.MM.yyyy");
project.Variables["DateUS"].Value = DateTime.Now.ToString("MM/dd/yyyy");
 
// Unix timestamp
project.Variables["Timestamp"].Value = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds().ToString();

Операции с датами

// Добавление дней к дате
string currentDateStr = project.Variables["StartDate"].Value;
DateTime startDate = DateTime.Parse(currentDateStr);
DateTime endDate = startDate.AddDays(30);
project.Variables["EndDate"].Value = endDate.ToString("yyyy-MM-dd");
 
// Вычисление разности между датами
string date1Str = project.Variables["Date1"].Value;
string date2Str = project.Variables["Date2"].Value;
DateTime date1 = DateTime.Parse(date1Str);
DateTime date2 = DateTime.Parse(date2Str);
TimeSpan difference = date2 - date1;
project.Variables["DaysDifference"].Value = difference.Days.ToString();

🌐 РАБОТА С URL И ПУТЯМИ

Формирование URL

// Базовый URL с параметрами
string baseUrl = project.Variables["BaseUrl"].Value;
string userId = project.Variables["UserId"].Value;
string apiKey = project.Variables["ApiKey"].Value;
project.Variables["FullUrl"].Value = $"{baseUrl}/user/{userId}?key={apiKey}";
 
// URL-кодирование параметров
string searchQuery = project.Variables["SearchQuery"].Value;
string encodedQuery = Macros.TextProcessing.UrlEncode(searchQuery, "utf-8");
project.Variables["EncodedQuery"].Value = encodedQuery;

Извлечение частей URL

// Извлечение домена из URL
string fullUrl = project.Variables["FullUrl"].Value;
Uri uri = new Uri(fullUrl);
project.Variables["Domain"].Value = uri.Host;
project.Variables["Path"].Value = uri.AbsolutePath;
project.Variables["Query"].Value = uri.Query;

🔍 УСЛОВНАЯ ЛОГИКА С ПЕРЕМЕННЫМИ

If-else конструкции

// Простое условие
string status = project.Variables["Status"].Value;
if (status == "success") {
    project.Variables["Message"].Value = "Операция выполнена успешно";
} else if (status == "error") {
    project.Variables["Message"].Value = "Произошла ошибка";
} else {
    project.Variables["Message"].Value = "Неизвестный статус";
}
 
// Множественные условия
string userType = project.Variables["UserType"].Value;
string isVip = project.Variables["IsVip"].Value;
string discount = "0";
 
if (userType == "premium") {
    discount = "15";
} else if (userType == "regular" && isVip == "True") {
    discount = "10";
} else if (userType == "regular") {
    discount = "5";
}
project.Variables["Discount"].Value = discount;

Switch-подобная логика

// Эмуляция switch через if-else
string action = project.Variables["Action"].Value;
string result = "";
 
if (action == "login") {
    result = "Выполняется авторизация...";
} else if (action == "logout") {
    result = "Выполняется выход...";
} else if (action == "register") {
    result = "Выполняется регистрация...";
} else {
    result = "Неизвестное действие";
}
project.Variables["ActionResult"].Value = result;

🔧 ПРАКТИЧЕСКИЕ ПРИМЕРЫ

Счетчик попыток с ограничением

// Получаем текущее количество попыток
string attemptsStr = project.Variables["LoginAttempts"].Value;
int attempts = int.Parse(attemptsStr);
 
// Увеличиваем счетчик
attempts++;
project.Variables["LoginAttempts"].Value = attempts.ToString();
 
// Проверяем лимит
int maxAttempts = 3;
if (attempts >= maxAttempts) {
    project.Variables["MaxAttemptsReached"].Value = "True";
    project.SendWarningToLog($"Достигнуто максимальное количество попыток: {attempts}", false);
    
    // Прерываем выполнение
    ZennoPoster.SetTries(new Guid(project.TaskId), 0);
}

Генерация уникальных идентификаторов

// GUID
project.Variables["UniqueId"].Value = Guid.NewGuid().ToString();
 
// Timestamp + случайное число
string timestamp = DateTimeOffset.Now.ToUnixTimeSeconds().ToString();
string random = Global.Classes.rnd.Next(1000, 9999).ToString();
project.Variables["SessionId"].Value = timestamp + "_" + random;

Работа с массивами данных в одной переменной

// Сохранение массива как строки с разделителем
string[] emails = {"test1@mail.com", "test2@mail.com", "test3@mail.com"};
project.Variables["EmailList"].Value = string.Join("|", emails);
 
// Извлечение массива из строки
string emailListStr = project.Variables["EmailList"].Value;
if (!string.IsNullOrEmpty(emailListStr)) {
    string[] emailArray = emailListStr.Split('|');
    if (emailArray.Length > 0) {
        project.Variables["FirstEmail"].Value = emailArray[0];
        project.Variables["EmailCount"].Value = emailArray.Length.ToString();
    }
}

Валидация данных

// Проверка email
string email = project.Variables["Email"].Value;
bool isValidEmail = !string.IsNullOrEmpty(email) && email.Contains("@") && email.Contains(".");
project.Variables["IsValidEmail"].Value = isValidEmail.ToString();
 
// Проверка телефона (простая)
string phone = project.Variables["Phone"].Value;
bool isValidPhone = !string.IsNullOrEmpty(phone) && phone.Length >= 10;
project.Variables["IsValidPhone"].Value = isValidPhone.ToString();
 
// Комплексная валидация
bool allValid = isValidEmail && isValidPhone;
project.Variables["AllFieldsValid"].Value = allValid.ToString();

⚡ ОПТИМИЗАЦИЯ И ЛУЧШИЕ ПРАКТИКИ

Избегание повторных обращений

// ❌ Плохо - множественные обращения к одной переменной
if (project.Variables["Status"].Value == "processing") {
    project.SendInfoToLog($"Статус: {project.Variables["Status"].Value}", false);
}
 
// ✅ Хорошо - одно обращение
string status = project.Variables["Status"].Value;
if (status == "processing") {
    project.SendInfoToLog($"Статус: {status}", false);
}

Инициализация переменных по умолчанию

// Проверка и установка значений по умолчанию
string counter = project.Variables["Counter"].Value;
if (string.IsNullOrEmpty(counter)) {
    project.Variables["Counter"].Value = "0";
}
 
string status = project.Variables["Status"].Value;
if (string.IsNullOrEmpty(status)) {
    project.Variables["Status"].Value = "idle";
}

🚨 ОБРАБОТКА ОШИБОК

Безопасная работа с переменными (EAFP подход)

// EAFP - Easier to Ask for Forgiveness than Permission
try {
    // Пытаемся получить и обработать переменную
    string valueStr = project.Variables["Count"].Value;
    int value = int.Parse(valueStr);
    value++;
    project.Variables["Count"].Value = value.ToString();
    
} catch (Exception ex) {
    // Если что-то пошло не так - обрабатываем ошибку
    project.SendErrorToLog($"Ошибка при работе с переменной Count: {ex.Message}", false);
    
    // Устанавливаем безопасное значение по умолчанию
    project.Variables["Count"].Value = "1";
}

Проверка существования переменной

// Функция для проверки существования переменной
bool VariableExists(string variableName) {
    try {
        string value = project.Variables[variableName].Value;
        return true;
    } catch {
        return false;
    }
}
 
// Использование
if (VariableExists("OptionalSetting")) {
    string setting = project.Variables["OptionalSetting"].Value;
    // Работаем с переменной
} else {
    project.SendInfoToLog("Переменная OptionalSetting не найдена", false);
}

🌐 ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ

Что такое глобальные переменные?

Глобальные переменные в ZennoPoster - это переменные, которые:

  • Доступны всем потокам и проектам в рамках одного экземпляра ZennoPoster
  • Организованы по пространствам имен (namespaces) для лучшей структуризации
  • Могут быть созданы программно во время выполнения
  • Сохраняют свои значения между запусками разных потоков

Получение глобальной переменной

// Получение глобальной переменной по namespace и имени
IGlobalVariable gv = project.GlobalVariables["MyNamespace", "VariableName"];
 
// Получение значения
string value = gv.Value.ToString();
 
// Безопасное получение с проверкой на null
IGlobalVariable gv = project.GlobalVariables["Settings", "ApiKey"];
if (gv != null && gv.Value != null) {
    string apiKey = gv.Value.ToString();
    project.SendInfoToLog($"API ключ получен: {apiKey}", false);
} else {
    project.SendWarningToLog("Глобальная переменная ApiKey не найдена", false);
}

Создание и установка глобальных переменных

// Создание новой глобальной переменной с установкой значения
project.GlobalVariables.SetVariable("MyNamespace", "NewVariableName", "NewValue");
 
// Создание переменных для разных целей
project.GlobalVariables.SetVariable("Counters", "TotalProcessed", "0");
project.GlobalVariables.SetVariable("Settings", "MaxRetries", "5");
project.GlobalVariables.SetVariable("Auth", "AccessToken", "your_token_here");
project.GlobalVariables.SetVariable("Timing", "LastUpdate", DateTime.Now.ToString());

Изменение значения существующей глобальной переменной

// Получаем переменную и изменяем её значение
IGlobalVariable counter = project.GlobalVariables["Counters", "TotalProcessed"];
if (counter != null) {
    int currentValue = int.Parse(counter.Value.ToString());
    currentValue++;
    counter.Value = currentValue.ToString();
}
 
// Более короткий способ через SetVariable (перезапишет существующую)
string currentCountStr = project.GlobalVariables["Counters", "TotalProcessed"]?.Value?.ToString() ?? "0";
int currentCount = int.Parse(currentCountStr);
currentCount++;
project.GlobalVariables.SetVariable("Counters", "TotalProcessed", currentCount.ToString());

Работа с метаданными глобальной переменной

// Получение информации о переменной
IGlobalVariable gv = project.GlobalVariables["Settings", "DatabaseUrl"];
if (gv != null) {
    string name = gv.Name;           // Имя переменной
    string ns = gv.Namespace;        // Пространство имен
    string comment = gv.Comment;     // Комментарий
    object value = gv.Value;         // Значение
    
    // Установка комментария
    if (string.IsNullOrWhiteSpace(comment)) {
        gv.Comment = "URL для подключения к базе данных";
    }
    
    project.SendInfoToLog($"Переменная {ns}.{name}: {value} ({comment})", false);
}

🔄 ПРАКТИЧЕСКИЕ СЦЕНАРИИ ИСПОЛЬЗОВАНИЯ ГЛОБАЛЬНЫХ ПЕРЕМЕННЫХ

Глобальный счетчик для всех потоков

// Инициализация счетчика (выполнять только один раз)
project.GlobalVariables.SetVariable("Statistics", "ProcessedItems", "0");
 
// Увеличение счетчика в каждом потоке (потокобезопасно)
IGlobalVariable counter = project.GlobalVariables["Statistics", "ProcessedItems"];
if (counter != null) {
    lock (counter) {
        int current = int.Parse(counter.Value.ToString());
        current++;
        counter.Value = current.ToString();
        
        project.SendInfoToLog($"Обработано элементов: {current}", false);
        
        // Проверка лимита
        if (current >= 1000) {
            project.GlobalVariables.SetVariable("Control", "StopProcessing", "True");
        }
    }
}

Общие настройки для всех потоков

// Инициализация настроек (в главном потоке или один раз)
project.GlobalVariables.SetVariable("Config", "ApiUrl", "https://api.example.com");
project.GlobalVariables.SetVariable("Config", "Timeout", "30");
project.GlobalVariables.SetVariable("Config", "UserAgent", "MyBot/1.0");
 
// Использование настроек в любом потоке
string apiUrl = project.GlobalVariables["Config", "ApiUrl"]?.Value?.ToString() ?? "";
string timeoutStr = project.GlobalVariables["Config", "Timeout"]?.Value?.ToString() ?? "30";
string userAgent = project.GlobalVariables["Config", "UserAgent"]?.Value?.ToString() ?? "DefaultUA";
 
int timeout = int.Parse(timeoutStr) * 1000;
 
// Использование в HTTP запросе
string response = ZennoPoster.HTTP.Request(
    method: ZennoLab.InterfacesLibrary.Enums.Http.HttpMethod.GET,
    url: apiUrl + "/data",
    proxy: project.GetProxy(),
    UserAgent: userAgent,
    Timeout: timeout,
    respType: ZennoLab.InterfacesLibrary.Enums.Http.ResponceType.BodyOnly
);

Система глобальных флагов управления

// Инициализация флагов управления
project.GlobalVariables.SetVariable("Control", "PauseAllThreads", "False");
project.GlobalVariables.SetVariable("Control", "StopOnError", "False");
project.GlobalVariables.SetVariable("Control", "MaintenanceMode", "False");
 
// Проверка флагов в каждом потоке
string pauseFlag = project.GlobalVariables["Control", "PauseAllThreads"]?.Value?.ToString() ?? "False";
if (pauseFlag == "True") {
    project.SendInfoToLog("Поток приостановлен по глобальному флагу", false);
    
    // Ожидание снятия флага
    while (pauseFlag == "True") {
        Thread.Sleep(5000);
        pauseFlag = project.GlobalVariables["Control", "PauseAllThreads"]?.Value?.ToString() ?? "False";
    }
}
 
// Установка флага при критической ошибке
try {
    // Критически важная операция
} catch (Exception ex) {
    project.SendErrorToLog($"Критическая ошибка: {ex.Message}", true);
    project.GlobalVariables.SetVariable("Control", "StopOnError", "True");
    
    // Прерывание выполнения
    ZennoPoster.SetTries(new Guid(project.TaskId), 0);
}

Кеширование данных между потоками

// Кеширование токена авторизации
string cachedToken = project.GlobalVariables["Cache", "AuthToken"]?.Value?.ToString() ?? "";
string tokenExpiry = project.GlobalVariables["Cache", "TokenExpiry"]?.Value?.ToString() ?? "";
 
bool needNewToken = string.IsNullOrEmpty(cachedToken);
if (!string.IsNullOrEmpty(tokenExpiry)) {
    DateTime expiry = DateTime.Parse(tokenExpiry);
    needNewToken = DateTime.Now >= expiry;
}
 
if (needNewToken) {
    // Получение нового токена (только один поток должен это делать)
    IGlobalVariable tokenVar = project.GlobalVariables["Cache", "AuthToken"];
    if (tokenVar != null) {
        lock (tokenVar) {
            // Повторная проверка после получения блокировки
            cachedToken = tokenVar.Value?.ToString() ?? "";
            if (string.IsNullOrEmpty(cachedToken)) {
                // Получаем новый токен
                string newToken = GetAuthToken(); // Ваша функция получения токена
                DateTime newExpiry = DateTime.Now.AddHours(1);
                
                project.GlobalVariables.SetVariable("Cache", "AuthToken", newToken);
                project.GlobalVariables.SetVariable("Cache", "TokenExpiry", newExpiry.ToString());
                
                cachedToken = newToken;
            }
        }
    }
}
 
// Использование кешированного токена
string headers = $"Authorization: Bearer {cachedToken}";

Глобальная статистика и мониторинг

// Инициализация статистики
project.GlobalVariables.SetVariable("Stats", "TotalRequests", "0");
project.GlobalVariables.SetVariable("Stats", "SuccessfulRequests", "0");
project.GlobalVariables.SetVariable("Stats", "FailedRequests", "0");
project.GlobalVariables.SetVariable("Stats", "StartTime", DateTime.Now.ToString());
 
// Обновление статистики в потоке
void UpdateStats(bool isSuccess) {
    // Общее количество запросов
    IGlobalVariable totalVar = project.GlobalVariables["Stats", "TotalRequests"];
    if (totalVar != null) {
        lock (totalVar) {
            int total = int.Parse(totalVar.Value.ToString());
            total++;
            totalVar.Value = total.ToString();
        }
    }
    
    // Успешные или неуспешные
    string statType = isSuccess ? "SuccessfulRequests" : "FailedRequests";
    IGlobalVariable statVar = project.GlobalVariables["Stats", statType];
    if (statVar != null) {
        lock (statVar) {
            int count = int.Parse(statVar.Value.ToString());
            count++;
            statVar.Value = count.ToString();
        }
    }
}
 
// Использование
try {
    // Выполнение запроса
    string response = ZennoPoster.HTTP.Request(/* параметры */);
    UpdateStats(true);
} catch {
    UpdateStats(false);
}
 
// Вывод статистики
string total = project.GlobalVariables["Stats", "TotalRequests"]?.Value?.ToString() ?? "0";
string success = project.GlobalVariables["Stats", "SuccessfulRequests"]?.Value?.ToString() ?? "0";
string failed = project.GlobalVariables["Stats", "FailedRequests"]?.Value?.ToString() ?? "0";
project.SendInfoToLog($"Статистика: Всего={total}, Успешно={success}, Ошибок={failed}", false);

🔒 ПОТОКОБЕЗОПАСНОСТЬ ГЛОБАЛЬНЫХ ПЕРЕМЕННЫХ

Правильное использование lock

// Правильный способ - блокировка на объекте переменной
IGlobalVariable sharedCounter = project.GlobalVariables["Shared", "Counter"];
if (sharedCounter != null) {
    lock (sharedCounter) {
        int current = int.Parse(sharedCounter.Value.ToString());
        current++;
        sharedCounter.Value = current.ToString();
        
        // Любые другие операции с этой переменной
        project.SendInfoToLog($"Счетчик: {current}", false);
    }
}
 
// Комплексная операция с несколькими переменными
IGlobalVariable var1 = project.GlobalVariables["Data", "Variable1"];
IGlobalVariable var2 = project.GlobalVariables["Data", "Variable2"];
 
if (var1 != null && var2 != null) {
    // Блокируем по одной переменной для избежания deadlock
    lock (var1) {
        lock (var2) {
            // Атомарная операция с двумя переменными
            int val1 = int.Parse(var1.Value.ToString());
            int val2 = int.Parse(var2.Value.ToString());
            
            val1++;
            val2 += val1;
            
            var1.Value = val1.ToString();
            var2.Value = val2.ToString();
        }
    }
}

⚖️ СРАВНЕНИЕ: ЛОКАЛЬНЫЕ vs ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ

ХарактеристикаЛокальные переменныеГлобальные переменные
Область видимостиТолько текущий потокВсе потоки
API доступаproject.Variables["name"]project.GlobalVariables["namespace", "name"]
СозданиеТолько в ProjectMakerВ коде или ProjectMaker
Пространства именНетДа
ПотокобезопасностьНе требуетсяТребуется lock
ПроизводительностьВысокаяНиже (из-за синхронизации)
ИспользованиеДанные потокаОбщие настройки, счетчики

Когда использовать глобальные переменные:

  • Общие настройки для всех потоков
  • Счетчики и статистика
  • Флаги управления выполнением
  • Кеширование данных между потоками
  • Координация между потоками

Когда использовать локальные переменные:

  • Данные специфичные для потока
  • Промежуточные результаты
  • Состояние выполнения конкретного потока
  • Временные значения