298 lines
13 KiB
GDScript
298 lines
13 KiB
GDScript
class_name rtr
|
||
extends Node
|
||
|
||
#region Перечисления
|
||
enum State { IDLE, REQUESTING_LEFT, REQUESTING_RIGHT, WAITING_TIMEOUT }
|
||
#endregion
|
||
|
||
#region Сигналы
|
||
# Сигналы отправки запроса
|
||
signal request_sent_left(url: String) # Отправлен запрос к левому борту
|
||
signal request_sent_right(url: String) # Отправлен запрос к правому борту
|
||
|
||
# Сигналы получения ответа
|
||
signal response_received_left(response: String, success: bool) # Получен ответ от левого борта
|
||
signal response_received_right(response: String, success: bool) # Получен ответ от правого борта
|
||
|
||
#endregion
|
||
|
||
#region Константы
|
||
# Словарь с текстовым описанием кодов результатов HTTP запросов
|
||
const RESULT_STRINGS = {
|
||
HTTPRequest.Result.RESULT_SUCCESS: 'Запрос успешен',
|
||
HTTPRequest.Result.RESULT_CHUNKED_BODY_SIZE_MISMATCH: 'Несоответствие размеров частей сообщения',
|
||
HTTPRequest.Result.RESULT_CANT_CONNECT: 'Запрос не выполнен при подключении',
|
||
HTTPRequest.Result.RESULT_CANT_RESOLVE: 'Запрос не выполнен при разрешении',
|
||
HTTPRequest.Result.RESULT_CONNECTION_ERROR: 'Запрос не выполнен из-за ошибки соединения',
|
||
HTTPRequest.Result.RESULT_TLS_HANDSHAKE_ERROR: 'Запрос не выполнен на TLS рукопожатии',
|
||
HTTPRequest.Result.RESULT_NO_RESPONSE: 'Запрос не имеет ответа (пока)',
|
||
HTTPRequest.Result.RESULT_BODY_SIZE_LIMIT_EXCEEDED: 'Запрос превысил максимальный размер',
|
||
HTTPRequest.Result.RESULT_BODY_DECOMPRESS_FAILED: 'Не удалось распаковать сообщение',
|
||
HTTPRequest.Result.RESULT_REQUEST_FAILED: 'Запрос не удался',
|
||
HTTPRequest.Result.RESULT_DOWNLOAD_FILE_CANT_OPEN: 'Невозможно открыть файл загрузки',
|
||
HTTPRequest.Result.RESULT_DOWNLOAD_FILE_WRITE_ERROR: 'Невозможно записать в файл загрузки',
|
||
HTTPRequest.Result.RESULT_REDIRECT_LIMIT_REACHED: 'Достигнут лимит перенаправлений',
|
||
HTTPRequest.Result.RESULT_TIMEOUT: 'Время истекло'
|
||
}
|
||
#endregion
|
||
|
||
#region Переменные
|
||
var http_request: HTTPRequest # HTTP клиент для выполнения запросов
|
||
var addresses: Dictionary # Словарь с URL адресами устройств
|
||
var current_state: State = State.IDLE # Текущее состояние машины состояний
|
||
var current_url: String = '' # Текущий URL для запроса
|
||
var timeout_timer: Timer # Таймер ожидания ответа (30 секунд)
|
||
|
||
# Результаты запросов
|
||
var last_response_left: String = '' # Последний успешный ответ левого борта
|
||
var last_response_right: String = '' # Последний успешный ответ правого борта
|
||
var last_error_left: String = '' # Последняя ошибка левого борта
|
||
var last_error_right: String = '' # Последняя ошибка правого борта
|
||
|
||
# Статус online для каждого борта
|
||
var online_left: bool = false
|
||
var online_right: bool = false
|
||
|
||
# Время последнего успешного ответа
|
||
var last_success_time_left: int = 0
|
||
var last_success_time_right: int = 0
|
||
|
||
var timeout: float
|
||
#endregion
|
||
|
||
#region Инициализация
|
||
func _ready() -> void:
|
||
# Создаем и настраиваем HTTP клиент
|
||
http_request = HTTPRequest.new()
|
||
add_child(http_request)
|
||
http_request.request_completed.connect(_on_request_completed)
|
||
|
||
# Создаем и настраиваем таймер для обработки таймаутов
|
||
timeout_timer = Timer.new()
|
||
add_child(timeout_timer)
|
||
timeout_timer.timeout.connect(_on_timeout)
|
||
timeout_timer.one_shot = true
|
||
|
||
# Подписываемся на сигнал запуска управления устройством
|
||
signaller.conn(signaller.start_contol_device, Callable(self, '_on_start_contol_device'))
|
||
#endregion
|
||
|
||
#region Публичные методы
|
||
# Возвращает текстовое описание кода результата HTTP запроса
|
||
func get_result_string(result: int) -> String:
|
||
return RESULT_STRINGS.get(result, '<неизвестный код результата HTTPRequest - %d>' % result)
|
||
|
||
# Геттеры для получения результатов запросов
|
||
func get_left_response() -> String:
|
||
return last_response_left
|
||
|
||
func get_right_response() -> String:
|
||
return last_response_right
|
||
|
||
func get_left_error() -> String:
|
||
return last_error_left
|
||
|
||
func get_right_error() -> String:
|
||
return last_error_right
|
||
|
||
# Проверка успешности запросов
|
||
func has_left_success() -> bool:
|
||
return not last_response_left.is_empty()
|
||
|
||
func has_right_success() -> bool:
|
||
return not last_response_right.is_empty()
|
||
|
||
# Геттеры для статуса online
|
||
func is_left_online() -> bool:
|
||
return online_left
|
||
|
||
func is_right_online() -> bool:
|
||
return online_right
|
||
|
||
# Обновление статуса online
|
||
func _update_online_status(side: String, is_online: bool) -> void:
|
||
var unit_instance
|
||
|
||
# Выбираем нужный экземпляр в зависимости от борта
|
||
if side == "left":
|
||
unit_instance = network.get_unit_instance('уарэп-афсп-левый')
|
||
else: # side == "right"
|
||
unit_instance = network.get_unit_instance('уарэп-афсп-правый')
|
||
|
||
# Обновляем статус если изменился
|
||
if unit_instance and unit_instance.online != is_online:
|
||
unit_instance.online = is_online
|
||
unit_instance.emit_signal('line_changed', unit_instance)
|
||
#endregion
|
||
|
||
#region Обработчики сигналов
|
||
# Сигнал от signaller - начало управления устройством
|
||
func _on_start_contol_device() -> void:
|
||
# Если уже выполняется запрос - игнорируем
|
||
if current_state != State.IDLE:
|
||
return
|
||
|
||
# Сбрасываем предыдущие результаты
|
||
last_response_left = ''
|
||
last_response_right = ''
|
||
last_error_left = ''
|
||
last_error_right = ''
|
||
|
||
# Загружаем URL адреса из ProjectSettings
|
||
addresses['Адрес АФСП левого борта'] = ProjectSettings.get_setting('application/config/%s' % 'Адрес АФСП левого борта')
|
||
addresses['Адрес АФСП правого борта'] = ProjectSettings.get_setting('application/config/%s' % 'Адрес АФСП правого борта')
|
||
timeout = float(ProjectSettings.get_setting('application/config/%s' % 'Период опроса состояния АФСП, секунды'))
|
||
# Начинаем с запроса к левому борту
|
||
_request_next(State.REQUESTING_LEFT)
|
||
|
||
# Сигнал от HTTPRequest - получен ответ на запрос
|
||
func _on_request_completed(result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
|
||
# Если таймаут уже сработал - игнорируем ответ
|
||
if current_state == State.WAITING_TIMEOUT:
|
||
return
|
||
|
||
# Останавливаем таймер ожидания
|
||
timeout_timer.stop()
|
||
|
||
var is_left = (current_state == State.REQUESTING_LEFT)
|
||
var current_time = Time.get_ticks_msec()
|
||
|
||
# Проверяем успешность ответа
|
||
if response_code == 200:
|
||
var response_text = body.get_string_from_utf8()
|
||
_save_response(response_text)
|
||
|
||
# Обновляем статус online
|
||
if is_left:
|
||
last_success_time_left = current_time
|
||
_update_online_status("left", true)
|
||
emit_signal('response_received_left', response_text, true)
|
||
else:
|
||
last_success_time_right = current_time
|
||
_update_online_status("right", true)
|
||
emit_signal('response_received_right', response_text, true)
|
||
|
||
_on_request_finished()
|
||
else:
|
||
var error_msg = 'HTTP ошибка %d: %s' % [response_code, get_result_string(result)]
|
||
_save_error(error_msg)
|
||
|
||
# Обновляем статус online (ошибка)
|
||
if is_left:
|
||
_update_online_status("left", false)
|
||
emit_signal('response_received_left', error_msg, false)
|
||
else:
|
||
_update_online_status("right", false)
|
||
emit_signal('response_received_right', error_msg, false)
|
||
|
||
_on_request_finished()
|
||
|
||
# Сигнал от таймера - истекло время ожидания ответа
|
||
func _on_timeout() -> void:
|
||
current_state = State.WAITING_TIMEOUT
|
||
http_request.cancel_request()
|
||
var timeout_msg = 'Таймаут %.1f секунд - %s' % [timeout, get_result_string(HTTPRequest.Result.RESULT_TIMEOUT)]
|
||
_save_error(timeout_msg)
|
||
|
||
var is_left = (current_state == State.REQUESTING_LEFT)
|
||
|
||
# Обновляем статус online (таймаут = offline)
|
||
if is_left:
|
||
_update_online_status("left", false)
|
||
emit_signal('response_received_left', timeout_msg, false)
|
||
else:
|
||
_update_online_status("right", false)
|
||
emit_signal('response_received_right', timeout_msg, false)
|
||
|
||
_on_request_finished()
|
||
#endregion
|
||
|
||
#region Управление запросами
|
||
# Переход к следующему запросу в очереди
|
||
func _request_next(next_state: State) -> void:
|
||
current_state = next_state
|
||
|
||
# Определяем URL для текущего состояния
|
||
match current_state:
|
||
State.REQUESTING_LEFT:
|
||
current_url = addresses.get('Адрес АФСП левого борта', '')
|
||
State.REQUESTING_RIGHT:
|
||
current_url = addresses.get('Адрес АФСП правого борта', '')
|
||
State.IDLE:
|
||
return
|
||
|
||
# Проверяем, задан ли URL
|
||
if current_url.is_empty():
|
||
print('URL не задан для ', current_state)
|
||
var error_msg = 'URL не задан'
|
||
_save_error(error_msg)
|
||
|
||
var is_left = (current_state == State.REQUESTING_LEFT)
|
||
|
||
# Испускаем сигнал с ошибкой
|
||
if is_left:
|
||
_update_online_status("left", false)
|
||
emit_signal('response_received_left', error_msg, false)
|
||
else:
|
||
_update_online_status("right", false)
|
||
emit_signal('response_received_right', error_msg, false)
|
||
|
||
_on_request_finished()
|
||
return
|
||
|
||
# Испускаем сигнал отправки запроса
|
||
match current_state:
|
||
State.REQUESTING_LEFT:
|
||
emit_signal('request_sent_left', current_url)
|
||
State.REQUESTING_RIGHT:
|
||
emit_signal('request_sent_right', current_url)
|
||
|
||
# Запускаем таймер и отправляем запрос
|
||
timeout_timer.start(timeout)
|
||
var error = http_request.request(current_url)
|
||
if error != OK:
|
||
print('Ошибка запроса: ', error_string(error))
|
||
var error_msg = 'Ошибка запроса: ' + error_string(error)
|
||
_save_error(error_msg)
|
||
|
||
var is_left = (current_state == State.REQUESTING_LEFT)
|
||
|
||
# Испускаем сигнал с ошибкой
|
||
if is_left:
|
||
_update_online_status("left", false)
|
||
emit_signal('response_received_left', error_msg, false)
|
||
else:
|
||
_update_online_status("right", false)
|
||
emit_signal('response_received_right', error_msg, false)
|
||
|
||
_on_request_finished()
|
||
|
||
# Обработка завершения текущего запроса (успех/ошибка/таймаут)
|
||
func _on_request_finished() -> void:
|
||
match current_state:
|
||
State.REQUESTING_LEFT:
|
||
# После левого борта переходим к правому
|
||
_request_next(State.REQUESTING_RIGHT)
|
||
State.REQUESTING_RIGHT, State.WAITING_TIMEOUT:
|
||
# После правого борта или таймаута возвращаемся в IDLE
|
||
current_state = State.IDLE
|
||
#endregion
|
||
|
||
#region Сохранение результатов
|
||
# Сохраняет успешный ответ от устройства
|
||
func _save_response(response: String) -> void:
|
||
match current_state:
|
||
State.REQUESTING_LEFT:
|
||
last_response_left = response
|
||
State.REQUESTING_RIGHT:
|
||
last_response_right = response
|
||
|
||
# Сохраняет ошибку от устройства
|
||
func _save_error(error: String) -> void:
|
||
match current_state:
|
||
State.REQUESTING_LEFT:
|
||
last_error_left = error
|
||
State.REQUESTING_RIGHT:
|
||
last_error_right = error
|
||
#endregion
|