सामग्री पर जाएँ

Signal Lab को सर्वर के रूप में चलाना ​

signal-lab-server Signal Lab है बिना विंडो के: वही इंजन, ब्राउज़र को वही इंटरफ़ेस परोसता हुआ। इसे उपकरणों के पास वाली किसी मशीन पर रखें — रैक PC, शो-कंट्रोल VM, साझा लैब बॉक्स — और नेटवर्क पर कहीं से भी Chrome, Firefox या Edge में खोलें: हर स्क्रीन डेस्कटॉप ऐप की तरह काम करती है, और रन, रिपोर्ट तथा एक्सपोर्ट ब्राउज़र से डाउनलोड होते हैं।

स्क्रिप्ट और पाइपलाइन उसी सर्वर का उपयोग उसके HTTP API के ज़रिए करते हैं, और signallab --server उस पर रन भेजता है।

डेस्कटॉप ऐप से कुछ चीज़ें अलग हैं:

  • एक सर्वर एक इंजन। उस पर साइन इन हर पेज को वही चल रहे जॉब, वही सिग्नल और एमुलेटर लाइब्रेरी, और HTTP स्क्रीन की वही कुकी जार (कुकी रखें) दिखती है। जो लोग एक सर्वर साझा करते हैं, वे ये सब भी साझा करते हैं।
  • सीक्रेट सर्वर के हैं, उसके एनवायरनमेंट या फ़ाइलों से पढ़े जाते हैं; ब्राउज़र से उन्हें सेट नहीं किया जा सकता (देखें सीक्रेट)।
  • फ़ायरवॉल होस्ट का है। सर्वर उसे कभी नहीं बदलता; डेस्कटॉप ऐप की फ़ायरवॉल सूचना नहीं दिखती।
  • यह अपनी इमेज के साथ अपडेट होता है, ऐप के अपडेटर से नहीं (देखें अपडेट करना)।

Linux होस्ट पर, एक ही कमांड में ​

इंटरनेट वाली Linux मशीन पर:

bash
curl -fsSL https://raw.githubusercontent.com/ProAnima/SignalLab/main/deploy/install.sh | sh

स्क्रिप्ट:

  1. अगर Docker नहीं है तो उसे इंस्टॉल करती है — पहले पूछकर, Docker के अपने इंस्टॉलर (get.docker.com) से;
  2. /opt/signallab में एक compose.yaml लिखती है (जब आप रूट न हों तो ~/signallab);
  3. इमेज खींचती है और सर्वर को होस्ट नेटवर्किंग के साथ शुरू करती है, ताकि OSC, UDP, ब्रॉडकास्ट, मल्टीकास्ट और डिस्कवरी असली नेटवर्क तक पहुँचें;
  4. तब तक प्रतीक्षा करती है जब तक सर्वर अपनी हेल्थ चेक का जवाब न दे (अधिकतम 90 सेकंड);
  5. खोलने के पते, साइन इन करने का एक्सेस टोकन, और अपडेट करने, लॉग पढ़ने तथा हटाने के कमांड छापती है;
  6. जब ufw या firewalld चालू हो, तो सर्वर का पोर्ट खोलने का प्रस्ताव देती है (देखें होस्ट का फ़ायरवॉल)।

sh -s -- के बाद विकल्प दें:

bash
curl -fsSL https://raw.githubusercontent.com/ProAnima/SignalLab/main/deploy/install.sh | sh -s -- --version 1.0.0 --port 8430
विकल्पयह क्या करता हैडिफ़ॉल्ट
--version X.Y.Zइमेज का संस्करण (latest या X.Y.Z; आगे लगा v हटा दिया जाता है)।latest
--port Nब्राउज़र जिस पोर्ट का उपयोग करते हैं।1430
--listen IP:PORTकेवल एक पते पर सुनें।0.0.0.0:<port>
--dir DIRcompose फ़ाइल कहाँ जाएगी।रूट होने पर /opt/<name>, वरना ~/<name>
--name NAMEकंटेनर और उसका डेटा वॉल्यूम: छोटे अक्षर, अंक, - और _। एक ही होस्ट पर दूसरे सर्वर के लिए अपना अलग नाम चाहिए।signallab
--image NAMEकोई दूसरी इमेज या रजिस्ट्री; पूरा NAME:TAG जैसा है वैसा ही उपयोग होता है।ghcr.io/proanima/signallab
--open-udp PORTSफ़ायरवॉल चालू होने पर, इन पोर्ट पर UDP भी अंदर आने दें, मॉनिटर और waits के लिए: 9000,9100:9110।
--no-firewallufw या firewalld कभी न बदलें।
--yes, -yहाँ कहें: Docker इंस्टॉल करें, फ़ायरवॉल खोलें, --purge के साथ डेटा मिटाएँ।
--uninstallसर्वर रोकें और हटाएँ; डेटा रहता है।
--purge--uninstall के साथ: डेटा और टोकन भी मिटाएँ।
--help, -hविकल्प छापें।

