Роботы, плагины и скрипты к чату MyChat. Разработка альтернативных клиентов и различных утилит. Технические вопросы по программированию, замечания и предложения по развитию API
Аватара пользователя
ChimMAG
Скрипт раз в час пробегает всех пользователей и

Код: Выделить всё
//Автоматически добавляем новых пользователей в общий список контактов
//и удаляем оттуда заблокированных
var i:integer;
   UserActive:string;
begin
   for i:=2 to mGetMaxRegisteredUIN do
    begin
      //1. Удаляем заблокированных
      UserActive:=mGetUserAttribute(i,'Active'); //0-заблочен, 1-включён, пустая строка - нет такого
      //if (UserActive='0') and (Length(mGetUserDepartmentName(i))>0) then mDeleteUserFromCommonContacts(i);
      if (UserActive='0') and (mGetUserDepartmentID(i)>0) then mDeleteUserFromCommonContacts(i);
      //Добавляем новых пользователей в общий список контактов
      if (UserActive='1') and (mGetUserDepartmentID(i)=-1) then mAddUserToCommonContacts(i,1);
    end;
       
    //Синхронизируем список контактов
    mCommonContactsRebuild;
end.


Результат:
Ошибка #167: в скрипте "CommonContacts из события "hour" обнаружена ошибка: "Script timed out". Скрипт не выполнен
Ошибка #130: скрипт "CommonContacts" отключен из-за превышения времени выполнения (5288 ms)


Скрипт начинает выполняться и... Галка "Отключать скрипты из-за превышения времени выполнения" НЕ СТОИТ, но всё равно после 5 секунд (и всегда менее 6) скрипт останавливается. Специально проверил - проблема в функции mDeleteUserFromCommonContacts - комментирование этой строки даёт время выполнения в 234мс. Я даже пробовал заменить первоначальную функцию
Код: Выделить всё
Length(mGetUserDepartmentName(i))>0
на
Код: Выделить всё
mGetUserDepartmentID(i)>0
в надежде, что это даст некий прирост производительности, но нет.

Я понимаю, что через некоторое время всё-таки, путём многократных запусков (а каждый раз оно часть работы проделывает и в следующий раз уже обработанные контакты пропускаются быстро) дойдётся всё до конца и дальше будет работать нормально, ибо в дальнейшем не будет массовых добавлений/удалений пользователей из общего списка контактов. Но всё же три вопроса остаются:
    - почему (или где настраивается) выкидывает по таймауту?
    - как в итоге выполнять такие скрипты (иногда они могут быть и разовыми, просто что бы облегчить ручную тупую работу)
    - что за ошибки #167 и #130? Они в виде ссылок, но она не ведёт на справку по ним.
Аватара пользователя
Алексей Пикуров
Скрипт работает слишком долго и сервер прерывает его выполнение. Он очень неоптимально написан.

Сделайте так:

Код: Выделить всё
const
  GROUP_NAME = 'Сотрудники компании';
var
  sUsersList, sUserActive: string;
  iUIN, iGroupID: integer;
begin
  SetScriptTimeOut(10000);
 
  iGroupID := mGetDepartmentIDByTextPath(GROUP_NAME);
  sUsersList := mGetUsersListByParams('online') + ',' + mGetUsersListByParams('offline');
 
    while length(sUsersList) > 0 do begin
      iUIN := StrToIntDef(Fetch(sUsersList, ','), -1);
     
        if iUIN <> -1 then begin
          sUserActive := mGetUserAttribute(iUIN, 'Active');
         
            if (sUserActive = '0') and (mGetUserDepartmentID(iUIN) > 0) then
              mDeleteUserFromCommonContacts(iUIN)
            else if (sUserActive = '1') and (mGetUserDepartmentID(iUIN) = -1) then
              mAddUserToCommonContacts(iUIN, iGroupID);
        end;
    end;

  mCommonContactsRebuild;
end.

