10.1. נקודת הקצה הראשונה שלך¶
לפני שהמצלמה יכולה לעשות משהו מעניין, שאר הרשת צריכה להיות מסוגלת להגיע אליה. הדבר הזול ביותר שמוכיח שהשרת חי הוא נקודת קצה HTTP עם נתיב יחיד שמחזירה מעט JSON:
from microdot import Microdot
app = Microdot()
frame_count = 0
trigger_count = 0
@app.get('/status')
async def status(request):
return {'frames': frame_count, 'triggers': trigger_count}
app.run(host='0.0.0.0', port=80)
הריצו אותה ב-IDE. מכל מכונה אחרת ברשת המקומית (LAN) פתחו את http://<cam-ip>/status. הדפדפן מציג:
{"frames": 0, "triggers": 0}
המונים הם ממלאי מקום – שום דבר עדיין לא נוגע בהם – אבל הבקשה חצתה את הרשת, המצלמה ניתבה אותה, הריצה מטפל, ושלחה JSON בחזרה.
10.1.1. מה כל שורה עושה¶
מופע microdot.Microdot אחד לכל סקריפט. המופע הוא הבעלים של טבלת הניתוב, מטפלי השגיאות, ומחזור החיים (הפעלה, שירות, עצירה). יישומים גדולים מתחלקים למספר מודולי Python אך עדיין חולקים אובייקט app יחיד.
@app.get('/status') הוא דקורטור הנתיב. אנו משתמשים כאן רק ב-microdot.Microdot.get(); post(), put(), ו-delete() מופיעים בעמודים מאוחרים יותר כשהמצלמה מתחילה לקבל כתיבות.
כל מטפל נתיב הוא קורוטינה של asyncio ומקבל את הבקשה כארגומנט הראשון שלו. המטפל אינו חייב להשתמש ב-request – זה כאן מתעלם ממנו – אבל הפרמטר תמיד שם כך שהחתימה עקבית.
החזרת dict היא הדרך הקצרה ביותר לשלוח JSON. Microdot מסדרת (serializes) את ה-dict ל-JSON אוטומטית ומגדירה Content-Type: application/json בתגובה. החזרת מחרוזת שולחת text/plain. החזרת microdot.Response במפורש היא הצורה הארוכה – נחוצה כאשר גוף ההודעה הוא בינארי או כאשר התגובה רוצה כותרות מותאמות אישית.
app.run(host='0.0.0.0', port=80) מפעיל את השרת. 0.0.0.0 פירושו להאזין לכל ממשק שיש למצלמה – גם הרשת הקווית (ethernet) וגם ה-wifi STA, אם שניהם פעילים. פורט 80 הוא ברירת המחדל של HTTP, כך שדפדפנים אינם צריכים להקליד מספר פורט.
10.1.2. בקשה אחת, מקצה לקצה¶
הטלפון פותח חיבור TCP, כותב את שורת הבקשה ואת הכותרות, וממתין. המצלמה קוראת את הבתים מהשקע (socket), מפרשת אותם לאובייקט microdot.Request, מתאימה את הנתיב והשיטה מול טבלת הניתוב, ממתינה (awaits) לקורוטינת המטפל, מסדרת (serializes) את כל מה שהוחזר, כותבת שורת סטטוס, כותרות, וגוף בחזרה אל השקע, ואז סוגרת את החיבור (ברירת מחדל של HTTP/1.0) או ממחזרת אותו (HTTP/1.1 עם Connection: keep-alive). כל ההחלפה אורכת בערך כמשך הלוך-ושוב ברשת בתוספת כל מה שהמטפל עשה.
10.1.3. הערה על חסימה¶
run() הוא חוסם – הוא לעולם אינו חוזר עד שהשרת נעצר. זה בסדר עבור שרת ייעודי. יישום שגם לוכד פריימים או מריץ קורוטינות אחרות משתמש ב-start_server() בתוך asyncio.run() במקום זאת, כך ששרת ה-HTTP יכול לחלוק את הלולאה עם כל השאר.
היישום עונה לכתובת URL אחת.