public SyncResponse Sync(string serverKey, List<PluginResource> discoveries = null, List<AnalyzerResult> metricResults = null, Dictionary<string, string> commandResults = null)
        {
            if (AgentContext.Current.PluginBlacklist != null)
            {
                discoveries = discoveries.Where(p => !AgentContext.Current.PluginBlacklist.Contains(p.Category, StringComparer.InvariantCultureIgnoreCase)).ToList();
            }

            // build payload
            var payLoad = new SyncRequest();
            payLoad.AddPluginResources(discoveries);
            payLoad.AddCommandResults(commandResults);

            if (metricResults != null && metricResults.Any())
            {
                payLoad.AddCollectedMetrics(metricResults.SelectMany(r => r.Metrics).ToList());
                payLoad.AddAnomalies(metricResults.SelectMany(r => r.Anomalies).ToList());
            }

            payLoad.AddRegisteredCustomMetrics();

            payLoad.AddUpdateConfig();

            payLoad.AddAgentVersion();

            Log.DebugFormat("Syncing payload with cloud service:\n{0}", JsonConvert.SerializeObject(payLoad, Formatting.Indented));

            // send request
            var response = RestHelper.Post<JObject>("sync", new AggregatorAuthenticator(serverKey), r => r.AddBody(payLoad), r =>
            {
                Log.ErrorFormat("Call to /sync resulted in an error with status code {0} ({1})", r.StatusCode, r.StatusDescription);
            });

            // parse response
            if (response != null)
            {
                Log.DebugFormat("Received sync response from cloud:\n{0}", response.ToString(Formatting.Indented));

                var syncResponse = new SyncResponse();

                if (response["schedules"] != null)
                {
                    var newSchedules = ParsePluginResourceSchedulesFromJson(response["schedules"]);
                    if (newSchedules.Any())
                    {
                        syncResponse.PluginResourcesSchedules = newSchedules;
                    }
                }

                var newCommands = response["commands"];
                if (newCommands != null && newCommands.Any())
                {
                    syncResponse.AdminCommands = ((IDictionary<string, JToken>)newCommands).ToDictionary(c => c.Key, c => c.Value.Value<string>());
                }

                return syncResponse;
            }

            return null;
        }
        private void ProcessCloudResponse(SyncResponse response)
        {
            if (response.PluginResourcesSchedules != null)
            {
                AgentContext.Current.PluginResourceSchedules = response.PluginResourcesSchedules.Where(s => s.PluginResourceTextKey.Split('.').FirstOrDefault() == AgentContext.CustomMetricPluginTextkey || AgentContext.Current.PluginResources.Any(r => r.TextKey == s.PluginResourceTextKey)).ToList();
            }

            if (response.AdminCommands != null)
            {
                var commandResults = new Dictionary<string, string>();
                Parallel.ForEach(response.AdminCommands, c =>
                {
                    var command = CommandFactory.Create(c.Key);
                    if (command != null)
                    {
                        var result = command.Process(c.Value);

                        if (!string.IsNullOrEmpty(result))
                        {
                            lock (commandResults)
                            {
                                commandResults.Add(c.Key, result);
                            }
                        }
                    }
                    else
                    {
                        Log.WarnFormat("Command by key '{0}' not supported by agent", c.Key);
                    }
                });

                // queue results for sync
                if (commandResults.Any())
                {
                    AgentContext.Current.QueueCommandsResult(commandResults);
                }
            }
        }