Управление шаблоном c#

DmitryAk

Client
Joined
Dec 14, 2016
Messages
860
Reaction score
824
Points
93
Часто задают вопросы, как запустить шаба из шаба, как управлять, добавить потоки итд.
Люди начинают создавать некошерные батники и прочими образами извращаться, хотя зенка предоставляет не очень приличный, но достаточный api для решения этих вопросов более адекватным путем.
Выкладываю небольшой статический класс упрощающий работу с запуском вторичных шабов.

Класс вставляем в общий код после
Code:
namespace ZennoLab.OwnCode
{

Code:
public static class TaskHelper
   {
     
       public static string GetTaskId(string TaskName)
     {
       var tasksList = ZennoPoster.TasksList;
       foreach (var task in tasksList){         
        string tname = Regex.Match(task,@"(?<=<Name>).*?(?=</Name>)").Value;
          string tid  = Regex.Match(task,@"(?<=<Id>).*?(?=</Id><Name>)").Value;
         
          if (tname == TaskName){
           return tid;
          }
       }   
       return "";
     }
     
     public static int GetNumberOfTries(string TaskName)
     {
         string sid = TaskHelper.GetTaskId(TaskName);
       var id = Guid.Parse(sid);
       var taskInfo = ZennoPoster.GetTaskInfo(id);
       string execsettings = Regex.Match(taskInfo,@"(?<=<ExecutionSettings>).*?(?=</ExecutionSettings>)").Value;
       string ntries =  Regex.Match(execsettings,@"(?<=<NumberOfTries>).*?(?=</NumberOfTries>)").Value;
       int res=0;
       Int32.TryParse(ntries,out res);
       return res;       
     }
     
     public static string GetStatus(string TaskName)
     {
       string sid = TaskHelper.GetTaskId(TaskName);
       var id = Guid.Parse(sid);
       var taskInfo = ZennoPoster.GetTaskInfo(id);
       string status = Regex.Match(taskInfo,@"(?<=<Status>).*?(?=</Status>)").Value;
       return status;
       
       //Perform - работает
       //Complite - завершен
       //Stop - остановлен
       //Schedule - запланирован
       //WaitPerform - компилится
     }
     
     public static void WaitRun(IZennoPosterProjectModel project,string TaskName)
     {
         int nt = GetNumberOfTries(TaskName);
       string status = GetStatus(TaskName);
       while( nt >0 )
       {    
         if(((ZennoLab.InterfacesLibrary.ProjectModel.Collections.IContextExt)project.Context).IsInterrupted) return; // Прерывание в ZP
         if(Global.Variables.IsProjectMaker && !Global.Variables.IsDebugMode) return; // Прерывание в PM
         
           Thread.Sleep(3000);
         
           nt = TaskHelper.GetNumberOfTries(TaskName);
         status = GetStatus(TaskName);
         
         switch (status)
         {
           case "Perform":
             break;
           case "Complite": nt = 0;
             break;
           case "Stop": nt = 0;
             break;
           case "Schedule":
             break;
           case "WaitPerform":
             break;
         }
         
           project.SendInfoToLog("Ожидаем завершения "+TaskName,true);   
       }
     }
   }
Примеры использования

Поиск айди шаблона по имени:
Code:
string tempname = "имя шаба";
if (TaskHelper.GetTaskId(tempname)==""){
  project.SendErrorToLog("Не смогли найти проект "+tempname, true);
  throw new Exception("Не найден проект");
}
Добавление нужного числа исполнений и ожидание завершения:
Code:
string tempname = "имя шаба";
int tries = 50; // будет добавлено 50 исполнений
if (tries>0){
   ZennoPoster.AddTries(tempname , tries);
   TaskHelper.WaitRun(project,tempname );  //ожидаем завершения всех исполнений
}
GetStatus - получить статус шаблона
Code:
//Perform - работает
//Complite - завершен
//Stop - остановлен
//Schedule - запланирован
//WaitPerform - компилится
GetNumberOfTries - получить кол-во заданых исполнений
 

Для запуска проектов требуется программа ZennoPoster.
Это основное приложение, предназначенное для выполнения автоматизированных шаблонов действий (ботов).
Подробнее...

Для того чтобы запустить шаблон, откройте программу ZennoPoster. Нажмите кнопку «Добавить», и выберите файл проекта, который хотите запустить.
Подробнее о том, где и как выполняется проект.

Lord_Alfred

Client
Joined
Oct 9, 2015
Messages
3,916
Reaction score
3,882
Points
113
Очень полезно и красиво! :-)