इसे Docker के Compose प्लगइन की ज़रूरत है (docker-compose-plugin पैकेज), जो Docker का इंस्टॉलर साथ लाता है। इमेज x86_64 और arm64 के लिए बनी है।

अपडेट करने के लिए इसे फिर चलाएँ: वही कमांड नवीनतम इमेज (या आपका दिया --version) खींचती है और सर्वर को रीस्टार्ट करती है; डेटा और टोकन रहते हैं। --name के साथ, वही नाम फिर दें।

अपनी सेटिंग्स — प्रयोग के सीक्रेट, SIGNALLAB_ALLOWED_HOSTS, HTTPS के पीछे SIGNALLAB_SECURE_COOKIE — compose फ़ाइल के बगल वाली compose.override.yaml में डालें। Docker Compose उसे मिला देता है, और स्क्रिप्ट हर रन पर compose.yaml फिर से लिखती है पर override को कभी नहीं छूती। जो compose.yaml उसने नहीं लिखी, वह compose.yaml.before-install के रूप में रखी जाती है।

yaml
# compose.override.yaml
services:
  signallab:
    environment:
      SIGNALLAB_ALLOWED_HOSTS: lab-pc.example.com,192.0.2.10
      SIGNALLAB_SECRET_API_TOKEN: ${API_TOKEN}

इसे हटाने के लिए:

bash
curl -fsSL https://raw.githubusercontent.com/ProAnima/SignalLab/main/deploy/install.sh | sh -s -- --uninstall

डेटा अपने Docker वॉल्यूम में रहता है, और दोबारा इंस्टॉल करने पर वही टोकन लेकर वापस आता है। --uninstall --purge पूछने के बाद डेटा और टोकन भी मिटा देता है।

होस्ट का फ़ायरवॉल ​

होस्ट नेटवर्किंग के साथ सर्वर होस्ट के ही पोर्ट पर सुनता है, इसलिए यह होस्ट का फ़ायरवॉल तय करता है कि उस तक कौन पहुँचता है। जब ufw या firewalld चालू हो, तो स्क्रिप्ट सर्वर का TCP पोर्ट और --open-udp के UDP पोर्ट खोलने से पहले पूछती है, जो खोला उसे लिख लेती है (compose फ़ाइल के बगल .firewall में), और --uninstall ठीक वही फिर बंद कर देता है। आप मना करें, तो दूसरी मशीनों के ब्राउज़र सर्वर तक तभी पहुँचते हैं जब फ़ायरवॉल उन्हें आने दे, और मॉनिटर तथा waits दूसरी मशीनों को केवल उन UDP पोर्ट पर सुनते हैं जो वह खोलता है।

Docker ​

इमेज ​

ghcr.io/proanima/signallab, linux/amd64 और linux/arm64 के लिए, हर रिलीज़ के साथ प्रकाशित:

टैगयह क्या है
X.Y.Zवह रिलीज़।
X.Yउस श्रृंखला की नवीनतम स्थिर रिलीज़।
latestनवीनतम स्थिर रिलीज़।

इसमें signal-lab-server, बना हुआ इंटरफ़ेस और कमांड लाइन signallab होते हैं, और यह सर्वर को इन सेटिंग्स के साथ शुरू करती है:

वैरिएबलइमेज में मान
SIGNALLAB_LISTEN0.0.0.0:1430
SIGNALLAB_DATA_DIR/data
SIGNALLAB_UI_DIR/usr/share/signal-lab/ui
SIGNALLAB_GENERATE_TOKENtrue

