Uppy uploaderがcomposerへの複数ファイルドロップで破損する

こんにちは。
最後のアップデート(マネージド環境を使用しています)以降、アップロード機能が壊れているようですが、特別なことは何もしていません。

テーマコンポーネント内で api.addComposerUploadHandler() を登録しているだけです。
これは、複数のファイルをコンポーザーにドラッグ&ドロップした場合にうまく機能していました。しかし現在、コンソールにエラーが表示され、それはUppy(私たちが望まないもの)に関連しているようです。

私たちのコードは非常にシンプルですが、それでもUppyが干渉しているようです。

// 動画用のカスタムアップロードハンドラーを登録します。

api.addComposerUploadHandler(["mp4", "mov", "mkv", "avi", "m4v"], (file, editor) => {
console.log("Handling upload for", file.name);
})

3つのファイル(mkv、mov、mkv)をコンポーザーにドラッグ&ドロップすると、「ファイルが4MBより大きいです」というエラーメッセージが表示されます。これは、すべてGdriveにアップロードするため、本来ならバイパスしたかったものです。

Chromeコンソールには次のようなエラーが表示されます。

50MBの単一ファイルをドロップしても、「ファイルが大きすぎます」というエラーは発生せず、期待どおりにファイルは正常に処理されます。したがって、エラーは複数のファイルと、4MBのファイル制限を超えるファイル(どこで設定されているかは不明)で発生しているようです。

この問題について、何か助けがあれば幸いです。これはDiscourse自体の最後のアップデートに関連していると思います。

@martin

@Sören_Geier様、こんにちは。最近この領域に変更がありましたが、コンポーザーの既存のアップロードハンドラーとの整合性を維持しようとしました。ユースケースをよりよく把握したいだけです。私の理解では、コンポーザーのuppyではないバージョンでさえ、api.addComposerUploadHandler を介してアップロードする場合でも、一度に1つのファイルしか処理しません。

https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/mixins/composer-upload.js#L215-L222

したがって、複数のファイルをドロップすると、通常のフローが発生し、このトピックのOPの場合、通常のアップロードフローからのファイルサイズ制限にヒットしているだけだと思います。

複数のファイルを一度にドラッグアンドドロップしたときに、以前は何が起こっていましたか、または何が起こることが期待されていますか?テーマコンポーネントのコードを見せていただけると幸いです。公開することに抵抗がある場合は、Metaでここにプライベートメッセージを送ってください。

確認のため、弊社でホストされていますか?

「いいね!」 2

@martin 、迅速な回答ありがとうございます。

はい、貴社でホスティングしています。通常、ファイルをコンポーザーにドラッグすると、「処理中 <ファイル名>」のようなテキストがコンポーザーに挿入されます。また、API.addComposerUploadHandler([“mp4”, “mov”, “mkv”, “avi”, “m4v”]) を使用する場合、これは Discourse がファイルをカスタムハンドラーに渡す前に行われます。このプレースホルダーテキストの挿入は、ある時点で機能しなくなったため、ハンドラー内でコードを自分で挿入しました。

composerController.model.appEvents.trigger("composer:insert-block", `[処理中: ${file.name}...]()`);

次に壊れたのは、ビデオ拡張機能が「テーマで承認された拡張機能」設定から突然削除されたため、ハンドラーが起動しなくなったことです。または、再び機能させるためにそれらを再度追加する必要がありました。

その後、前述のように「複数」ファイルのドロップの問題を発見しました。

エラーメッセージが表示されずに 2 つ以上のファイルをドロップできるよう、ある程度機能していました。また、Discourse の検証ロジックをすべてバイパスしていたため、正しく感じられました。

関連するコードスニペットを以下に示します。

ここでは、Discourse がドロップされたファイルを渡してくれることを単純に期待しています。一度に 1 つずつ。

// ビデオ用のカスタムアップロードハンドラーを登録します。
api.addComposerUploadHandler(["mp4", "mov", "mkv", "avi", "m4v"], (file, editor) => {
console.log("アップロードを処理中:", file.name);
sendToGDrive(file, api);
})

Discourse がファイルを個別に渡してくれたため、配列を埋め、タイムアウト後に実際のアップローダー関数を起動する中間関数を作成しました。そのため、Discourse から渡されたファイルを独自の配列に収集しています。

// すべてのドロップされたファイルをシーケンスで収集します - Discourse ハンドラーによって報告されます。
function sendToGDrive(file, api) {
clearTimeout(uploaderStartTimeout);
filesHolder.push(file)
const composerController = api.container.lookup("controller:composer");
composerController.model.appEvents.trigger("composer:insert-block", `[処理中: ${file.name}...]()`);

uploaderStartTimeout = setTimeout(function () {
initFileSend(api);
}, 300);
}

次に、各ファイルを個別に Gdrive にアップロードします。

// 各ファイルを個別に処理します。
async function initFileSend(api) {
for (const file of filesHolder) {
const content = await sendFileToGdrive(file, api, uploadFolderId);
}
}

