Saltar al contenido
Last updated

Carga y descarga de archivos de Cloud Phone

Esta guía cubre el flujo completo: cargar un archivo local, exportar un archivo del Cloud Phone, consultar tareas asíncronas y recuperarse de tiempos de espera.

Elegir la superficie de API

PasoOpen APILocal API
Base URLhttps://api.morelogin.comhttp://127.0.0.1:40000
AutenticaciónAuthorization: Bearer <token>Local API token
Solicitar URL de cargaPOST /cloudphone/uploadUrlPOST /api/cloudphone/upload/file/signedUrl
Registrar el objeto cargadoPOST /cloudphone/uploadFilePOST /api/cloudphone/upload/file
Consultar el resultado de cargaPOST /cloudphone/uploadFileResultPOST /api/cloudphone/upload/file/result
Solicitar exportaciónPOST /cloudphone/downloadPOST /api/cloudphone/download
Consultar el resultado de exportaciónPOST /cloudphone/download/resultPOST /api/cloudphone/download/result

Los ejemplos usan Open API. Para Local API, cambie la URL base y las rutas según la tabla. Mantenga id, fileId y downId como cadenas; JavaScript no debe convertirlos con Number.

Atajo multipart de Local API

Si el archivo está en el mismo equipo que el cliente MoreLogin, puede enviarlo directamente. La respuesta correcta es un objeto vacío y no incluye un ID de tarea. Use el flujo de URL firmada si necesita seguimiento o reintentos observables.

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

Flujo de carga

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. Solicitar una URL prefirmada

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. Enviar los bytes al almacenamiento

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

3. Registrar el objeto para su entrega

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. Consultar el resultado de carga

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

Guarde data.presignedUrl. Envíe el archivo directamente a esa URL sin el token Bearer. Continúe solo tras un estado HTTP correcto, registre la URL del objeto y guarde data.fileId.

data / data.statusSignificadoAcción
nullLa tarea aún no es visibleEspere y vuelva a consultar
0CargandoEspere y vuelva a consultar
1CorrectoDetenga la consulta
2FallidoDetenga y comunique requestId

Flujo de descarga

La descarga exporta el archivo del Cloud Phone a una URL temporal. Guarde data.downId y consulte el resultado hasta alcanzar un estado terminal.

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. Solicitar la exportación

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. Esperar hasta que la URL esté lista

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.statusSignificadoAcción
10En cursoEspere y vuelva a consultar
20CorrectoDescargue desde data.downUrl
30FallidoDetenga y comunique requestId
40CanceladoDetenga; cree otra tarea solo si sigue siendo necesario

3. Descargar desde la URL temporal

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

Ejemplo completo en Python

El ejemplo valida HTTP y el code de negocio, reutiliza los ID de tarea y aplica un plazo de consulta.

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")

Lista de comprobación para producción

  • Compruebe code == 0; HTTP 200 por sí solo no confirma el éxito de negocio.
  • Conserve los ID como cadenas y consulte el estado antes de repetir una operación de escritura tras un timeout.
  • No registre tokens ni URL firmadas; guarde requestId para soporte.
  • Limite la concurrencia y respete los límites de solicitudes documentados.