Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- ПРОТОТИП: диспетчер внешних команд без центрального switch.
- Идея:
- 1. Модуль регистрирует handler на конкретный command_id при Init.
- 2. Poll читает строки из `external_commands` и зовёт только нужный callback.
- 3. Lifecycle (OK / BAD_REQUEST / DELETE / WAIT_RESPONSE) остаётся здесь.
- Пример в модуле:
- public: FamilyTabletInit()
- {
- ExternalCommands:Register(COMMAND_FML_UPLOAD_LOGO, "FamilyTablet_OnExtUploadLogo");
- }
- public: FamilyTablet_OnExtUploadLogo(sql_id, command_type, data_1, data_2, data_3, data_string_1[])
- {
- if (data_1)
- return COMMAND_STATE_OK; // старый формат — пропускаем
- if (isnull(data_string_1))
- {
- ExternalCommands:SetResponse("Error: Empty logo upload data");
- return COMMAND_STATE_BAD_REQUEST;
- }
- FamilyTablet:UploadLogo(data_string_1);
- return COMMAND_STATE_OK;
- }
- Текущий external_commands.pwn этим файлом не заменяется — это набросок архитектуры.
- */
- #if defined _external_commands_dispatch_included
- #endinput
- #endif
- #define _external_commands_dispatch_included
- #define ExternalCommands:%0(%1) ExtCmd_%0(%1)
- #if !defined MAX_EXTERNAL_COMMANDS
- #define MAX_EXTERNAL_COMMANDS 256
- #endif
- #if !defined EXT_CMD_CALLBACK_LEN
- #define EXT_CMD_CALLBACK_LEN 48
- #endif
- // Типы команд
- enum
- {
- COMMAND_TYPE_EXECUTE = 1,
- COMMAND_TYPE_WAIT_RESPONSE,
- COMMAND_TYPE_PROCESS
- }
- // Статусы ответа
- enum
- {
- COMMAND_STATE_WAIT_RESPONSE = 1,
- COMMAND_STATE_OK,
- COMMAND_STATE_BAD_REQUEST,
- COMMAND_STATE_NOT_IMPLEMENTED,
- COMMAND_STATE_NOT_FOUND,
- COMMAND_STATE_SERVER_ERROR
- }
- /*
- Сигнатура handler'а (обязательно public):
- public: Module_OnExtCmd(sql_id, command_type, data_1, data_2, data_3, data_string_1[])
- {
- // ...
- return COMMAND_STATE_OK;
- }
- Возврат = новый state команды.
- Текст ответа пишется через ExternalCommands:SetResponse(...) либо напрямую в FormatData_256.
- Для async (WAIT_RESPONSE): вернуть COMMAND_STATE_WAIT_RESPONSE и позже вызвать ExternalCommands:Finish(...).
- */
- static stock g_ext_cmd_callback[MAX_EXTERNAL_COMMANDS][EXT_CMD_CALLBACK_LEN];
- // ---------------------------------------------------------------------------
- // API регистрации
- // ---------------------------------------------------------------------------
- stock ExternalCommands:Register(command_id, const callback[])
- {
- if (!(0 <= command_id < MAX_EXTERNAL_COMMANDS))
- {
- printf("[external-commands] Register failed: command_id %d out of range 0..%d", command_id, MAX_EXTERNAL_COMMANDS - 1);
- return 0;
- }
- if (!isnull(g_ext_cmd_callback[command_id]))
- {
- printf("[external-commands] Register overwrite: command_id %d (%s -> %s)", command_id, g_ext_cmd_callback[command_id], callback);
- }
- format(g_ext_cmd_callback[command_id], EXT_CMD_CALLBACK_LEN, "%s", callback);
- printf("[external-commands] registered command_id %d -> %s", command_id, callback);
- return 1;
- }
- stock ExternalCommands:Unregister(command_id)
- {
- if (!(0 <= command_id < MAX_EXTERNAL_COMMANDS))
- return 0;
- g_ext_cmd_callback[command_id][0] = EOS;
- return 1;
- }
- stock bool: ExternalCommands:HasHandler(command_id)
- {
- return (0 <= command_id < MAX_EXTERNAL_COMMANDS) && !isnull(g_ext_cmd_callback[command_id]);
- }
- stock ExternalCommands:SetResponse(const response[])
- {
- strdel(FormatData_256, 0, sizeof FormatData_256);
- strcat(FormatData_256, response);
- return 1;
- }
- /*
- Завершение async-команды (COMMAND_TYPE_WAIT_RESPONSE),
- когда результат известен позже (например после mysql / Shared_InitLoadData).
- */
- stock ExternalCommands:Finish(sql_id, command_state, const response[] = "OK")
- {
- mysql_format(
- mysql,
- FormatData_512,
- sizeof FormatData_512,
- "UPDATE `external_commands` SET response = '%e', `state` = %d WHERE `id` = %d",
- response,
- command_state,
- sql_id
- );
- mysql_tquery(mysql, FormatData_512);
- printf("[external-commands] Finish sql_id=%d state=%d response=%s", sql_id, command_state, response);
- return 1;
- }
- // ---------------------------------------------------------------------------
- // Poll / dispatch
- // ---------------------------------------------------------------------------
- stock ExternalCommands:OnTimerProcess()
- {
- strdel(FormatData_256, 0, sizeof FormatData_256);
- format(
- FormatData_256, sizeof FormatData_256,
- "SELECT *, `command_type` + 0 AS `command_type_int` \
- FROM `external_commands` \
- WHERE `command_type` = %d OR (`command_type` = %d AND `state` = %d)",
- COMMAND_TYPE_EXECUTE,
- COMMAND_TYPE_WAIT_RESPONSE,
- COMMAND_STATE_WAIT_RESPONSE
- );
- mysql_tquery(mysql, FormatData_256, "OnUpdateExternalCommands");
- }
- public: OnUpdateExternalCommands()
- {
- new rows = cache_num_rows();
- for (new idx; idx < rows; idx++)
- {
- new sql_id, command, command_type;
- new data_1, data_2, data_3;
- new data_string_1[256];
- cache_get_value_name_int(idx, "id", sql_id);
- cache_get_value_name_int(idx, "command", command);
- cache_get_value_name_int(idx, "command_type_int", command_type);
- cache_get_value_name_int(idx, "data_1", data_1);
- cache_get_value_name_int(idx, "data_2", data_2);
- cache_get_value_name_int(idx, "data_3", data_3);
- cache_get_value_name(idx, "data_string_1", data_string_1);
- strdel(FormatData_512, 0, sizeof FormatData_512);
- strdel(FormatData_256, 0, sizeof FormatData_256);
- strcat(FormatData_256, "OK");
- printf("[external-commands] process sql_id=%d command=%d type=%d", sql_id, command, command_type);
- new new_state = ExternalCommands:Dispatch(sql_id, command, command_type, data_1, data_2, data_3, data_string_1);
- if (command_type == COMMAND_TYPE_WAIT_RESPONSE)
- {
- // Если handler вернул WAIT_RESPONSE — ответ допишет ExternalCommands:Finish позже.
- if (new_state != COMMAND_STATE_WAIT_RESPONSE)
- {
- ExternalCommands:Finish(sql_id, new_state, FormatData_256);
- }
- }
- else if (command_type == COMMAND_TYPE_EXECUTE)
- {
- mysql_format(mysql, FormatData_512, sizeof FormatData_512, "DELETE FROM `external_commands` WHERE `id` = %d", sql_id);
- mysql_tquery(mysql, FormatData_512);
- }
- }
- return 1;
- }
- stock ExternalCommands:Dispatch(sql_id, command, command_type, data_1, data_2, data_3, data_string_1[])
- {
- if (!(0 <= command < MAX_EXTERNAL_COMMANDS) || isnull(g_ext_cmd_callback[command]))
- {
- format(FormatData_256, sizeof FormatData_256, "Error: Unknown command %d", command);
- printf("[external-commands] no handler for command %d", command);
- return COMMAND_STATE_BAD_REQUEST;
- }
- /*
- CallLocalFunction:
- i = sql_id
- i = command_type
- i = data_1
- i = data_2
- i = data_3
- s = data_string_1
- Возврат callback'а = COMMAND_STATE_*.
- */
- new state = CallLocalFunction(
- g_ext_cmd_callback[command],
- "iiiiis",
- sql_id,
- command_type,
- data_1,
- data_2,
- data_3,
- data_string_1
- );
- if (state <= 0)
- state = COMMAND_STATE_OK;
- return state;
- }
- stock CleanupWaitingExternalCommands()
- {
- strdel(FormatData_256, 0, sizeof FormatData_256);
- mysql_format(
- mysql,
- FormatData_256,
- sizeof FormatData_256,
- "DELETE FROM `external_commands` WHERE `command_type` = %i AND `state` != %i",
- COMMAND_TYPE_WAIT_RESPONSE,
- COMMAND_STATE_WAIT_RESPONSE
- );
- mysql_tquery(mysql, FormatData_256);
- return 1;
- }
- // ---------------------------------------------------------------------------
- // Пример: как выглядит handler в family_tablet (НЕ подключать отсюда)
- // ---------------------------------------------------------------------------
- #if defined EXT_CMD_DISPATCH_EXAMPLES
- public: FamilyTablet_OnExtUploadLogo(sql_id, command_type, data_1, data_2, data_3, data_string_1[])
- {
- #pragma unused sql_id, command_type, data_2, data_3
- // Старый формат от микросервиса (data_1 заполнен) — игнор, ждём новую команду.
- if (data_1)
- return COMMAND_STATE_OK;
- if (isnull(data_string_1))
- {
- ExternalCommands:SetResponse("Error: Empty logo upload data");
- return COMMAND_STATE_BAD_REQUEST;
- }
- FamilyTablet:UploadLogo(data_string_1);
- return COMMAND_STATE_OK;
- }
- /*
- Пример async (WAIT_RESPONSE), по аналогии с REMOVE_DONATE / Shared load:
- public: SomeModule_OnExtRemoveDonate(sql_id, command_type, data_1, data_2, data_3, data_string_1[])
- {
- // data_1 = amount, data_string_1 = name
- Shared_InitPlayerByName(data_string_1, "SomeModule_OnPlayerLoaded", ...);
- return COMMAND_STATE_WAIT_RESPONSE;
- }
- public: SomeModule_OnPlayerLoaded(playerid, ...)
- {
- // ... логика ...
- ExternalCommands:Finish(sql_id, COMMAND_STATE_OK, "OK: donate removed");
- }
- */
- #endif
Advertisement
Add Comment
Please, Sign In to add comment