feat: add type-aware server content workflows and workshop metadata support
Agent-Logs-Url: https://github.com/GameServerPanel/GSP/sessions/211fb593-b55a-42ad-b657-a3a4ca4764ff Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com>
This commit is contained in:
parent
caa80f6c3b
commit
7e183d77a0
9 changed files with 676 additions and 71 deletions
|
|
@ -1,5 +1,42 @@
|
||||||
$(function() {
|
$(function() {
|
||||||
// Tooltips are annoying
|
var methodToRows = {
|
||||||
// Use title attribute instead
|
download_zip: ['#scm-row-url', '#scm-row-path', '#scm-row-post-script'],
|
||||||
// $( 'input,textarea' ).tooltip();
|
download_file: ['#scm-row-url', '#scm-row-path', '#scm-row-post-script'],
|
||||||
|
steam_workshop: ['#scm-row-workshop-id', '#scm-row-workshop-app-id', '#scm-row-target-path-template', '#scm-row-optional-folder-name', '#scm-row-launch-param-additions', '#scm-row-config-edit-rule', '#scm-row-post-script'],
|
||||||
|
post_script: ['#scm-row-post-script'],
|
||||||
|
config_edit: ['#scm-row-path', '#scm-row-config-edit-rule', '#scm-row-post-script'],
|
||||||
|
create_folder: ['#scm-row-path']
|
||||||
|
};
|
||||||
|
var allRows = [
|
||||||
|
'#scm-row-url',
|
||||||
|
'#scm-row-path',
|
||||||
|
'#scm-row-workshop-id',
|
||||||
|
'#scm-row-workshop-app-id',
|
||||||
|
'#scm-row-target-path-template',
|
||||||
|
'#scm-row-optional-folder-name',
|
||||||
|
'#scm-row-post-script',
|
||||||
|
'#scm-row-config-edit-rule',
|
||||||
|
'#scm-row-launch-param-additions'
|
||||||
|
];
|
||||||
|
var $method = $('#scm-install-method');
|
||||||
|
var $help = $('#scm-install-method-help');
|
||||||
|
|
||||||
|
function applyContentTypeUi() {
|
||||||
|
if ($method.length === 0) return;
|
||||||
|
var value = $method.val();
|
||||||
|
var shown = methodToRows[value] || [];
|
||||||
|
for (var i = 0; i < allRows.length; i++) {
|
||||||
|
$(allRows[i]).hide();
|
||||||
|
}
|
||||||
|
for (var j = 0; j < shown.length; j++) {
|
||||||
|
$(shown[j]).show();
|
||||||
|
}
|
||||||
|
var selectedOption = $method.find('option:selected');
|
||||||
|
var helpText = selectedOption.data('help') || '';
|
||||||
|
$help.text(helpText);
|
||||||
|
$('#scm-path-label').text(value === 'config_edit' ? 'Config Target Path' : 'Target Path');
|
||||||
|
}
|
||||||
|
|
||||||
|
$method.on('change', applyContentTypeUi);
|
||||||
|
applyContentTypeUi();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ define('LANG_plugin', "Plugins / Mods");
|
||||||
define('LANG_mappack', "Map Packs");
|
define('LANG_mappack', "Map Packs");
|
||||||
define('LANG_config', "Config Packs");
|
define('LANG_config', "Config Packs");
|
||||||
// Additional category labels (for future content types already defined in server_content_categories.php)
|
// Additional category labels (for future content types already defined in server_content_categories.php)
|
||||||
|
if (!defined('LANG_version')) define('LANG_version', "Version");
|
||||||
define('LANG_server_content_version', "Server Versions");
|
define('LANG_server_content_version', "Server Versions");
|
||||||
define('LANG_modpack', "Modpacks");
|
define('LANG_modpack', "Modpacks");
|
||||||
define('LANG_workshop', "Workshop Content");
|
define('LANG_workshop', "Workshop Content");
|
||||||
|
|
@ -63,9 +64,15 @@ define('LANG_addons_db', "Server Content Database");
|
||||||
define('LANG_addon_has_been_created', "The server content item \"%s\" has been created.");
|
define('LANG_addon_has_been_created', "The server content item \"%s\" has been created.");
|
||||||
define('LANG_remove_addon', "Remove");
|
define('LANG_remove_addon', "Remove");
|
||||||
define('LANG_fill_the_url_address_to_a_compressed_file', "Please enter a URL for the compressed file to download.");
|
define('LANG_fill_the_url_address_to_a_compressed_file', "Please enter a URL for the compressed file to download.");
|
||||||
|
define('LANG_fill_the_download_url', "Please enter a download URL.");
|
||||||
|
define('LANG_fill_the_workshop_id', "Please enter a Workshop ID.");
|
||||||
|
define('LANG_fill_the_target_install_path', "Please select a target install path.");
|
||||||
|
define('LANG_fill_the_script_action_body', "Please enter a script/action body.");
|
||||||
|
define('LANG_fill_the_config_edit_rule', "Please enter a config edit rule.");
|
||||||
define('LANG_fill_the_addon_name', "Please enter a name for the server content item.");
|
define('LANG_fill_the_addon_name', "Please enter a name for the server content item.");
|
||||||
define('LANG_select_an_addon_type', "Please select a content type.");
|
define('LANG_select_an_addon_type', "Please select a content type.");
|
||||||
define('LANG_select_a_game_type', "Please select a game type.");
|
define('LANG_select_a_game_type', "Please select a game type.");
|
||||||
|
define('LANG_select_a_content_type', "Please select a content type.");
|
||||||
define('LANG_edit_addon', "Edit");
|
define('LANG_edit_addon', "Edit");
|
||||||
define('LANG_invalid_addon', "Invalid server content item or access denied.");
|
define('LANG_invalid_addon', "Invalid server content item or access denied.");
|
||||||
define('LANG_invalid_addon_type', "Invalid content type selected.");
|
define('LANG_invalid_addon_type', "Invalid content type selected.");
|
||||||
|
|
@ -79,4 +86,16 @@ define('LANG_show_to_group', "Show to group");
|
||||||
define('LANG_all_groups', "All groups");
|
define('LANG_all_groups', "All groups");
|
||||||
define('LANG_show_addons_for_selected_group', "Show content for selected group");
|
define('LANG_show_addons_for_selected_group', "Show content for selected group");
|
||||||
define('LANG_group', "Group");
|
define('LANG_group', "Group");
|
||||||
|
define('LANG_content_type', "Content Type");
|
||||||
|
define('LANG_workshop_id', "Workshop ID");
|
||||||
|
define('LANG_target_path_template', "Target Path");
|
||||||
|
define('LANG_optional_folder_name', "Optional Folder Name");
|
||||||
|
define('LANG_config_edit_rule', "Config Edit Rule");
|
||||||
|
define('LANG_launch_param_additions', "Launch Parameter Additions");
|
||||||
|
define('LANG_content_type_help_download_zip', "Downloads and extracts an archive into the target path.");
|
||||||
|
define('LANG_content_type_help_download_file', "Downloads a single file without extraction.");
|
||||||
|
define('LANG_content_type_help_steam_workshop', "Downloads/updates a Workshop item and applies it to the server.");
|
||||||
|
define('LANG_content_type_help_post_script', "Runs a script/action only, with no URL required.");
|
||||||
|
define('LANG_content_type_help_config_edit', "Applies config edit rules to a target path, with no URL required.");
|
||||||
|
define('LANG_content_type_help_create_folder', "Creates target folders/paths only, with no URL required.");
|
||||||
?>
|
?>
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,10 @@ require_once("protocol/lgsl/lgsl_protocol.php");
|
||||||
// Central category map — all valid addon_type values and their labels.
|
// Central category map — all valid addon_type values and their labels.
|
||||||
require_once(dirname(__FILE__) . '/server_content_categories.php');
|
require_once(dirname(__FILE__) . '/server_content_categories.php');
|
||||||
require_once(dirname(__FILE__) . '/server_content_helpers.php');
|
require_once(dirname(__FILE__) . '/server_content_helpers.php');
|
||||||
|
require_once(dirname(__FILE__) . '/workshop_action.php');
|
||||||
|
if (file_exists(dirname(__FILE__) . '/../steam_workshop/includes/functions.php')) {
|
||||||
|
require_once(dirname(__FILE__) . '/../steam_workshop/includes/functions.php');
|
||||||
|
}
|
||||||
|
|
||||||
function exec_ogp_module() {
|
function exec_ogp_module() {
|
||||||
|
|
||||||
|
|
@ -161,7 +165,7 @@ function exec_ogp_module() {
|
||||||
{
|
{
|
||||||
$addon_id = (int)$_REQUEST['addon_id'];
|
$addon_id = (int)$_REQUEST['addon_id'];
|
||||||
|
|
||||||
$addons_rows = $db->resultQuery("SELECT url, path, post_script, addon_type, install_method, content_version, requires_stop, restart_after_install FROM OGP_DB_PREFIXaddons WHERE addon_id=".$addon_id.$query_groups);
|
$addons_rows = $db->resultQuery("SELECT url, path, post_script, addon_type, install_method, content_version, requires_stop, restart_after_install, workshop_item_id, workshop_app_id, target_path_template, optional_folder_name, config_edit_rule, launch_param_additions, name FROM OGP_DB_PREFIXaddons WHERE addon_id=".$addon_id.$query_groups);
|
||||||
if (!is_array($addons_rows)) {
|
if (!is_array($addons_rows)) {
|
||||||
$addons_rows = [];
|
$addons_rows = [];
|
||||||
}
|
}
|
||||||
|
|
@ -174,10 +178,24 @@ function exec_ogp_module() {
|
||||||
|
|
||||||
$remote = new OGPRemoteLibrary($home_info['agent_ip'],$home_info['agent_port'],$home_info['encryption_key'],$home_info['timeout']);
|
$remote = new OGPRemoteLibrary($home_info['agent_ip'],$home_info['agent_port'],$home_info['encryption_key'],$home_info['timeout']);
|
||||||
|
|
||||||
$addon_info = $addons_rows[0];
|
$addon_info = $addons_rows[0];
|
||||||
$install_method = isset($addon_info['install_method']) ? $addon_info['install_method'] : 'download_zip';
|
$install_method = scm_get_install_method_default(isset($addon_info['install_method']) ? $addon_info['install_method'] : 'download_zip');
|
||||||
$content_version = isset($addon_info['content_version']) ? $addon_info['content_version'] : '';
|
$content_version = isset($addon_info['content_version']) ? $addon_info['content_version'] : '';
|
||||||
$requires_stop = !empty($addon_info['requires_stop']) ? 1 : 0;
|
$requires_stop = !empty($addon_info['requires_stop']) ? 1 : 0;
|
||||||
|
$post_script = '';
|
||||||
|
$validation_payload = array(
|
||||||
|
'url' => isset($addon_info['url']) ? $addon_info['url'] : '',
|
||||||
|
'path' => isset($addon_info['path']) ? $addon_info['path'] : '',
|
||||||
|
'workshop_item_id' => isset($addon_info['workshop_item_id']) ? $addon_info['workshop_item_id'] : '',
|
||||||
|
'target_path_template' => isset($addon_info['target_path_template']) ? $addon_info['target_path_template'] : '',
|
||||||
|
'post_script' => isset($addon_info['post_script']) ? $addon_info['post_script'] : '',
|
||||||
|
'config_edit_rule' => isset($addon_info['config_edit_rule']) ? $addon_info['config_edit_rule'] : '',
|
||||||
|
);
|
||||||
|
$validation_message = '';
|
||||||
|
if ($state == "start" && !scm_validate_install_method_payload($install_method, $validation_payload, $validation_message)) {
|
||||||
|
print_failure($validation_message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// ── requires_stop guard ───────────────────────────────────────────────
|
// ── requires_stop guard ───────────────────────────────────────────────
|
||||||
// If the content item requires the server to be stopped first, check
|
// If the content item requires the server to be stopped first, check
|
||||||
|
|
@ -261,7 +279,155 @@ function exec_ogp_module() {
|
||||||
$cache_mode
|
$cache_mode
|
||||||
);
|
);
|
||||||
$_SESSION['scm_history_id_' . $home_id . '_' . $addon_id] = $history_id;
|
$_SESSION['scm_history_id_' . $home_id . '_' . $addon_id] = $history_id;
|
||||||
$pid = $remote->start_file_download( $addon_info['url'], $home_info['home_path']."/".$addon_info['path'], $filename, "uncompress", $post_script);
|
scm_log_content_install_action(array(
|
||||||
|
'addon_id' => (int)$addon_id,
|
||||||
|
'addon_name' => isset($addon_info['name']) ? $addon_info['name'] : '',
|
||||||
|
'content_type' => $install_method,
|
||||||
|
'home_id' => (int)$home_id,
|
||||||
|
'home_cfg_id' => (int)$home_info['home_cfg_id'],
|
||||||
|
'workshop_id' => isset($addon_info['workshop_item_id']) ? (string)$addon_info['workshop_item_id'] : '',
|
||||||
|
'target_path' => isset($addon_info['target_path_template']) ? (string)$addon_info['target_path_template'] : (string)$addon_info['path'],
|
||||||
|
'action' => 'started',
|
||||||
|
));
|
||||||
|
if ($install_method === 'steam_workshop') {
|
||||||
|
scm_ensure_workshop_schema($db);
|
||||||
|
$workshop_item_id = trim((string)$addon_info['workshop_item_id']);
|
||||||
|
$target_path_template = trim((string)$addon_info['target_path_template']);
|
||||||
|
$resolved = function_exists('steam_workshop_install_item_to_home')
|
||||||
|
? steam_workshop_install_item_to_home($db, $home_info, $workshop_item_id, $target_path_template, array(
|
||||||
|
'optional_folder_name' => trim((string)$addon_info['optional_folder_name']),
|
||||||
|
'workshop_app_id' => trim((string)$addon_info['workshop_app_id']),
|
||||||
|
))
|
||||||
|
: array('ok' => false);
|
||||||
|
if (empty($resolved['ok'])) {
|
||||||
|
$fallback_profile = function_exists('sw_get_profile_for_home') ? sw_get_profile_for_home($db, (int)$home_id) : false;
|
||||||
|
$fallback_workshop_app_id = trim((string)$addon_info['workshop_app_id']);
|
||||||
|
if ($fallback_workshop_app_id === '' && is_array($fallback_profile) && !empty($fallback_profile['workshop_app_id'])) {
|
||||||
|
$fallback_workshop_app_id = (string)$fallback_profile['workshop_app_id'];
|
||||||
|
}
|
||||||
|
if ($fallback_workshop_app_id === '') {
|
||||||
|
$fallback_workshop_app_id = scm_extract_workshop_app_id($server_xml);
|
||||||
|
}
|
||||||
|
$placeholder_map = scm_build_placeholder_map($home_info, array('exe_location' => (string)$server_xml->exe_location), array(
|
||||||
|
'WORKSHOP_ID' => $workshop_item_id,
|
||||||
|
'WORKSHOP_APP_ID' => $fallback_workshop_app_id,
|
||||||
|
'STEAM_APP_ID' => (is_array($fallback_profile) && !empty($fallback_profile['steam_app_id'])) ? (string)$fallback_profile['steam_app_id'] : '',
|
||||||
|
));
|
||||||
|
$resolved = array(
|
||||||
|
'workshop_app_id' => $fallback_workshop_app_id,
|
||||||
|
'steam_app_id' => (is_array($fallback_profile) && !empty($fallback_profile['steam_app_id'])) ? (string)$fallback_profile['steam_app_id'] : '',
|
||||||
|
'target_path_resolved' => scm_apply_placeholders($target_path_template, $placeholder_map),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$workshop_app_id = isset($resolved['workshop_app_id']) ? (string)$resolved['workshop_app_id'] : '';
|
||||||
|
$steam_app_id = isset($resolved['steam_app_id']) ? (string)$resolved['steam_app_id'] : '';
|
||||||
|
$target_path_resolved = isset($resolved['target_path_resolved']) ? (string)$resolved['target_path_resolved'] : '';
|
||||||
|
$extra_manifest = array(
|
||||||
|
'addon_id' => (int)$addon_id,
|
||||||
|
'target_path_template' => $target_path_template,
|
||||||
|
'target_path_resolved' => $target_path_resolved,
|
||||||
|
'optional_folder_name' => trim((string)$addon_info['optional_folder_name']),
|
||||||
|
'config_edit_rule' => trim((string)$addon_info['config_edit_rule']),
|
||||||
|
'launch_param_additions' => trim((string)$addon_info['launch_param_additions']),
|
||||||
|
'workshop_app_id' => $workshop_app_id,
|
||||||
|
'steam_app_id' => $steam_app_id,
|
||||||
|
);
|
||||||
|
$workshop_error = '';
|
||||||
|
$workshop_ok = scm_workshop_write_manifest_and_run($db, $home_info, $server_xml, 'install', array($workshop_item_id), $workshop_error, $extra_manifest);
|
||||||
|
if ($workshop_ok) {
|
||||||
|
scm_record_install_done($db, (int)$history_id, 'installed', 0, 'workshop_install_ok');
|
||||||
|
scm_upsert_manifest($db, $home_id, $addon_id, array(
|
||||||
|
'install_method' => $install_method,
|
||||||
|
'content_version' => $content_version,
|
||||||
|
'install_state' => 'installed',
|
||||||
|
'source_url' => 'steam://workshop/' . $workshop_item_id,
|
||||||
|
'installed_by' => $user_id,
|
||||||
|
));
|
||||||
|
scm_log_content_install_action(array(
|
||||||
|
'addon_id' => (int)$addon_id,
|
||||||
|
'addon_name' => isset($addon_info['name']) ? $addon_info['name'] : '',
|
||||||
|
'content_type' => $install_method,
|
||||||
|
'home_id' => (int)$home_id,
|
||||||
|
'home_cfg_id' => (int)$home_info['home_cfg_id'],
|
||||||
|
'workshop_id' => $workshop_item_id,
|
||||||
|
'target_path' => $target_path_resolved,
|
||||||
|
'action' => 'succeeded',
|
||||||
|
));
|
||||||
|
print_success(get_lang('addon_installed_successfully'));
|
||||||
|
} else {
|
||||||
|
scm_record_install_done($db, (int)$history_id, 'failed', 1, $workshop_error);
|
||||||
|
scm_log_content_install_action(array(
|
||||||
|
'addon_id' => (int)$addon_id,
|
||||||
|
'addon_name' => isset($addon_info['name']) ? $addon_info['name'] : '',
|
||||||
|
'content_type' => $install_method,
|
||||||
|
'home_id' => (int)$home_id,
|
||||||
|
'home_cfg_id' => (int)$home_info['home_cfg_id'],
|
||||||
|
'workshop_id' => $workshop_item_id,
|
||||||
|
'target_path' => $target_path_resolved,
|
||||||
|
'action' => 'failed',
|
||||||
|
'error' => $workshop_error,
|
||||||
|
));
|
||||||
|
print_failure($workshop_error);
|
||||||
|
}
|
||||||
|
echo "<p><a href=\"?m=addonsmanager&p=user_addons&home_id=$home_id&mod_id=$mod_id&ip=$ip&port=$port\">".get_lang('back')."</a></p>";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($install_method === 'post_script') {
|
||||||
|
$script_command = "cd " . escapeshellarg($home_info['home_path']) . " && /bin/bash -lc " . escapeshellarg((string)$post_script) . " ; echo __GSP_SCRIPT_EXIT:$?";
|
||||||
|
$script_output = $remote->exec($script_command);
|
||||||
|
$script_ok = is_string($script_output) && preg_match('/__GSP_SCRIPT_EXIT:(\d+)/', $script_output, $sm) && (int)$sm[1] === 0;
|
||||||
|
if ($script_ok) {
|
||||||
|
scm_record_install_done($db, (int)$history_id, 'installed', 0, trim((string)$script_output));
|
||||||
|
scm_upsert_manifest($db, $home_id, $addon_id, array(
|
||||||
|
'install_method' => $install_method,
|
||||||
|
'content_version' => $content_version,
|
||||||
|
'install_state' => 'installed',
|
||||||
|
'source_url' => '',
|
||||||
|
'installed_by' => $user_id,
|
||||||
|
));
|
||||||
|
scm_log_content_install_action(array('addon_id' => (int)$addon_id, 'addon_name' => isset($addon_info['name']) ? $addon_info['name'] : '', 'content_type' => $install_method, 'home_id' => (int)$home_id, 'home_cfg_id' => (int)$home_info['home_cfg_id'], 'action' => 'succeeded'));
|
||||||
|
print_success(get_lang('addon_installed_successfully'));
|
||||||
|
} else {
|
||||||
|
$error_msg = 'Script/action failed.';
|
||||||
|
scm_record_install_done($db, (int)$history_id, 'failed', 1, trim((string)$script_output));
|
||||||
|
scm_log_content_install_action(array('addon_id' => (int)$addon_id, 'addon_name' => isset($addon_info['name']) ? $addon_info['name'] : '', 'content_type' => $install_method, 'home_id' => (int)$home_id, 'home_cfg_id' => (int)$home_info['home_cfg_id'], 'action' => 'failed', 'error' => trim((string)$script_output)));
|
||||||
|
print_failure($error_msg);
|
||||||
|
}
|
||||||
|
echo "<p><a href=\"?m=addonsmanager&p=user_addons&home_id=$home_id&mod_id=$mod_id&ip=$ip&port=$port\">".get_lang('back')."</a></p>";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($install_method === 'config_edit' || $install_method === 'create_folder') {
|
||||||
|
$placeholder_map = scm_build_placeholder_map($home_info, array('exe_location' => (string)$server_xml->exe_location));
|
||||||
|
$target_template = trim((string)$addon_info['path']);
|
||||||
|
$resolved_path = scm_apply_placeholders($target_template, $placeholder_map);
|
||||||
|
if ($resolved_path === '' || strpos($resolved_path, '/') !== 0) {
|
||||||
|
$resolved_path = clean_path(rtrim($home_info['home_path'], '/') . '/' . ltrim($resolved_path, '/'));
|
||||||
|
}
|
||||||
|
$ok = false;
|
||||||
|
if ($install_method === 'create_folder') {
|
||||||
|
$ok = is_string($remote->exec("mkdir -p " . escapeshellarg($resolved_path) . " && echo __GSP_FOLDER_OK"));
|
||||||
|
} else {
|
||||||
|
$config_rule = trim((string)$addon_info['config_edit_rule']);
|
||||||
|
$dir = dirname($resolved_path);
|
||||||
|
$cmd = "mkdir -p " . escapeshellarg($dir) . " && touch " . escapeshellarg($resolved_path) . " && printf %s " . escapeshellarg($config_rule . PHP_EOL) . " >> " . escapeshellarg($resolved_path) . " && echo __GSP_CONFIG_OK";
|
||||||
|
$out = $remote->exec($cmd);
|
||||||
|
$ok = is_string($out) && strpos($out, '__GSP_CONFIG_OK') !== false;
|
||||||
|
}
|
||||||
|
if ($ok) {
|
||||||
|
scm_record_install_done($db, (int)$history_id, 'installed', 0, $install_method . '_ok');
|
||||||
|
scm_upsert_manifest($db, $home_id, $addon_id, array('install_method' => $install_method, 'content_version' => $content_version, 'install_state' => 'installed', 'source_url' => '', 'installed_by' => $user_id));
|
||||||
|
scm_log_content_install_action(array('addon_id' => (int)$addon_id, 'addon_name' => isset($addon_info['name']) ? $addon_info['name'] : '', 'content_type' => $install_method, 'home_id' => (int)$home_id, 'home_cfg_id' => (int)$home_info['home_cfg_id'], 'target_path' => $resolved_path, 'action' => 'succeeded'));
|
||||||
|
print_success(get_lang('addon_installed_successfully'));
|
||||||
|
} else {
|
||||||
|
scm_record_install_done($db, (int)$history_id, 'failed', 1, $install_method . '_failed');
|
||||||
|
scm_log_content_install_action(array('addon_id' => (int)$addon_id, 'addon_name' => isset($addon_info['name']) ? $addon_info['name'] : '', 'content_type' => $install_method, 'home_id' => (int)$home_id, 'home_cfg_id' => (int)$home_info['home_cfg_id'], 'target_path' => $resolved_path, 'action' => 'failed', 'error' => $install_method . '_failed'));
|
||||||
|
print_failure('Content action failed.');
|
||||||
|
}
|
||||||
|
echo "<p><a href=\"?m=addonsmanager&p=user_addons&home_id=$home_id&mod_id=$mod_id&ip=$ip&port=$port\">".get_lang('back')."</a></p>";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$download_action = ($install_method === 'download_file') ? "" : "uncompress";
|
||||||
|
$pid = $remote->start_file_download( $addon_info['url'], $home_info['home_path']."/".$addon_info['path'], $filename, $download_action, $post_script);
|
||||||
}
|
}
|
||||||
|
|
||||||
$headers = get_headers($url, 1);
|
$headers = get_headers($url, 1);
|
||||||
|
|
@ -319,10 +485,22 @@ function exec_ogp_module() {
|
||||||
if(!$download_available)
|
if(!$download_available)
|
||||||
{
|
{
|
||||||
print_failure(get_lang('failed_to_start_file_download'));
|
print_failure(get_lang('failed_to_start_file_download'));
|
||||||
|
scm_log_content_install_action(array(
|
||||||
|
'addon_id' => (int)$addon_id,
|
||||||
|
'addon_name' => isset($addon_info['name']) ? $addon_info['name'] : '',
|
||||||
|
'content_type' => $install_method,
|
||||||
|
'home_id' => (int)$home_id,
|
||||||
|
'home_cfg_id' => (int)$home_info['home_cfg_id'],
|
||||||
|
'action' => 'failed',
|
||||||
|
'error' => 'failed_to_start_file_download',
|
||||||
|
));
|
||||||
}
|
}
|
||||||
elseif( $remote->is_file_download_in_progress($pid) === 1 )
|
elseif( $remote->is_file_download_in_progress($pid) === 1 )
|
||||||
{
|
{
|
||||||
print_success(get_lang_f('wait_while_decompressing', $filename));
|
if ($install_method === 'download_zip')
|
||||||
|
print_success(get_lang_f('wait_while_decompressing', $filename));
|
||||||
|
else
|
||||||
|
print_success(get_lang('install') . " " . $filename . "...");
|
||||||
echo "<p><a href=\"?m=addonsmanager&p=addons&state=refresh&home_id=$home_id&mod_id=$mod_id".
|
echo "<p><a href=\"?m=addonsmanager&p=addons&state=refresh&home_id=$home_id&mod_id=$mod_id".
|
||||||
"&ip=$ip&port=$port&addon_id=$addon_id&pid=$pid\">".get_lang('refresh')."</a></p>";
|
"&ip=$ip&port=$port&addon_id=$addon_id&pid=$pid\">".get_lang('refresh')."</a></p>";
|
||||||
$view->refresh("?m=addonsmanager&p=addons&state=refresh&home_id=$home_id&mod_id=$mod_id".
|
$view->refresh("?m=addonsmanager&p=addons&state=refresh&home_id=$home_id&mod_id=$mod_id".
|
||||||
|
|
@ -344,6 +522,15 @@ function exec_ogp_module() {
|
||||||
'source_url' => $addon_info['url'],
|
'source_url' => $addon_info['url'],
|
||||||
'installed_by' => $user_id,
|
'installed_by' => $user_id,
|
||||||
));
|
));
|
||||||
|
scm_log_content_install_action(array(
|
||||||
|
'addon_id' => (int)$addon_id,
|
||||||
|
'addon_name' => isset($addon_info['name']) ? $addon_info['name'] : '',
|
||||||
|
'content_type' => $install_method,
|
||||||
|
'home_id' => (int)$home_id,
|
||||||
|
'home_cfg_id' => (int)$home_info['home_cfg_id'],
|
||||||
|
'target_path' => isset($addon_info['path']) ? (string)$addon_info['path'] : '',
|
||||||
|
'action' => 'succeeded',
|
||||||
|
));
|
||||||
echo "<p><a href=\"?m=addonsmanager&p=user_addons&home_id=$home_id".
|
echo "<p><a href=\"?m=addonsmanager&p=user_addons&home_id=$home_id".
|
||||||
"&mod_id=$mod_id&ip=$ip&port=$port\">".get_lang('back')."</a></p>";
|
"&mod_id=$mod_id&ip=$ip&port=$port\">".get_lang('back')."</a></p>";
|
||||||
$view->refresh("?m=addonsmanager&p=user_addons&home_id=$home_id".
|
$view->refresh("?m=addonsmanager&p=user_addons&home_id=$home_id".
|
||||||
|
|
|
||||||
|
|
@ -41,32 +41,16 @@ function exec_ogp_module() {
|
||||||
$addon_type_labels = get_server_content_categories(); // key => label
|
$addon_type_labels = get_server_content_categories(); // key => label
|
||||||
$install_methods = scm_get_install_methods(); // install_method keys => labels
|
$install_methods = scm_get_install_methods(); // install_method keys => labels
|
||||||
|
|
||||||
if (isset($_POST['create_addon']) AND isset($_POST['name']) AND $_POST['url']=="")
|
if (isset($_POST['create_addon']))
|
||||||
{
|
|
||||||
print_failure(get_lang("fill_the_url_address_to_a_compressed_file"));
|
|
||||||
}
|
|
||||||
elseif(isset($_POST['create_addon']) AND isset($_POST['url']) AND $_POST['name']=="")
|
|
||||||
{
|
|
||||||
print_failure(get_lang("fill_the_addon_name"));
|
|
||||||
}
|
|
||||||
elseif(isset($_POST['create_addon']) AND isset($_POST['name']) and isset($_POST['url']) and empty($_POST['addon_type']) )
|
|
||||||
{
|
|
||||||
print_failure(get_lang("select_an_addon_type"));
|
|
||||||
}
|
|
||||||
elseif(isset($_POST['create_addon']) AND isset($_POST['name']) and isset($_POST['url']) and isset($_POST['addon_type']) and empty($_POST['home_cfg_id']) )
|
|
||||||
{
|
|
||||||
print_failure(get_lang("select_a_game_type"));
|
|
||||||
}
|
|
||||||
elseif (isset($_POST['create_addon']) AND isset($_POST['name']) AND isset($_POST['url']) AND isset($_POST['addon_type']) and isset($_POST['home_cfg_id']) )
|
|
||||||
{
|
{
|
||||||
$valid_install_methods = array_keys($install_methods);
|
$valid_install_methods = array_keys($install_methods);
|
||||||
$fields['name'] = $_POST['name'];
|
$fields['name'] = isset($_POST['name']) ? trim((string)$_POST['name']) : '';
|
||||||
$fields['url'] = $_POST['url'];
|
$fields['url'] = isset($_POST['url']) ? trim((string)$_POST['url']) : '';
|
||||||
$fields['path'] = $_POST['path'];
|
$fields['path'] = isset($_POST['path']) ? trim((string)$_POST['path']) : '';
|
||||||
$fields['addon_type'] = $_POST['addon_type'];
|
$fields['addon_type'] = isset($_POST['addon_type']) ? trim((string)$_POST['addon_type']) : '';
|
||||||
$fields['home_cfg_id'] = $_POST['home_cfg_id'];
|
$fields['home_cfg_id'] = isset($_POST['home_cfg_id']) ? (int)$_POST['home_cfg_id'] : 0;
|
||||||
$fields['post_script'] = $_POST['post_script'];
|
$fields['post_script'] = isset($_POST['post_script']) ? trim((string)$_POST['post_script']) : '';
|
||||||
$fields['group_id'] = $_POST['group_id'];
|
$fields['group_id'] = isset($_POST['group_id']) ? (int)$_POST['group_id'] : 0;
|
||||||
$fields['install_method'] = in_array($_POST['install_method'], $valid_install_methods) ? $_POST['install_method'] : 'download_zip';
|
$fields['install_method'] = in_array($_POST['install_method'], $valid_install_methods) ? $_POST['install_method'] : 'download_zip';
|
||||||
$fields['content_version'] = isset($_POST['content_version']) ? $_POST['content_version'] : '';
|
$fields['content_version'] = isset($_POST['content_version']) ? $_POST['content_version'] : '';
|
||||||
$fields['requires_stop'] = !empty($_POST['requires_stop']) ? 1 : 0;
|
$fields['requires_stop'] = !empty($_POST['requires_stop']) ? 1 : 0;
|
||||||
|
|
@ -74,11 +58,46 @@ function exec_ogp_module() {
|
||||||
$fields['restart_after_install'] = !empty($_POST['restart_after_install']) ? 1 : 0;
|
$fields['restart_after_install'] = !empty($_POST['restart_after_install']) ? 1 : 0;
|
||||||
$fields['is_cacheable'] = !empty($_POST['is_cacheable']) ? 1 : 0;
|
$fields['is_cacheable'] = !empty($_POST['is_cacheable']) ? 1 : 0;
|
||||||
$fields['description'] = isset($_POST['description']) ? $_POST['description'] : '';
|
$fields['description'] = isset($_POST['description']) ? $_POST['description'] : '';
|
||||||
if( is_numeric($db->resultInsertId( 'addons', $fields )) )
|
$fields['workshop_item_id'] = isset($_POST['workshop_item_id']) ? trim((string)$_POST['workshop_item_id']) : '';
|
||||||
|
$fields['workshop_app_id'] = isset($_POST['workshop_app_id']) ? trim((string)$_POST['workshop_app_id']) : '';
|
||||||
|
$fields['target_path_template']= isset($_POST['target_path_template']) ? trim((string)$_POST['target_path_template']) : '';
|
||||||
|
$fields['optional_folder_name']= isset($_POST['optional_folder_name']) ? trim((string)$_POST['optional_folder_name']) : '';
|
||||||
|
$fields['config_edit_rule'] = isset($_POST['config_edit_rule']) ? trim((string)$_POST['config_edit_rule']) : '';
|
||||||
|
$fields['launch_param_additions'] = isset($_POST['launch_param_additions']) ? trim((string)$_POST['launch_param_additions']) : '';
|
||||||
|
|
||||||
|
if ($fields['name'] === '')
|
||||||
{
|
{
|
||||||
print_success(get_lang_f("addon_has_been_created",$_POST['name']));
|
print_failure(get_lang("fill_the_addon_name"));
|
||||||
if (isset($_POST['addon_id']) && (int)$_POST['addon_id'] > 0 && isset($_POST['edit']))
|
}
|
||||||
$db->query("DELETE FROM OGP_DB_PREFIXaddons WHERE addon_id=" . (int)$_POST['addon_id']);
|
elseif (empty($fields['addon_type']) || !in_array($fields['addon_type'], $addon_types))
|
||||||
|
{
|
||||||
|
print_failure(get_lang("select_an_addon_type"));
|
||||||
|
}
|
||||||
|
elseif (empty($fields['home_cfg_id']))
|
||||||
|
{
|
||||||
|
print_failure(get_lang("select_a_game_type"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$validation_payload = array(
|
||||||
|
'url' => $fields['url'],
|
||||||
|
'path' => $fields['path'],
|
||||||
|
'workshop_item_id' => $fields['workshop_item_id'],
|
||||||
|
'target_path_template' => $fields['target_path_template'],
|
||||||
|
'post_script' => $fields['post_script'],
|
||||||
|
'config_edit_rule' => $fields['config_edit_rule'],
|
||||||
|
);
|
||||||
|
$validation_message = '';
|
||||||
|
if (!scm_validate_install_method_payload($fields['install_method'], $validation_payload, $validation_message))
|
||||||
|
{
|
||||||
|
print_failure($validation_message);
|
||||||
|
}
|
||||||
|
elseif (is_numeric($db->resultInsertId('addons', $fields)))
|
||||||
|
{
|
||||||
|
print_success(get_lang_f("addon_has_been_created", $fields['name']));
|
||||||
|
if (isset($_POST['addon_id']) && (int)$_POST['addon_id'] > 0 && isset($_POST['edit']))
|
||||||
|
$db->query("DELETE FROM OGP_DB_PREFIXaddons WHERE addon_id=" . (int)$_POST['addon_id']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,6 +116,12 @@ function exec_ogp_module() {
|
||||||
$restart_after_install = isset($_POST['restart_after_install']) ? (int)$_POST['restart_after_install'] : 0;
|
$restart_after_install = isset($_POST['restart_after_install']) ? (int)$_POST['restart_after_install'] : 0;
|
||||||
$is_cacheable = isset($_POST['is_cacheable']) ? (int)$_POST['is_cacheable'] : 0;
|
$is_cacheable = isset($_POST['is_cacheable']) ? (int)$_POST['is_cacheable'] : 0;
|
||||||
$description = isset($_POST['description']) ? $_POST['description'] : "";
|
$description = isset($_POST['description']) ? $_POST['description'] : "";
|
||||||
|
$workshop_item_id = isset($_POST['workshop_item_id']) ? $_POST['workshop_item_id'] : "";
|
||||||
|
$workshop_app_id = isset($_POST['workshop_app_id']) ? $_POST['workshop_app_id'] : "";
|
||||||
|
$target_path_template = isset($_POST['target_path_template']) ? $_POST['target_path_template'] : "";
|
||||||
|
$optional_folder_name = isset($_POST['optional_folder_name']) ? $_POST['optional_folder_name'] : "";
|
||||||
|
$config_edit_rule = isset($_POST['config_edit_rule']) ? $_POST['config_edit_rule'] : "";
|
||||||
|
$launch_param_additions = isset($_POST['launch_param_additions']) ? $_POST['launch_param_additions'] : "";
|
||||||
|
|
||||||
if (isset($_POST['addon_id']) && (int)$_POST['addon_id'] > 0 && isset($_POST['edit']))
|
if (isset($_POST['addon_id']) && (int)$_POST['addon_id'] > 0 && isset($_POST['edit']))
|
||||||
{
|
{
|
||||||
|
|
@ -119,6 +144,12 @@ function exec_ogp_module() {
|
||||||
$restart_after_install = isset($addon_info['restart_after_install']) ? (int)$addon_info['restart_after_install'] : 0;
|
$restart_after_install = isset($addon_info['restart_after_install']) ? (int)$addon_info['restart_after_install'] : 0;
|
||||||
$is_cacheable = isset($addon_info['is_cacheable']) ? (int)$addon_info['is_cacheable'] : 0;
|
$is_cacheable = isset($addon_info['is_cacheable']) ? (int)$addon_info['is_cacheable'] : 0;
|
||||||
$description = isset($addon_info['description']) ? $addon_info['description'] : "";
|
$description = isset($addon_info['description']) ? $addon_info['description'] : "";
|
||||||
|
$workshop_item_id = isset($addon_info['workshop_item_id']) ? $addon_info['workshop_item_id'] : "";
|
||||||
|
$workshop_app_id = isset($addon_info['workshop_app_id']) ? $addon_info['workshop_app_id'] : "";
|
||||||
|
$target_path_template = isset($addon_info['target_path_template']) ? $addon_info['target_path_template'] : "";
|
||||||
|
$optional_folder_name = isset($addon_info['optional_folder_name']) ? $addon_info['optional_folder_name'] : "";
|
||||||
|
$config_edit_rule = isset($addon_info['config_edit_rule']) ? $addon_info['config_edit_rule'] : "";
|
||||||
|
$launch_param_additions = isset($addon_info['launch_param_additions']) ? $addon_info['launch_param_additions'] : "";
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<form action="" method="post">
|
<form action="" method="post">
|
||||||
|
|
@ -131,7 +162,25 @@ function exec_ogp_module() {
|
||||||
<input type="text" value="<?php echo $name; ?>" name="name" size="85" title="<?php print_lang('addon_name_info'); ?>" />
|
<input type="text" value="<?php echo $name; ?>" name="name" size="85" title="<?php print_lang('addon_name_info'); ?>" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr id="scm-row-install-method">
|
||||||
|
<td align="right">
|
||||||
|
<b><?php print_lang('content_type'); ?></b>
|
||||||
|
</td>
|
||||||
|
<td align="left">
|
||||||
|
<select name="install_method" id="scm-install-method">
|
||||||
|
<?php
|
||||||
|
$install_help = scm_get_install_method_help_text();
|
||||||
|
foreach ((array)$install_methods as $method_key => $method_label) {
|
||||||
|
$sel = ($method_key == $install_method) ? 'selected="selected"' : '';
|
||||||
|
$help = isset($install_help[$method_key]) ? $install_help[$method_key] : '';
|
||||||
|
echo '<option value="'.htmlspecialchars($method_key).'" data-help="'.htmlspecialchars($help, ENT_QUOTES, 'UTF-8').'" '.$sel.'>'.htmlspecialchars($method_label).'</option>'."\n";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</select>
|
||||||
|
<div id="scm-install-method-help" style="color:#666;margin-top:4px;"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="scm-row-url">
|
||||||
<td align="right">
|
<td align="right">
|
||||||
<b><?php print_lang('url'); ?></b>
|
<b><?php print_lang('url'); ?></b>
|
||||||
</td>
|
</td>
|
||||||
|
|
@ -141,17 +190,50 @@ function exec_ogp_module() {
|
||||||
</tr>
|
</tr>
|
||||||
<!-- Destination path — must be relative to the game server home directory.
|
<!-- Destination path — must be relative to the game server home directory.
|
||||||
Path traversal (../) is not allowed; the agent enforces this. -->
|
Path traversal (../) is not allowed; the agent enforces this. -->
|
||||||
<tr>
|
<tr id="scm-row-path">
|
||||||
<td align="right">
|
<td align="right">
|
||||||
<b><?php print_lang('path'); ?></b>
|
<b id="scm-path-label"><?php print_lang('path'); ?></b>
|
||||||
</td>
|
</td>
|
||||||
<td align="left">
|
<td align="left">
|
||||||
<input type="text" value="<?php echo $path; ?>" name="path" size="85" title="<?php print_lang('path_info'); ?>" />
|
<input type="text" value="<?php echo $path; ?>" name="path" size="85" title="<?php print_lang('path_info'); ?>" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr id="scm-row-workshop-id">
|
||||||
<td align="right">
|
<td align="right">
|
||||||
<b><?php print_lang('post-script'); ?></b><br>
|
<b><?php print_lang('workshop_id'); ?></b>
|
||||||
|
</td>
|
||||||
|
<td align="left">
|
||||||
|
<input type="text" value="<?php echo htmlspecialchars($workshop_item_id, ENT_QUOTES, 'UTF-8'); ?>" name="workshop_item_id" size="85" placeholder="e.g. 450814997" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="scm-row-workshop-app-id">
|
||||||
|
<td align="right">
|
||||||
|
<b>Workshop App ID</b>
|
||||||
|
</td>
|
||||||
|
<td align="left">
|
||||||
|
<input type="text" value="<?php echo htmlspecialchars($workshop_app_id, ENT_QUOTES, 'UTF-8'); ?>" name="workshop_app_id" size="85" placeholder="Optional override, e.g. 221100" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="scm-row-target-path-template">
|
||||||
|
<td align="right">
|
||||||
|
<b><?php print_lang('target_path_template'); ?></b>
|
||||||
|
</td>
|
||||||
|
<td align="left">
|
||||||
|
<input type="text" value="<?php echo htmlspecialchars($target_path_template, ENT_QUOTES, 'UTF-8'); ?>" name="target_path_template" size="85" placeholder="{SERVER_ROOT}/mods/{WORKSHOP_ID}" />
|
||||||
|
<small style="color:#666;">Supported placeholders: {HOME_ID}, {SERVER_ROOT}, {GAME_ROOT}, {WORKSHOP_ID}, {WORKSHOP_APP_ID}, {STEAM_APP_ID}</small>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="scm-row-optional-folder-name">
|
||||||
|
<td align="right">
|
||||||
|
<b><?php print_lang('optional_folder_name'); ?></b>
|
||||||
|
</td>
|
||||||
|
<td align="left">
|
||||||
|
<input type="text" value="<?php echo htmlspecialchars($optional_folder_name, ENT_QUOTES, 'UTF-8'); ?>" name="optional_folder_name" size="85" placeholder="@MyWorkshopMod" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="scm-row-post-script">
|
||||||
|
<td align="right">
|
||||||
|
<b>Post-Install Script / Action</b><br>
|
||||||
<u><?php print_lang('replacements'); ?></u><br>
|
<u><?php print_lang('replacements'); ?></u><br>
|
||||||
%home_path%<br>
|
%home_path%<br>
|
||||||
%home_name%<br>
|
%home_name%<br>
|
||||||
|
|
@ -166,6 +248,22 @@ function exec_ogp_module() {
|
||||||
<textarea name="post_script" style="width:99%;height:175px;" title="<?php print_lang('post-script_info'); ?>" ><?php echo strip_real_escape_string($post_script); ?></textarea>
|
<textarea name="post_script" style="width:99%;height:175px;" title="<?php print_lang('post-script_info'); ?>" ><?php echo strip_real_escape_string($post_script); ?></textarea>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr id="scm-row-config-edit-rule">
|
||||||
|
<td align="right">
|
||||||
|
<b><?php print_lang('config_edit_rule'); ?></b>
|
||||||
|
</td>
|
||||||
|
<td align="left">
|
||||||
|
<textarea name="config_edit_rule" style="width:99%;height:90px;" placeholder="Text/rules to append or apply to the target config."><?php echo htmlspecialchars($config_edit_rule, ENT_QUOTES, 'UTF-8'); ?></textarea>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="scm-row-launch-param-additions">
|
||||||
|
<td align="right">
|
||||||
|
<b><?php print_lang('launch_param_additions'); ?></b>
|
||||||
|
</td>
|
||||||
|
<td align="left">
|
||||||
|
<input type="text" value="<?php echo htmlspecialchars($launch_param_additions, ENT_QUOTES, 'UTF-8'); ?>" name="launch_param_additions" size="85" placeholder="-mod=@myMod;@anotherMod" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="right">
|
<td align="right">
|
||||||
<b><?php print_lang('select_game_type'); ?></b>
|
<b><?php print_lang('select_game_type'); ?></b>
|
||||||
|
|
@ -241,23 +339,6 @@ function exec_ogp_module() {
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<!-- ── Phase 2 fields ────────────────────────────────────────────────── -->
|
|
||||||
<tr>
|
|
||||||
<td align="right">
|
|
||||||
<b>Install Method</b>
|
|
||||||
</td>
|
|
||||||
<td align="left">
|
|
||||||
<select name="install_method">
|
|
||||||
<?php
|
|
||||||
foreach ((array)$install_methods as $method_key => $method_label) {
|
|
||||||
$sel = ($method_key == $install_method) ? 'selected="selected"' : '';
|
|
||||||
echo '<option value="'.htmlspecialchars($method_key).'" '.$sel.'>'.htmlspecialchars($method_label).'</option>'."\n";
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</select>
|
|
||||||
<small style="color:#666;"> The mechanism used to deliver this content to the server.</small>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td align="right">
|
<td align="right">
|
||||||
<b>Content Version</b>
|
<b>Content Version</b>
|
||||||
|
|
@ -313,7 +394,6 @@ function exec_ogp_module() {
|
||||||
</small>
|
</small>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<!-- ── end Phase 2 fields ─────────────────────────────────────────────── -->
|
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2" align="center">
|
<td colspan="2" align="center">
|
||||||
<?php
|
<?php
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@
|
||||||
|
|
||||||
// Module general information
|
// Module general information
|
||||||
$module_title = "Server Content Manager";
|
$module_title = "Server Content Manager";
|
||||||
$module_version = "2.2";
|
$module_version = "2.3";
|
||||||
$db_version = 4;
|
$db_version = 5;
|
||||||
$module_required = TRUE;
|
$module_required = TRUE;
|
||||||
$module_menus = array(
|
$module_menus = array(
|
||||||
array( 'subpage' => 'addons_manager', 'name' => 'Server Content Manager', 'group' => 'admin' )
|
array( 'subpage' => 'addons_manager', 'name' => 'Server Content Manager', 'group' => 'admin' )
|
||||||
|
|
@ -165,4 +165,35 @@ $install_queries[3] = array(
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ── db_version 5 : content-type specific metadata for Workshop/config/folder actions ──
|
||||||
|
$install_queries[4] = array(
|
||||||
|
function ($db) {
|
||||||
|
$prefix = OGP_DB_PREFIX;
|
||||||
|
$new_columns = array(
|
||||||
|
'workshop_item_id' => "VARCHAR(64) NULL AFTER `description`",
|
||||||
|
'workshop_app_id' => "VARCHAR(32) NULL AFTER `workshop_item_id`",
|
||||||
|
'target_path_template' => "VARCHAR(255) NULL AFTER `workshop_app_id`",
|
||||||
|
'optional_folder_name' => "VARCHAR(255) NULL AFTER `target_path_template`",
|
||||||
|
'config_edit_rule' => "TEXT NULL AFTER `optional_folder_name`",
|
||||||
|
'launch_param_additions' => "VARCHAR(255) NULL AFTER `config_edit_rule`",
|
||||||
|
);
|
||||||
|
foreach ($new_columns as $col => $definition) {
|
||||||
|
$escaped_col = $db->realEscapeSingle($col);
|
||||||
|
$escaped_table = $db->realEscapeSingle($prefix . 'addons');
|
||||||
|
$check = $db->resultQuery(
|
||||||
|
"SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE()
|
||||||
|
AND TABLE_NAME = '{$escaped_table}'
|
||||||
|
AND COLUMN_NAME = '{$escaped_col}'"
|
||||||
|
);
|
||||||
|
if (empty($check)) {
|
||||||
|
if (!$db->query("ALTER TABLE `{$prefix}addons` ADD COLUMN `{$col}` {$definition}")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
);
|
||||||
?>
|
?>
|
||||||
|
|
|
||||||
|
|
@ -255,15 +255,146 @@ function scm_get_cache_mode($db)
|
||||||
function scm_get_install_methods()
|
function scm_get_install_methods()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'download_zip' => 'Download & extract archive (.zip / .tar.gz)',
|
'download_zip' => 'Compressed file download',
|
||||||
'download_file' => 'Download single file (no extraction)',
|
'download_file' => 'Direct file download',
|
||||||
'post_script' => 'Run post-script only (no download)',
|
'steam_workshop' => 'Steam Workshop item',
|
||||||
'steam_workshop' => 'Steam Workshop (via agent SteamCMD)',
|
'post_script' => 'Script/action only',
|
||||||
'minecraft_jar' => 'Minecraft server jar / version switcher',
|
'config_edit' => 'Config edit only',
|
||||||
'profile_copy' => 'Copy stored profile directory',
|
'create_folder' => 'Folder/create path only',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function scm_get_install_method_help_text()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'download_zip' => 'Downloads and extracts an archive into the target path.',
|
||||||
|
'download_file' => 'Downloads a single file to the target path without extraction.',
|
||||||
|
'steam_workshop' => 'Downloads/updates a Steam Workshop item and applies it to the server path.',
|
||||||
|
'post_script' => 'Runs only the post-install script/action body (no download).',
|
||||||
|
'config_edit' => 'Applies config edit rules to a target config file/path.',
|
||||||
|
'create_folder' => 'Creates the target directory path only.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scm_get_install_method_required_fields()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'download_zip' => array('url', 'path'),
|
||||||
|
'download_file' => array('url', 'path'),
|
||||||
|
'steam_workshop' => array('workshop_item_id', 'target_path_template'),
|
||||||
|
'post_script' => array('post_script'),
|
||||||
|
'config_edit' => array('path', 'config_edit_rule'),
|
||||||
|
'create_folder' => array('path'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scm_get_install_method_validation_errors()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'url' => 'Please enter a download URL.',
|
||||||
|
'workshop_item_id' => 'Please enter a Workshop ID.',
|
||||||
|
'target_path_template' => 'Please select a target install path.',
|
||||||
|
'post_script' => 'Please enter a script/action body.',
|
||||||
|
'config_edit_rule' => 'Please enter a config edit rule.',
|
||||||
|
'path' => 'Please select a target install path.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scm_get_install_method_default($value = '')
|
||||||
|
{
|
||||||
|
$methods = scm_get_install_methods();
|
||||||
|
$value = trim((string)$value);
|
||||||
|
return isset($methods[$value]) ? $value : 'download_zip';
|
||||||
|
}
|
||||||
|
|
||||||
|
function scm_validate_install_method_payload($install_method, array $payload, &$message = '')
|
||||||
|
{
|
||||||
|
$install_method = scm_get_install_method_default($install_method);
|
||||||
|
$required = scm_get_install_method_required_fields();
|
||||||
|
$errors = scm_get_install_method_validation_errors();
|
||||||
|
if (!isset($required[$install_method])) {
|
||||||
|
$message = 'Invalid install/content type selected.';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach ($required[$install_method] as $field) {
|
||||||
|
$value = isset($payload[$field]) ? trim((string)$payload[$field]) : '';
|
||||||
|
if ($value === '') {
|
||||||
|
$message = isset($errors[$field]) ? $errors[$field] : 'Missing required field.';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($install_method === 'steam_workshop') {
|
||||||
|
$wid = isset($payload['workshop_item_id']) ? trim((string)$payload['workshop_item_id']) : '';
|
||||||
|
if ($wid === '' || !preg_match('/^[0-9]+$/', $wid)) {
|
||||||
|
$message = 'Please enter a Workshop ID.';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$message = '';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function scm_build_placeholder_map(array $home_info, array $server_context = array(), array $overrides = array())
|
||||||
|
{
|
||||||
|
$home_id = (int)(isset($home_info['home_id']) ? $home_info['home_id'] : 0);
|
||||||
|
$server_root = rtrim(clean_path((string)(isset($home_info['home_path']) ? $home_info['home_path'] : '')), '/');
|
||||||
|
$game_root = $server_root;
|
||||||
|
if (!empty($server_context['exe_location'])) {
|
||||||
|
$exe_location = clean_path((string)$server_context['exe_location']);
|
||||||
|
$exe_dir = dirname($exe_location);
|
||||||
|
if ($exe_dir !== '.' && $exe_dir !== '/') {
|
||||||
|
$game_root = clean_path($server_root . '/' . ltrim($exe_dir, '/'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$map = array(
|
||||||
|
'{HOME_ID}' => (string)$home_id,
|
||||||
|
'{SERVER_ROOT}' => $server_root,
|
||||||
|
'{GAME_ROOT}' => $game_root,
|
||||||
|
'{WORKSHOP_ID}' => '',
|
||||||
|
'{WORKSHOP_APP_ID}' => '',
|
||||||
|
'{STEAM_APP_ID}' => '',
|
||||||
|
);
|
||||||
|
foreach ($overrides as $key => $value) {
|
||||||
|
$token = '{' . strtoupper(trim((string)$key, '{}')) . '}';
|
||||||
|
$map[$token] = (string)$value;
|
||||||
|
}
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
function scm_apply_placeholders($template, array $placeholder_map)
|
||||||
|
{
|
||||||
|
$template = (string)$template;
|
||||||
|
if ($template === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return str_replace(array_keys($placeholder_map), array_values($placeholder_map), $template);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scm_content_logs_dir()
|
||||||
|
{
|
||||||
|
return dirname(__FILE__) . '/logs';
|
||||||
|
}
|
||||||
|
|
||||||
|
function scm_content_log_file()
|
||||||
|
{
|
||||||
|
return scm_content_logs_dir() . '/content_install.log';
|
||||||
|
}
|
||||||
|
|
||||||
|
function scm_log_content_install_action(array $context)
|
||||||
|
{
|
||||||
|
$dir = scm_content_logs_dir();
|
||||||
|
if (!is_dir($dir)) {
|
||||||
|
@mkdir($dir, 0775, true);
|
||||||
|
}
|
||||||
|
$context['logged_at'] = date('Y-m-d H:i:s');
|
||||||
|
$line = json_encode($context);
|
||||||
|
if ($line === false) {
|
||||||
|
$line = '{"logged_at":"' . date('Y-m-d H:i:s') . '","error":"json_encode_failed"}';
|
||||||
|
}
|
||||||
|
@error_log($line . PHP_EOL, 3, scm_content_log_file());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Idempotently ensures the Phase 2 schema is present.
|
* Idempotently ensures the Phase 2 schema is present.
|
||||||
* Called from pages that use manifest / history data so that existing
|
* Called from pages that use manifest / history data so that existing
|
||||||
|
|
@ -290,6 +421,12 @@ function scm_ensure_phase2_schema($db)
|
||||||
'restart_after_install' => "TINYINT(1) NOT NULL DEFAULT 0",
|
'restart_after_install' => "TINYINT(1) NOT NULL DEFAULT 0",
|
||||||
'is_cacheable' => "TINYINT(1) NOT NULL DEFAULT 0",
|
'is_cacheable' => "TINYINT(1) NOT NULL DEFAULT 0",
|
||||||
'description' => "TEXT NULL",
|
'description' => "TEXT NULL",
|
||||||
|
'workshop_item_id' => "VARCHAR(64) NULL",
|
||||||
|
'workshop_app_id' => "VARCHAR(32) NULL",
|
||||||
|
'target_path_template' => "VARCHAR(255) NULL",
|
||||||
|
'optional_folder_name' => "VARCHAR(255) NULL",
|
||||||
|
'config_edit_rule' => "TEXT NULL",
|
||||||
|
'launch_param_additions'=> "VARCHAR(255) NULL",
|
||||||
);
|
);
|
||||||
foreach ($new_columns as $col => $definition) {
|
foreach ($new_columns as $col => $definition) {
|
||||||
$escaped_col = $db->realEscapeSingle($col);
|
$escaped_col = $db->realEscapeSingle($col);
|
||||||
|
|
@ -489,4 +626,3 @@ function scm_upsert_manifest($db, $home_id, $addon_id, array $fields = array())
|
||||||
updated_at = NOW()"
|
updated_at = NOW()"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ function scm_workshop_filter_existing_ids($db, $home_id, array $item_ids)
|
||||||
return array_values($allowed);
|
return array_values($allowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
function scm_workshop_write_manifest_and_run($db, array $home_info, $server_xml, $action, array $item_ids, &$error = '')
|
function scm_workshop_write_manifest_and_run($db, array $home_info, $server_xml, $action, array $item_ids, &$error = '', array $extra_manifest = array())
|
||||||
{
|
{
|
||||||
$error = '';
|
$error = '';
|
||||||
if (empty($item_ids)) {
|
if (empty($item_ids)) {
|
||||||
|
|
@ -102,6 +102,9 @@ function scm_workshop_write_manifest_and_run($db, array $home_info, $server_xml,
|
||||||
'workshop_app_id' => scm_extract_workshop_app_id($server_xml),
|
'workshop_app_id' => scm_extract_workshop_app_id($server_xml),
|
||||||
'items' => array_values($item_ids),
|
'items' => array_values($item_ids),
|
||||||
);
|
);
|
||||||
|
if (!empty($extra_manifest)) {
|
||||||
|
$manifest['extra'] = $extra_manifest;
|
||||||
|
}
|
||||||
$manifest_json = json_encode($manifest);
|
$manifest_json = json_encode($manifest);
|
||||||
if ($manifest_json === false) {
|
if ($manifest_json === false) {
|
||||||
$error = 'Failed to encode workshop manifest JSON.';
|
$error = 'Failed to encode workshop manifest JSON.';
|
||||||
|
|
@ -274,4 +277,3 @@ function scm_workshop_handle_action($db, array $home_info, $user_id, $action, $r
|
||||||
$message = 'Invalid workshop action.';
|
$message = 'Invalid workshop action.';
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -577,3 +577,61 @@ function sw_apply_detected_profile_defaults($db, array $profile, array $detected
|
||||||
);
|
);
|
||||||
return $updated;
|
return $updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function steam_workshop_resolve_paths($db, array $home_info, $workshop_id, $target_path_template = '', $optional_folder_name = '', $workshop_app_id_override = '')
|
||||||
|
{
|
||||||
|
$profile = sw_get_profile_for_home($db, (int)$home_info['home_id']);
|
||||||
|
if (!$profile || !is_array($profile)) {
|
||||||
|
return array('ok' => false, 'error' => 'No enabled Steam Workshop profile for this server home.');
|
||||||
|
}
|
||||||
|
$workshop_id = trim((string)$workshop_id);
|
||||||
|
if ($workshop_id === '' || !preg_match('/^[0-9]+$/', $workshop_id)) {
|
||||||
|
return array('ok' => false, 'error' => 'Invalid Workshop ID.');
|
||||||
|
}
|
||||||
|
$workshop_app_id = trim((string)$workshop_app_id_override);
|
||||||
|
if ($workshop_app_id === '') {
|
||||||
|
$workshop_app_id = (string)$profile['workshop_app_id'];
|
||||||
|
}
|
||||||
|
$folder_name = trim((string)$optional_folder_name);
|
||||||
|
if ($folder_name === '') {
|
||||||
|
$folder_name = '@' . $workshop_id;
|
||||||
|
}
|
||||||
|
$vars = array(
|
||||||
|
'HOME_ID' => (int)$home_info['home_id'],
|
||||||
|
'SERVER_ROOT' => rtrim((string)$home_info['home_path'], '/'),
|
||||||
|
'GAME_ROOT' => rtrim((string)$home_info['home_path'], '/'),
|
||||||
|
'WORKSHOP_ID' => $workshop_id,
|
||||||
|
'WORKSHOP_APP_ID' => $workshop_app_id,
|
||||||
|
'STEAM_APP_ID' => (string)$profile['steam_app_id'],
|
||||||
|
'FOLDER_NAME' => $folder_name,
|
||||||
|
'MOD_FOLDER' => $folder_name,
|
||||||
|
);
|
||||||
|
$target_template = trim((string)$target_path_template);
|
||||||
|
if ($target_template === '') {
|
||||||
|
$target_template = !empty($profile['install_path_template']) ? (string)$profile['install_path_template'] : '{SERVER_ROOT}/{MOD_FOLDER}';
|
||||||
|
}
|
||||||
|
$resolved_target = sw_apply_template($target_template, $vars);
|
||||||
|
return array(
|
||||||
|
'ok' => true,
|
||||||
|
'profile' => $profile,
|
||||||
|
'workshop_id' => $workshop_id,
|
||||||
|
'workshop_app_id' => $workshop_app_id,
|
||||||
|
'steam_app_id' => (string)$profile['steam_app_id'],
|
||||||
|
'folder_name' => $folder_name,
|
||||||
|
'target_path_template' => $target_template,
|
||||||
|
'target_path_resolved' => $resolved_target,
|
||||||
|
'vars' => $vars,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function steam_workshop_download_item($db, array $home_info, $workshop_id, $target_path_template = '', array $options = array())
|
||||||
|
{
|
||||||
|
$optional_folder_name = isset($options['optional_folder_name']) ? $options['optional_folder_name'] : '';
|
||||||
|
$workshop_app_id = isset($options['workshop_app_id']) ? $options['workshop_app_id'] : '';
|
||||||
|
return steam_workshop_resolve_paths($db, $home_info, $workshop_id, $target_path_template, $optional_folder_name, $workshop_app_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function steam_workshop_install_item_to_home($db, array $home_info, $workshop_id, $target_path_template = '', array $options = array())
|
||||||
|
{
|
||||||
|
return steam_workshop_download_item($db, $home_info, $workshop_id, $target_path_template, $options);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1357,6 +1357,10 @@ function api_litefm()
|
||||||
function api_addonsmanager()
|
function api_addonsmanager()
|
||||||
{
|
{
|
||||||
global $request, $db, $user_info;
|
global $request, $db, $user_info;
|
||||||
|
require_once(MODULES.'addonsmanager/server_content_helpers.php');
|
||||||
|
require_once(MODULES.'addonsmanager/workshop_action.php');
|
||||||
|
if (file_exists(MODULES.'steam_workshop/includes/functions.php'))
|
||||||
|
require_once(MODULES.'steam_workshop/includes/functions.php');
|
||||||
|
|
||||||
if($db->isModuleInstalled('addonsmanager') === FALSE)
|
if($db->isModuleInstalled('addonsmanager') === FALSE)
|
||||||
return array("status" => '349', "message" => "This function is not available because the module is not installed.");
|
return array("status" => '349', "message" => "This function is not available because the module is not installed.");
|
||||||
|
|
@ -1427,9 +1431,22 @@ function api_addonsmanager()
|
||||||
|
|
||||||
$addon_info = $addons_rows[0];
|
$addon_info = $addons_rows[0];
|
||||||
|
|
||||||
|
$install_method = scm_get_install_method_default(isset($addon_info['install_method']) ? $addon_info['install_method'] : 'download_zip');
|
||||||
|
$validation_payload = array(
|
||||||
|
'url' => isset($addon_info['url']) ? $addon_info['url'] : '',
|
||||||
|
'path' => isset($addon_info['path']) ? $addon_info['path'] : '',
|
||||||
|
'workshop_item_id' => isset($addon_info['workshop_item_id']) ? $addon_info['workshop_item_id'] : '',
|
||||||
|
'target_path_template' => isset($addon_info['target_path_template']) ? $addon_info['target_path_template'] : '',
|
||||||
|
'post_script' => isset($addon_info['post_script']) ? $addon_info['post_script'] : '',
|
||||||
|
'config_edit_rule' => isset($addon_info['config_edit_rule']) ? $addon_info['config_edit_rule'] : '',
|
||||||
|
);
|
||||||
|
$validation_message = '';
|
||||||
|
if (!scm_validate_install_method_payload($install_method, $validation_payload, $validation_message))
|
||||||
|
return array("status" => '422', "message" => $validation_message);
|
||||||
$url = $addon_info['url'];
|
$url = $addon_info['url'];
|
||||||
$filename = basename($url);
|
$filename = basename($url);
|
||||||
|
|
||||||
|
$post_script = '';
|
||||||
if($addon_info['post_script'] != "")
|
if($addon_info['post_script'] != "")
|
||||||
{
|
{
|
||||||
$addon_info['post_script'] = strip_real_escape_string($addon_info['post_script']);
|
$addon_info['post_script'] = strip_real_escape_string($addon_info['post_script']);
|
||||||
|
|
@ -1461,7 +1478,45 @@ function api_addonsmanager()
|
||||||
$post_script = preg_replace( "/\%incremental\%/i", $home_info['incremental'], $post_script);
|
$post_script = preg_replace( "/\%incremental\%/i", $home_info['incremental'], $post_script);
|
||||||
}
|
}
|
||||||
|
|
||||||
$pid = $remote->start_file_download($addon_info['url'], $home_info['home_path']."/".$addon_info['path'], $filename, "uncompress", $post_script);
|
if ($install_method === 'steam_workshop') {
|
||||||
|
scm_ensure_workshop_schema($db);
|
||||||
|
$workshop_item_id = trim((string)$addon_info['workshop_item_id']);
|
||||||
|
$workshop_error = '';
|
||||||
|
$extra_manifest = array(
|
||||||
|
'addon_id' => (int)$addon_id,
|
||||||
|
'target_path_template' => isset($addon_info['target_path_template']) ? (string)$addon_info['target_path_template'] : '',
|
||||||
|
'optional_folder_name' => isset($addon_info['optional_folder_name']) ? (string)$addon_info['optional_folder_name'] : '',
|
||||||
|
'config_edit_rule' => isset($addon_info['config_edit_rule']) ? (string)$addon_info['config_edit_rule'] : '',
|
||||||
|
'launch_param_additions' => isset($addon_info['launch_param_additions']) ? (string)$addon_info['launch_param_additions'] : '',
|
||||||
|
);
|
||||||
|
$ok = scm_workshop_write_manifest_and_run($db, $home_info, $server_xml, 'install', array($workshop_item_id), $workshop_error, $extra_manifest);
|
||||||
|
if ($ok)
|
||||||
|
return array("status" => "200", "message" => "Workshop content installed successfully.");
|
||||||
|
return array("status" => "342", "message" => "Workshop install failed: ".$workshop_error);
|
||||||
|
}
|
||||||
|
if ($install_method === 'post_script') {
|
||||||
|
$output = $remote->exec("cd " . escapeshellarg($home_info['home_path']) . " && /bin/bash -lc " . escapeshellarg((string)$post_script) . " ; echo __GSP_SCRIPT_EXIT:$?");
|
||||||
|
if (is_string($output) && preg_match('/__GSP_SCRIPT_EXIT:(\d+)/', $output, $m) && (int)$m[1] === 0)
|
||||||
|
return array("status" => "200", "message" => "Script/action completed.");
|
||||||
|
return array("status" => "342", "message" => "Script/action failed.");
|
||||||
|
}
|
||||||
|
if ($install_method === 'config_edit' || $install_method === 'create_folder') {
|
||||||
|
$path = trim((string)$addon_info['path']);
|
||||||
|
if ($path === '')
|
||||||
|
return array("status" => "422", "message" => "Please select a target install path.");
|
||||||
|
$target = (strpos($path, '/') === 0) ? $path : clean_path(rtrim($home_info['home_path'], '/') . '/' . ltrim($path, '/'));
|
||||||
|
if ($install_method === 'create_folder')
|
||||||
|
$out = $remote->exec("mkdir -p " . escapeshellarg($target) . " && echo __GSP_FOLDER_OK");
|
||||||
|
else {
|
||||||
|
$rule = trim((string)$addon_info['config_edit_rule']);
|
||||||
|
$out = $remote->exec("mkdir -p " . escapeshellarg(dirname($target)) . " && touch " . escapeshellarg($target) . " && printf %s " . escapeshellarg($rule . PHP_EOL) . " >> " . escapeshellarg($target) . " && echo __GSP_CONFIG_OK");
|
||||||
|
}
|
||||||
|
if (is_string($out))
|
||||||
|
return array("status" => "200", "message" => "Content action completed.");
|
||||||
|
return array("status" => "342", "message" => "Content action failed.");
|
||||||
|
}
|
||||||
|
$download_action = ($install_method === 'download_file') ? "" : "uncompress";
|
||||||
|
$pid = $remote->start_file_download($addon_info['url'], $home_info['home_path']."/".$addon_info['path'], $filename, $download_action, $post_script);
|
||||||
if($pid > 0)
|
if($pid > 0)
|
||||||
{
|
{
|
||||||
$status = "200";
|
$status = "200";
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue