myDC.ru

Здравствуйте, гость ( Вход | Регистрация )

 
 
Ответить в данную темуНачать новую тему

> Особенности приготовления PtokaX, Некоторые особенности работы скриптов на данном хабе

Теги
Нет тегов для показа
Enyby
сообщение 19.1.2012, 2:36
Сообщение #1


Освоившийся участник
*****

Группа: Пользователи
Сообщений: 391
Регистрация: 4.11.2009
Из: Дом
Пользователь №: 4 923
Спасибо сказали: 239 раз




Итак. Вводная:

HubVersion = 0.4.1.1
LuaVersion = Lua 5.1
OS = Windows_NT

Теперь по порядку.
  • Первый момент который меня поразил - при передаче измененного MyINFO в MyINFOArrival, оно уже отпарсено и изменения внесены в таблицу tUser. Так что искать там отличия бесполезно. Хотя по логике, казалось бы, обработка после успешного возврата. Из этого следует интересный факт: return true в данной функции не запретит обработку команды хабом, поскольку она вызывается ДО скриптов. Это только запрещает дальнейшую обработку другими скриптами.
  • Второй момент. Если вы возьмете всех юзеров командой Core.GetOnlineUsers(), посчитаете их количество через for ipairs(), а потом сравните с Core.GetUsersCount(), то не всегда эти два числа будут совпадать. Это особенно актуально, если у вас в скрипте есть таймер с малым временем перезапуска. Дело в том, что есть такие моменты при входе юзера, когда UserConnected уже вызвана, Core.GetUsersCount() возвращает увеличенное значение, а Core.GetOnlineUsers() - не возвращает этого юзера в результирующей таблице.


Думаю эта информция будет не лишней для разработчиков скриптов.


Спасибо сказали:
Go to the top of the page
+Quote Post
Enyby
сообщение 22.1.2012, 22:58
Сообщение #2


Освоившийся участник
*****

Группа: Пользователи
Сообщений: 391
Регистрация: 4.11.2009
Из: Дом
Пользователь №: 4 923
Спасибо сказали: 239 раз




Продолжая тему. Предлагаю вашему вниманию простой скрипт:
Код
local iCheckInterval = 1

function OnStartup()
    TmrMan.AddTimer(iCheckInterval, "CheckPtokaX")
end

function CheckPtokaX()
    local sReport = ""
    local iDelta = 0
    local iCount = Core.GetUsersCount()
    local tUsers = Core.GetOnlineUsers()
    iDelta = iCount
    for _, _ in ipairs(tUsers) do
        iDelta = iDelta - 1
    end
    if iDelta ~= 0 then
        sReport = sReport.."ipairs = "..iDelta.."\n"
    end
    iDelta = iCount
    for _, _ in pairs(tUsers) do
        iDelta = iDelta - 1
    end
    if iDelta ~= 0 then
        sReport = sReport.."pairs = "..iDelta.."\n"
    end
    iDelta = iCount - #tUsers
    if iDelta ~= 0 then
        sReport = sReport.."# = "..iDelta.."\n"
    end
    if sReport ~= "" then
        Core.SendToOps(sReport)
    end
end

Суть проста, собрать всех пользователей через Core.GetOnlineUsers(), а потом сравнить число полученных пользователей с числом, возвращаемым Core.GetUsersCount(). Как уже было сказано, эти два числа не всегда могут быть одинаковыми. Но на одном хабе я обнаружил что второе количество (Core.GetUsersCount()) ПОСТОЯННО больше первого. "Постоянно" это значит, в рамках достаточно длительного интервала времени. Думаю что после старта хаба все нормально.


Спасибо сказали:
Go to the top of the page
+Quote Post
Setuper
сообщение 23.1.2012, 9:09
Сообщение #3


RusHub team lead
**************

Группа: Модераторы
Сообщений: 4 030
Регистрация: 20.6.2008
Из: г. Королёв (Моск. обл.)
Пользователь №: 46
Спасибо сказали: 1708 раз