Расскажи только, пожалуйста, как работать с:
if(((ZennoLab.InterfacesLibrary.ProjectModel.Collections.IContextExt)project.Context).IsInterrupted) return; // Прерывание в ZP
if(Global.Variables.IsProjectMaker && !Global.Variables.IsDebugMode) return; // Прерывание в PM
?
 
  • Thank you
Reactions: viol2021

DmitryAk

Client
Joined
Dec 14, 2016
Messages
860
Reaction score
824
Points
93
как работать с
Есть снипет где вызван WaitRun. Соответственно, пока вторичный шаб не завершит работу мы в этом снипе и крутимся в цикле.
Соответственно для выхода из цикла при остановке по кнопке стоп из PM или "прервать" в зенке надо ловить соответствующие события, что эти две строки и делают - проверяют был ли шаб остановлен стопом (pm) или прерыванием (ZP) и выходит из цикла простым ретурном и шаб завершается.
 
  • Thank you
Reactions: Lord_Alfred

Lord_Alfred

Client
Joined
Oct 9, 2015
Messages
3,916
Reaction score
3,882
Points
113
Соответственно для выхода из цикла при остановке по кнопке стоп из PM или "прервать" в зенке надо ловить соответствующие события
Это именно отлов событий, а не необходимость создавать глобальные переменные / контекст, чтобы остановить шаблон?
Просто не встречал нигде описания такого способа отлова этих событий, вот и удивился :-) Незадокументированные фичи?)
 

DmitryAk

Client
Joined
Dec 14, 2016
Messages
860
Reaction score
824
Points
93
Это именно отлов событий, а не необходимость создавать глобальные переменные / контекст, чтобы остановить шаблон?
Ненене, ничего создавать не надо.. это "родные" зенновские глобалки.

Просто не встречал нигде описания такого способа отлова этих событий, вот и удивился :-) Незадокументированные фичи?)
Я их и сам тут на форуме нашел) Хз, может и недокументированные.
 
  • Thank you
Reactions: Lord_Alfred

systema

Client
Joined
Jul 25, 2013
Messages
174
Reaction score
64
Points
28
Все разобрался.
Спасибо за код, то что нужно :ay:
 
Last edited:

Yuriy Zymlex

Client
Joined
Oct 23, 2016
Messages
6,713
Reaction score
3,478
Points
113

Lord_Alfred

Client
Joined
Oct 9, 2015
Messages
3,916
Reaction score
3,882
Points
113
Быть может у кого-то есть идеи или наработки как запускать шаблон, но при этом передавая туда ещё и конфиг какой-то? (без использования файлов и прочего - чисто конфиг, который мы в зенке выставляем у шаблона)

Просто тут мысль в голову пришла, что было бы интересно допилить этот класс до реализации подобия запуска асинхронных тасков с передачей аргументов каких-то в шаблон. То есть родительский шаблон что-то парсит, посылая в дочерний шаблон какие-то переменные (конфиг), а дочерний шаблон асинхронно что-то доделывает с теми данными, что передал ему родительский.

Звучит дико извращенно, но от того и интересно это)
 

DmitryAk

Client
Joined
Dec 14, 2016
Messages
860
Reaction score
824
Points
93
Просто тут мысль в голову пришла, что было бы интересно допилить этот класс до реализации подобия запуска асинхронных тасков с передачей аргументов каких-то в шаблон.
Перед запуском субпроекта ему входные настройки установить через SetExecutionSettings.
Но хз как это будет отрабатывать в случае "установил, запустил, не дождался завершения снова установил, еще одно исполнение добавил".

В принципе, для подобной задачи я этот класс и реализовывал, только задача была не асинхронка, а быстро отработать пул задач по парсингу, используя многопоток и дополнительные аккаунты. Т.е. изначально первичный проект делал всю задачу от и до. Но проект выполнялся двое-трое суток.
А так первичный проект выпарсивает первичные данные и пишет их в табличку, где каждая запись - отдельная задача для субпроекта. Дальше запускается субпроект многопотоком, для каждого потока подсасывается свободный аккаунт, свободный прокси и тд подтягивается через лок ОДНА задача из таблички и производится обработка. Результат пишется в ту же табличку в отдельное поле. Для другого проекта - в отдельную табличку с указанием айдишника задачи. Максимальное количество потоков для субпроекта стоит либо зависимо от мощности компа, либо зависимо от количества доступных "рабочих" аккаунтов. Субпроект при завершении ставит аккаунту и прокси статус "свободен" и завершает работу.
Первичный проект ждет завершения обработки и продолжает свое дело уже на основе всех обработанных данных.
В итоге 2-5 часов на обработку.