यह एक बिना विशेषाधिकार वाले उपयोगकर्ता (uid और gid 10001) के रूप में चलती है, केवल /data (एक वॉल्यूम) में लिखती है, पोर्ट 1430 खोलती है, और हर 30 सेकंड में अपनी हेल्थ जाँचती है।

इसे शुरू करना ​

bash
docker run -d --name signallab --network host --restart unless-stopped \
  -v signallab-data:/data --read-only --cap-drop ALL --security-opt no-new-privileges \
  ghcr.io/proanima/signallab:1.0.0
docker logs signallab                    # on the first start: "Sign in with it:" and the token

फिर http://<host>:1430 खोलें और टोकन से साइन इन करें। बाद में टोकन फिर देखने के लिए:

bash
docker exec signallab cat /data/token

--read-only, --cap-drop ALL और no-new-privileges वैकल्पिक हैं और कुछ खर्च नहीं करते: सर्वर को किसी विशेषाधिकार की ज़रूरत नहीं और वह केवल /data में लिखता है।

Docker Compose ​

रिपॉज़िटरी की deploy/compose.yaml Compose फ़ाइल जैसी ही है:

yaml
name: signallab

services:
  signallab:
    image: ${SIGNALLAB_IMAGE:-ghcr.io/proanima/signallab:latest}
    container_name: signallab
    network_mode: host
    environment:
      SIGNALLAB_GENERATE_TOKEN: "true"
    volumes:
      - signallab-data:/data
    read_only: true
    cap_drop: [ALL]
    security_opt: ["no-new-privileges:true"]
    restart: unless-stopped
    stop_grace_period: 15s

volumes:
  signallab-data:
bash
docker compose up -d
docker exec signallab cat /data/token

किसी संस्करण को पिन करने के लिए SIGNALLAB_IMAGE=ghcr.io/proanima/signallab:X.Y.Z सेट करें।

नेटवर्किंग ​

Docker नेटवर्किंगक्या काम करता हैक्या नहीं
--network host (network_mode: host), Linux होस्ट परसब कुछ: LAN तक OSC, UDP, TCP, HTTP, WebSocket और MQTT, सुनने वाले पोर्ट, ब्रॉडकास्ट, मल्टीकास्ट, डिस्कवरी।—
ब्रिज (डिफ़ॉल्ट), प्रकाशित पोर्ट के साथजिन होस्ट तक कंटेनर पहुँचता है उन्हें यूनिकास्ट; प्रकाशित पोर्ट पर लिसनर (-p 1430:1430 -p 9000:9000/udp)।ब्रॉडकास्ट और मल्टीकास्ट; उन पोर्ट के जवाब जो प्रकाशित नहीं हैं।
Windows या macOS पर Docker Desktopयूनिकास्ट और प्रकाशित लिसनर।भौतिक नेटवर्क तक होस्ट नेटवर्किंग। Windows पर डेस्कटॉप ऐप उपयोग करें।

डेटा वॉल्यूम ​

/data वह सब रखता है जो सर्वर सँभालता है: प्रयोग, सिग्नल और एमुलेटर लाइब्रेरी, रन रिपोर्ट, एक्सपोर्ट, और टोकन। ऊपर जैसा नामित वॉल्यूम शुरू में इमेज के उपयोगकर्ता के स्वामित्व में होता है। वहाँ माउंट किया गया होस्ट का कोई फ़ोल्डर uid 10001 से लिखने योग्य होना चाहिए:

bash
sudo mkdir -p /srv/signallab && sudo chown 10001:10001 /srv/signallab
docker run -d --name signallab --network host -v /srv/signallab:/data ghcr.io/proanima/signallab:1.0.0

Docker के बिना ​

सर्वर इमेज के रूप में प्रकाशित है। signal-lab-server को सीधे चलाने के लिए, इसे स्रोत से बनाएँ (देखें बनाना):

bash
npm install
npm run build                            # the interface, into dist/
cargo run --release -p signal-lab-server

यह http://127.0.0.1:1430 पर dist/ परोसता है, केवल इसी मशीन के लिए, बिना टोकन की ज़रूरत के। नेटवर्क के लिए खोलने के लिए --listen और एक टोकन जोड़ें।

विकल्प ​

हर विकल्प का एक एनवायरनमेंट वैरिएबल होता है, कंटेनर के लिए। विकल्प वैरिएबल पर भारी पड़ते हैं।