Тут всё дело в том, что функция Core.GetUsersCount() возвращает полностью вошедших юзеров, то есть тех, кто прошёл все стадии входа, в отличие от функции Core.GetOnlineUsers(), которая возвращает всех пользователей, даже тех, которые только входят (находятся на какой-то стадии входа).

Кстати, в русхабе для этого сделана такая фишка:
Core.GetUsers() - таблица со всеми вошедшими пользователями хаба.
Core.GetUsers(true) - таблица со всеми пользователями хаба, даже которые только входят и ещё не вошли.
Go to the top of the page
+Quote Post
Enyby
сообщение 23.1.2012, 9:14
Сообщение #4


Освоившийся участник
*****

Группа: Пользователи
Сообщений: 391
Регистрация: 4.11.2009
Из: Дом
Пользователь №: 4 923
Спасибо сказали: 239 раз




Нет.
Core.GetUsersCount() - возвращает общее число юзеров завершивших вход + число юзеров, находящихся на разных этапах входа.
Core.GetOnlineUsers() - Возвращает "виртуальную" таблицу пользователей tAllUsers, в которой содержатся пользователи прошедшие процедуру входа.
Фишка в том, что вызов UserConnected и подобных их функций происходит ДО завершения процедуры входа. После возврата из нее проходит некоторое время и только потом этот пользователь появляется в отдаче Core.GetOnlineUsers().
Go to the top of the page
+Quote Post
Setuper
сообщение 23.1.2012, 9:19
Сообщение #5


RusHub team lead
**************

Группа: Модераторы
Сообщений: 4 030
Регистрация: 20.6.2008
Из: г. Королёв (Моск. обл.)
Пользователь №: 46
Спасибо сказали: 1708 раз




Ну да, я это и имел ввиду. Только немного наоборот написал big_smile.gif
Go to the top of the page
+Quote Post
Enyby
сообщение 23.1.2012, 11:13
Сообщение #6


Освоившийся участник
*****

Группа: Пользователи
Сообщений: 391
Регистрация: 4.11.2009
Из: Дом
Пользователь №: 4 923
Спасибо сказали: 239 раз




Кстати, из этого следует:
  • Core.SendToAll и прочие ALL функции работают только с теми пользователями, которые находятся в виртуальной таблице tAllUsers, возвращаемой Core.GetOnlineUsers(), а, поскольку, на момент вызова Connected функций, пользователь туда не занесен, то Core.SendToAll не пришлет этому пользователю отправленный текст. (Попадет он туда примерно через 7/64 с после завершения Connected функции. Время может вариироваться в зависимости от нагрузки хаба, текущего железа и выполняемых скриптов.)

К слову Disconnected функции вызываются ДО удаления этого пользователя из виртуальной таблицы tAllUsers.

ADD:
Провел дополнительные тесты. Все не так уж плохо, как кажется на первый взгляд. Все намного хуже. big_smile.gif
Итак. Процедура входа пользователя:
  1. SupportsArrival (tUser, sData)
  2. ValidateNickArrival (tUser, sData)
  3. VersionArrival (tUser, sData)
  4. GetNickListArrival (tUser, sData)
  5. MyINFOArrival (tUser, sData)
  6. UserConnected (tUser, sData)
  7. Core.GetUsersCount = Core.GetUsersCount + 1
  8. CallTimer
  9. CallTimer
  10. CallTimer
  11. CallTimer
  12. CallTimer
  13. CallTimer
  14. CallTimer
  15. MOTD
  16. table.insert(tAllUsers, tUser)

CallTimer означает что здесь успела вызваться функция таймера с минимальным интервалом. Если в это время будет запущена какая либо-функция, то в ее коде будет выполнятся следующее условие:
Код
#Core.GetOnlineUsers() ~= Core.GetUsersCount()

