Amazon S3: ファイルダウンロード

Amazon S3: ファイルダウンロード

Amazon S3: Download File

この工程は、Amazon S3 の指定ファイルをダウンロードします。一度に複数のダウンロードが可能です。複数ダウンロードする場合、データ項目では 1 行につき 1 つずつオブジェクトキーを書くようにしてください。

Basic Configs
工程名
メモ
Auto Step icon
Configs for this Auto Step
conf_AccessKey
C1: アクセスキー *
conf_SecretKey
C2: シークレットアクセスキー *
conf_Region
C3: リージョンコード *
conf_Bucket
C4: バケット名 *
conf_Keys
C5: ダウンロードするファイルのオブジェクトキー *
conf_Files
C6: ダウンロードファイルを追加保存するデータ項目 *

Notes

Capture

See Also

Script (click to open)
  • 次のスクリプトが記述されている XML ファイルをダウンロードできます
    • aws-s3-file-download.xml (C) Questetra, Inc. (MIT License)
    • Professional のワークフロー基盤では、ファイル内容を改変しオリジナルのアドオン自動工程として活用できます

const MAX_OBJECT_KEY_BYTES = 1024;

function main() {
    ////// == 工程コンフィグ・ワークフローデータの参照 / Config & Data Retrieving ==
    const awsKey = configs.getObject("conf_AccessKey").getToken();
    const awsSecret = configs.getObject("conf_SecretKey").getToken();
    const region = retrieveRegion();
    const bucket = retrieveBucket();
    const objectKeys = retrieveObjectKeys();

    ////// == 演算 / Calculating ==
    if (objectKeys.length === 0) {
        return;
    }

    const fileDef = configs.getObject("conf_Files");
    const files = engine.findData(fileDef) ?? new java.util.ArrayList();
    objectKeys.forEach(objectKey => {
        const newFile = downloadFile(awsKey, awsSecret, region, bucket, objectKey);
        files.add(newFile);
    });
    engine.setData(fileDef, files);
}

/**
 * config からリージョンコードを読み出す
 * リージョンコードの形式として不正な場合はエラー
 * @return {String}
 */
function retrieveRegion() {
    const region = configs.get("conf_Region");
    // 今後リージョンが増えることも考えて、中央の最大文字数には余裕をみている
    const reg = new RegExp("^[a-z]{2}-[a-z]{4,16}-[1-9]$");
    if (!reg.test(region)) {
        throw new Error("Region Code is invalid.");
    }
    return region;
}

/**
 * form-type="SELECT" editable="true"
 * の設定値を読み出す
 * @return {String}
 */
function getConfSelectValue(configName) {
    const def = configs.getObject(configName);
    if (def === null) {
        return configs.get(configName);
    }
    return engine.findData(def) ?? "";
}

/**
 * config からバケット名を読み出す
 * バケット名の形式として不正な場合はエラー
 * @return {String}
 */
function retrieveBucket() {
    const bucket = getConfSelectValue("conf_Bucket");
    if (bucket === "") {
        throw new Error("Bucket Name is blank.");
    }
    const reg = new RegExp("^[0-9a-z][0-9a-z-.]{1,61}[0-9a-z]$");
    if (!reg.test(bucket) || bucket.includes("..")) {
        throw new Error("Bucket Name is invalid.");
    }
    return bucket;
}

/**
 * config からオブジェクトキーを読み出す
 * @return {Array<String>}
 */
function retrieveObjectKeys() {
    const keyStr = getConfSelectValue("conf_Keys");
    const keys = keyStr.split("\n").filter(key => key.length !== 0); // 空行は読み飛ばす。
    keys.forEach(key => {
        if (encodeURIComponent(key).replace(/%../g, "x").length > MAX_OBJECT_KEY_BYTES) {
            throw new Error(`The object key "${key}" is too long. Object key must be less than ${MAX_OBJECT_KEY_BYTES} bytes.`);
        }
        if(key.endsWith('/')) {
            throw new Error(`The object key "${key}" is invalid. Object key must not end with a slash.`);
        }
    });
    if (keys.length > httpClient.getRequestingLimit()) {
        throw new Error("The number of object keys exceeds the limit.");
    }

    return keys;
}

/**
 * 保存時のファイル名の最大長
 */
const FILE_NAME_MAX_LENGTH = 200;

/**
 * ファイルダウンロード
 * @param key アクセスキー
 * @param secret シークレットアクセスキー
 * @param region リージョン
 * @param bucket バケット
 * @param objectKey オブジェクトキー
 */
function downloadFile(key, secret, region, bucket, objectKey) {
    const encodedObjectKey = encodeURIComponent(objectKey);
    const url = `https://${bucket}.s3.${region}.amazonaws.com/${encodedObjectKey}`;
    const response = httpClient.begin()
        .awsSignV4(key, secret, region, "s3")
        .header("x-amz-checksum-mode", "ENABLED")
        .get(url);
    const status = response.getStatusCode();
    if (status !== 200) {
        engine.log(response.getResponseAsString());
        throw new Error(`Failed to download "${objectKey}" from S3. status: ${status}`);
    }

    const data = response.getResponse();
    // SHA-256 か SHA-1 のチェックサムがある場合、検証
    validateChecksum(objectKey, response, "x-amz-checksum-sha256", () => digest.sha256(data));
    validateChecksum(objectKey, response, "x-amz-checksum-sha1", () => digest.sha1(data));

    let fileName = objectKey.split("/").pop();
    if(fileName.length > FILE_NAME_MAX_LENGTH) {
        fileName = fileName.substring(0, FILE_NAME_MAX_LENGTH-3) + "...";
    }
    return new com.questetra.bpms.core.event.scripttask.NewQfile(
        fileName,
        response.getContentType(),
        data
    );
}

/**
 * チェックサムの検証
 * @param objectKey ダウンロードしたファイルのオブジェクトキー
 * @param response レスポンス
 * @param headerName チェックサムヘッダー名
 * @param calculate チェックサムを計算する関数
 */
function validateChecksum(objectKey, response, headerName, calculate) {
    let checksumHeaders = response.getHeaderValues(headerName);
    if (checksumHeaders.isEmpty()) {
        return;
    }
    const checksum = checksumHeaders.get(0);
    const calculated = base64.encodeToString(calculate());
    if (checksum !== calculated) {
        throw new Error(`The checksum of the downloaded file "${objectKey}" does not match. s3: ${checksum}, file: ${calculated}`);
    }
    engine.log(`Checksum of "${objectKey}" is OK. ${checksum}`);
}
    
上部へスクロール

Questetra Supportをもっと見る

今すぐ購読し、続きを読んで、すべてのアーカイブにアクセスしましょう。

続きを読む