観察された問題点:

  • 「複数ファイル」のドロップはファイルサイズ検証を引き起こしますが、単一ファイルのドロップは引き起こしません。
「いいね!」 1

この詳細なレポートと関連コードをありがとうございます。アップロードハンドラーについては、すでに同様のことを考えていました。ハンドラーに一致する各ファイルを、ここで実行したようなキューまたはプールに入れ、すべてを一度にアップロードするか、他のUIに渡すようにすることです。1つずつという制限は奇妙だと感じていました。しかし、お話からすると、古いコンポーザーのアップロードハンドラーで1つずつという制限がどのように機能していたのか、誤解していたのかもしれません。

古いuppyではないアップローダーが、提供された関数の簡略版をテーマコンポーネントでアップロードハンドラー経由で複数のファイルをどのように扱っていたかを確認するために、ローカルテストを行います。その後、新しい方法と古い方法の同等性を達成しようと試みます。これは、一度に1つのファイルしか許可しないよりもはるかに柔軟になるでしょう。

修正には少し時間がかかるかもしれませんが、本日中に取り組みます。

「いいね!」 2

簡単なアップデートをお知らせします。pre-uppy composer upload handlers を確認したところ、コードは 1 つのファイルのみがアップロードされたかどうかをチェックしますが、これは正確ではありません。なぜなら、jQuery file uploader は、一度に複数のファイルをドロップした場合でも、このコードパスを通じて一度に 1 つのファイルしか送信しないからです。これは、uppy が追加されたファイルをグループで処理するのとは対照的です。この一度に 1 つのファイルしか処理しないという前提は、api.addComposerUploadHandler を利用する他の 2 つのプラグインでも行われているため、一般的な問題のようです。

前述の通り、このハンドラーが複数のファイルを処理できるようにし、それをプラグイン/テーマ作成者にとって意味のある方法でどこかにバッチ処理して送信できるようにするのが最善の方法だと思います。少なくとも、uppy のアップロードハンドラーの、一度に 1 つのファイルしか送信できないという前提を修正できます。アップデートがあれば、またここに投稿します。

「いいね!」 2

週末前の最終アップデートです。来週初めにマージされる予定の修正により、「uppy」以前のやり方がuppy内で復元されます。これにより、実装が正しく動作するようになります。

ただし、その後addComposerUploadHandlerを変更し、ハンドラーコールバックに複数のファイルを配列で渡すようにするPRも追加します。これにより、複数のファイルが渡されるのを処理するためにキューとsetTimeoutコールバックを設定する必要がなくなります。これは、いずれにしてもより正しい方法であり、API全体の改善だと思います。

その後、ハンドラーは次のようになります。

// 動画用のカスタムアップロードハンドラーを登録します。
api.addComposerUploadHandler(
  ["mp4", "mov", "mkv", "avi", "m4v"],
  (files, editor) => {
    console.log("Handling upload for", files.map((file) => file.name).join(", "));
    sendToGDrive(files, api);
  }
);
「いいね!」 2

素晴らしい。迅速なご対応ありがとうございます!
どうぞ、良い週末をお過ごしください :blush:

「いいね!」 2

@Sören_Geier uppy が一度に複数のファイルをアップロードハンドラーに送信するように DEV: Send multiple files in batches to composer upload handlers when using uppy by martin-brennan · Pull Request #15124 · discourse/discourse · GitHub をマージしました。テーマコンポーネントを更新して対応する必要があります :slight_smile:

「いいね!」 3

それは素晴らしいですね。まだ展開されていませんよね?

スタンダードホスティングをご利用ですか?もしそうであれば、すでにデプロイされているはずです :slight_smile:

「いいね!」 3

苦情が寄せられており、アップロードしようとしたユーザーで問題が発生したとのことです。
調査したところ、当初はファイルオブジェクトをGDRIVEに送信する際に問題が発生しました。ファイルオブジェクトが、バイナリファイルをuppyでラップした表現であることが判明しました。その様子は以下の通りです。

ネイティブのファイルオブジェクトに実際にアクセスするには、files[0].dataを操作する必要がありました。(これは破壊的な変更でしょうか?)

その変更前は、ハンドラーはネイティブのファイルオブジェクトをそのまま渡していました。この変更により、他の人も機能が壊れる可能性があるか、私にはわかりません。

現在はすべて正常に動作しています。迅速な対応とサポートに大変感謝いたします!

「いいね!」 3

おっと、おっしゃる通りです。最近のリファクタリングの際に、それに気づかなかったとは思いもよりませんでした!:sweat: 今朝中に修正をプッシュします。それほど時間はかからないでしょう。

編集:修正はこちらです。数時間以内に標準ホスティングにデプロイされるはずです。

「いいね!」 3

素晴らしい、コードも調整しました。これでトピックは終了できると思います。@martin さん、格別なご支援ありがとうございました。

「いいね!」 1

問題ありません!私が散らかしたので、私が片付けるのが当然です😅

「いいね!」 1