Так что вношу поправку к предыдущему посту:
Core.GetUsersCount() - возвращает общее число юзеров завершивших вход + число юзеров, находящихся на конечном этапе процедуры входа (после вызова Connected функции).

ADD:
Последствия вышесказанного:
Используя код, наподобие:
Код
function OnStartup()
    for _, tUser in ipairs(Core.GetOnlineUsers()) do
        -- do something
    end
end

Вы рискуете потерять всех пользователей "находящихся на конечном этапе процедуры входа (после вызова Connected функции)", если ваш скрипт будет стартовать в какой-то из промежутков CallTimer. Для маленьких хабов это не особо актуально, но для больших хабов это проблема.

И да, то что CallTimer у меня всего 7, это не значит что их не может быть больше или меньше.

ADD:
Еще одно дополнение.
Если вызвать Core.Disconnect в UserConnected, то вызова UserDisconnected не будет!
Общее утверждение: Пока не завершена процедура входа, юзер не считается вошедшим и для него не вызывается UserDisconnected.

Теперь интересный момент. Это когда Core.Disconnect вызывается между Core.GetUsersCount = Core.GetUsersCount + 1 и table.insert(tAllUsers, tUser). big_smile.gif
Ничего криминального не происходит, однако UserDisconnected вызывается. После вызова выполняется: Core.GetUsersCount = Core.GetUsersCount - 1 и все живет как жило.
Go to the top of the page
+Quote Post
Setuper
сообщение 23.1.2012, 16:40
Сообщение #7


RusHub team lead
**************

Группа: Модераторы
Сообщений: 4 030
Регистрация: 20.6.2008
Из: г. Королёв (Моск. обл.)
Пользователь №: 46
Спасибо сказали: 1708 раз




Итог - очень не удобно. И это далеко не все недостатки птохи big_smile.gif
Go to the top of the page
+Quote Post
Enyby
сообщение 23.1.2012, 16:42
Сообщение #8


Освоившийся участник
*****

Группа: Пользователи
Сообщений: 391
Регистрация: 4.11.2009
Из: Дом
Пользователь №: 4 923
Спасибо сказали: 239 раз




  • Core.GetUsersCount()
    Просто выводит переменную ui32Logged.
  • Core.GetOnlineUsers()

    Выводит таблицу пользователей. Кстати, если передать в функцию -2, то результат будет аналогичен вызову без параметров.
    Код ответственный за вывод:
    Код
            if(curUser->iState == User::STATE_ADDED) {
                    lua_pushnumber(L, ++i);
                    ScriptPushUser(L, curUser, bFullTable);
                    lua_rawset(L, t);
                }


Теперь если посмотреть процедуру входа, то там будет такая картина:
  1. Все происходит в рамках очереди получения.
  2. Вызов Connected функции.
  3. Если после вызова юзер имеет статус закрытия, то передаем всем остальным скриптам по очереди, но не обрабатываем дальше.
  4. Скрипты закончены. Идет выделение памяти.
  5. Вызов проверки на подозрительный тэг.
  6. Добавление в служебный список пользователей (список MyINFO, IP и прочего).
  7. ui32Logged++;
  8. Состояние устанавливается в User::STATE_ADDME_2LOOP
  9. Общая шара увеличивается на шару юзера. // еще один глюк связанный с тем что если посчитать всю шару через Core.GetOnlineUsers(), то она не всегда будет совпадать с этой переменной.
  10. Проверка на превышения пика юзеров. Если есть, то пик обновляется. // снова, если мониторить в скрипте через Core.GetOnlineUsers() то пики могут быть разными
  11. Отсылаем юзеру $Hello.
  12. Дальнейшая обработка присланных команд.
  13. Через некоторое время прошлая очередь (приема) завершается и стартует новая очередь, очередь отправки. Время зависит от количества команд во входящей и позиции в исходящей очереди нашего пользователя.
  14. Из состояния User::STATE_ADDME_2LOOP он переходит в User::STATE_ADDED
  15. Добавление в общий список пользователей и появление юзера в Core.GetOnlineUsers()
  16. Отправка MOTD ну и дальше по накатанной.