По идее передать в субпроекты данные еще можно используя любую технологию межпроцессной передачи данных, но это излишне замороченно для подобной задачи имхо.
 

Lord_Alfred

Client
Joined
Oct 9, 2015
Messages
3,916
Reaction score
3,882
Points
113
Но хз как это будет отрабатывать в случае "установил, запустил, не дождался завершения снова установил, еще одно исполнение добавил".
Да, тоже вот уже после того как запостил - задумался о том, что будет оверхед на валидацию того дошли ли настройки до запуска и не нужно ли ожидать ещё. Ещё потом была мысль, что возможно поможет какой-нибудь Parallel.For и внутри просто запуск подпроекта на C# (т.к. там даже в PM табы не открываются в случае запуска через C# метод). Скорее всего такой дикий вариант буду пробовать или вообще по-другому архитектуру построю - пока не знаю)
 

Lord_Alfred

Client
Joined
Oct 9, 2015
Messages
3,916
Reaction score
3,882
Points
113
Обновлю информацию по задуманной в предыдущем посте дичи. Пишу отдельным, чтоб увидел @DmitryAk и с радостью бы послушал @amyboose или @Adigen.

Вообщем, получилось запустить асинхронно вложенный шаблон с помощью такой вот конструкции:

Общий код:
C#:
using System.Threading.Tasks;

namespace ZennoLab.OwnCode
{
    public class Runner {
        public static void Inner(IZennoPosterProjectModel project) {
            var mapVars = new List<Tuple<string, string>>();
            mapVars.Add(new Tuple<string, string>("var1", "IN_var1")); // маппинг переменных из родительского шаблона => в дочерний
            string project_path = Path.Combine(project.Directory, "template_name.xmlz"); // имя дочернего шаблона
            project.ExecuteProject(project_path, mapVars, true, false, false);
        }
      
        public static void Run(IZennoPosterProjectModel project) {
            System.Threading.Tasks.Task.Run(() => Inner(project));
        }
    }
}
C# сниппет:
C#:
Runner.Run(project);
Да, запускается он асинхронно и вроде как отрабатывает до конца, при этом не блокируя родительский процесс. Но меня, конечно, очень смущает эта идея уже :-) Сделал её уже просто из спортивного интереса, но, к моему сожалению, совсем не понимаю как оно будет распределяться по ядрам в случае ударной нагрузки? И есть ли какие-то таймауты, по которым может таск отвалится и недоработать? А память не потечет от такой дичи?
Уже не говорю про то, что нужно точно знать завершился таск до конца или нет, т.к. по счастливой случайности в конце я пишу файл, который можно потом будет почекать.
 

DmitryAk

Client
Joined
Dec 14, 2016
Messages
860
Reaction score
824
Points
93
Хорошее решение.. т.е. это запуск "проекта в проекте" отдельным потоком по факту. "Дичью" это назвать нельзя, по идее это вполне нормальный подход. Течь не должно.. наверное, но это не точно))
Имхо юзать не слишком удобно.. замэпить все переменные надо.

А на браузерном проекте тестил? Т.е. и первичный и вторичный браузерные? Как себя ведет?
 
  • Thank you
Reactions: Lord_Alfred

Lord_Alfred

Client
Joined
Oct 9, 2015
Messages
3,916
Reaction score
3,882
Points
113
Имхо юзать не слишком удобно.. замэпить все переменные надо.
Да, меня эта реализация передачи переменных тоже немного напрягает(

А на браузерном проекте тестил? Т.е. и первичный и вторичный браузерные? Как себя ведет?
Неа, к сожалению, не потестил. У меня задача на безбраузерных шабах сейчас построена, допилил вот и выложил сразу как понял что работает) Даже толком не погонял ведь, чтоб наверняка говорить.
Мне вообще кажется, что такими "ухищрениями" по отношению к версиям zp ниже максималки (пишу чуть завуалировано, сорян) занимался Амибозыч, я помню такое очень давно он где-то рассказывал ВладЗену это, там как раз вроде он и тестил похожие подходы. Не скажу только решение 1 в 1 было или чем-то отличалось
 

Lord_Alfred

