メインコンテンツへスキップ

レジューム可能なアップロードの扱い方

Batch compliance の endpoint を使用する場合、開発者は大量の X のデータを一括アップロードし、データセットがユーザーの意図や X 上のコンテンツの最新状態を反映させるために必要な対応を把握できます。システムや接続が安定して信頼できる場合、リモートサーバーへの大量データのアップロードは比較的単純な操作です。しかし、常にそうとは限りません。環境によっては、一定時間が経過すると接続タイムアウトが発生し、App とアップロードサーバー間の接続が切断されることがあります。また、例えばノートPCからWi‑Fi接続で大きなファイルをアップロードしようとすると、接続上の問題に遭遇する場合もあります。こうした状況では、単一の連続した接続に頼るのではなく、ファイルをより小さな単位に分割して順次アップロードすることが望まれます。 X の batch compliance endpoint は、大きなファイルを処理するために Google Cloud Storage に依存しています。この種のストレージはさまざまな用途に最適化されており、Cloud Storage は「レジューム可能なアップロード」と呼ばれる大容量ファイルの管理手法をサポートしています。 アップロード中に問題が発生した場合でも、Google Cloud Storage は中断地点から処理を再開できます。

中断から再開できるジョブの作成

手順 1:

まず、コンプライアンスジョブを作成し、type パラメータでアップロード対象が Post ID かユーザーの id かを指定します。さらに、リクエストボディに resumable を追加し、値を true に設定します。下記の $APP_ACCESS_TOKEN は、ご自身の App only Access Token に必ず置き換えてください。
curl --request POST \
 'https://api.x.com/2/compliance/jobs' --header 'Authorization: Bearer $APP_ACCESS_TOKEN --header 'Content-Type: application/json' --data-raw '{
   "type": "tweets",
   "resumable": true
}'
API 呼び出しが成功すると、次のようなレスポンスが返されます。
{
   "data": {
       "download_expires_at": "2021-08-18T19:42:55.000Z",
       "status": "created",
       "upload_url": "https://storage.googleapis.com/twttr-tweet-compliance/1425543269983784962/submission/1202726487847104512_1425543269983784962?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=complianceapi-public-svc-acct%40twttr-compliance-public-prod.iam.gserviceaccount.com%2F20210811%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20210811T194255Z&X-Goog-Expires=900&X-Goog-SignedHeaders=content-type%3Bhost&X-Goog-Signature=355e4c4739ae508304d3df15b4e13e64b6c7752d8d79d73676a4d8e60dc5241f83924ad2a1f8b7bddcc768062bb9c64d39b8e8f7cce7f66ffbea9f9ed33a4da975b3a2c127fb738c1c1ff3c3964bd4d9dc0706e6c8a70e67522160ea774e090d2793e06f890d1158ce86be3031c1c471b74f961b6f18743a28730611000336286ad0111b41fb5d14aa813ff00cf06b3572dc68d0b3c6fdc07f25c1b1196c1af4325a9ead68994944bbef0d2123585ea051deb9765aa7f5832446440bc9ba76af327b69df1fd7b1a99bd4419c128f1f697dbbacbc62bbc7c2c9aebc82a2128be0ed05d48a54d814162daad1232a0d13081e9543ab8557f567149af82281193f37",
       "created_at": "2021-08-11T19:42:55.000Z",
       "resumable": false,
       "id": "1425543269983784962",
       "type": "tweets",
       "download_url": "https://storage.googleapis.com/twttr-tweet-compliance/1425543269983784962/delivery/1202726487847104512_1425543269983784962?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=complianceapi-public-svc-acct%40twttr-compliance-public-prod.iam.gserviceaccount.com%2F20210811%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20210811T194255Z&X-Goog-Expires=604800&X-Goog-SignedHeaders=host&X-Goog-Signature=0a11dd5a3c5adb508f32ce904568abada863dc9499ba2adeafb3452ccee0dcb3dade17910dbc502dcbe54c130ac4d8638eb176c8b7344de068139b06c970794efa6312f0a5149f40da441eafcaf475f670c93ca73951999902a531d34dfab1e5490918929e5b06ae803b5604e0c0c26852255ccdbc79a2c1e2eefe924e5e6bf5b6603a7f287d1621333b9548ec6cc203716070528bebc2e67c12e92b1f4e54471db92c15a54799f2b855ae224250ca44c47993fd7d79a4940a0f68fe09f73fc8b291e88cfd10ade860b4b35c2b964d1777c1d93cd300c313138d9ca90aa8b3ecd3bf9dc73d3ebe32ba7634228fe07e1e4ecdda57cd94c802afc520162735d5a3",
       "upload_expires_at": "2021-08-11T19:57:55.000Z"
   }
}
upload_url の値をメモしておいてください。次の手順で使用します。