विकल्पवैरिएबलडिफ़ॉल्टयह क्या करता है
--listen IP:PORTSIGNALLAB_LISTEN127.0.0.1:1430कहाँ सुनें। लूपबैक के अलावा किसी भी पते के लिए टोकन चाहिए।
--token-file PATHSIGNALLAB_TOKEN_FILEएक्सेस टोकन रखने वाली फ़ाइल (मान लें, कोई Docker सीक्रेट)।
--token TOKENSIGNALLAB_TOKENख़ुद एक्सेस टोकन। फ़ाइल को प्राथमिकता दें: आर्ग्युमेंट मशीन के दूसरे उपयोगकर्ताओं को दिखते हैं।
--generate-tokenSIGNALLAB_GENERATE_TOKENबंदटोकन दिए बिना, लूपबैक से आगे के किसी पते पर: <data folder>/token में रखा टोकन उपयोग करें, पहली बार शुरू होने पर उसे बनाकर।
--data-dir PATHSIGNALLAB_DATA_DIRउपयोगकर्ता के home फ़ोल्डर में Documents/SignalLabडेटा फ़ोल्डर।
--secrets-dir PATHSIGNALLAB_SECRETS_DIR/run/secrets/signallabकेवल पढ़ने योग्य सीक्रेट का फ़ोल्डर, हर नाम के लिए एक फ़ाइल।
--ui-dir PATHSIGNALLAB_UI_DIRप्रोग्राम के बगल ui, वरना ./distबना हुआ इंटरफ़ेस। इसके बिना केवल API परोसी जाती है।
--allowed-host NAMESIGNALLAB_ALLOWED_HOSTSहोस्ट नाम जिनसे सर्वर तक पहुँचा जा सकता है, कॉमा से अलग। ये और लूपबैक नाम हमेशा स्वीकार होते हैं, टोकन के साथ या बिना; कुछ न दिया हो तो टोकन वाला सर्वर किसी भी नाम को जवाब देता है और बिना टोकन वाला केवल लूपबैक नामों को (देखें होस्ट नाम)।
--secure-cookieSIGNALLAB_SECURE_COOKIEबंदसेशन कुकी केवल HTTPS पर भेजें। इसे HTTPS प्रॉक्सी के पीछे सेट करें।
--log FILTERSIGNALLAB_LOGinfoक्या लॉग करें: error, warn, info, debug, या प्रति मॉड्यूल (signal_lab_server=debug)।
--log-format text|jsonSIGNALLAB_LOG_FORMATtextलॉग पंक्तियाँ टेक्स्ट में, या हर पंक्ति पर एक JSON ऑब्जेक्ट।

स्विच अपने वैरिएबल से true या false लेते हैं: SIGNALLAB_GENERATE_TOKEN=true.

कमांडयह क्या करती है
signal-lab-server tokenएक नया रैंडम टोकन छापती है: 64 हेक्साडेसिमल अक्षर।
signal-lab-server healthcheckजब --listen पर कोई सर्वर जवाब दे तो 0 के साथ बाहर निकलती है (इमेज की हेल्थ चेक)।
signal-lab-server --versionसंस्करण छापती है।
signal-lab-server --helpहर विकल्प छापती है।

एग्ज़िट कोड: Ctrl+C या SIGTERM से रुकने पर 0; सेटिंग्स अस्वीकार होने पर 2 (पहुँच योग्य पते पर टोकन नहीं, टोकन बहुत छोटा, टोकन दो बार दिया गया, पढ़ी न जा सकने वाली टोकन फ़ाइल, डेटा फ़ोल्डर के बिना --generate-token); पते पर सुन न पाने, या डेटा फ़ोल्डर में लिख न पाने पर 1। कारण stderr पर छपता है।

एक्सेस टोकन ​

टोकन के बिना सर्वर केवल लूपबैक पर सुनता है और केवल इस मशीन को परोसता है। किसी दूसरे पते पर उसे टोकन चाहिए, और उसके बिना वह शुरू होने से इनकार कर देता है। इसे देने के तीन तरीके हैं:

