// This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddScoped <IBrowserOptimizeCssService, BrowserOptimizeCssService>();
            services.AddScoped <ICustomOptimizeCssService, CustomOptimizeCssService>();

            services.AddMvc(opt => opt.Filters.Add <GlobalExceptionFilter>());

            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1",
                             new Info
                {
                    Title   = ApiName,
                    Version = "v1"
                });

                // UseFullTypeNameInSchemaIds replacement for .NET Core
                c.CustomSchemaIds(x => x.FullName);
            });

            //just use this to be sure that AngleSharp lib will be loaded
            var initAngleSharp = AngleSharp.Configuration.Default.GetType();

            //Register popular encoding providers (to be able parse response from http client)
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

            //Register options
            var chromeSessionPoolConfig = Configuration.GetSection(ConfigurationConstants.CHROME_SESSION_POOL_CONFIGURATION_SECTION);

            services.Configure <CacheConfiguration>(Configuration.GetSection(ConfigurationConstants.CACHE_CONFIGURATION_SECTION));
            services.Configure <ChromeSessionPoolConfiguration>(chromeSessionPoolConfig);

            //Don't wait until chrome sessions pool will be initialize.
            //In production probably will be better to wait.
            var chromeSessionPoolConfigObject = chromeSessionPoolConfig.Get <ChromeSessionPoolConfiguration>();

            if (chromeSessionPoolConfigObject.IsPreInitializeChromeSessionPool)
            {
                if (chromeSessionPoolConfigObject.WaitForInitializing)
                {
                    Task.WaitAll(ChromeSessionPool.InitPool(chromeSessionPoolConfigObject));
                }
                else
                {
                    ChromeSessionPool.InitPool(chromeSessionPoolConfigObject);
                }
            }
        }
Example #2
0
        private async Task <string> GetMinCssForUrlAsync(string url)
        {
            //Take from cache if exists
            if (_cache.Get <string>(url) != null)
            {
                return(_cache.Get <string>(url));
            }

            //Take available session from pool
            var chromeSession = ChromeSessionPool.GetInstance();

            try
            {
                //Navigate to page, enable and start rule usage tracking
                await chromeSession.InternalSession.DOM.Enable(new DOM.EnableCommand());

                await chromeSession.InternalSession.CSS.Enable(new CSS.EnableCommand());

                await chromeSession.InternalSession.CSS.StartRuleUsageTracking(new CSS.StartRuleUsageTrackingCommand());

                await chromeSession.InternalSession.Page.Navigate(new NavigateCommand { Url = url });

                var rules = new List <RuleUsage>();
                TakeCoverageDeltaCommandResponse coverageResponse;


                //TODO: smart logic to wait report, currently just wait when delta == 0
                var waitCount = 0;
                do
                {
                    //https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-takeCoverageDelta
                    coverageResponse = await chromeSession.InternalSession.CSS.TakeCoverageDelta(new TakeCoverageDeltaCommand());

                    coverageResponse.Coverage = coverageResponse.Coverage ?? new RuleUsage[0];

                    //If no found.. sleep and try it again
                    if (coverageResponse.Coverage.Length == 0)
                    {
                        Thread.Sleep(++waitCount * 100);

                        //try again after sleep
                        //timeout 120 seconds
                        coverageResponse = await chromeSession.InternalSession.CSS.TakeCoverageDelta(new TakeCoverageDeltaCommand());

                        coverageResponse.Coverage = coverageResponse.Coverage ?? new RuleUsage[0];

                        rules.AddRange(coverageResponse.Coverage);

                        //if found, reset sleep count, because it means that chrome is processing css
                        if (coverageResponse.Coverage.Length > 0)
                        {
                            waitCount = 0;
                        }
                    }
                }while (coverageResponse.Coverage.Length != 0 ||
                        waitCount <= 3);

                //Stop tacking
                await chromeSession.InternalSession.CSS.StopRuleUsageTracking(new CSS.StopRuleUsageTrackingCommand());

                //Get stylesheets
                var usedRules     = rules.Where(r => r.Used).ToList();
                var styleSheetIds = usedRules.Select(r => r.StyleSheetId).Distinct();
                var styleSheets   = styleSheetIds.Select(s => new
                {
                    chromeSession.InternalSession.CSS.GetStyleSheetText(new GetStyleSheetTextCommand {
                        StyleSheetId = s
                    }).Result.Text,
                    StyleSheetId = s
                }).ToList();


                //Get only used css, and constrcut it
                var usedCssStrb = new StringBuilder();
                foreach (var rule in usedRules)
                {
                    var styleSheetText = styleSheets.First(s => s.StyleSheetId.Equals(rule.StyleSheetId)).Text;

                    var ruleString = styleSheetText.Substring((int)rule.StartOffset, (int)rule.EndOffset - (int)rule.StartOffset);
                    usedCssStrb.Append(ruleString);
                }

                //minimize CSS
                var minCss = Uglify.Css(usedCssStrb.ToString()).Code;

                //Cache it for one hour
                _cache.Set(url, minCss, TimeSpan.FromSeconds(_cacheConfiguration.UrlCacheTime));

                return(minCss);
            }
            finally
            {
                //Free up resource
                ChromeSessionPool.ReleaseInstance(chromeSession);
            }
        }
 private void OnShutdown()
 {
     ChromeSessionPool.Dispose();
 }
Example #4
0
 public Task <IEnumerable <ChromeSession> > GetActiveSessions()
 {
     return(ChromeSessionPool.GetActiveSessions());
 }