Go to the top of the page
+Quote Post
Enyby
сообщение 28.1.2012, 23:13
Сообщение #9


Освоившийся участник
*****

Группа: Пользователи
Сообщений: 391
Регистрация: 4.11.2009
Из: Дом
Пользователь №: 4 923
Спасибо сказали: 239 раз




Теперь немного о вещах, которые проистекают из вышеописанного.
Как уже было сказано, если выполняется отключение юзера, не важно сам он это сделал или скрипт, во время UserConnected, то UserDisconnected вызвано не будет.
Это может создавать несовместимость скриптов.
Допустим у нас есть два скрипта. Скрипт А - реализует защиту и выполняет какие-то проверки для пользователя в UserConnected. При не прохождении попытки вызывается Core.Disconnect. Скрипт Б - занимается чем-то с учетом ников пользователей. т. е. он содержит таблицу пользователей, пополняемую при входе и сокращаемую при выходе. Допустим у нас есть две версии этого скрипта: Б1 - выше А и Б2 - ниже А.
Теперь рассмотрим ситуацию, когда пользователь будет отключен в скрипте А:
  1. Б1: UserConnected - нормальная обработка, заносим пользователя в таблицу
  2. А: UserConnected - обнаружили, что пользователь не подходит, вызвали Core.Disconnect
  3. Б2: UserConnected - нормальная обработка, заносим пользователя в таблицу

Обработка завершена. Оба скрипта и Б1 и Б2 имеют фейкового юзера, который был добавлен в таблицу, но которого нет на хабе. UserDisconnected для него вызвано не будет. Т. е. этому багу подвержены все скрипты, как выше, так и ниже отключающего скрипта А.
Go to the top of the page
+Quote Post
Setuper
сообщение 28.1.2012, 23:22
Сообщение #10


RusHub team lead
**************

Группа: Модераторы
Сообщений: 4 030
Регистрация: 20.6.2008
Из: г. Королёв (Моск. обл.)
Пользователь №: 46
Спасибо сказали: 1708 раз




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


Спасибо сказали:
Go to the top of the page
+Quote Post
Enyby
сообщение 29.1.2012, 0:10
Сообщение #11


Освоившийся участник
*****

Группа: Пользователи
Сообщений: 391
Регистрация: 4.11.2009
Из: Дом
Пользователь №: 4 923
Спасибо сказали: 239 раз




Кстати, насчет функций. KeyArrival не вызывается на Win версии, даже если в командной строке НЕ указано /nokeycheck. Пытался отследить это через исходники - ничего не нашел.
Go to the top of the page
+Quote Post
Setuper
сообщение 29.1.2012, 0:38
Сообщение #12


RusHub team lead
**************

Группа: Модераторы
Сообщений: 4 030
Регистрация: 20.6.2008
Из: г. Королёв (Моск. обл.)
Пользователь №: 46
Спасибо сказали: 1708 раз




Ага этот недочёт тянется ещё с ранних версий, то есть эта функция никогда не работала)))
Go to the top of the page
+Quote Post
Ksan
сообщение 29.1.2012, 9:07
Сообщение #13


Белый Волк
*********

Группа: Пользователи
Сообщений: 1 723
Регистрация: 11.9.2008
Из: г.Томск
Пользователь №: 516
Спасибо сказали: 657 раз




Цитата
UserDisconnected для него вызвано не будет. Т. е. этому багу подвержены все скрипты, как выше, так и ниже отключающего скрипта А.

