מאמרים בנושא ‏CppCMS‏.

Comet בצורה שפויה

ב־יום ראשון, 12 באוגוסט 2012, מאת ארתיום; פורסם תחת: תכנה חופשית, פיתוח, תכנה ומחשבים, CppCMS; ‏0 תגובות

‏ HTML5 ו־Comet

היום HTML5 מציע שני כלים עיקריים ליישומי ‏Comet‏:

מבחינה טכנית, WebSockets ‏(WS) מייצרים קשר דו־כיווני מלא ומאפשרים הן לשרת והן לקוח לשלוח הודעות בזמן אמת - בלי לפתוח קשרים נוספים. לעומת זאת Server-Sent Events‏ (SSE) זהו קשר חד־כיווני, בו השרת הוא זה ששולח אירועים ללקוח ואם הלקוח צריך לשלוח משהו לשרת, הוא משתשמש בכלי Ajax נוכחיים כמו XMLHttpRequest‏ (XHR).

למען האמת, עד עכשיו יצא לי לעקוב אחרי התפתחות של WS. הפרוטוקול החליף מספר גרסאות, הדפדפנים שינו את המימושים בהתאם עד שהפרוטוקול התייצב. כיום התמיכה ב־WS קיימת ברוב הדפדפנים עדכניים ואמורה להיכנס גם ל־IE10. לעומת זאת, כל הנושא של SSE חלף על פניי ולא שמתי עליו לב.

כיוון שאני מעסק בצד השרת בעיקר, הכנסתי את נושא ה־WS לתכנית העבודה שלי. אבל עדיין לא הצלחתי להגיע אליו; ולא במקרה.

למרות העתיד ה"זוהר" של WS, המימוש הוא לא פשוט. לא מדובר כאן בבעיה טכנית, הרי תמיכה ב־Comet כבר קיימת ועובדת יפה, הבעיה היא בעיה מהותית: כדי לממש WS צריך לשנות פרוטוקול HTTP. ברגע ש"לחיצה היד" של WS נגמרת, לא מדובר עוד ב־HTTP, אלא בפרוטוקול שונה לחלוטין.

לכן, הכלים ופרוטוקולים שבעזרתם יישומים מתקשרים עם שרתי Web, לא מתאימים. למשל, אי אפשר להעביר תקשורת של WS מעל FastCGI, SCGI או CGI. גם אם היישום שלך עובד ב־HTTP, לא כל שרת web ידע להתמודד עם הבעיה: החלפת ה־HTTP בפרוטוקול חלופי.

לכן, אפילו ש־WS, זאת טכנולוגיה מבטיחה, היא עדיין רחוקה מהבשלות האמתית.

לעומת זאת, SSE, שנדחקו הצדה, לא סובלים מהבעיות האלה!

  • SSE לא משנים את פרוטוקול ה־HTTP, לכן, אין בעיות שימוש בתשתיות הקיימות.
  • הביצועים של SSE לא נופלים על אלה של WS.
  • SSE הרבה יותר קלים לתפעול:

    • מכילים מנגנון סנכרון אוטומטי, במקרה של התנתקות
    • מאפשרים לשלוח אירועים שונים ברמת JavaScript בלי שכבות נוספות
    • ניתן לסגת בקלות ל־Long Polling עם XHR פשוט במקרה שהדפדפן לא תומך ב־SSE.

החיסרון היחידי של SSE לעומת WS: לא ניתן לשלוח הודעות באותו הקשר לשרת. אלא לכל הודעה לשרת צריך לשלוח XHR משלו. אבל? SSE מכסה את הרוב המקרים של שימוש ב־Comet!

המימוש? קיים ב־Firefox,‏ Opera‏, Chrome‏, Safari ואמור להיכנס ל־IE10

אז איך זה עובד

בואו נדגים אפליקציה שמציגה את מחיר המניה העדכני ביותר בדפדפן:

בצד הלקוח, אנחנו נכתוב את הקוד הפשוט הבא:

function read_data() {
    var stream = new EventSource('/ticker/get');
    stream.onmessage = function(e){
        document.getElementById('price').innerHTML=e.data;
    };

    stream.onerror = function(e){
        console.log(e);
    };
}

read_data();

אנחנו פותחים EventSource ועל כל אירוע שמכיל מידע אנחנו מעדכנים שדה html עם המחיר העדכני ביותר.

בצד השרת הנושא שקצת יותר מורכב כי אנחנו צריכים לנהל מספר קשרים:

כשנכנס קשר חדש, אנחנו מכינים אותו - מגדירים את ה-Content-Type כ־text/event-stream, מבטלים caching בדרך.

לוקחים את ה־id של הערך הידוע האחרון, זה יאפשר לנו לדעת אם הלקוח התנתק אז אם הוא יודע את המחיר העדכני ביותר או לא. אם הערך שונה מהערך הנוכחי, אנחנו שולחים עדכון, אחרת מכניסית אותו ל"רשימת המתנה" - כל הלקוחות הממתינים לעדכון.

