public static ResultReport <Root> ReadUpdateJson(string metaJsonFile) { // Prepare JsonSerializer JsonSerializer serializer = CreateJsonSerializer(); // Read json file Root jsonRoot; try { // Use UTF-8 without a BOM signature, as the file was served by a web server using (StreamReader sr = new StreamReader(metaJsonFile, new UTF8Encoding(false), false)) using (JsonTextReader jr = new JsonTextReader(sr)) { jsonRoot = serializer.Deserialize <Root>(jr); } } catch (JsonException e) { return(new ResultReport <Root>(false, null, $"Update json file is corrupted: {Logger.LogExceptionMessage(e)}")); } // Validate json instance ResultReport report = jsonRoot.Validate(); if (!report.Success) { return(new ResultReport <Root>(false, null, report.Message)); } return(new ResultReport <Root>(true, jsonRoot)); }
/// <summary> /// Return true if a schema is valid /// </summary> /// <returns>True if valid</returns> public ResultReport Validate() { if (!Enum.IsDefined(typeof(ScriptFormat), Format)) { return(new ResultReport(false, $"Not supported script format {Format}")); } switch (Format) { case ScriptFormat.IniBased: if (IniBased == null) { return(new ResultReport(false, $"Unable to find script information")); } ResultReport report = IniBased.Validate(); if (!report.Success) { return(report); } break; default: return(new ResultReport(false, $"Internal error at {nameof(UpdateJson)}.{nameof(ScriptInfo)}.{nameof(Validate)}")); } return(new ResultReport(true)); }
public (Script[], LogInfo[]) UpdateScripts(IEnumerable <Script> scripts, bool preserveScriptState) { // Get updateable scripts urls Script[] updateableScripts = scripts.Where(s => s.IsUpdateable).ToArray(); List <Script> newScripts = new List <Script>(updateableScripts.Length); List <LogInfo> logs = new List <LogInfo>(updateableScripts.Length); if (_m != null) { _m.BuildScriptProgressVisibility = Visibility.Collapsed; } _m?.SetBuildCommandProgress("Download Progress", updateableScripts.Length); try { int i = 0; foreach (Script sc in updateableScripts) { i++; ScriptStateBackup stateBackup = null; if (preserveScriptState) { stateBackup = BackupScriptState(sc); Debug.Assert(stateBackup != null, "ScriptStateBackup is null"); } if (_m != null) { _m.BuildEchoMessage = $"Updating script [{sc.Title}]... ({i}/{updateableScripts.Length})"; } ResultReport <Script> report = InternalUpdateOneScript(sc, stateBackup); if (report.Success && report.Result != null) { newScripts.Add(report.Result); } logs.Add(report.ToLogInfo()); if (_m != null) { _m.BuildCommandProgressValue += 1; } } } finally { _m?.ResetBuildCommandProgress(); if (_m != null) { _m.BuildEchoMessage = string.Empty; _m.BuildScriptProgressVisibility = Visibility.Visible; } } return(newScripts.ToArray(), logs.ToArray()); }
/// <summary> /// Return true if schema is valid /// </summary> /// <returns>True if valid</returns> public ResultReport Validate() { // Check if properties are not null if (SchemaVer == null || PEBakeryMinVer == null) { return(new ResultReport(false, "Update json is corrupted")); } // Check schema_ver and pebakery_min_ver if (Global.Const.UpdateSchemaMaxVerInst < SchemaVer) { return(new ResultReport(false, "Requires newer version of PEBakery")); } if (SchemaVer < Global.Const.UpdateSchemaMinVerInst) { return(new ResultReport(false, "Update json is too old to be read by PEbakery")); } if (Global.Const.ProgramVersionInst < PEBakeryMinVer) { return(new ResultReport(false, $"Requires PEBakery {Global.Const.ProgramVersionStr} or higher")); } // Check created_at if (CreatedAt.Equals(DateTime.MinValue)) { return(new ResultReport(false, "Update json is corrupted")); } // Check file index if (Index == null) { return(new ResultReport(false, "Update json is corrupted")); } ResultReport report = Index.Validate(); if (!report.Success) { return(report); } return(new ResultReport(true)); }
public static LogInfo ToLogInfo <T1, T2>(this ResultReport <T1, T2> report) { LogState state = report.Success ? LogState.Success : LogState.Error; return(new LogInfo(state, report.Message)); }
private ResultReport <Script> InternalUpdateOneScript(Script sc, ScriptStateBackup stateBackup) { // Never should be triggered, because Script class constructor check it Debug.Assert(sc.ParsedVersion != null, $"Local script [{sc.Title}] does not provide proper version information"); string updateUrl = sc.UpdateUrl; string metaJsonUrl = Path.ChangeExtension(updateUrl, ".meta.json"); string metaJsonFile = FileHelper.GetTempFile(".meta.json"); string tempScriptFile = FileHelper.GetTempFile(".script"); try { // Download .meta.json HttpFileDownloader.Report httpReport = DownloadFile(metaJsonUrl, metaJsonFile); if (!httpReport.Result) { // Failed to send a request, such as network not available if (httpReport.StatusCode == 0) { return(new ResultReport <Script>(false, null, $"Unable to connect to the server")); } // Try downloading .deleted to check if a script is deleted string errorMsg; string deletedUrl = Path.ChangeExtension(updateUrl, ".deleted"); string deletedFile = Path.ChangeExtension(metaJsonFile, ".deleted"); try { httpReport = DownloadFile(deletedUrl, deletedFile); if (httpReport.Result) { // Successfully received response if (httpReport.StatusCode == 200) // .deleted file exists in the server { errorMsg = $"[{sc.Title}] was deleted from the server"; } else // There is no .deleted file in the server { errorMsg = $"Update is not available for [{sc.Title}]"; } } else { if (httpReport.StatusCode == 0) // Failed to send a request, such as network not available { errorMsg = $"Unable to connect to the server"; } else { errorMsg = $"Update is not available for [{sc.Title}]"; } } } finally { if (File.Exists(deletedFile)) { File.Delete(deletedFile); } } return(new ResultReport <Script>(false, null, errorMsg)); } // Check and read .meta.json ResultReport <UpdateJson.Root> jsonReport = UpdateJson.ReadUpdateJson(metaJsonFile); if (!jsonReport.Success) { return(new ResultReport <Script>(false, null, jsonReport.Message)); } UpdateJson.Root metaJson = jsonReport.Result; UpdateJson.FileIndex index = metaJson.Index; if (index.Kind != UpdateJson.IndexEntryKind.Script) { return(new ResultReport <Script>(false, null, "Update json is not of a script file")); } UpdateJson.ScriptInfo scInfo = index.ScriptInfo; if (scInfo.Format != UpdateJson.ScriptFormat.IniBased) { return(new ResultReport <Script>(false, null, $"Format [{scInfo.Format}] of remote script [{sc.Title}] is not supported")); } UpdateJson.IniBasedScript iniScInfo = scInfo.IniBased; if (iniScInfo.Version <= sc.ParsedVersion) { return(new ResultReport <Script>(false, null, $"You are using the lastest version of script [{sc.Title}]")); } // Download .script file httpReport = DownloadFile(updateUrl, tempScriptFile); if (!httpReport.Result) { return(new ResultReport <Script>(false, null, httpReport.ErrorMsg)); } // Verify downloaded .script file with FileMetadata ResultReport verifyReport = index.FileMetadata.VerifyFile(tempScriptFile); if (!verifyReport.Success) { return(new ResultReport <Script>(false, null, $"Remote script [{sc.Title}] is corrupted")); } // Check downloaded script's version and check // Must have been checked with the UpdateJson string remoteVerStr = IniReadWriter.ReadKey(tempScriptFile, "Main", "Version"); VersionEx remoteVer = VersionEx.Parse(remoteVerStr); if (remoteVer == null) { return(new ResultReport <Script>(false, null, $"Version of remote script [{sc.Title}] is corrupted")); } if (!remoteVer.Equals(iniScInfo.Version)) { return(new ResultReport <Script>(false, null, $"Version of remote script [{sc.Title}] is corrupted")); } if (remoteVer <= sc.ParsedVersion) { return(new ResultReport <Script>(false, null, $"Version of remote script [{sc.Title}] is corrupted")); } // Check if remote script is valid Script remoteScript = _p.LoadScriptRuntime(tempScriptFile, new LoadScriptRuntimeOptions { IgnoreMain = false, AddToProjectTree = false, OverwriteToProjectTree = false, }); if (remoteScript == null) { return(new ResultReport <Script>(false, null, $"Remote script [{sc.Title}] is corrupted")); } // Overwrite backup state to new script if (stateBackup != null) { RestoreScriptState(remoteScript, stateBackup); // Let's be extra careful remoteScript = _p.RefreshScript(remoteScript); if (remoteScript == null) { return(new ResultReport <Script>(false, null, $"Internal error at {nameof(FileUpdater)}.{nameof(RestoreScriptState)}")); } } // Copy downloaded remote script into new script File.Copy(tempScriptFile, sc.DirectRealPath, true); Script newScript = _p.RefreshScript(sc); // Return updated script instance return(new ResultReport <Script>(true, newScript, $"Updated script [{sc.Title}] to [v{sc.RawVersion}] from [v{newScript.RawVersion}]")); } finally { if (File.Exists(metaJsonFile)) { File.Delete(metaJsonFile); } if (File.Exists(tempScriptFile)) { File.Delete(tempScriptFile); } } }
/// <summary> /// Recursively check sanity of the FileIndex and its children. Return true if a schema is valid. /// </summary> /// <returns>Return true if a schema is valid.</returns> public ResultReport Validate() { Queue <FileIndex> q = new Queue <FileIndex>(); q.Enqueue(this); do { FileIndex fi = q.Dequeue(); // Check if properties are not null if (fi.Name == null) { return(new ResultReport(false, "File index is corrupted")); } // Check filename / foldername if (!FileHelper.CheckWin32Path(Name, false, false)) { return(new ResultReport(false, "File index is corrupted")); } // Check per kind switch (fi.Kind) { case IndexEntryKind.Folder: { if (Children == null) { return(new ResultReport(false, $"Children of folder [{Name}] is corrupted")); } foreach (FileIndex sub in Children) { q.Enqueue(sub); } } break; case IndexEntryKind.Script: { // Check null if (FileMetadata == null) { return(new ResultReport(false, $"Metadata of script [{Name}] is corrupted")); } if (ScriptInfo == null) { return(new ResultReport(false, $"Information of script [{Name}] is corrupted")); } // Check file metadata ResultReport report = FileMetadata.Validate(); if (!report.Success) { return(report); } // Check script information report = ScriptInfo.Validate(); if (!report.Success) { return(report); } } break; case IndexEntryKind.NonScriptFile: { if (FileMetadata == null) { return(new ResultReport(false, $"Metadata of script {Name} is corrupted")); } // Check file metadata ResultReport report = FileMetadata.Validate(); if (!report.Success) { return(report); } } break; } }while (0 < q.Count); return(new ResultReport(true)); }