Получается, что в скрипте А желательно после дисконнекта юзера провести операцию чистки таблицы юзеров хаба (попросту говоря, удалить юзера)?
Это прокатит при случае, когда скрипт Б стоит выше. Но прокатит ли, когда он ниже? Не останется ли юзер в таблице, потому что в табицу занесёт скрипт Б?
Тут же есть нюансы одновременности/неодновременности операций в разных скриптах при выполнении функции UserConnected или есть однозначный ответ?
А ведь может быть больше одного скрипта, заносящего каких-то юзеров в свою таблицу по своим категориям, в которые может попасть юзер, скинутый скриптом А.
Наверно, надо проверить это.

PS: Кстати, я тоже замечал, что один скрипт скидывает юзера при входе (ну так ему велено по условию) и сообщает мне, а другой стоит ниже и мне тоже сообщает, что зашёл такой-то юзер (выполняется другое условие big_smile.gif ). Хорошо, что я помню, что юзер уже скинут..Хотя вообще вначале я надеялся (ну логично же), что второй скрипт в таком случае уже не получит вхождение.
Go to the top of the page
+Quote Post
Enyby
сообщение 29.1.2012, 11:37
Сообщение #14


Освоившийся участник
*****

Группа: Пользователи
Сообщений: 391
Регистрация: 4.11.2009
Из: Дом
Пользователь №: 4 923
Спасибо сказали: 239 раз




Нет, юзера в таблице не будет. Между UserConnected и появлением юзера в списке пользователей происходит какое-то время, а если в каком-то скрипте вызвано Disconnect, во время того, как идет это время, или в коде UserConnected, то юзер вообще не появляется в общей таблице юзеров.
Когда я говорил что скрипты Б1 и Б2 заносят юзера в таблицу, я имел в виду занесение пользователей во внутренние таблицы этих скриптов.
Они не доступны из скрипта А. так что там ничего сделать нельзя. и сделать скрипт А не подверженным этому багу можно только в одном случае - вызывать Disconnect, или до UserСonnected, или после, когда пользователь появится в общем списке пользователей.
Реализацию можно сделать через таблицу ников которые нужно отключить и таймер, который получает таблицу со всеми юзерами и смотрит, есть ли там нужный ник, если есть, то скрипт его отключает.
Для скриптов Б1 и Б2 нужно предусматривать свою защиту. У меня, например, в User Mode Fixer проверяется на соответствие число юзеров на хабе и число юзеров во внутренней таблице. Все это в таймере главного цикла. Если происходит расхождение этих двух чисел, то стартует очистка, все юзеры которые есть на хабе - добавляются ко мне, путем прямого вызова UserConnected для них, а все юзеры, которые есть у меня, но хаб на них возвращает nil, вместо таблицы пользователя - удаляются вызовом функции очистки. По хорошему там надо было бы вызвать UserDisconnected, но у меня нет таблицы юзера, которая нужна, чтобы передать в эту функцию (юзер то вышел уже).

Насчет PS - в этом случае багу подвержены были бы все скрипты, находящиеся выше, отключающего скрипта. Что, конечно, лучше, чем все скрипты, но все равно не самая лучшая ситуация.

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

ADD:
Чтобы было понятнее работа скриптов сделал диаграмму.
Прикрепленный файл  PtokaX.png ( 83.91 килобайт ) Кол-во скачиваний: 142
Go to the top of the page
+Quote Post
Setuper
сообщение 29.1.2012, 12:57
Сообщение #15


RusHub team lead
**************

Группа: Модераторы
Сообщений: 4 030
Регистрация: 20.6.2008
Из: г. Королёв (Моск. обл.)
Пользователь №: 46
Спасибо сказали: 1708 раз




А что за "обычная работа скрипта" ?
Это что-то непонятное, ибо все работы скриптов являются событийными, то есть порождаются каким-то событием.

Там должна стоять просто внутренняя обработка безо всяких обычных работ скрипта.

Или под обычной работой скрипта подразумевается работа таймерных функций?
Go to the top of the page
+Quote Post
Enyby
сообщение 29.1.2012, 13:02
Сообщение #16


Освоившийся участник
*****