ステップ2:

次に、再開可能アップロードを開始します。前のステップで取得した upload_url に対して POST リクエストを送信し、以下のヘッダーを必ず含めてください: Content-Type: text/plain Content-Length: 0 x-goog-resumable: start
curl --request POST \
'https://storage.googleapis.com/twttr-tweet-compliance/1430227686685757442/submission/1202726487847104512_1430227686685757442?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=complianceapi-public-svc-acct%40twttr-compliance-public-prod.iam.gserviceaccount.com%2F20210824%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20210824T175707Z&X-Goog-Expires=900&X-Goog-SignedHeaders=content-length%3Bcontent-type%3Bhost%3Bx-goog-resumable&X-Goog-Signature=890d958f9c7dcb7f238e4971b59da5afc5b8329fb197c67b5930fe0f9dfe180afe2d4bec341111809b88ccfab46ab1f81f4242abc1af7b67c6e8977c52e6d486f5f43ce6a37a7a6530d25f15e2bcd9bb54655fe4ee22b26f8886ba71b67b7b11afd1198d658d1b6f0c41260f55260a260e1be0239977feba43dce40bc0e8e6293a4a3a3f7ee0afc74d3d2f7f2d3d514f108d5887a52ac85760385e5b9bb67cd26bfcf6b1c19151ea8111e217a29407722dc0dc9ab373334e88c18159546237ec9334f9a1e33717dc82800c6a45bba82706d5aece84ecdf3fcac52b21c8a3085a639047cf2707a8b9e4c296fc7cf05edbb110f07b89e38f0f5ea77e8b313cade7' \
--header 'Content-Type: text/plain' --header \
 'Content-Length: 0' --header \
 'x-goog-resumable: start
この呼び出しが成功すると、201 のレスポンスコードが返されます。次に、レスポンスヘッダーで Location ヘッダーの値をコピーします。値は次のような形式になります。
https://storage.googleapis.com/twttr-tweet-compliance/1430227686685757442/submission/1202726487847104512_1430227686685757442?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=complianceapi-public-svc-acct%40twttr-compliance-public-prod.iam.gserviceaccount.com%2F20210824%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20210824T175707Z&X-Goog-Expires=900&X-Goog-SignedHeaders=content-length%3Bcontent-type%3Bhost%3Bx-goog-resumable&X-Goog-Signature=890d958f9c7dcb7f238e4971b59da5afc5b8329fb197c67b5930fe0f9dfe180afe2d4bec341111809b88ccfab46ab1f81f4242abc1af7b67c6e8977c52e6d486f5f43ce6a37a7a6530d25f15e2bcd9bb54655fe4ee22b26f8886ba71b67b7b11afd1198d658d1b6f0c41260f55260a260e1be0239977feba43dce40bc0e8e6293a4a3a3f7ee0afc74d3d2f7f2d3d514f108d5887a52ac85760385e5b9bb67cd26bfcf6b1c19151ea8111e217a29407722dc0dc9ab373334e88c18159546237ec9334f9a1e33717dc82800c6a45bba82706d5aece84ecdf3fcac52b21c8a3085a639047cf2707a8b9e4c296fc7cf05edbb110f07b89e38f0f5ea77e8b313cade7&upload_id=ADPycds-_Ow7aqcpbG4XguXSVAgd_2fy-XiDA2qm-It9PCwBlZhF4e2bfOAQzEmRJ4T_l6jU6LfYdfrKa_KlFFBOyx3PjYzrxQ
その後、クイックスタート ガイドの手順2以降に従って、Post または User の id をこのロケーションにアップロードできます。 技術的に複雑なため、レジューム対応アップロードはコードと併用するのが最適です。本ガイドでは、Node.js と needle リクエストライブラリ を使用します。

