Ejemplo n.º 1
0
        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());
        }
Ejemplo n.º 2
0
        /// <summary>
        /// To the best-effort to restore script state
        /// </summary>
        /// <remarks>
        /// This method does not refresh the Script instance, it is the responsibility of a callee
        /// </remarks>
        private static void RestoreScriptState(Script sc, ScriptStateBackup backup)
        {
            List <string> ifaceSectionNames = sc.GetInterfaceSectionNames(false);

            // Restore selected state
            IniReadWriter.WriteKey(sc.RealPath, ScriptSection.Names.Main, Script.Const.Selected, backup.Selected.ToString());

            // Restore interfaces
            List <UIControl> newCtrls = new List <UIControl>();

            foreach (var kv in backup.IfaceSectionDict)
            {
                string           ifaceSectionName = kv.Key;
                List <UIControl> bakCtrls         = kv.Value;

                if (!ifaceSectionNames.Contains(ifaceSectionName))
                {
                    continue;
                }

                (List <UIControl> uiCtrls, _) = sc.GetInterfaceControls(ifaceSectionName);
                foreach (UIControl uiCtrl in uiCtrls)
                {
                    // Get old uiCtrl, equality identified by Type and Key.
                    UIControl bakCtrl = bakCtrls.FirstOrDefault(bak => bak.Type == uiCtrl.Type && bak.Key.Equals(uiCtrl.Key, StringComparison.OrdinalIgnoreCase));
                    if (bakCtrl == null)
                    {
                        continue;
                    }

                    // Get old value
                    string bakValue = bakCtrl.GetValue(false);
                    Debug.Assert(bakValue != null, "Internal Logic Error at FileUpdater.RestoreInterface");

                    // Add to newCtrls only if apply was successful
                    if (uiCtrl.SetValue(bakValue, false, out _))
                    {
                        newCtrls.Add(uiCtrl);
                    }
                }
            }

            // Write to file
            UIControl.Update(newCtrls);
        }
Ejemplo n.º 3
0
        public (Script, LogInfo) UpdateScript(Script sc, bool preserveScriptState)
        {
            if (!sc.IsUpdateable)
            {
                return(null, new LogInfo(LogState.Error, $"Script [{sc.Title} is not updateable"));
            }

            // Backup interface state of original script
            ScriptStateBackup stateBackup = null;

            if (preserveScriptState)
            {
                stateBackup = BackupScriptState(sc);
                Debug.Assert(stateBackup != null, "ScriptStateBackup is null");
            }

            ResultReport <Script> report;

            _m?.SetBuildCommandProgress("Download Progress", 1);
            try
            {
                if (_m != null)
                {
                    _m.BuildEchoMessage = $"Updating script [{sc.Title}]...";
                }

                report = InternalUpdateOneScript(sc, stateBackup);

                if (_m != null)
                {
                    _m.BuildCommandProgressValue = 1;
                }
            }
            finally
            {
                _m?.ResetBuildCommandProgress();
                if (_m != null)
                {
                    _m.BuildEchoMessage = string.Empty;
                }
            }

            return(report.Result, report.ToLogInfo());
        }
Ejemplo n.º 4
0
        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);
                }
            }
        }