Kruzya
Участник
- Сообщения
- 12,970
- Реакции
- 10,914
- Команда форума
- #1
Все наверное знают или пользовались такими функциями, как SQL_TConnect() или SQL_TQuery(), которые по завершению работы вызывают переданную им функцию. Вот мне на днях понадобилось сделать что-то подобное.
Есть три плагина:
Меня это не устраивало, и я решил, что надо в плагин sourcebans.smx (т. н. ядро) добавить натив, который будет делать запрос к БД, и возвращать результат в переданный каллбек. Подобно функции SQL_TQuery(), да, но без хендла БД (оно и ясно почему).
В этой небольшой статье я распишу, как можно это сделать.
Для начала, в include-файле своего плагина надо написать "слепок" каллбека. Чтобы это сделать, надо приблизительно представить, что на каллбек должно передаваться. Поскольку у меня ф-ия выполнения запроса к БД, то я решил, что каллбек должен вызываться с тремя аргументами:
Вообще, желательно такое писать на английском, но для примера, я буду писать всё на русском.
Теперь, нам нужен натив, вызывая который, плагины будут передавать свой каллбек, кастомные данные и, собственно, запрос. Ещё можно разрешить передавать приоритет. У меня получился такой натив:
Теперь можно писать, собственно, сам натив :)
Открываем свой плагин (у меня sourcebans.sp), ищем форвард AskPluginLoad2() (или создаём вручную, если он до сих пор не существует) и добавляём в нём строчку создания Вашего натива.
Теперь, нам необходимо создать функцию, которая, собственно, будет обрабатывать запрос.
Вот так просто можно создать натив, в который передаётся функция, которая рано или будет вызвана. Можно придумать множество использований таких ф-ий. Как пример, достаточно посмотреть на VIP-ядро от R1KO. В него тоже передаются функции-каллбеки при создании VIP-функции.
Есть три плагина:
- sourcebans.smx
- sourcecomms.smx
- sbchecker.smx
Меня это не устраивало, и я решил, что надо в плагин sourcebans.smx (т. н. ядро) добавить натив, который будет делать запрос к БД, и возвращать результат в переданный каллбек. Подобно функции SQL_TQuery(), да, но без хендла БД (оно и ясно почему).
В этой небольшой статье я распишу, как можно это сделать.
Для начала, в include-файле своего плагина надо написать "слепок" каллбека. Чтобы это сделать, надо приблизительно представить, что на каллбек должно передаваться. Поскольку у меня ф-ия выполнения запроса к БД, то я решил, что каллбек должен вызываться с тремя аргументами:
- DBResultSet. Собственно, сами данные из БД, если это SELECT-запрос.
- char[]. Строка с ошибкой, если такая появилась при выполнении.
- any. Некоторые данные, которые были переданы на натив выполнения запроса, и должны вернуться в каллбек для идентификации запроса.
PHP:
// Каллбек для запросов к БД СБ.
//
// @param hDBResults Результаты запроса. null, если нечего вернуть.
// @param szError Строка с текстом ошибки, если таковая произошла.
// @param data Кастомные параметры, переданные из вызванного натива.
typedef SBDBCallback = function void(DBResultSet hDBResults, const char[] error, any data);
Теперь, нам нужен натив, вызывая который, плагины будут передавать свой каллбек, кастомные данные и, собственно, запрос. Ещё можно разрешить передавать приоритет. У меня получился такой натив:
PHP:
/*********************************************************
* Выполняет запрос к БД SourceBans в отдельном потоке.
*
* @param szQuery Строка с запросом. Используйте в нём {{prefix}}
* в тех местах, где необходимо подставить
* префикс таблиц.
* @param funcCall Каллбек.
* @param prio Приоритет для запроса.
* @param data Кастомные данные. Вернутся в каллбеке.
* @noreturn
*********************************************************/
native void SBProcessQuery(char[] szQuery, SBDBCallback funcCall, DBPriority prio = DBPrio_Normal, any data = 0);
Открываем свой плагин (у меня sourcebans.sp), ищем форвард AskPluginLoad2() (или создаём вручную, если он до сих пор не существует) и добавляём в нём строчку создания Вашего натива.
PHP:
CreateNative("SBProcessQuery", Native_DBQuery);
PHP:
// сам натив
public int Native_DBQuery(Handle hPlugin, int iNumParams) {
char szQuery[4096];
GetNativeString(1, szQuery, sizeof(szQuery));
ReplaceString(szQuery, sizeof(szQuery), "{{prefix}}", DatabasePrefix, true);
DataPack hDatapack = CreateDataPack();
WritePackCell(hDatapack, view_as<int>(hPlugin)); // Хендл плагина нам пригодится при вызове функции.
WritePackFunction(hDatapack, GetNativeFunction(2));
WritePackCell(hDatapack, GetNativeCell(4));
#if defined DEBUG
char szPluginName[PLATFORM_MAX_PATH];
GetPluginFilename(hPlugin, szPluginName, sizeof(szPluginName));
LogToFile(logFile, "Processing custom query for plugin %s: %s", szPluginName, szQuery);
#endif
SQL_TQuery(DB, PluginQueriesCallback, szQuery, hDatapack, view_as<DBPriority>(GetNativeCell(3)));
}
// каллбек запроса
public void PluginQueriesCallback(Handle owner, Handle hndl, char[] error, any data) {
ResetPack(data);
Handle hPlugin = view_as<Handle>(ReadPackCell(data));
Call_StartFunction(hPlugin, ReadPackFunction(data));
Call_PushCell(view_as<int>(hndl));
Call_PushString(error);
Call_PushCell(ReadPackCell(data));
Call_Finish();
delete data;
}