依存関係をインストールする

先に進む前に、Node.js 環境をインストールしておいてください。Node.js は公式サイトから入手できます。インストール後、Node.js には npm というユーティリティが含まれています。以下のコマンドを実行して Node と npm の両方がインストールされており、エラーにならないことを確認してください。 $ npm -v 6.4.1 このようなバージョン番号が表示されれば、環境の準備は整っています(バージョン番号は異なる場合があります)。npm を使用してアップロード用ライブラリをインストールします。次のコマンドを実行してください。 $ npm install -g needle これで準備は完了です。追加の設定は不要です。

再開可能な送信先をリクエストする

新しいジョブを作成する際は、resumable パラメータを true に設定して、再開可能なアップロードに対応した送信先を取得します。レスポンスのペイロードでは、upload_url の値が返されます。
"upload_url":\
"https://storage.googleapis.com/compliance_tweet_ids/customer_test_object_12950882_GlYjiE?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=193969463581-compute%40developer.gserviceaccount.com%2F20200618%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20200618T184154Z&X-Goog-Expires=900&X-Goog-SignedHeaders=content-type%3Bhost&X-Goog-Signature=b7bdcf32479b08715be91ed47b06471b8acdcdb319f8e4f423bf3a3056dfa03ed83e47446f33338e292967a15c08fa5ba34395edaf057a2ac975b88e710ca994adb023a9e1673a7c58ce2fa0d73537f72812af78e92b708dfe6b907a7d75bd0f6cfa61fec867e80ac83ced0725d1ee59787c9dbca50d41f7b0f513dad63a7564136b1a70042a2ec6ba6b697cbe480a4405362f7a08255a5e8205aa7baa562f99e6a092f0420f33d67ffaeb132f877fbaf16c969630b5f173e8a3f31c473707241fa4e28f4bed13fb2ea01d3af1c449321a2e6ee9ec1e331b447cabcfc6f9d1f99f564d180f0cc1d28ea54972c996102c67c6501c6c16a00c13d17756f960e0e1"

ファイルをアップロードするコードを準備する

デフォルトでは、ライブラリはアップロード先(bucket と呼ばれる)とアップロードするファイル名を受け取り、新しいアップロード先を作成します。バッチコンプライアンスの endpoint は独自のアップロード先を作成するため、ライブラリに対して、すでにアップロードを受け付ける準備ができている場所を使用することを伝える必要があります。 この値を、アップロードする data を含むファイルの名前とあわせて、アップロードライブラリに渡します。ファイルを作成し、名前を twitter-upload.js とします。次のコードを追加してください:
const needle = require('needle');
const fs = require('fs');
const path = require('path');

const [, scriptName, filename, uploadURL] = process.argv;
if (!filename || !uploadURL) {
  console.error(`使用方法: node ${path.basename(scriptName)} filename upload_url`);
  process.exit(-1);
}

async function uploadFile(file, url) {
  // rangeEndはファイル内の最後のバイトのインデックス、つまりファイル内のバイト数
  const rangeEnd = (await fs.promises.stat(file)).size;

  let options = {
    headers: {
      'Content-Range': `bytes */${rangeEnd}`,
    },
  };

  const response = await needle('put', url, null, options);

  switch (response.statusCode) {
    case 200:
    case 201:
      console.log('アップロード完了');
      return;
    case 308:
      return resumeUpload(response, file, url);
    default:
      console.log('予期しないレスポンスコードを受信しました: ', response.statusCode);
      return;
  }
}

