# maclustr-mobile — les iPhones comme nœuds du cluster MacLustr Un iPhone ne peut ni recevoir de SSH ni travailler en arrière-plan. Les iPhones du cluster **tirent** donc leur travail : l'app **MacLustr iOS ≥ 4.3.0** (onglet **Nœud**, TestFlight) s'enregistre auprès de ce coordinateur, envoie un battement toutes les 20 s (batterie, thermique, réseau, mémoire) et fait du long-poll sur `/api/worker/next` ; chaque job est exécuté sur l'iPhone puis renvoyé sur `/api/worker/result`. ``` laptop / apps / scripts ──POST /api/jobs──▶ maclustr-mobile (M4M64a:9320, PM2, py3.9 stdlib) ◀──GET /api/jobs/{id}/wait── ▲ long-poll /api/worker/next │ POST /api/worker/result, /heartbeat maclustr-agentd (9210) ──GET /api/workers (loopback)──▶ │ → /api/cluster.mobile, /health.mobileOnline iPhone 17 Pro Max ×3 (app MacLustr, onglet Nœud, Tailscale) ``` ## Types de jobs | type | payload | résultat | |---|---|---| | `http.fetch` | `url`, `method`, `headers`, `body`/`bodyBase64`/`json`, `timeoutS`, `maxBytes` (2 Mo), `wantJson` | `status`, `headers`, `body` ou `bodyBase64`, `finalUrl`, `bytes`, `durationMs` — la requête part de l'IP de l'iPhone (Wi-Fi ou cellulaire) | | `js.run` | `code` (définit `function main(args)`), `args`, `timeoutS` | `value` (retour JSON de `main`), `logs`. API : `ml.http(url, {method, headers, body, timeout})` synchrone, `ml.log`, `ml.sleep(ms)`, `ml.now()`, `ml.device`, `ml.worker`, `console.log` | | `sys.info` | — | modèle, puce, iOS, batterie, thermique, mémoire, disque, réseau | | `ping` | `t` | `pong`, écho, heure de l'appareil | Champs communs : `target` (nom d'un iPhone, sinon n'importe lequel), `tag` (regrouper un lot), `timeoutS`, `maxAttempts` (3). Un job dont le bail expire (app fermée, iPhone en arrière-plan) est re-mis en file ; une erreur réseau/timeout est rejouée, une erreur « métier » (exception JS, HTTP 4xx) ne l'est pas. ## Utilisation ```bash mlmobile nodes # iPhones connus : en ligne, batterie, thermique, jobs mlmobile ping ; mlmobile info --on iph17a mlmobile fetch https://www.centris.ca/fr --raw --on iph17a mlmobile run script.js --args '{"q":"immo"}' # function main(args){ … return … } mlmobile fetch-list urls.txt --out out.jsonl # 1 fetch par URL, réparti sur tous les iPhones mlmobile map script.js items.json # 1 job JS par élément, résultats agrégés mlmobile jobs --state failed ; mlmobile job ; mlmobile cancel ``` API directe : `curl -H "Authorization: Bearer $MOBILE_TOKEN" http://M4M64a.maclustr.io:9320/api/workers`. ## Déploiement (mld) ```bash scp deploy/maclustr-mobile.json M1M32:~/dispatch/apps/maclustr-mobile.json mld stage ~/Desktop/Cluster/maclustr-mobile maclustr-mobile # .mldignore exclut ios/ et data/ mld deploy maclustr-mobile # épinglé M4M64a (même hôte qu'agentd) ``` Aucune route publique : les iPhones et le laptop joignent `http://M4M64a.maclustr.io:9320` par Tailscale (l'app Tailscale doit être connectée sur l'iPhone, comme pour l'onglet Cluster). Pour exposer publiquement : DNS `A mobile.maclustr.io → 51.161.112.61` puis `mld tunnel route` ; changer l'URL dans Nœud → Réglages. Jeton unique `MOBILE_TOKEN` (manifeste, app iOS, `agentd config.json → mobile_token`). Données : `~/apps/maclustr-mobile/data/mobile.db` (workers, jobs 7 jours). ## Côté iPhone Installer MacLustr (TestFlight) → onglet **Nœud** → **Mode nœud**. Réglages : nom (défaut dérivé du nom de l'appareil), URL, jeton, jobs simultanés (1–6), écran allumé. Garder l'iPhone **branché** et l'app **ouverte sur l'onglet** ; iOS suspend l'app en arrière-plan (le coordinateur re-met alors les jobs en file). Pour du 24/7 : Réglages iOS → Accessibilité → Accès guidé sur l'app MacLustr.