זרימת שמירת קוד (Save Flow)
סקירה כללית
זרימת השמירה מאפשרת למשתמשים לשמור קטעי קוד בבוט דרך מספר מסלולים:
- הדבקת קוד ישירה
- העלאת קובץ (עד 20MB)
- מצב איסוף ארוך (מספר הודעות עם /done)
מצבי שמירה
מצב |
טריגר |
תיאור |
|---|---|---|
|
|
מצב המתנה לקוד |
|
לאחר קבלת קוד |
מצב המתנה לשם קובץ |
|
לאחר קבלת שם |
מצב המתנה להערה (אופציונלי) |
|
|
מצב איסוף מספר הודעות |
|
במצב איסוף ארוך |
מצב המתנה להוספת קוד נוסף |
זרימת עבודה בסיסית
sequenceDiagram
participant U as User
participant B as Bot
participant H as SaveFlow Handler
participant CS as CodeService
participant DB as MongoDB
U->>B: ➕ הוסף קוד חדש
B->>H: start_save_flow()
H->>H: בדיקת מצב (GET_CODE)
H->>U: "שלח את הקוד שלך"
U->>H: קוד (הודעה/קובץ)
H->>H: בדיקת גודל
alt קוד > 300KB
H->>H: מעבר ל-LONG_COLLECT
H->>H: _schedule_long_collect_timeout()
H->>U: "מצב איסוף ארוך. שלח עוד קוד או /done"
else קוד רגיל
H->>H: נרמול קוד (normalize_code)
H->>H: זיהוי secrets (_detect_secrets)
alt נמצאו secrets
H->>U: "אזהרה: נמצאו סודות בקוד"
end
H->>H: מעבר ל-GET_FILENAME
H->>U: "מה שם הקובץ?"
end
U->>H: שם קובץ
H->>H: בדיקת כפילויות
alt קובץ קיים
H->>U: תפריט: החלף/שנה שם/ביטול
else קובץ חדש
H->>H: מעבר ל-GET_NOTE
H->>U: "הוסף הערה (אופציונלי) או /skip"
end
U->>H: הערה או /skip
H->>CS: process_code(code, filename, language)
CS->>CS: זיהוי שפה (detect_language)
CS->>CS: ניתוח קוד (analyze_code)
CS->>DB: save_snippet()
DB-->>CS: file_id
CS-->>H: success
H->>U: "נשמר בהצלחה: {filename}"
מצב איסוף ארוך (LONG_COLLECT)
מצב זה מאפשר איסוף קוד במספר הודעות:
# הגדרות
LONG_COLLECT_MAX_BYTES = 300 * 1024 # 300KB
LONG_COLLECT_TIMEOUT_SECONDS = 15 * 60 # 15 דקות
זרימה:
משתמש שולח
/longאו קוד >300KBהבוט עובר למצב
LONG_COLLECTכל הודעה נוספת מצטרפת ל-
context.user_data['code_parts']טיימאאוט של 15 דקות ללא פעילות מבטל את המצב
/doneמסיים את האיסוף ומעביר ל-GET_FILENAME
טיפול בטיימאאוט:
def _schedule_long_collect_timeout(update, context):
jid = f"long_collect_timeout:{update.effective_user.id}"
job = context.job_queue.run_once(
long_collect_timeout_job,
when=LONG_COLLECT_TIMEOUT_SECONDS,
data={'chat_id': ..., 'user_id': ...},
name=jid,
job_kwargs={'id': jid, 'replace_existing': True}
)
context.user_data['long_collect_job'] = job
זיהוי סודות (Secrets Detection)
המערכת מזהה סודות בקוד לפני שמירה:
patterns = [
r"ghp_[A-Za-z0-9]{36,}", # GitHub Personal Access Token
r"github_pat_[A-Za-z0-9_]{30,}", # GitHub Fine-grained Token
r"AIza[0-9A-Za-z\-_]{35}", # Google API Key
r"sk_(live|test)_[0-9A-Za-z]{20,}", # Stripe Key
r"xox[abprs]-[0-9A-Za-z\-]{10,}", # Slack Token
r"AWS_ACCESS_KEY_ID\s*=\s*[A-Z0-9]{16,20}",
r"AWS_SECRET_ACCESS_KEY\s*=\s*[A-Za-z0-9/+=]{30,}",
r"-----BEGIN (RSA |EC |)PRIVATE KEY-----",
r"(?i)(api|secret|token|key)[\s:=\"]{1,20}[A-Za-z0-9_\-]{16,}"
]
התנהגות: - אם נמצאו סודות, המשתמש מקבל אזהרה - השמירה ממשיכה (לא נחסמת) - המשתמש יכול לבחור לבטל
טיפול בכפילויות
כאשר קובץ עם אותו שם כבר קיים:
# בדיקת קיום
existing = await db.get_file_by_name(user_id, filename)
if existing:
# תפריט החלפה
keyboard = [
[InlineKeyboardButton("🔄 החלף", callback_data=f"replace:{file_id}")],
[InlineKeyboardButton("📝 שנה שם", callback_data="rename")],
[InlineKeyboardButton("❌ ביטול", callback_data="cancel")]
]
נרמול קוד
כל קוד עובר נרמול לפני שמירה:
from utils import normalize_code
normalized = normalize_code(code)
# הסרת תווים נסתרים
# נרמול שורות ריקות
# טיפול בקידודים שונים
הערות לסוכנים:
הנורמלייזר מסיר רווחים ריקים בסוף כל שורה, ואז מוריד גם
\nעודפים בסוף הטקסט. כלומר אם המשתמש לא שלח שורה ריקה אחרונה – לא נוסיף אחת באופן מלאכותי.אם מבחני יחידה או תסריטים חיצוניים מצפים לשורת סיום מסוימת, צריך להוסיף אותה במפורש בקוד לפני הקריאה ל-
normalize_codeאו להתאים את האסרט.
Edge Cases
קוד ריק: - נדחה עם הודעת שגיאה
קובץ גדול מאוד (>20MB): - נדחה עם הודעת שגיאה - מוצע להשתמש ב-GitHub או Google Drive
טיימאאוט במצב LONG_COLLECT: - המצב מתבטל אוטומטית - המשתמש מקבל הודעה - כל הקוד שנאסף נמחק
שגיאת שמירה ב-DB: - המשתמש מקבל הודעת שגיאה - האירוע נרשם ב-Observability - מונה שגיאות Prometheus מתעדכן