import 'dart:convert'; import 'dart:io'; import 'package:crypto/crypto.dart' as crypto; import 'package:flutter/foundation.dart'; import 'Backend.dart'; import 'DebugHelper.dart'; import 'package:path/path.dart' as Path; import 'package:http/http.dart' as http; import 'FileHashEntry.dart'; class InstallHelper{ static String GetFilePath(int id) => Backend.prefs!.getString('${Backend.Games[id].name}_path') ?? '${Path.join(Backend.docPath!.path, Backend.Games[id].name)}'; static String GetValidationSaveKey(int id)=>'${Backend.Games[id].code}_localFileData'; static String? GetSavedValidationData(int id) => Backend.prefs!.getString(GetValidationSaveKey(id)); static Future> GetMissingFiles(int gameId, {bool force = false}) async{ List missingFiles = []; Directory pathDir = Directory(GetFilePath(gameId)); List localFiles = []; bool usedLocalSave = false; if(!force){ String? savedData =GetSavedValidationData(gameId); if(savedData != null){ localFiles = FileHashEntry.listFromJson(savedData); usedLocalSave=true; }else{ localFiles = await getHashtable(pathDir); } }else{ localFiles = await getHashtable(pathDir); } //Get local hashtable // Debug.Log(localFilesJson); //Write to file if(!usedLocalSave){ String localFilesJson = FileHashEntry.listToJson(localFiles); Backend.prefs!.setString(GetValidationSaveKey(gameId),localFilesJson); if(kDebugMode) { File writeJsonFile = File(Path.join(pathDir.parent.path, "hashes.txt")); writeJsonFile.writeAsString(localFilesJson); } } //Get remote hashtable String link ='${Backend.API_ENDPOINT}${Backend.Games[gameId].code}/get_hashes.php'; var remoteHashResponse = (await http.post(Uri.parse(link))); Debug.LogResponse(remoteHashResponse.body.toString(),src: link); List remoteList = FileHashEntry.listFromJson(remoteHashResponse.body.toString()); //Comapreeee for(int i = 0; i > getHashtable(Directory pathDir) async{ if(!pathDir.existsSync()){return [];} List list =await pathDir.list(recursive: true).toList(); List output = []; for(int i =0; i < list.length; i++){ FileSystemEntity element = list[i]; File file = File(element.path); if(await file.exists()) { String hash = await calculateMD5SumAsyncWithCrypto(element.path); int size = file.lengthSync(); output.add(FileHashEntry(element.path.replaceAll(pathDir.path, ''), hash, size)); // Debug.Log('${element.path}: ${hash}: ${size}'); } } return output; } static String DOWNLOAD_BIN_ROOT = "https://vps.playpoolstudios.com/metahunt/data/bin/"; static List GetMissingFileLinks(List missingList,int gameId){ List output = []; missingList.forEach((element) { output.add(GetFileUrl(element.file, gameId)); }); return output; } static String GetFileUrl(String path, int id){ return '${DOWNLOAD_BIN_ROOT}${Backend.Games[id].code}${path.replaceAll('\\', '/')}'; } static Future calculateMD5SumAsyncWithCrypto(String filePath) async { var ret = ''; var file = File(filePath); if (await file.exists()) { try { var md5 = crypto.md5; var hash = await md5.bind(file.openRead()).first; ret = hash.toString(); // ret = base64.encode(hash.bytes); } catch (exception) { print('Unable to evaluate the MD5 sum :$exception'); return ''; } } else { print('`$filePath` does not exits so unable to evaluate its MD5 sum.'); return ''; } return ret; } static String GetExeFilePath(int i){ return Path.join(GetFilePath(i), Backend.Games[i].exeName); } }