Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  file-consent-invoke.ts

  Sprache: JAVA
 

import { formatUnknownError } from "./errors.js";
import { buildFileInfoCard, parseFileConsentInvoke, uploadToConsentUrl } from "./file-consent.js";
import { normalizeMSTeamsConversationId } from "./inbound.js";
import type { MSTeamsMonitorLogger } from "./monitor-types.js";
import { getPendingUploadFs, removePendingUploadFs } from "./pending-uploads-fs.js";
import { getPendingUpload, removePendingUpload } from "./pending-uploads.js";
import { withRevokedProxyFallback } from "./revoked-context.js";
import type { MSTeamsTurnContext } from "./sdk-types.js";

/**
 * Handle fileConsent/invoke activities for large file uploads.
 */

export async function handleMSTeamsFileConsentInvoke(
  context: MSTeamsTurnContext,
  log: MSTeamsMonitorLogger,
): Promise<boolean> {
  const expiredUploadMessage =
    "The file upload request has expired. Please try sending the file again.";
  const activity = context.activity;
  if (activity.type !== "invoke" || activity.name !== "fileConsent/invoke") {
    return false;
  }

  const consentResponse = parseFileConsentInvoke(activity);
  if (!consentResponse) {
    log.debug?.("invalid file consent invoke", { value: activity.value });
    return false;
  }

  const uploadId =
    typeof consentResponse.context?.uploadId === "string"
      ? consentResponse.context.uploadId
      : undefined;
  // Prefer the in-memory store (same-process reply path); fall back to the
  // FS-backed store so CLI `message send --media` flows work even when the
  // invoke callback is delivered to a different process.
  const inMemoryFile = getPendingUpload(uploadId);
  const fsFile = inMemoryFile ? undefined : await getPendingUploadFs(uploadId);
  const pendingFile:
    | {
        buffer: Buffer;
        filename: string;
        contentType?: string;
        conversationId: string;
        consentCardActivityId?: string;
      }
    | undefined = inMemoryFile ?? fsFile;
  if (pendingFile) {
    const pendingConversationId = normalizeMSTeamsConversationId(pendingFile.conversationId);
    const invokeConversationId = normalizeMSTeamsConversationId(activity.conversation?.id ?? "");
    if (!invokeConversationId || pendingConversationId !== invokeConversationId) {
      log.info("file consent conversation mismatch", {
        uploadId,
        expectedConversationId: pendingConversationId,
        receivedConversationId: invokeConversationId || undefined,
      });
      if (consentResponse.action === "accept") {
        await context.sendActivity(expiredUploadMessage);
      }
      return true;
    }
  }

  if (consentResponse.action === "accept" && consentResponse.uploadInfo) {
    if (pendingFile) {
      log.debug?.("user accepted file consent, uploading", {
        uploadId,
        filename: pendingFile.filename,
        size: pendingFile.buffer.length,
      });

      try {
        await uploadToConsentUrl({
          url: consentResponse.uploadInfo.uploadUrl,
          buffer: pendingFile.buffer,
          contentType: pendingFile.contentType,
        });

        const fileInfoCard = buildFileInfoCard({
          filename: consentResponse.uploadInfo.name,
          contentUrl: consentResponse.uploadInfo.contentUrl,
          uniqueId: consentResponse.uploadInfo.uniqueId,
          fileType: consentResponse.uploadInfo.fileType,
        });

        if (!pendingFile.consentCardActivityId) {
          await context.sendActivity({
            type: "message",
            attachments: [fileInfoCard],
          });
        }

        if (pendingFile.consentCardActivityId) {
          try {
            await context.updateActivity({
              id: pendingFile.consentCardActivityId,
              type: "message",
              attachments: [fileInfoCard],
            });
          } catch {
            await context.sendActivity({
              type: "message",
              attachments: [fileInfoCard],
            });
          }
        }

        log.info("file upload complete", {
          uploadId,
          filename: consentResponse.uploadInfo.name,
          uniqueId: consentResponse.uploadInfo.uniqueId,
        });
      } catch (err) {
        log.error("file upload failed", { uploadId, error: formatUnknownError(err) });
        await context.sendActivity("File upload failed. Please try again.");
      } finally {
        removePendingUpload(uploadId);
        await removePendingUploadFs(uploadId);
      }
    } else {
      log.debug?.("pending file not found for consent", { uploadId });
      await context.sendActivity(expiredUploadMessage);
    }
  } else {
    log.debug?.("user declined file consent", { uploadId });
    removePendingUpload(uploadId);
    await removePendingUploadFs(uploadId);
  }

  return true;
}

export async function respondToMSTeamsFileConsentInvoke(
  context: MSTeamsTurnContext,
  log: MSTeamsMonitorLogger,
): Promise<void> {
  await context.sendActivity({ type: "invokeResponse", value: { status: 200 } });

  try {
    await withRevokedProxyFallback({
      run: async () => await handleMSTeamsFileConsentInvoke(context, log),
      onRevoked: async () => true,
      onRevokedLog: () => {
        log.debug?.("turn context revoked during file consent invoke; skipping delayed response");
      },
    });
  } catch (err) {
    log.debug?.("file consent handler error", { error: formatUnknownError(err) });
  }
}

Messung V0.5 in Prozent
C=98 H=97 G=97

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet am  2026-05-26) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge