コンテンツへスキップ
Last updated

Cloud Phone のファイルアップロードとダウンロード

このガイドでは、ローカルファイルのアップロード、Cloud Phone からの書き出し、非同期タスクのポーリング、タイムアウト後の復旧までを説明します。

API の選択

手順Open APILocal API
Base URLhttps://api.morelogin.comhttp://127.0.0.1:40000
認証Authorization: Bearer <token>Local API token
アップロード URL を取得POST /cloudphone/uploadUrlPOST /api/cloudphone/upload/file/signedUrl
アップロード済みオブジェクトを登録POST /cloudphone/uploadFilePOST /api/cloudphone/upload/file
アップロード結果を照会POST /cloudphone/uploadFileResultPOST /api/cloudphone/upload/file/result
書き出しを要求POST /cloudphone/downloadPOST /api/cloudphone/download
書き出し結果を照会POST /cloudphone/download/resultPOST /api/cloudphone/download/result

例では Open API を使います。Local API では表に従ってベース URL とパスを変更してください。id、fileId、downId は文字列のまま扱い、JavaScript の Number に変換しないでください。

Local API の multipart ショートカット

MoreLogin クライアントと同じ端末にファイルがある場合は直接送信できます。成功時は空オブジェクトが返り、タスク ID はありません。状態確認や再試行が必要な場合は署名付き URL フローを使ってください。

curl --request POST "http://127.0.0.1:40000/api/cloudphone/uploadFile" \
  --form 'id=1661515884160372' \
  --form 'uploadDest=/Download' \
  --form 'file=@./report.csv'

アップロード手順

Cloud PhoneStorageMoreLogin APIClientCloud PhoneStorageMoreLogin APIClientloop[status 0]1. uploadUrlpresignedUrl2. PUT bytes3. uploadFilefileId4. uploadFileResultdeliver file
Cloud PhoneStorageMoreLogin APIClientCloud PhoneStorageMoreLogin APIClientloop[status 0]1. uploadUrlpresignedUrl2. PUT bytes3. uploadFilefileId4. uploadFileResultdeliver file

1. 署名付き URL を取得

curl --request POST "https://api.morelogin.com/cloudphone/uploadUrl" \
  --header "Authorization: Bearer $MORELOGIN_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "id": "1661515884160372",
    "fileName": "report.csv"
  }'

2. ストレージへファイル本体を送信

curl --location --request PUT \
  --upload-file "./report.csv" \
  "$PRESIGNED_URL"

3. 配信用オブジェクトを登録

FILE_URL="${PRESIGNED_URL%%\?*}"

curl --request POST "https://api.morelogin.com/cloudphone/uploadFile" \
  --header "Authorization: Bearer $MORELOGIN_TOKEN" \
  --header "Content-Type: application/json" \
  --data "$(jq -n \
    --arg id '1661515884160372' \
    --arg url "$FILE_URL" \
    --arg dest '/Download' \
    '{id: $id, url: $url, uploadDest: $dest, uploadType: 1}')"

4. アップロード結果を照会

curl --request POST "https://api.morelogin.com/cloudphone/uploadFileResult" \
  --header "Authorization: Bearer $MORELOGIN_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "id": "1661515884160372",
    "fileId": "1661515884160111"
  }'

data.presignedUrl を保存し、Bearer トークンを付けずにファイルを直接送信します。HTTP 成功後だけ次へ進み、オブジェクト URL を登録して data.fileId を保存してください。

data / data.status意味対応
nullタスクがまだ確認できない待って再照会
0アップロード中待って再照会
1成功照会を終了
2失敗終了して requestId を報告

ダウンロード手順

ダウンロードは Cloud Phone 内のファイルを一時 URL へ書き出す処理です。data.downId を保存し、終端状態まで結果を照会してください。

StorageCloud PhoneMoreLogin APIClientStorageCloud PhoneMoreLogin APIClientloop[status 10]1. download(id, filePath)export filedownId2. download/resultwrite filestatus 20, downUrl3. GET downUrl
StorageCloud PhoneMoreLogin APIClientStorageCloud PhoneMoreLogin APIClientloop[status 10]1. download(id, filePath)export filedownId2. download/resultwrite filestatus 20, downUrl3. GET downUrl

1. ファイル書き出しを要求

curl --request POST "https://api.morelogin.com/cloudphone/download" \
  --header "Authorization: Bearer $MORELOGIN_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "id": "1661515884160372",
    "filePath": "/sdcard/Download/report.csv"
  }'

2. URL の準備完了を待つ

curl --request POST "https://api.morelogin.com/cloudphone/download/result" \
  --header "Authorization: Bearer $MORELOGIN_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{
    "id": "1661515884160372",
    "downId": "1661515884160999"
  }'
data.status意味対応
10実行中待って再照会
20成功data.downUrl から取得
30失敗終了して requestId を報告
40キャンセル終了し、必要な場合だけ新規タスクを作成

3. 一時 URL から取得

curl --location "$DOWN_URL" --output "./report.csv"

完全な Python 例

この例は HTTP と業務 code を検証し、タスク ID を再利用してポーリング期限を設定します。

import os
import time
from pathlib import Path

import requests

BASE_URL = "https://api.morelogin.com"
TOKEN = os.environ["MORELOGIN_TOKEN"]
PHONE_ID = "1661515884160372"
HEADERS = {"Authorization": f"Bearer {TOKEN}"}


def api_post(path, payload):
    response = requests.post(
        f"{BASE_URL}{path}", json=payload, headers=HEADERS, timeout=30
    )
    response.raise_for_status()
    body = response.json()
    if body.get("code") != 0:
        raise RuntimeError(
            f"API error code={body.get('code')} msg={body.get('msg')} "
            f"requestId={body.get('requestId')}"
        )
    return body


def wait_for(path, payload, terminal, timeout=300):
    deadline = time.monotonic() + timeout
    while time.monotonic() < deadline:
        body = api_post(path, payload)
        data = body.get("data")
        if data is not None and data.get("status") in terminal:
            return body
        time.sleep(2)
    raise TimeoutError(f"Timed out while polling {path}; keep the task ID")


def upload_to_phone(local_path, destination="/Download"):
    path = Path(local_path)
    signed = api_post(
        "/cloudphone/uploadUrl", {"id": PHONE_ID, "fileName": path.name}
    )
    presigned_url = signed["data"]["presignedUrl"]
    with path.open("rb") as stream:
        put_response = requests.put(presigned_url, data=stream, timeout=120)
    put_response.raise_for_status()

    object_url = presigned_url.split("?", 1)[0]
    created = api_post(
        "/cloudphone/uploadFile",
        {
            "id": PHONE_ID,
            "url": object_url,
            "uploadDest": destination,
            "uploadType": 1,
        },
    )
    file_id = created["data"]["fileId"]
    result = wait_for(
        "/cloudphone/uploadFileResult",
        {"id": PHONE_ID, "fileId": file_id},
        terminal={1, 2},
    )
    if result["data"]["status"] != 1:
        raise RuntimeError(f"Upload failed; requestId={result.get('requestId')}")
    return file_id


def download_from_phone(remote_path, local_path):
    created = api_post(
        "/cloudphone/download", {"id": PHONE_ID, "filePath": remote_path}
    )
    down_id = created["data"]["downId"]
    result = wait_for(
        "/cloudphone/download/result",
        {"id": PHONE_ID, "downId": down_id},
        terminal={20, 30, 40},
    )
    if result["data"]["status"] != 20:
        raise RuntimeError(f"Download export failed; requestId={result.get('requestId')}")

    with requests.get(result["data"]["downUrl"], stream=True, timeout=120) as response:
        response.raise_for_status()
        with open(local_path, "wb") as output:
            for chunk in response.iter_content(1024 * 1024):
                if chunk:
                    output.write(chunk)
    return down_id


upload_to_phone("./report.csv")
download_from_phone("/sdcard/Download/report.csv", "./downloaded-report.csv")

本番チェックリスト

  • code == 0 を確認してください。HTTP 200 だけでは業務成功を意味しません。
  • ID は文字列で保持し、タイムアウト後に書き込みを再実行する前に状態を照会してください。
  • トークンや署名付き URL をログへ保存せず、サポート用に requestId を保持してください。
  • 同時転送数を制限し、文書化されたリクエスト制限を守ってください。