Прокси на внутренний IP: анализ и скачивания через REST-эндпоинты WordPress (режим proxy/direct, настройки)
This commit is contained in:
1 parent
b3ac9491f6
commit
867fe7bc66
3 files changed
+191
-15
No files matched your search
+145
-5
@@ -2,7 +2,7 @@
|
||||
/**
|
||||
* Plugin Name: Med Diagnostics
|
||||
* Description: Интеграция сервиса «Диагностика по видео» (med.my-dpr.ru) в WordPress. Выводит вёрстку сервиса через шорткод [med_diagnostics].
|
||||
* Version: 1.0.0
|
||||
* Version: 1.1.0
|
||||
* Author: apuc
|
||||
* License: GPL-2.0-or-later
|
||||
* Text Domain: med-diagnostics
|
||||
@@ -18,11 +18,12 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Прямой доступ запрещён
|
||||
}
|
||||
|
||||
define( 'MED_DIAG_VERSION', '1.0.0' );
|
||||
define( 'MED_DIAG_VERSION', '1.1.0' );
|
||||
define( 'MED_DIAG_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
|
||||
|
||||
/**
|
||||
* URL API-бэкенда (Flask-приложение med.my-dpr.ru).
|
||||
* Используется в режиме «напрямую» и для публичных ссылок (share).
|
||||
* Можно переопределить фильтром: add_filter('med_diag_api_url', fn() => 'https://...');
|
||||
*/
|
||||
function med_diag_api_url() {
|
||||
@@ -30,6 +31,26 @@ function med_diag_api_url() {
|
||||
return apply_filters( 'med_diag_api_url', untrailingslashit( $url ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Внутренний URL API-бэкенда (для проксирования через PHP).
|
||||
* По умолчанию — внутренний IP сервера, где стоит и WordPress, и API.
|
||||
* Можно переопределить фильтром: add_filter('med_diag_internal_url', fn() => 'http://10.0.0.5:18018');
|
||||
*/
|
||||
function med_diag_internal_url() {
|
||||
$url = get_option( 'med_diag_internal_url', 'http://127.0.0.1:18018' );
|
||||
return apply_filters( 'med_diag_internal_url', untrailingslashit( $url ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Режим подключения к бэкенду:
|
||||
* 'proxy' — браузер шлёт запрос на этот же WordPress, PHP проксирует на внутренний IP (по умолчанию);
|
||||
* 'direct' — браузер шлёт запрос напрямую на публичный URL API (нужен CORS на бэкенде).
|
||||
*/
|
||||
function med_diag_mode() {
|
||||
$mode = get_option( 'med_diag_mode', 'proxy' );
|
||||
return apply_filters( 'med_diag_mode', in_array( $mode, array( 'proxy', 'direct' ), true ) ? $mode : 'proxy' );
|
||||
}
|
||||
|
||||
/* ─── Регистрация ассетов ─────────────────────────────────── */
|
||||
|
||||
add_action( 'wp_enqueue_scripts', 'med_diag_register_assets' );
|
||||
@@ -49,10 +70,101 @@ function med_diag_register_assets() {
|
||||
true // в футере
|
||||
);
|
||||
wp_localize_script( 'med-diag-js', 'MED_DIAG', array(
|
||||
'apiUrl' => med_diag_api_url(),
|
||||
'apiUrl' => med_diag_api_url(),
|
||||
'proxyUrl' => rest_url( 'med-diag/v1' ),
|
||||
'mode' => med_diag_mode(),
|
||||
) );
|
||||
}
|
||||
|
||||
/* ─── Прокси на внутренний IP (REST) ──────────────────────── */
|
||||
|
||||
add_action( 'rest_api_init', 'med_diag_register_routes' );
|
||||
|
||||
function med_diag_register_routes() {
|
||||
// Анализ: браузер → этот WordPress → внутренний IP бэкенда
|
||||
register_rest_route( 'med-diag/v1', '/analyze', array(
|
||||
'methods' => 'POST',
|
||||
'permission_callback' => '__return_true',
|
||||
'callback' => 'med_diag_proxy_analyze',
|
||||
) );
|
||||
|
||||
// Скачивания (PDF/DOCX/видео): /download/<id>/<pdf|docx|video>
|
||||
register_rest_route( 'med-diag/v1', '/download/(?P<id>[^/]+)/(?P<type>[a-z]+)', array(
|
||||
'methods' => 'GET',
|
||||
'permission_callback' => '__return_true',
|
||||
'callback' => 'med_diag_proxy_download',
|
||||
) );
|
||||
}
|
||||
|
||||
function med_diag_proxy_analyze( $request ) {
|
||||
$files = $request->get_file_params();
|
||||
if ( empty( $files['video'] ) ) {
|
||||
return new WP_Error( 'med_diag_no_video', 'Файл video не получен', array( 'status' => 400 ) );
|
||||
}
|
||||
$file = $files['video'];
|
||||
if ( $file['error'] !== UPLOAD_ERR_OK ) {
|
||||
return new WP_Error( 'med_diag_upload_error', 'Ошибка загрузки файла (код ' . $file['error'] . ')', array( 'status' => 400 ) );
|
||||
}
|
||||
if ( $file['size'] > 100 * 1024 * 1024 ) {
|
||||
return new WP_Error( 'med_diag_too_large', 'Видео больше 100 МБ', array( 'status' => 413 ) );
|
||||
}
|
||||
|
||||
$boundary = wp_generate_password( 24, false );
|
||||
$body = '--' . $boundary . "\r\n";
|
||||
$body .= 'Content-Disposition: form-data; name="video"; filename="' . basename( $file['name'] ) . '"' . "\r\n";
|
||||
$body .= 'Content-Type: ' . $file['type'] . "\r\n\r\n";
|
||||
$body .= file_get_contents( $file['tmp_name'] ) . "\r\n";
|
||||
$body .= '--' . $boundary . "--\r\n";
|
||||
|
||||
$response = wp_remote_post( med_diag_internal_url() . '/analyze', array(
|
||||
'timeout' => 300,
|
||||
'headers' => array( 'Content-Type' => 'multipart/form-data; boundary=' . $boundary ),
|
||||
'body' => $body,
|
||||
) );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return new WP_Error( 'med_diag_proxy_error', 'Бэкенд недоступен: ' . $response->get_error_message(), array( 'status' => 502 ) );
|
||||
}
|
||||
|
||||
$status = wp_remote_retrieve_response_code( $response );
|
||||
$data = json_decode( wp_remote_retrieve_body( $response ), true );
|
||||
if ( json_last_error() !== JSON_ERROR_NONE ) {
|
||||
return new WP_Error( 'med_diag_bad_response', 'Некорректный ответ бэкенда', array( 'status' => 502 ) );
|
||||
}
|
||||
|
||||
return new WP_REST_Response( $data, $status );
|
||||
}
|
||||
|
||||
function med_diag_proxy_download( $request ) {
|
||||
$id = rawurlencode( $request['id'] );
|
||||
$type = $request['type'];
|
||||
|
||||
$response = wp_remote_get( med_diag_internal_url() . '/download/' . $id . '/' . $type, array(
|
||||
'timeout' => 300,
|
||||
) );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return new WP_Error( 'med_diag_proxy_error', 'Бэкенд недоступен', array( 'status' => 502 ) );
|
||||
}
|
||||
|
||||
$status = wp_remote_retrieve_response_code( $response );
|
||||
if ( $status !== 200 ) {
|
||||
return new WP_Error( 'med_diag_download_error', 'Ошибка скачивания (HTTP ' . $status . ')', array( 'status' => $status ) );
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
$headers = wp_remote_retrieve_headers( $response );
|
||||
$content_type = isset( $headers['content-type'] ) ? $headers['content-type'] : 'application/octet-stream';
|
||||
|
||||
$filename = 'diagnostic_' . $request['id'] . '.' . ( 'video' === $type ? 'webm' : $type );
|
||||
|
||||
header( 'Content-Type: ' . $content_type );
|
||||
header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
|
||||
header( 'Content-Length: ' . strlen( $body ) );
|
||||
echo $body;
|
||||
exit;
|
||||
}
|
||||
|
||||
/* ─── Шорткод ─────────────────────────────────────────────── */
|
||||
|
||||
add_shortcode( 'med_diagnostics', 'med_diag_shortcode' );
|
||||
@@ -150,6 +262,16 @@ function med_diag_register_settings() {
|
||||
'sanitize_callback' => 'esc_url_raw',
|
||||
'default' => 'https://med.my-dpr.ru',
|
||||
) );
|
||||
register_setting( 'med_diag_settings', 'med_diag_internal_url', array(
|
||||
'type' => 'string',
|
||||
'sanitize_callback' => 'esc_url_raw',
|
||||
'default' => 'http://127.0.0.1:18018',
|
||||
) );
|
||||
register_setting( 'med_diag_settings', 'med_diag_mode', array(
|
||||
'type' => 'string',
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
'default' => 'proxy',
|
||||
) );
|
||||
}
|
||||
|
||||
function med_diag_settings_page() {
|
||||
@@ -160,11 +282,29 @@ function med_diag_settings_page() {
|
||||
<?php settings_fields( 'med_diag_settings' ); ?>
|
||||
<table class="form-table" role="presentation">
|
||||
<tr>
|
||||
<th scope="row"><label for="med_diag_api_url">URL API-бэкенда</label></th>
|
||||
<th scope="row"><label for="med_diag_mode">Режим подключения</label></th>
|
||||
<td>
|
||||
<select id="med_diag_mode" name="med_diag_mode">
|
||||
<option value="proxy" <?php selected( med_diag_mode(), 'proxy' ); ?>>Через сервер (внутренний IP)</option>
|
||||
<option value="direct" <?php selected( med_diag_mode(), 'direct' ); ?>>Напрямую из браузера (CORS)</option>
|
||||
</select>
|
||||
<p class="description">«Через сервер» — браузер шлёт видео на этот WordPress, PHP проксирует запрос на внутренний IP бэкенда (рекомендуется, когда WordPress и API на одном сервере). «Напрямую» — браузер обращается к публичному URL API (нужен CORS на бэкенде).</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><label for="med_diag_internal_url">Внутренний URL бэкенда</label></th>
|
||||
<td>
|
||||
<input type="url" id="med_diag_internal_url" name="med_diag_internal_url"
|
||||
value="<?php echo esc_attr( med_diag_internal_url() ); ?>" class="regular-text" />
|
||||
<p class="description">Адрес API-бэкенда, доступный с этого сервера (по умолчанию http://127.0.0.1:18018). Используется в режиме «Через сервер».</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><label for="med_diag_api_url">Публичный URL API-бэкенда</label></th>
|
||||
<td>
|
||||
<input type="url" id="med_diag_api_url" name="med_diag_api_url"
|
||||
value="<?php echo esc_attr( med_diag_api_url() ); ?>" class="regular-text" />
|
||||
<p class="description">Адрес Flask-приложения, которое выполняет анализ (по умолчанию https://med.my-dpr.ru).</p>
|
||||
<p class="description">Публичный адрес Flask-приложения (по умолчанию https://med.my-dpr.ru). Используется в режиме «Напрямую» и для ссылки «Поделиться».</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
Reference in new issue
Block a user