[Update/Refactor]

For data integration correctly, the plugins data (saved, downloaded, fetched) merge whenever update data each of it.
Separate plugins controllers.
This commit is contained in:
Sakamoto Shiina
2025-04-16 19:02:41 +09:00
parent 379ca86b45
commit 4c12e8b946
8 changed files with 268 additions and 175 deletions

View File

@@ -1,15 +1,24 @@
import React, { useEffect } from "react";
import React from "react";
import clsx from "clsx";
if (typeof window !== "undefined") {
window.React = React;
window.clsx = clsx;
}
import { LoadPluginsController } from "./plugins_controllers/LoadPluginsController";
import { FetchLatestPluginsDataController } from "./plugins_controllers/FetchLatestPluginsDataController";
import { MergeSavedPluginsStatusController } from "./plugins_controllers/MergeSavedPluginsStatusController";
// import { MergeSavedPluginsStatusController } from "./plugins_controllers/MergeSavedPluginsStatusController";
import { MergePluginsController } from "./plugins_controllers/MergePluginsController";
export const PluginsController = () => {
export const PluginsController = ({ pluginsControllerHasRunRef }) => {
return (
<>
<LoadPluginsController />
<FetchLatestPluginsDataController />
<MergeSavedPluginsStatusController />
<MergePluginsController />
<LoadPluginsController pluginsControllerHasRunRef={pluginsControllerHasRunRef}/>
<FetchLatestPluginsDataController pluginsControllerHasRunRef={pluginsControllerHasRunRef}/>
{/* <MergeSavedPluginsStatusController /> */}
</>
);
};

View File

@@ -1,115 +1,25 @@
import { useEffect } from "react";
import { usePlugins } from "@logics_configs";
export const FetchLatestPluginsDataController = () => {
export const FetchLatestPluginsDataController = ({ pluginsControllerHasRunRef }) => {
const {
asyncFetchPluginsInfo,
updatePluginsData,
downloadAndExtractPlugin,
currentIsInitializedLoadPlugin,
currentIsFetchedPluginsInfo,
updateIsFetchedPluginsInfo,
} = usePlugins();
const asyncUpdateLatestPluginsData = async () => {
const asyncInitFetchPluginsInfo = async () => {
try {
const info_array = await asyncFetchPluginsInfo();
updatePluginsData(prev => {
// Map を利用してそれぞれの配列を plugin_id で参照できるようにする
const info_map = new Map(info_array.map(info => [info.plugin_id, info]));
const prev_map = new Map(prev.data.map(item => [item.plugin_id, item]));
console.log(prev_map);
const new_data = [];
for (const info of info_array) {
let new_plugin_info = {};
if (prev_map.has(info.plugin_id)) { // plugin_id 登録済み
const target_downloaded_plugin = prev_map.get(info.plugin_id);
if (target_downloaded_plugin.is_downloaded) { // 既にダウンロード済み
const is_latest_version_available = !(target_downloaded_plugin.plugin_version === info.plugin_version);
new_plugin_info = {
...target_downloaded_plugin,
is_downloaded: true,
latest_plugin_info: { ...info },
is_latest_version_available: is_latest_version_available,
is_latest_version_already: (target_downloaded_plugin.downloaded_plugin_info?.plugin_version === info.plugin_version),
};
} else { // infoにもあり登録済みだがダウンロードされていない
new_plugin_info = {
...target_downloaded_plugin,
is_downloaded: false,
is_latest_version_already: false,
is_latest_version_available: info.is_latest_version_available,
latest_plugin_info: { ...info },
}
}
} else { // 未ダウンロード
new_plugin_info = {
plugin_id: info.plugin_id,
is_downloaded: false,
is_latest_version_already: false,
latest_plugin_info: { ...info },
};
}
new_data.push(new_plugin_info);
}
// prev.data にのみ存在するアイテム = latest plugin infoには存在しない
// を追加し、is_outdated: true を付与
prev.data.forEach(item => {
if (!info_map.has(item.plugin_id)) {
new_data.push({ ...item, is_outdated: true });
}
});
new_data.forEach(plugin => {
if (!plugin.is_outdated) {
plugin.is_latest_version_available = (plugin.latest_plugin_info.is_plugin_supported);
}
});
// ダウンロード済みで最新版じゃない場合、自動的にアップデート
// 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(async 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
}
}
});
return new_data;
});
await asyncFetchPluginsInfo();
} catch (error) {
console.error(error);
}
};
useEffect(() => {
console.log(currentIsInitializedLoadPlugin.data);
if (currentIsInitializedLoadPlugin.data && !currentIsFetchedPluginsInfo.data) {
asyncUpdateLatestPluginsData().then(() => {
updateIsFetchedPluginsInfo(true);
});
if (!pluginsControllerHasRunRef.current.is_init_fetched_plugins_info) {
asyncInitFetchPluginsInfo();
pluginsControllerHasRunRef.current.is_init_fetched_plugins_info = true;
}
}, [currentIsInitializedLoadPlugin.data]);
}, []);
return null;
};

View File

@@ -1,17 +1,9 @@
import React, { useEffect } from "react";
import { usePlugins } from "@logics_configs";
import clsx from "clsx";
if (typeof window !== "undefined") {
window.React = React;
window.clsx = clsx;
}
export const LoadPluginsController = () => {
export const LoadPluginsController = ({ pluginsControllerHasRunRef }) => {
const {
asyncLoadAllPlugins,
currentIsInitializedLoadPlugin,
updateIsInitializedLoadPlugin,
} = usePlugins();
@@ -24,11 +16,11 @@ export const LoadPluginsController = () => {
};
useEffect(() => {
if (!currentIsInitializedLoadPlugin.data) {
if (!pluginsControllerHasRunRef.current.is_initialized_load_plugin) {
asyncInitLoadPlugins().then(() => {
updateIsInitializedLoadPlugin(true);
});
pluginsControllerHasRunRef.current.is_initialized_load_plugin = true;
}
}, []);

View File

@@ -0,0 +1,207 @@
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
// }
// }
// });