(
instanceUuid: string,
page: number = 1,
pageSize: number = 50,
folder?: string
)
| 182 | } |
| 183 | |
| 184 | public async listMods( |
| 185 | instanceUuid: string, |
| 186 | page: number = 1, |
| 187 | pageSize: number = 50, |
| 188 | folder?: string |
| 189 | ): Promise<ModListResult> { |
| 190 | // Enforce max page size of 50 |
| 191 | if (pageSize > 50) pageSize = 50; |
| 192 | if (pageSize < 1) pageSize = 10; |
| 193 | if (page < 1) page = 1; |
| 194 | |
| 195 | const instance = InstanceSubsystem.getInstance(instanceUuid)!; |
| 196 | const cwd = instance.absoluteCwdPath(); |
| 197 | const fileManager = new FileManager( |
| 198 | resolveMCDRServerRoot(instance.config.type, cwd) ?? cwd, |
| 199 | instance.config?.fileCode |
| 200 | ); |
| 201 | |
| 202 | // if (!FileManager.checkFileName(folder ?? "")) { |
| 203 | // throw new Error("Invalid folder name"); |
| 204 | // } |
| 205 | |
| 206 | const result: ModInfo[] = []; |
| 207 | const folders: string[] = []; |
| 208 | const tasks: (() => Promise<void>)[] = []; |
| 209 | |
| 210 | const scanDir = async (dirName: string, defaultType: "mod" | "plugin") => { |
| 211 | const dir = fileManager.toAbsolutePath(dirName); |
| 212 | if (await fs.pathExists(dir)) { |
| 213 | if (!folders.includes(dirName.toLowerCase())) { |
| 214 | folders.push(dirName.toLowerCase()); |
| 215 | } |
| 216 | const files = await fs.readdir(dir); |
| 217 | for (const file of files) { |
| 218 | if (file.endsWith(".jar") || file.endsWith(".jar.disabled")) { |
| 219 | const fullPath = path.join(dir, file); |
| 220 | const enabled = !file.endsWith(".disabled"); |
| 221 | |
| 222 | tasks.push(async () => { |
| 223 | try { |
| 224 | const stat = await fs.stat(fullPath); |
| 225 | const cacheKey = `${instanceUuid}:${fullPath}`; |
| 226 | const cached = this.cache.get(cacheKey); |
| 227 | |
| 228 | let metadata: Partial<ModInfo> | null = null; |
| 229 | let hash = ""; |
| 230 | |
| 231 | if (cached && cached.mtime === stat.mtimeMs && cached.size === stat.size) { |
| 232 | metadata = cached.info; |
| 233 | hash = cached.hash; |
| 234 | } else { |
| 235 | metadata = await this.parseJarMetadata(fullPath); |
| 236 | hash = await this.getFileHash(fullPath); |
| 237 | if (this.cache.size >= this.MAX_CACHE_SIZE) { |
| 238 | const firstKey = this.cache.keys().next().value; |
| 239 | if (firstKey) this.cache.delete(firstKey); |
| 240 | } |
| 241 | this.cache.set(cacheKey, { |
no test coverage detected