Посібник описує повний процес: завантаження локального файлу, експорт файлу з Cloud Phone, опитування асинхронних завдань і відновлення після тайм-аутів.
| Крок | Open API | Local API |
|---|---|---|
| Base URL | https://api.morelogin.com | http://127.0.0.1:40000 |
| Автентифікація | Authorization: Bearer <token> | Local API token |
| Запросити URL завантаження | POST /cloudphone/uploadUrl | POST /api/cloudphone/upload/file/signedUrl |
| Зареєструвати об'єкт | POST /cloudphone/uploadFile | POST /api/cloudphone/upload/file |
| Перевірити результат завантаження | POST /cloudphone/uploadFileResult | POST /api/cloudphone/upload/file/result |
| Запросити експорт | POST /cloudphone/download | POST /api/cloudphone/download |
| Перевірити результат експорту | POST /cloudphone/download/result | POST /api/cloudphone/download/result |
Приклади використовують Open API. Для Local API змініть базовий URL і шляхи за таблицею. Зберігайте id, fileId і downId як рядки; JavaScript не повинен перетворювати їх через Number.
Якщо файл розташований на комп'ютері з клієнтом 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'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"
}'curl --location --request PUT \
--upload-file "./report.csv" \
"$PRESIGNED_URL"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}')"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. Передайте файл напряму за цим URL без Bearer-токена. Продовжуйте лише після успішного HTTP-статусу, зареєструйте URL об'єкта та збережіть data.fileId.
data / data.status | Значення | Дія |
|---|---|---|
null | Завдання ще не видно | Зачекати й повторити |
0 | Завантаження | Зачекати й повторити |
1 | Успішно | Припинити опитування |
2 | Помилка | Зупинитися й повідомити requestId |
Скачування експортує файл із Cloud Phone у тимчасовий URL. Збережіть data.downId і опитуйте результат до кінцевого стану.
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"
}'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 | Скасовано | Зупинитися; нове завдання створювати лише за потреби |
curl --location "$DOWN_URL" --output "./report.csv"Приклад перевіряє 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 для підтримки.
- Обмежуйте паралельні передачі та дотримуйтеся лімітів запитів.