async function resumeUpload(response, file, url) {
  console.log('アップロードが完了していません。再開します');
  if (response.headers.range) {
    let resumeOffset = Number(response.headers.range.split('-')[1]) + 1;

    let options = {
      headers: {
        'Content-Range': `bytes ${resumeOffset}-${rangeEnd-1}/${rangeEnd}`,
        'Content-Length': `${rangeEnd-resumeOffset}`,
      },
    };

    let readStream = fs.createReadStream(file, {start: resumeOffset});
    return needle('put', url, readStream, options);
  } else {
    console.log('アップロードを開始します');
    let options = {
      headers: {
        'Content-Type': 'text/plain'
      }
    };

    let readStream = fs.createReadStream(file);
    return needle('put', url, readStream, options);
  }
}

// 再開可能セッションURLをリクエスト
async function requestResumableSession(url) {
  const options = {
    headers: {
      'Content-Type': 'text/plain',
      'Content-Length': '0',
      'x-goog-resumable': 'start',
    },
  };

  const res = await needle('post', url, null, options);
  if (res.statusCode === 201) {
    const resumableSessionURL = res.headers['location'];
    console.log('アップロード開始先: ', resumableSessionURL);

    await uploadFile(filename, resumableSessionURL);
  } else {
    console.log('再開可能セッションURIの作成に失敗しました');
  }

}

requestResumableSession(uploadURL).then(result => console.log('アップロード完了'));
ファイルは最も適切な場所に保存してください。次に、コマンドラインでスクリプトを実行し、2つのパラメータを渡します。
  1. 1つ目は、アップロードしたいファイルの場所(Post または User のIDを含む)です。
  2. 2つ目は、compliance endpoint のレスポンスで受け取ったアップロード用のURLです。
URLはダブルクオーテーションで囲み、ファイル名にスペースやその他の文字が含まれる場合も同様にダブルクオーテーションで囲んでください。
node twitter-upload.js compliance_upload.txt\
"https://storage.googleapis.com/compliance_tweet_ids/customer_test_object_12950882_GlYjiE?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=193969463581-compute%40developer.gserviceaccount.com%2F20200618%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20200618T184154Z&X-Goog-Expires=900&X-Goog-SignedHeaders=content-type%3Bhost&X-Goog-Signature=b7bdcf32479b08715be91ed47b06471b8acdcdb319f8e4f423bf3a3056dfa03ed83e47446f33338e292967a15c08fa5ba34395edaf057a2ac975b88e710ca994adb023a9e1673a7c58ce2fa0d73537f72812af78e92b708dfe6b907a7d75bd0f6cfa61fec867e80ac83ced0725d1ee59787c9dbca50d41f7b0f513dad63a7564136b1a70042a2ec6ba6b697cbe480a4405362f7a08255a5e8205aa7baa562f99e6a092f0420f33d67ffaeb132f877fbaf16c969630b5f173e8a3f31c473707241fa4e28f4bed13fb2ea01d3af1c449321a2e6ee9ec1e331b447cabcfc6f9d1f99f564d180f0cc1d28ea54972c996102c67c6501c6c16a00c13d17756f960e0e1"
次のような出力が表示されます: Starting upload to: https://storage.googleapis.com/twttr-tweet-compliance/<redacted> Upload not completed, resuming Initiating upload Ctrl + C を押すか、コマンドラインを閉じることで、いつでもアップロードを一時停止できます。後で同じコマンドを実行すれば、中断したところからアップロードを再開できます。ファイルのアップロードが完了すると、次のメッセージが表示されます: Upload complete この時点で、compliance status endpoint を使用してコンプライアンスジョブのステータスを確認でき、完了後にコンプライアンス結果をダウンロードできます。
I