कैसेकब उपयोग करें
--generate-token (इमेज में चालू)कुछ सेट करने की ज़रूरत नहीं: पहली बार शुरू होने पर सर्वर एक टोकन बनाता है, उसे <data folder>/token में सहेजता है — केवल उसके अपने उपयोगकर्ता से पढ़ने योग्य — और उसे लॉग में एक बार छापता है। आगे के शुरू होने पर वही उपयोग होता है, इसलिए साइन इन किए ब्राउज़र और स्क्रिप्ट रीस्टार्ट और अपडेट के पार चलते रहते हैं। इसे एक डेटा फ़ोल्डर (--data-dir) चाहिए।
--token-file PATHकिसी फ़ाइल में आपका अपना टोकन, जैसे कोई Docker सीक्रेट। अंत में लगा लाइन ब्रेक टोकन का हिस्सा नहीं होता।
SIGNALLAB_TOKENएनवायरनमेंट में टोकन।

टोकन में कम से कम 24 अक्षर होते हैं और कोई स्पेस या लाइन ब्रेक नहीं; इसे केवल एक ही तरीके से दें। signal-lab-server token अच्छा टोकन बनाती है:

bash
docker run --rm ghcr.io/proanima/signallab:1.0.0 token > signallab_token.txt

और Compose उसे एक सीक्रेट के रूप में देता है (फ़ाइल uid 10001 से पढ़ने योग्य होनी चाहिए):

yaml
services:
  signallab:
    environment:
      SIGNALLAB_TOKEN_FILE: /run/secrets/signallab_token
    secrets:
      - signallab_token

secrets:
  signallab_token:
    file: ./signallab_token.txt

स्पष्ट रूप से दिया टोकन --generate-token पर भारी पड़ता है, और तब कुछ नहीं बनाया जाता। बना हुआ टोकन बदलने के लिए, सर्वर रोकें, <data folder>/token मिटाएँ और उसे फिर शुरू करें: वह एक नया बनाकर छाप देगा। ख़राब टोकन फ़ाइल की सूचना दी जाती है, उसे कभी बदला नहीं जाता।

साइन इन करना ​

http://<host>:1430 खोलें। टोकन वाला सर्वर ब्राउज़र को पहले उसके साइन-इन पेज पर भेजता है, ब्राउज़र की भाषा में; टोकन एक बार पेस्ट करें, और ब्राउज़र 7 दिन तक साइन इन रहता है। इंटरफ़ेस में साइन आउट करें सेशन समाप्त कर देता है। सेशन सर्वर की मेमोरी में रखे जाते हैं: रीस्टार्ट से सभी साइन आउट हो जाते हैं।

लूपबैक पर टोकन के बिना कोई साइन-इन नहीं होता।

स्क्रिप्ट हर रिक्वेस्ट के साथ टोकन भेजती हैं, Authorization: Bearer <token> के रूप में:

bash
curl -fsS http://192.0.2.10:1430/api/invoke/app_info \
  -H "Authorization: Bearer $(cat signallab_token.txt)" \
  -H "Content-Type: application/json" -d 'null'

देखें HTTP API, और इन सबके पीछे के नियमों के लिए सर्वर की सुरक्षा।

डेटा फ़ोल्डर ​

सर्वर अपनी फ़ाइलें डेटा फ़ोल्डर में रखता है: प्रयोग, सिग्नल और एमुलेटर लाइब्रेरी, रन रिपोर्ट, एक्सपोर्ट, और बनाया गया टोकन। यह --data-dir (SIGNALLAB_DATA_DIR) होता है, इमेज में /data, और वरना जिस उपयोगकर्ता के रूप में यह चलता है उसके home फ़ोल्डर में Documents/SignalLab। --data-dir से दिया डेटा फ़ोल्डर न होने पर बना दिया जाता है और शुरू होने पर जाँचा जाता है: अगर सर्वर वहाँ न लिख सके, तो वह रुक जाता है और फ़ोल्डर का नाम बताता है। देखें फ़ाइलें और फ़ोल्डर।

डाउनलोड (रिपोर्ट, एक्सपोर्ट) केवल इसी फ़ोल्डर के भीतर से आते हैं।

सीक्रेट ​

प्रयोग सीक्रेट को {{secret.NAME}} के रूप में पढ़ते हैं। सर्वर पर ये केवल पढ़ने योग्य होते हैं, इनसे:

  1. एनवायरनमेंट वैरिएबल SIGNALLAB_SECRET_NAME, वरना
  2. सीक्रेट फ़ोल्डर में फ़ाइल NAME (--secrets-dir, डिफ़ॉल्ट रूप से /run/secrets/signallab — Docker सीक्रेट लेआउट)।