Группа: Пользователи
Сообщений: 391
Регистрация: 4.11.2009
Из: Дом
Пользователь №: 4 923
Спасибо сказали: 239 раз




Ну там таймеры и прочее. Если говорить в контексте данного пользователя, то это будут таймеры + Arrival'ы остальных команд данного пользователя.
Не захотел расписывать, ибо это не критично для рассматриваемой ситуации.

ADD:
Можно добавить туда блок "есть события?" -> "вызываем обработчиков событий скрипта" или что-то подобное. Имхо, это не важно в данном контексте.
Go to the top of the page
+Quote Post

Ответить в данную темуНачать новую тему
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

Collapse

> Похожие темы

  Тема Ответов Автор Просмотров Последнее сообщение
No New Posts Перехват выполнения бана(ов) PtokaX
Возможно ли?
0 MIKHAIL 1 220 1.8.2022, 10:31 Посл. сообщение: MIKHAIL
No new Topic has attachmentsУстановка хаба PtokaX 0.5.2.2 на роутер под прошивкой LEDE 2017
DC++ сервер в роутере
15 мамин_парень 18 281 29.1.2021, 8:02 Посл. сообщение: мамин_парень
No new ВАЖНО: Topic has attachmentsPtokaX 0.5.0.1 Mod
Модификация PtokaX от alex82
112 alex82 108 690 13.9.2019, 17:57 Посл. сообщение: CyberGhost404
No new Topic has attachmentsPtokaX 0.5.2.1 Mod
Модификация PtokaX от alex82
17 alex82 22 304 22.8.2019, 12:27 Посл. сообщение: SergSat
No New Posts Ptokax 0.5.0.2
Crash-14.11.2014-01.11.48.log
8 Drakula 13 403 6.6.2019, 15:09 Посл. сообщение: avalon
No New Posts Topic has attachmentsПрошивка LEDE 17.01.4 для 740n v4,v5 c PtokaX 0.5.0.1
Готовая прошивка с поддержкой сервера DC++, все влезло в 4мб ))
1 мамин_парень 6 400 10.3.2018, 15:29 Посл. сообщение: мамин_парень
No New Posts Ptokax, opendchub (DC++) - Сборка пакета для OpenWRT, LEDE 2017
Пакеты хабов для прошивки роутера
0 мамин_парень 5 577 29.8.2017, 7:00 Посл. сообщение: мамин_парень
No new Topic has attachmentsАнтиреклама для PtokaX
API1, API2 | Скрипт антирекламы для чата и лички
39 Damaks 56 877 9.8.2017, 14:26 Посл. сообщение: Ksan
No new ВАЖНО: Topic has attachmentsPtokaX
Описание. Публикация новых версий
94 Svyat 186 650 11.4.2017, 23:08 Посл. сообщение: Alexey
No new Topic has attachmentsPtokaX в OpenWrt (Linux)
Ребята как собрать под эту систему?
21 мамин_парень 29 614 10.4.2017, 15:19 Посл. сообщение: мамин_парень
No New Posts Автозапуск PtokaX на Rassberry Pi?
Не могу запустить
13 Sezam 15 664 7.11.2016, 9:14 Посл. сообщение: Saymon21
No New Posts Доска обьявлений для Ptokax 0.5.0.x
3 NightmareUA 8 491 11.8.2016, 16:22 Посл. сообщение: Ksan
No New Posts FreeBSD 11.0 & PtokaX
Проблема подключения в клиенте PtokaX по имени
5 nsd7 8 981 22.4.2016, 3:47 Посл. сообщение: Saymon21
No New Posts От: PtokaX 0.5.2.1 Mod
От темы с ID: 5784
0 Alexey 4 542 21.4.2016, 18:16 Посл. сообщение: Alexey
No New Posts Перенос базы пользователей с RusHub на PtokaX
3 Angel_D 8 908 5.12.2015, 2:11 Посл. сообщение: Saymon21

 



RSS Сейчас: 27.11.2024, 1:44