Client
Joined
Oct 9, 2015
Messages
3,916
Reaction score
3,882
Points
113
Вообщем, поюзал я решение запуска асинхронных подпроектов, что выложил парой постов выше. Стоит рассказать о паре особенностей, которые заметил чтоб другие знали.
  1. Если писать в лог в этом асинхронном проекте, то месседж дойдёт до туда (что очевидно, но удивительно для меня). Причем дойдет он до туда, даже если родительский проект уже завершился. В PM так точно такая схема работает, что удобно. UPD: пишет в лог, но не всегда. Иногда пишет всё подряд, даже каждое выполненное действие, а иногда не пишет это. Вообщем, нужно быть осторожнее.
  2. Словил странный баг: в лог приходило сообщение с ошибкой "Последовательность не содержит что-то там", по но ID кубик не находился и при запуске "вручную" - такой ошибки не было. Отсюда, думаю, стоит заключить, что скорее всего из-за этого хитрого запуска - шаб не перекомпилируется, хотя должен. После перезапуска PM ошибка пропала, но вначале я потратил достаточно времени, чтоб понять почему она валится, почему не ищется по ID и где же всё таки она может быть.
 
Last edited:

ngusev

Client
Joined
Jun 26, 2013
Messages
14
Reaction score
4
Points
3
Доброго дня, не хватает стандартного планировщика. Тоже возник вопрос по позданию шаблона для расширенного управления выполнения шаблонов по расписанию
на данный момент необходимо:
1)Выполнение определенного количества рандомно выполненных заданий в заданый промежуток времени
Пример:Мне нужно лайкнуть свой пост 12 раз разными профилями с 9 00 утра до 11 00 , соответственно шаблон нужно
запустить 12 раз рандомно в этот промежуток времени(вариант лайкать каждые 10 минут меня не устраивает)
2)Выставлять разные промежутки времени и количество выполнений для дней недели и определенных дат
таких как праздничные дни.
3)Создавать разные сценарии выполнения под каждый шаблон.

Кто уже делал , интересует консультация или покупка , может у вас функционал больше , готов обсуждать !
 

molotok

Client
Joined
Apr 17, 2015
Messages
755
Reaction score
409
Points
63
А куда возвращает id шаблона этот код?
Code:
string tempname = "имя шаба";
if (TaskHelper.GetTaskId(tempname)==""){
  project.SendErrorToLog("Не смогли найти проект "+tempname, true);
  throw new Exception("Не найден проект");
}
 

DmitryAk

Client
Joined
Dec 14, 2016
Messages
860
Reaction score
824
Points
93
А куда возвращает id шаблона этот код
В данном случае в условие для проверки. можно дернуть айдишник с возвратом снипетом типа
Code:
string tempname = "имя шаба"; return TaskHelper.GetTaskId(tempname);
 

molotok

Client
Joined
Apr 17, 2015
Messages
755
Reaction score
409
Points
63
В данном случае в условие для проверки. можно дернуть айдишник с возвратом снипетом типа
Code:
string tempname = "имя шаба"; return TaskHelper.GetTaskId(tempname);
Я примерно так и сделал, но новички, которые будут просто копировать код, могут не понять почему не работает...

Code:
string tempname = "claimBot2_Get_0.1.2_2";
string strId = TaskHelper.GetTaskId(tempname);
if (strId==String.Empty){
  project.SendErrorToLog("Не смогли найти проект "+tempname, true); throw new Exception("Не найден проект");
  }else{
    project.SendErrorToLog(strId, true);
  }
Кстати, в общем коде, в методе GetTaskId можно добавить перевод сравниваемых строк в нижний регистр. Так как почему-то название шаблона в Зенке начинается с заглавной буквы, но при этом сам файл шаблона начинается с прописной.
 
  • Thank you
Reactions: JurgenZolle

Yuriy Zymlex

Client
Joined
Oct 23, 2016
Messages
6,713
Reaction score
3,478
Points
113
Имхо юзать не слишком удобно.. замэпить все переменные надо.
Если шабы свои, то проще передать объект через project.Context в удобном виде. Не забыв passProjectContext в true.
название шаблона в Зенке начинается с заглавной буквы, но при этом сам файл шаблона начинается с прописной
В конфиге имя файла присутствует, можно и с ним сравнивать.

Вообще, через XmlReader поудобней будет, чем регулярками.:-)
ConformanceLevel.Fragment позволяет с таким форматом работать.
 
Last edited:

Lord_Alfred