По ошибкам я дополню справку.
Аватара пользователя
Алексей Пикуров
P.S. Дополнительно оптимизировали функцию mDeleteUserFromCommonContacts, обновите сервер, дистрибутив уже на сайте.

Функция автоматически пересобирала общий список контактов + рассылала изменения всем онлайн-клиентам. Убрали это за ненужностью.
Аватара пользователя
ChimMAG
Посмотрел. Отличие в том, что у вас собирается ТОЛЬКО существующие пользователи. Я тоже хотел этим способом, но у меня получалось более сложным, чем у вас, путём и поэтому пошёл через простой цикл с счётчиком. Возьму на заметку, спасибо. Вообще была мысль предложить вам реализовать функции IncUIN и PredUIN для удобства [smilie=biggrin.gif]
Правда у вас тогда лишнее условие "if iUIN <> -1 then" - по определению нам не должны попадаться такие UINы. Кроме того, насколько я понимаю пропуск отсутствующих UINов проходит очень быстро и не особо влияет на производительность (маловероятно, что будут миллионы UINов задействованы, в таком случае глобальные проблемы со временем выполнения скрипта будут по другим причинам [smilie=biggrin.gif]).
А вот SetScriptTimeOut - я пропустил эту команду, искал в скриптах. Она бы очень помогла. И понятно почему после 5 секунд останавливался. Правда в данном случае не 10 секунд, а больше, но это частности.
И с оптимизацией функции тоже здорово.
Сейчас всё обработалось и уже выполняется без ошибок (сервер пока ещё не обновлял, просто дошло в итоге до конца и теперь нет массовых изменений списка контактов). Спасибо.
Аватара пользователя
Алексей Пикуров
Правда у вас тогда лишнее условие "if iUIN <> -1 then"

Не лишнее. Это условие сделано для анализа строки-списка UIN-ов. Если после выполнения

Код: Выделить всё
sUsersList := mGetUsersListByParams('online') + ',' + mGetUsersListByParams('offline');

Получится, что если онлайн никого не было, то строка будет выглядеть как ",1,2,3" и т.п., в начале строки будет просто запятая. Аналогично и для обратного случая, все онлайн, а офлайн никого, запятая будет в конце.

Функция StrToIntDef при преобразовании строки в число, если ей передадут туда не число, а пустую строку или какую-то ерунду, вернёт -1. Это значение мы и пропускаем.

Можно переписать скрипт ещё вот так (с учётом опции "All" для функции mGetUsersListByParams):

Код: Выделить всё
const
  GROUP_NAME = 'Сотрудники компании';
var
  sUsersList, sUserActive: string;
  iUIN, iGroupID: integer;
begin
  SetScriptTimeOut(10000);
 
  iGroupID := mGetDepartmentIDByTextPath(GROUP_NAME);
  sUsersList := mGetUsersListByParams('all');
 
    while length(sUsersList) > 0 do begin
      iUIN := StrToInt(Fetch(sUsersList, ','));
      sUserActive := mGetUserAttribute(iUIN, 'Active');
         
        if (sUserActive = '0') and (mGetUserDepartmentID(iUIN) > 0) then
          mDeleteUserFromCommonContacts(iUIN)
        else if (sUserActive = '1') and (mGetUserDepartmentID(iUIN) = -1) then
          mAddUserToCommonContacts(iUIN, iGroupID);
    end;

  mCommonContactsRebuild;
end.

По ошибкам справка дополнена:
#0130: скрипт "XXX" отключен из-за превышения времени на выполнение (NNN ms)
#0167: в скрипте "XXX" из события "YYY" обнаружена ошибка: "ERROR". Скрипт не выполнен
Аватара пользователя
ChimMAG
Всё, тогда вопрос закрыт. Огромное спасибо.
Аватара пользователя
Алексей Пикуров
Пожалуйста. Добавили две функции mIncUIN и mDecUIN для перебора зарегистрированных пользователей по одному.