Files
VRCT/src-ui/app/_app_controllers/plugins_controllers/MergePluginsController.jsx
Sakamoto Shiina 4c12e8b946 [Update/Refactor]
For data integration correctly, the plugins data (saved, downloaded, fetched) merge whenever update data each of it.
Separate plugins controllers.
2025-04-16 19:02:41 +09:00

207 lines
9.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useEffect, useRef } from "react";
import { usePlugins } from "@logics_configs";
import { useSoftwareVersion } from "@logics_common";
export const MergePluginsController = () => {
const {
currentLoadedPlugins,
updatePluginsData,
currentPluginsData,
currentFetchedPluginsInfo,
currentSavedPluginsStatus,
downloadAndExtractPlugin,
} = usePlugins();
const { checkVrctVerCompatibility } = useSoftwareVersion();
// downloaded, fetched, saved の各情報をまとめてマージ
useEffect(() => {
const mergePluginData = () => {
updatePluginsData(prev => {
// downloaded, fetched, 保存済み状態のMapをそれぞれ作成plugin_id をキー)
const downloaded_map = new Map(
currentLoadedPlugins.data.map(info => [info.plugin_id, info])
);
const fetched_map = new Map(
currentFetchedPluginsInfo.data.map(info => [info.plugin_id, info])
);
const saved_map = new Map(
currentSavedPluginsStatus.data.map(saved => [saved.plugin_id, saved])
);
const prev_map = new Map(
prev.data.map(item => [item.plugin_id, item])
);
// union_keys: Saved以外の情報に対して重複なくキーを取得する
const union_keys = new Set([
...downloaded_map.keys(),
...fetched_map.keys(),
...prev_map.keys(),
]);
const new_data = [];
for (const id of union_keys) {
const downloaded = downloaded_map.get(id);
const fetched = fetched_map.get(id);
const prev_plugin = prev_map.get(id);
let plugin = {};
if (downloaded) {
// ダウンロード済み情報に対してサポート確認
const { is_plugin_supported, is_plugin_supported_latest_vrct } =
checkVrctVerCompatibility(
downloaded.min_supported_vrct_version,
downloaded.max_supported_vrct_version
);
plugin = {
// prevの情報があれば引き継ぎつつ上書き
...(prev_plugin || {}),
plugin_id: downloaded.plugin_id,
component: downloaded.component,
is_downloaded: true,
downloaded_plugin_info: {
...downloaded,
is_plugin_supported,
is_plugin_supported_latest_vrct,
},
};
if (fetched) {
const is_latest_version_available =
(downloaded.plugin_version !== fetched.plugin_version && fetched.is_plugin_supported);
plugin = {
...plugin,
is_outdated: false,
latest_plugin_info: { ...fetched },
is_latest_version_available:
plugin.is_downloaded && is_latest_version_available,
is_latest_version_already:
downloaded.plugin_version === fetched.plugin_version,
};
} else {
// フェッチ情報がない場合の初期状態
plugin = {
...plugin,
is_latest_version_available: false,
is_latest_version_already: true,
};
}
} else if (fetched) {
// フェッチ情報のみの場合は、ダウンロードしていない初期状態
plugin = {
...(prev_plugin || {}),
plugin_id: fetched.plugin_id,
is_downloaded: false,
is_latest_version_available: fetched.is_plugin_supported,
is_latest_version_already: false,
is_outdated: false,
latest_plugin_info: { ...fetched },
};
} else if (prev_plugin) {
// 既存情報のみ存在する場合は outdated フラグを付与
plugin = { ...prev_plugin, is_outdated: true };
}
// いずれかの情報がある場合のみ new_data に追加
if (plugin.plugin_id) {
new_data.push(plugin);
}
}
// 保存済み状態currentSavedPluginsStatusのマージ
// ・new_dataに存在する各プラグインに対して、保存済みの is_enabled を上書き
new_data.forEach(plugin => {
if (saved_map.has(plugin.plugin_id)) {
plugin.is_enabled = saved_map.get(plugin.plugin_id).is_enabled;
}
});
// ・prev.data には存在せず、保存済み情報にのみある場合は追加
for (const [id, saved] of saved_map.entries()) {
if (!new_data.some(item => item.plugin_id === id)) {
new_data.push({ plugin_id: saved.plugin_id, is_enabled: saved.is_enabled });
}
}
// 追加処理: ダウンロード済みかつ有効なプラグインで、サポート対象でない場合は無効化
new_data.forEach(plugin => {
if (plugin.is_downloaded && plugin.is_enabled) {
if (
!plugin.downloaded_plugin_info?.is_plugin_supported &&
!plugin.latest_plugin_info?.is_plugin_supported
) {
plugin.is_enabled = false;
}
}
});
console.log("merged plugin data", new_data);
return new_data;
});
};
mergePluginData();
}, [currentFetchedPluginsInfo.data, currentLoadedPlugins.data, currentSavedPluginsStatus]);
// --- 自動アップデートダウンロード処理のuseEffect ---
// ※downloadAndExtractPlugin の重複実行を防ぐため、実行中の plugin_id を useRef で管理
const downloadingRef = useRef(new Set());
useEffect(() => {
if (!currentPluginsData.data.length) return;
// マージ結果の currentPluginsData.data を元にダウンロード処理をチェック
currentPluginsData.data.forEach(plugin => {
if (plugin.is_downloaded &&
plugin.is_enabled &&
!plugin.is_latest_version_already &&
plugin.is_latest_version_available
) {
console.log(!downloadingRef.current.has(plugin.plugin_id));
if (!downloadingRef.current.has(plugin.plugin_id)) {
downloadingRef.current.add(plugin.plugin_id);
// ※ downloadAndExtractPlugin は外部通信を伴い currentLoadedPlugins.data 更新を引き起こすので注意
downloadAndExtractPlugin(plugin)
.then(() => {
console.log(`Plugin ${plugin.plugin_id} updated successfully`);
downloadingRef.current.delete(plugin.plugin_id);
})
.catch((error) => {
console.error(`Plugin ${plugin.plugin_id} update failed`, error);
downloadingRef.current.delete(plugin.plugin_id);
});
}
}
});
}, [currentPluginsData.data]);
return null;
};
// ダウンロード済みで最新版じゃない場合、自動的にアップデート
// // is_latest_version_supported: true のみ。
// // 失敗した場合、現在のバージョンが非対応の場合はdisabledにする。
// new_data.forEach(async plugin => {
// if (plugin.is_enabled) {
// console.log(plugin);
// if (!plugin.is_latest_version_already && plugin.is_latest_version_available) {
// await downloadAndExtractPlugin(plugin);
// }
// }
// });
// new_data.forEach(plugin => {
// if (plugin.is_downloaded && plugin.is_enabled) {
// if (!plugin.downloaded_plugin_info?.is_plugin_supported && !plugin.latest_plugin_info?.is_plugin_supported) {
// plugin.is_enabled = false
// }
// }
// });