Client
Joined
Oct 9, 2015
Messages
3,916
Reaction score
3,882
Points
113
Вообщем, получилось запустить асинхронно вложенный шаблон с помощью такой вот конструкции:
Апдейтну ещё раз сам себя. Есть подозрения, что именно такой запуск подпроекта вместе с использованием куки-контейнера приводит к "смешиванию" кук. То есть в текущем аккаунте могут оказаться куки от предыдущего аккаунта. Ловил такое поведение в PM, как будет в ZP - без понятия.
Очень прошу модераторм апдейтнуть тот пост этой инфой и спрятать код под спойлер, чтоб кто-то не нахватал таких же багов. Сам не могу редактировать уже :(

Я у себя буду избавляться от такого запуска, буду переводить на использование файла/БД, куда буду помещать данные для запуска следующего потока для парсинга. А уже самой зенкой буду запускать каждую минуту этот таск, чтоб проверить не появилось ли чего нового.
Да, использовать выложенный мной выше вариант гораздо интереснее, но пойманный баг с куки-контейнером меня очень сильно огорчает :(
 
  • Thank you
Reactions: Yuriy Zymlex

Yuriy Zymlex

Client
Joined
Oct 23, 2016
Messages
6,713
Reaction score
3,478
Points
113
Есть подозрения, что именно такой запуск подпроекта вместе с использованием куки-контейнера приводит к "смешиванию" кук.
Для запросов, можно и отдельный куки-контейнер создать, но если требуется работа с инстансом, то только пробовать поднимать под каждый подпроект свой.
Лучше запускать через AddTask с inputsettings, но с получением результата будет проблемно.
 
Last edited:

Lord_Alfred

Client
Joined
Oct 9, 2015
Messages
3,916
Reaction score
3,882
Points
113
Для запросов, можно и отдельный куки-контейнер создать, но если требуется работа с инстансом, то только пробовать поднимать под каждый подпроект свой.
Я там кубиками запрос делал, жаль ты раньше не написал - переделал бы на C# кубики. Сам как-то не догадался)
Теперь в mysql базу пишу параметры запуска (входные настройки грубо говоря), а уже самой зенкой каждую минуту дергаю не появилось ли новых задач. Такая себе асинхронность, но зато без багов :-)
 

Yuriy Zymlex

Client
Joined
Oct 23, 2016
Messages
6,713
Reaction score
3,478
Points
113
Быть может у кого-то есть идеи или наработки как запускать шаблон, но при этом передавая туда ещё и конфиг какой-то?
Как пример, выложил свой старый код по запуску,
не в совсем лучшем виде, но сами допишите. :-)
Надо только ImportInputSettings добавить и будут как настройки.
 

Attachments

bizzon

Client
Joined
Sep 8, 2015
Messages
1,120
Reaction score
135
Points
63
Совсем нуб, не знаком с понятиями Общий код и т.д.
Выдает "Имя "TaskHelper" отсутствует в текущем контексте"
Что сделал не так?
 

DmitryAk

Client
Joined
Dec 14, 2016
Messages
860
Reaction score
824
Points
93
Да, очевидно, не вставил код класса TaskHelper в общий код.
 

bizzon

Client
Joined
Sep 8, 2015
Messages
1,120
Reaction score
135
Points
63
owncode.png
Да, очевидно, не вставил код класса TaskHelper в общий код
Вставил, вместо "// Insert your code here"
 

DmitryAk

Client
Joined
Dec 14, 2016
Messages
860
Reaction score
824
Points
93
Теперь еще раз внимательно читаем инструкцию:
Класс вставляем в общий код после
  • namespace ZennoLab.OwnCode
  • {
 
  • Thank you
Reactions: bizzon

inbox

Client
Joined
Nov 11, 2018
Messages
11
Reaction score
3
Points
3
Часто задают вопросы, как запустить шаба из шаба, как управлять, добавить потоки итд.
Люди начинают создавать некошерные батники и прочими образами извращаться, хотя зенка предоставляет не очень приличный, но достаточный api для решения этих вопросов более адекватным путем.
Выкладываю небольшой статический класс упрощающий работу с запуском вторичных шабов.
Спасибо друг, очень пригодился твой код. Систематизировал знания мои.
 

Lord_Alfred

Client
Joined
Oct 9, 2015
Messages
3,916
Reaction score
3,882
Points
113
PS: @DmitryAk спасибо ещё раз за:
C#:
if(((ZennoLab.InterfacesLibrary.ProjectModel.Collections.IContextExt)project.Context).IsInterrupted) return; // Прерывание в ZP
if(Global.Variables.IsProjectMaker && !Global.Variables.IsDebugMode) return; // Прерывание в PM
Очень пригодилось) Правда, пришлось на throw new Exception заменить, а то чет компилятор на return ругался )
 

DmitryAk

Client
Joined
Dec 14, 2016
Messages
860
Reaction score
824
Points
93
Да пожалуйста)
Очень пригодилось) Правда, пришлось на throw new Exception заменить, а то чет компилятор на return ругался )
Ну ретурн, это для сниппетов - выход по красной олд стайле или войд функций - мягкое прерывание без ошибок)
 
  • Thank you
Reactions: Lord_Alfred

Users Who Are Viewing This Thread (Total: 1, Members: 0, Guests: 1)