void main(std::string /*url*/)
{
    response().set_content_header("text/event-stream");
    response().set_header("Cache-Control", "no-cache");

    auto last_id = atoi(request().cgetenv("HTTP_LAST_EVENT_ID"));

    auto context=release_context();

    if(last_id != counter_) {
        async_send(context);
    }
    else
        waiters_.insert(context);
}

כיצד אנחנו שולחים עדכונים:

התוכן מורכב מה־id - של המחיר - מנגנון הסנכרון שלנו והתוכן - המחיר עצמו.

void async_send(booster::shared_ptr<cppcms::http::context> waiter)
{
    waiter->response().out() <<
        "id:" <<  counter_ <<"\n"
        "data:" << price_ << "\n"
        "\n";

אחר כך אנחנו מגדירים completion-handler שיבדוק אם פעולה הצליח (אם לא אז קשר נסגר אין מה לעשות) ואם כן, ואין עדכונים נוספים ומכניסים אותו לרשימת ההמתנה.

    waiter->async_flush_output([=,counter_](cppcms::http::context::completion_type status){
        if(status!=0)
            return;
        if(counter_ != this->counter_) {
            this->async_send(waiter);
        }
        else {
            this->waiters_.insert(waiter);
        }
    });

}

עכשיו נכתוב פונקציה קטנה שמאפשרת לנו לעדכן את אלו שממתינים למחיר חדש:

void update_price(double new_one)
{
    counter_++;
    price_ = new_one;
    for(auto waiter : waiters_) {
        async_send(waiter);
    }
    waiters_.clear();
}

נעדכן מונה כדי לסמן מחיר חדש, נעבור על הרשימה ונשלח מחיר מעודכן לכולם. מנגנון פשוט שניתן לממש עם כלים פשוטים (במידה והתשתית שלך תומכת ב־Comet).

ניתן למצוא כאן את הקוד המלא.

חיבור לשרת

כדי שהמנגנון הזה יעבוד צריך לוודא ששרת ה־Web ישלח את התוכן באופן מידי ולא ישמור אותו בזיכרון (בציפייה שעוד מידע יגיע).

  • Lighttpd עושה את זה בלי בעיה ב־FastCGI,‏ SCGI ו־HTTP כברירת מחדל.
  • Apache עושה את זה כברירת מחדל ב־SCGI ו־HTTP אבל ב־FastCGI דרושה אופציה ‎-flush ואז הכל תקין.

לעומת זאת, "Nginx המהולל" עושה בעיות. בפרוטוקולים SCGI ו־HTTP ניתן לבטל buffering עם אופציה http_buffering off או scgi_buffering off אבל ב־FastCGI, שהוא הפרוטוקול הכי נפוץ בעבודה עם שרת Web אופציה כזו לא קיימת! כרגיל, Nginx מפתיע... (או שלא).

אז כרגיל, עוד סיבה טובה לא להשתמש ב־Nginx. אז אני אחזור את הטענה שלי: Nginx, תודה לא, Lighttpd‏.

מצגת מאוגוסט פינגווין 2012

ב־יום שבת, 11 באוגוסט 2012, מאת ארתיום; פורסם תחת: תכנה חופשית, תכנה ומחשבים, CppCMS; ‏2 תגובות

המצגת של ההרצאה שלי באוגוסט פינגווין 2012 על CppCMS נמצאת כאן

גרסת ‏ODF‏, גרסת ‏PDF‏

רישיון: ייחוס-שיתוף זהה 1.0 ישראל של Creative Commons‏

לבנות RPM להרבה הפצות

ב־יום חמישי, 15 במרס 2012, מאת ארתיום; פורסם תחת: תכנה חופשית, לינוקס, תכנה ומחשבים, CppCMS; ‏2 תגובות

כשאתה מפתח הפרויקט קוד־פתוח, קל מאוד להפיץ קוד מקור, אבל כשזה מגיע לקבצים בינאריים, זה הופך לבעיה הרבה יותר משמעותית. יש עשרות הפצות, כל אחת מגיע במספר גרסאות שונות ומביא אתה חבילות טיפה שונות. לכן, לאדם אחד זה כמעט ובלתי אפשרי לבנות חבילות לכל הפצה אפשרית.

בזכות debootstrap היה לי יחסית קל לבנות חבילות deb ל־Debian ו־Ubuntu, אבל המצב הרבה יותר מורכב כשמדובר ב־rpm כי אין דרך קלה לשים את הפצת rpm בספריה ולעשות לתוכה chroot.

בהמלצת שגיא בן־עקיבא התחלתי להשתמש ב־Open Build Service של OpenSuse.