किसी फ़ाइल का अंत में लगा लाइन ब्रेक मान का हिस्सा नहीं होता; खाली मान को सेट न किया हुआ माना जाता है; मान अधिकतम 16 KiB होता है। नाम अक्षर, अंक और _ होते हैं, अंक से शुरू नहीं होते। इंटरफ़ेस दिखाता है कि सर्वर पर कौन-से सीक्रेट सेट हैं, पर ब्राउज़र से कोई सेट करना अस्वीकार किया जाता है — मान कभी किसी कमज़ोर जगह नहीं जाते, और कभी वापस बाहर नहीं आते (देखें सीक्रेट)।

Compose के साथ, हर नाम के लिए एक सीक्रेट फ़ाइल:

yaml
services:
  signallab:
    secrets:
      - source: api_token
        target: /run/secrets/signallab/API_TOKEN

secrets:
  api_token:
    file: ./api_token.txt

फ़ाइल uid 10001 से पढ़ने योग्य होनी चाहिए।

HTTPS प्रॉक्सी के पीछे ​

सर्वर सादा HTTP बोलता है। HTTPS के लिए, उसके आगे एक रिवर्स प्रॉक्सी रखें (Caddy, nginx, Traefik) जो:

  • Host हेडर को बिना बदले आगे भेजे;
  • WebSocket अपग्रेड आगे भेजे (इंटरफ़ेस /api/events के लिए एक खुला रखता है);

और सर्वर को --secure-cookie के साथ शुरू करें, ताकि सेशन कुकी केवल HTTPS पर जाए, और --allowed-host को वह नाम देकर जिससे लोग पहुँचते हैं।

अपडेट करना ​

सर्वर अपनी इमेज के साथ अपडेट होता है: डेस्कटॉप ऐप के अपडेटर का इससे कोई लेना-देना नहीं।

  • स्क्रिप्ट से इंस्टॉल किया: वही कमांड फिर चलाएँ।
  • Compose के साथ: docker compose pull && docker compose up -d.
  • docker run के साथ: नई इमेज खींचें, फिर कंटेनर हटाएँ और उसे उसी वॉल्यूम के साथ फिर शुरू करें।

डेटा और टोकन वॉल्यूम में हैं, इसलिए वे रहते हैं।

हेल्थ चेक ​

GET /api/health सबको जवाब देता है, बिना टोकन:

bash
curl -s http://127.0.0.1:1430/api/health
# {"auth":true,"status":"ok","version":"1.0.0"}

auth बताता है कि सर्वर टोकन माँगता है या नहीं। कमांड signal-lab-server healthcheck इसी मशीन पर वही पूछती है और जवाब आने पर 0 के साथ बाहर निकलती है; इमेज इसे हर 30 सेकंड में चलाती है (5 सेकंड का टाइमआउट, 3 प्रयास), इसलिए docker ps कंटेनर को स्वस्थ दिखाता है।

लॉग ​

सर्वर stdout पर लॉग करता है: docker logs -f signallab. डिफ़ॉल्ट स्तर (info) पर यह बताता है कि कहाँ सुनता है और उसे टोकन चाहिए या नहीं, उसके डेटा और इंटरफ़ेस फ़ोल्डर, शुरू किया गया हर जॉब — मॉनिटर, जनरेटर, स्टॉर्म, स्कैन, रन, एमुलेटर — क्लाइंट के पते के साथ, हर साइन इन, ग़लत टोकन के साथ हर साइन इन (चेतावनी के रूप में), और जब कोई पेज इवेंट से पीछे छूटता है। स्तर --log debug हर कमांड जोड़ देता है। पंक्तियाँ केवल टर्मिनल पर रंगीन होती हैं (NO_COLOR सेट होने पर कभी नहीं); --log-format json लॉग कलेक्टर के लिए हर पंक्ति पर एक JSON ऑब्जेक्ट लिखता है।

रोकना ​

Ctrl+C, docker stop या SIGTERM हर पेज का कनेक्शन बंद कर देता है, हर जॉब रोक देता है — चल रहा रन रुका हुआ बनकर समाप्त होता है — और 0 के साथ बाहर निकलता है। compose फ़ाइलें इसके लिए उसे 15 सेकंड देती हैं।