예제 #1
0
 public WebHookProcessor(string requestBody,
                         WebhookProcessorContext context,
                         IAuthentication authentication,
                         GitHubHttpClient httpClient,
                         List <IRecordWriter> recordWriters,
                         IEventsBookkeeper eventsBookkeeper,
                         ICache <RecordTableEntity> recordsCache,
                         ICache <RepositoryItemTableEntity> collectorCache,
                         ITelemetryClient telemetryClient,
                         string apiDomain)
 {
     this.requestBody      = requestBody;
     this.context          = context;
     this.authentication   = authentication;
     this.httpClient       = httpClient;
     this.recordWriters    = recordWriters;
     this.eventsBookkeeper = eventsBookkeeper;
     this.recordsCache     = recordsCache;
     this.collectorCache   = collectorCache;
     this.telemetryClient  = telemetryClient;
     this.apiDomain        = apiDomain;
 }
예제 #2
0
        public async Task ProcessWebHookActivity([ActivityTrigger] IDurableActivityContext durableContext)
        {
            OrchestrationContext context = durableContext.GetInput <OrchestrationContext>();
            string requestBody           = context.RequestBody;
            WebhookProcessorContext       functionContext = context.Downgrade();
            WebhookProcessorContextWriter contextWriter   = new WebhookProcessorContextWriter();

            JObject record = JObject.Parse(requestBody);
            string  organizationName;

            Dictionary <string, string> additionalTelemetryProperties = new Dictionary <string, string>();

            foreach (KeyValuePair <string, string> property in GetMainCollectorSessionStartEventProperties(functionContext, identifier: functionContext.EventType, functionContext.LogicAppRunId))
            {
                additionalTelemetryProperties.Add(property.Key, property.Value);
            }
            string           outputPaths     = string.Empty;
            bool             success         = false;
            ITelemetryClient telemetryClient = new GitHubApplicationInsightsTelemetryClient(this.telemetryClient, functionContext);

            try
            {
                // Not all payloads have a "repository" attribute e.g., membership, organization, project, project_card, etc. paylods. Look under $organization attribute first, if available.
                JToken organizationNameToken = record.SelectToken("$.organization.login");
                if (organizationNameToken == null)
                {
                    organizationNameToken = record.SelectToken("$.repository.owner.login");
                }
                if (organizationNameToken == null)
                {
                    // NOTE: BELOW RELEVANT IF WE ARE RELYING ON APP WEBHOOKS
                    // In theory, all event payloads will have repository.owner.login (see https://developer.github.com/webhooks/event-payloads/#webhook-payload-object-common-properties)
                    // However, there are certain app-specific webhooks (e.g. new_permissions_accepted, which is not documented/can't be found by a search engine) that lack this.
                    // note: other example app-specific webhooks - app installed into repo, app uninstalled from repo, etc.
                    throw new FatalTerminalException("Could not find organization name in webhook payload.");
                }
                organizationName = organizationNameToken.Value <string>();

                IEventsBookkeeper eventsBookkeeper = new EventsBookkeeper(telemetryClient);
                await eventsBookkeeper.InitializeAsync().ConfigureAwait(false);

                ICache <RecordTableEntity> recordsCache = new AzureTableCache <RecordTableEntity>(telemetryClient, "records");
                await recordsCache.InitializeAsync().ConfigureAwait(false);

                ICache <RepositoryItemTableEntity> collectorCache = new AzureTableCache <RepositoryItemTableEntity>(telemetryClient, "github");
                await collectorCache.InitializeAsync().ConfigureAwait(false);

                ICache <RateLimitTableEntity> rateLimiterCache = new AzureTableCache <RateLimitTableEntity>(telemetryClient, "ratelimiter");
                await rateLimiterCache.InitializeAsync().ConfigureAwait(false);

                ICache <ConditionalRequestTableEntity> requestsCache = new AzureTableCache <ConditionalRequestTableEntity>(telemetryClient, "requests");
                await requestsCache.InitializeAsync().ConfigureAwait(false);

                IRateLimiter     rateLimiter = new GitHubRateLimiter(this.configManager.UsesGitHubAuth(context.CollectorType) ? organizationName : "*", rateLimiterCache, this.httpClient, telemetryClient, maxUsageBeforeDelayStarts: 90.0, this.apiDomain);
                GitHubHttpClient httpClient  = new GitHubHttpClient(this.httpClient, rateLimiter, requestsCache, telemetryClient);

                IAuthentication authentication = this.configManager.GetAuthentication(CollectorType.Main, httpClient, organizationName, this.apiDomain);

                StorageManager       storageManager;
                List <IRecordWriter> recordWriters;
                using (storageManager = this.configManager.GetStorageManager(context.CollectorType, telemetryClient))
                {
                    recordWriters = storageManager.InitializeRecordWriters(identifier: functionContext.EventType, functionContext, contextWriter, this.adlsClient.AdlsClient);
                    WebHookProcessor processor = new WebHookProcessor(requestBody, functionContext, authentication, httpClient, recordWriters, eventsBookkeeper, recordsCache, collectorCache, telemetryClient, this.apiDomain);
                    additionalTelemetryProperties = await processor.ProcessAsync().ConfigureAwait(false);

                    foreach (KeyValuePair <string, string> property in GetMainCollectorSessionStartEventProperties(functionContext, identifier: functionContext.EventType, functionContext.LogicAppRunId))
                    {
                        additionalTelemetryProperties.Add(property.Key, property.Value);
                    }
                }

                await storageManager.FinalizeRecordWritersAsync().ConfigureAwait(false);

                outputPaths = RecordWriterExtensions.GetOutputPaths(recordWriters);
                success     = true;
            }
            catch (Exception exception) when(!(exception is FatalException))
            {
                telemetryClient.TrackException(exception, "ProcessWebHookActivity failed.");
                throw exception;
            }
            finally
            {
                SendSessionEndEvent(telemetryClient, functionContext.FunctionStartDate, outputPaths, additionalTelemetryProperties, success);
            }
        }