האמת, אני מאוד מרוצה! כל מה שצריך זה להעלות Source RPM או קובץ spec, כל השאר ייעשה בצורה אוטומטית: בניה למספר הפצות ופלטפורמות, הכנת מקורות מסודרים ואפילו אתה מקבל repository מסודר.

בצורה כזו הכנתי rpmים ל־3 הפצות (Fedora, Suse, CentOS) כולל מספר גרסאות וגם הכל עבור שתי ארכיטקטורות: x86 ו־x86_64.

http://download.opensuse.org/repositories/home:/artyom-beilis/

מה שנותר... להבין כיצד משתמשים בשירות עבור debים

שוחררה גרסה יציבה 1.0.0 של CppCMS המופצת תחת רישיון כפול

ב־יום שני, 27 בפברואר 2012, מאת ארתיום; פורסם תחת: תכנה חופשית, אינטרנט, לינוקס, פיתוח, תכנה ומחשבים, CppCMS; תגובה אחת

היום, אחרי מספר שנות פיתוח, שוחררה גרסה יציבה של CppCMS 1.0.0, אחרי תקופה ארוכה של גרסאות בטא. הגרסה הזו מהווה אבן דרך משמעותית בהתפתחות של CppCMS, הן מבחינה טכנולוגיות והן מבחינה עסקית.

החל מגרסה 1.0.0, ספריית CppCMS תהיה זמינה תחת רישיון חופשי LGPLv3 ותחת רישיון מסחרי שיאפשר פיתוח יישומים קנייניים תוך שמירה על שלמות המוצר והגנה על הסודות המסחריים שלו.

למידע נוסף על הרישוי החלופי והמחירים אנא כנסו לאתר שלנו:
http://commercial.cppcms.com

גרסה זו, עברה שכתוב יסודי ושינויים ארכיטקטוניים עמוקים שהזניקו את הפופולריות שלה מיד עם שחרור גרסאות בטא ראשונות. מבין החידושים הטכנולוגיים:

  • הכנסה של API ו־ABI יציבים
  • תמיכה מובנית ב־Ajax ו־Comet
  • שיפורים מהותיים בלוקליזציה
  • תמיכה מובנית ב־Windows
  • שיפורים משמעותיים באבטחה: מסנני XSS וכלים למניעת CSRF ועוד.
  • שרת HTTP מובנה לפיתוח ומערכות משובצות

הענף הישן יציב CppCMS 0.0.x לא נתמך יותר. כל משתמשיי הענף הישן מתבקשים לעבור לגרסה החדשה. יש לציין, לא ידוע לי על משתמש אחד שנשאר עם הגרסה הישנה.

הגיע הזמן לשרת וירטואלי פרטי

ב־יום חמישי, 26 בינואר 2012, מאת ארתיום; פורסם תחת: תכנה חופשית, אינטרנט, תכנה ומחשבים, CppCMS; ‏9 תגובות

אחרי חמש שנים שהחזקתי את הבלוג שלי ואת כל האתרים שלי על המחשב הביתי, הגיע הזמן להעביר את התפקיד לשרת וירטואלי אי־שם בענן.

הסיבה העיקריות למעבר הן:

  • Uptime נמוך, בעיקר אודות חברת החשמל וגם מידי פעם תקלות חומרה.
  • חיבור לא אמין במיוחד מחו"ל שגרם לי להחזיק אתר המראה סטטי לפרויקט שלי.

אז הגיע הזמן לשדרג. כיוון שהאתרים שלי רצים על טהרת CppCMS זה לא היה דבר טריביאלי,

  • מצד אחד, אני צריך שרת וירטואלי עם שליטה מלאה על יכולת התקנת התכנה, כולל התקנה של קובצי הריצה משלי, לכן, שירותי אירוח משותפים לא באו בחשבון, כי רובם לא מותאמים לטכנולוגיות כאלה.
  • מצד שני, ממש אין לי צורך בשרת חזק, בעיקר בגלל שהטכנולוגית CppCMS היא חסכונית להפליא.

אחרי הרבה השוואות של מחירים (לא זולים) של שרתי VPS החלטתי ללכת על Amazon EC2, כיוון שאני משלם על מה שאני משתמש... וחוץ מרוחב הפס אני לא ממש הולך להשתמש בהרבה :-). לכן, החלטתי ש־Amazon EC2 יהיה אידאלי לטכנולוגיה שאני מציע.

ובכן, רכשתי שם המתחם, סידרתי שרת ב־EC2 ותוך זמן קצר עברתי ל־VPS משלי בענן.

כרגע יש לי שרת שמריץ lighttpd ומאחוריו שלוש יישומי FastCGI: עבור האתרים:

השרת מהיר וקל כנוצה עם ערכי uptime:load average שווים ל־0.

העמוד הבא

העמוד הבא

דפים

נושאים