Beispiel #1
0
        /// <summary>
        /// Generates composite Javascript from a list of scripts
        /// </summary>
        /// <param name="webConnection"></param>
        /// <param name="scriptUrls"></param>
        /// <returns></returns>
        private string GenerateCompositeJavascript(IWebConnection webConnection, IEnumerable<string> scriptUrls)
        {
            StringBuilder scriptBuilder = new StringBuilder();

            foreach (string scriptUrl in scriptUrls)
            {
                try
                {
                    IWebResults webResult = webConnection.ShellTo(scriptUrl);

                    int statusCode = (int)webResult.Status;

                    if ((statusCode >= 200) && (statusCode < 300))
                    {
                        string script = webResult.ResultsAsString;
                        script = JavaScriptMinifier.Instance.Minify(script);

                        scriptBuilder.AppendFormat("\n// {0}\n", scriptUrl);
                        scriptBuilder.Append("try {");
                        scriptBuilder.Append(script);
                        scriptBuilder.Append("} catch (exception) { }");

                        // Note: exceptions are swallowed
                        // This form of compression shouldn't be used when a developer is trying to debug, instead, they should
                        // turn on Javascript debug mode, which disables this compression and allows them to use the browser's
                        // debugger
                    }
                }
                catch (Exception e)
                {
                    log.Error("Error loading script in GenerateCompositeJavascript for script " + scriptUrl, e);
                }
            }

            return scriptBuilder.ToString();
        }
        /// <summary>
        /// Given an enumeration of script names, this returns ALL of the scripts that are needed, and their MD5s for caching.  This
        /// recursively inspects scripts to find dependant scripts underneath
        /// </summary>
        /// <param name="requestedScripts"></param>
        /// <param name="addedScripts">Scripts that have already been added through script tags</param>
        /// <returns></returns>
        public IEnumerable<ScriptAndMD5> DetermineDependantScripts(IEnumerable<string> requestedScripts, IWebConnection webConnection)
        {
            List<string> uninspected = new List<string>();

            // resolve user variables like [blahblah]
            foreach (string requestedScript in requestedScripts)
                uninspected.Add(webConnection.ResolveUserVariables(requestedScript));

            requestedScripts = uninspected.ToArray();

            // Each needed script, and the scripts that it depends on
            Dictionary<string, List<string>> dependancies = new Dictionary<string, List<string>>();

            // Cache of loaded scripts
            Dictionary<string, string> loadedScriptCache = new Dictionary<string, string>();

            // Find all of the needed scripts
            while (uninspected.Count > 0)
            {
                // These are all of the scripts that this script depends on
                List<string> scriptDependancies = new List<string>();

                string scriptToInspect = uninspected[0];
                uninspected.RemoveAt(0);

                if (!webConnection.Scripts.Contains(scriptToInspect))
                {
                    IWebResults shelledScript = webConnection.ShellTo(scriptToInspect);

                    if (null != shelledScript)
                    {
                        string script = shelledScript.ResultsAsString;

                        loadedScriptCache[scriptToInspect] = script;

                        string firstLine = script.Split('\n', '\r')[0];
                        if (firstLine.StartsWith("// Scripts:"))
                        {
                            string unbrokenScripts = firstLine.Substring(11).Trim(); // (The list of scripts must be all on the first line, seperated by commas)

                            foreach (string dependantScriptUntrimmed in unbrokenScripts.Split(','))
                            {
                                string dependantScript = webConnection.ResolveUserVariables(dependantScriptUntrimmed.Trim());

                                // If the script hasn't been scanned, queue it for scanning
                                if (!uninspected.Contains(dependantScript))
                                    if (!dependancies.ContainsKey(dependantScript))
                                        uninspected.Add(dependantScript);

                                scriptDependancies.Add(dependantScript);
                            }
                        }

                        dependancies[scriptToInspect] = scriptDependancies;
                    }
                }
            }

            // Now that all of the needed scripts, and what depends on what are known, create a complete list of needed
            // scripts, sorted so that the lowest-level dependancy comes first
            List<string> sortedDependancies = new List<string>();
            SortDependantScriptsHelper(requestedScripts, dependancies, sortedDependancies);

            // Calculate the results to return
            List<ScriptAndMD5> toReturn = new List<ScriptAndMD5>();
            foreach (string scriptName in sortedDependancies)
                if (!webConnection.Scripts.Contains(scriptName))
                {
                    ScriptAndMD5 scriptAndMD5 = new ScriptAndMD5();
                    scriptAndMD5.ScriptName = scriptName;

                    byte[] scriptBytes = System.Text.Encoding.UTF8.GetBytes(loadedScriptCache[scriptName]);

                    // Get a free hash calculator
                    MD5CryptoServiceProvider hashAlgorithm = StaticRecycler<MD5CryptoServiceProvider>.Get();

                    byte[] scriptHash;
                    try
                    {
                        scriptHash = hashAlgorithm.ComputeHash(scriptBytes);
                    }
                    finally
                    {
                        // Save the hash calculator for reuse
                        StaticRecycler<MD5CryptoServiceProvider>.Recycle(hashAlgorithm);
                    }

                    scriptAndMD5.MD5 = Convert.ToBase64String(scriptHash);

                    toReturn.Add(scriptAndMD5);

                    webConnection.Scripts.Add(scriptName);
                }

            return toReturn;
        }