private static async Task <string> GetSecret(string secretName, KeyVault kvService)
        {
            var secretValue = await kvService.GetSecretValue(secretName);

            return(string.IsNullOrEmpty(secretValue) ?
                   Environment.GetEnvironmentVariable(secretName) : secretValue);
        }
        private static async Task UpsertDocument(dynamic doc, KeyVault kvService, TraceWriter log)
        {
            var endpoint = await GetSecret("cosmos_uri", kvService);

            var auth = await GetSecret("cosmos_key", kvService);

            var client  = new DocumentClient(new Uri(endpoint), auth);
            var dbName  = "pets";
            var colName = "checks";

            doc.Analyzed = DateTime.UtcNow;
            await client.UpsertDocumentAsync(
                UriFactory.CreateDocumentCollectionUri(dbName, colName), doc);

            log.Info($"--- CosmosDb document updated.");
        }
        public static async Task RunPetChecker(
            [CosmosDBTrigger("pets", "checks", ConnectionStringSetting = "constr",
                             CreateLeaseCollectionIfNotExists = true)] IReadOnlyList <Document> document,
            [SignalR(HubName = "petcheckin", ConnectionStringSetting = "AzureSignalRConnectionString")] IAsyncCollector <SignalRMessage> sender,
            TraceWriter log)
        {
            var sendingResponse = false;

            try
            {
                foreach (dynamic doc in document)
                {
                    sendingResponse = false;
                    var isProcessed = doc.IsApproved != null;
                    if (isProcessed)
                    {
                        continue;
                    }

                    var url      = doc.MediaUrl.ToString();
                    var uploaded = (DateTime)doc.Created;
                    log.Info($">>> Processing image in {url} upladed at {uploaded.ToString()}");

                    using (var httpClient = new HttpClient())
                    {
                        var kvService = new KeyVault(log);
                        var res       = await httpClient.GetAsync(url);

                        var stream = await res.Content.ReadAsStreamAsync() as Stream;

                        log.Info($"--- Image succesfully downloaded from storage");
                        var(allowed, message, tags) = await PassesImageModerationAsync(stream, kvService, log);

                        log.Info($"--- Image analyzed. It was {(allowed ? string.Empty : "NOT")} approved");
                        doc.IsApproved = allowed;
                        doc.Message    = message;
                        log.Info($"--- Updating CosmosDb document to have historical data");
                        await UpsertDocument(doc, kvService, log);

                        log.Info($"--- Updating Graph");
                        await InsertInGraph(tags, doc, kvService, log);

                        log.Info("--- Sending SignalR response.");
                        sendingResponse = true;
                        await SendSignalRResponse(sender, allowed, message);

                        log.Info($"<<< Done! Image in {url} processed!");
                    }
                }
            }
            catch (Exception ex)
            {
                var msg = $"Error {ex.Message} ({ex.GetType().Name})";
                log.Info("!!! " + msg);

                if (ex is AggregateException aggex)
                {
                    foreach (var innex in aggex.InnerExceptions)
                    {
                        log.Info($"!!! (inner) Error {innex.Message} ({innex.GetType().Name})");
                    }
                }

                if (!sendingResponse)
                {
                    await SendSignalRResponse(sender, false, msg);
                }
                throw ex;
            }
        }
        public static async Task <(bool allowd, string message, string[] tags)> PassesImageModerationAsync(Stream image, KeyVault kvService, TraceWriter log)
        {
            try
            {
                log.Info("--- Creating VisionApi client and analyzing image");

                var key = await GetSecret("MicrosoftVisionApiKey", kvService);

                var endpoint = await GetSecret("MicrosoftVisionApiEndpoint", kvService);

                var numTags = await GetSecret("MicrosoftVisionNumTags", kvService);

                var client   = new VisionServiceClient(key, endpoint);
                var features = new VisualFeature[] { VisualFeature.Description };
                var result   = await client.AnalyzeImageAsync(image, features);

                log.Info($"--- Image analyzed with tags: {String.Join(",", result.Description.Tags)}");
                if (!int.TryParse(numTags, out var tagsToFetch))
                {
                    tagsToFetch = 5;
                }
                var    fetchedTags = result?.Description?.Tags.Take(tagsToFetch).ToArray() ?? new string[0];
                bool   isAllowed   = fetchedTags.Contains("dog");
                string message     = result?.Description?.Captions.FirstOrDefault()?.Text;
                return(isAllowed, message, fetchedTags);
            }
            catch (Exception ex)
            {
                log.Info("Vision API error! " + ex.Message);
                return(false, "error " + ex.Message, new string[0]);
            }
        }
        private static async Task InsertInGraph(IEnumerable <string> tags, dynamic doc, KeyVault kvService, TraceWriter log)
        {
            var hostname = await GetSecret("gremlin_endpoint", kvService);

            var port = await GetSecret("gremlin_port", kvService);

            var database   = "pets";
            var collection = "checks";
            var authKey    = Environment.GetEnvironmentVariable("gremlin_key");
            var portToUse  = 443;

            portToUse = int.TryParse(port, out portToUse) ? portToUse : 443;

            var gremlinServer = new GremlinServer(hostname, portToUse, enableSsl: true,
                                                  username: "******" + database + "/colls/" + collection,
                                                  password: authKey);
            var gremlinClient = new GremlinClient(gremlinServer, new GraphSON2Reader(), new GraphSON2Writer(), GremlinClient.GraphSON2MimeType);

            foreach (var tag in tags)
            {
                log.Info("--- --- Checking vertex for tag " + tag);
                await TryAddTag(gremlinClient, tag, log);
            }

            var queries = AddPetToGraphQueries(doc, tags);

            log.Info("--- --- Adding vertex for pet checkin ");
            foreach (string query in queries)
            {
                await gremlinClient.SubmitAsync <dynamic>(query);
            }
        }