تطوير مواقع الويب في باسكال (الواجهة الخلفية)

في هذه المقالة سوف أتحدث عن لماذا ولماذا وكيف بدأت في إنشاء مواقع في Pascal: Delphi / FPC.
ربما يرتبط "موقع باسكال" بشيء مثل:

writeln('Content-type: text/html');

ولكن لا ، كل شيء أكثر إثارة للاهتمام! ومع ذلك ، فإن شفرة المصدر لموقع حقيقي (تقريبًا) متاحة على GitHub.

لماذا؟


بشكل عام ، لست مطورًا محترفًا على الويب مطلقًا - فأنا أصنع الألعاب. اللعبة ، وخاصة لعبة على الإنترنت ، تحتاج إلى موقع على شبكة الإنترنت. لذلك ، حدث أن بدأت في إنشاء المزيد من المواقع لألعابي. باستخدام CGI على بيرل - في أوائل / منتصف 2000s كان شائعًا. كان كل شيء على ما يرام حتى نشأت مشكلة.

في عام 2013 ، بدأنا في إقامة دورات عبر الإنترنت للعبة Spectromancer . للقيام بذلك ، قمت بإنشاء صفحة بطولة على موقع اللعبة ، والتي توضح من سيلعب معه ، والنتائج الحالية ، وما إلى ذلك. في بداية البطولة ، تم تحديث صفحة اللاعبين و ... لم يتم تحميلها. ضغط الناس على F5 ، مما زاد من تفاقم المشكلة. اتضح أنه حتى 4-5 طلبات في الثانية لبرنامج نصي CGI ، تعمل كعملية Perl منفصلة ، تبطئ الخادم بشكل ملحوظ ، و> 10 طلبات في الثانية تجعله غير قابل للوصول تمامًا.

من الجيد أن اختبار الضغط هذا قد تم خلال دورة التدريب: في وقت لاحق استخدمت بالفعل الصفحة الثابتة المحدثة للبطولات.

لماذا ا؟


وهكذا ، عندما نشأت الحاجة لجعل هذا الموقع لعبة جديدة ، نشأ السؤال - على ماذا؟ الفرامل CGI على بيرل ليست خيارا. FastCGI في بيرل؟ لا أستطيع أن أتخيل كيفية كتابة وتصحيح برنامج متعدد المقالات في بيرل ، لقد واجهت مشاكل كافية مع النصوص العادية. Node.js؟ ربما سيكون هذا هو الخيار الأفضل ، إن لم يكن لبعض العداء لشبيبة. وبما أن اللعبة نفسها وخادمها مكتوبان بلغة باسكال (في الواقع دلفي ، لكن FPC جيدة أيضًا) ، نشأت الفكرة - هل يجب أن نجعل الموقع باللغة نفسها؟ سيؤدي ذلك إلى تبسيط التكامل مع خادم اللعبة. "المحاولة ليست تعذيباً!" فكرت ، وقررت أن أجربها.

كيف؟


اخترت SimpleCGI (SCGI) كواجهة: إنها أبسط إلى حد ما من FastCGI ، ومزايا هذا الأخير ليست ذات صلة بالنسبة لي - ليست هناك حاجة لتوزيع الواجهة الخلفية على خوادم مختلفة ، كل شيء يعمل على نفس الخادم. لذا فإن المهمة تتلخص في تطوير إطار عمل SCGI معين يقوم بمعالجة الطلبات من الخادم وينشئ صفحات HTML استجابة لبعض الفراغات والقوالب. والنتيجة هي إطار الوحدة النمطية . وتتكون من الأجزاء التالية:

  • الحلقة الرئيسية : تقبل الاتصالات الواردة ، وتقرأ الطلبات وتضعها في قائمة انتظار للمعالجة. يكتب الردود الجاهزة على الطلبات المجهزة لمآخذ التوصيل وإغلاقها.
  • (N ): , . worker' — .
  • : HTML- ( ) . .
  • : ( CGI.pm Perl). , ..


ميزة ملائمة للغاية في نصوص Perl النصية هي أنه من السهل جدًا إجراء تغييرات بسيطة على الموقع: فقط قم بتحرير كود البرنامج النصي وهذا كل ما في الأمر. لا حاجة لتجميع ونشر. بالطبع ، باسكال هي لغة مترجمة ، ولن تعمل على هذا النحو ، ولكن ما زلت أريد أن أتمكن من إجراء التغييرات كلما أمكن ذلك دون إعادة تشغيل العملية. لذلك ، حاولت أن أجعل نظام القالب مرنًا بما فيه الكفاية.

إنها تعمل بهذه الطريقة. توجد ملفات القوالب في مجلد "القوالب": يتم تحميلها عند بدء العملية وإعادة تحميلها أيضًا عند تغييرها - وبهذه الطريقة يمكنك تغيير المحتوى الديناميكي دون إعادة تشغيل العملية. يمكن أن يحتوي كل ملف على قالب واحد أو أكثر. يشكلون معًا قاموسًا (أو تجزئة) للنماذج: {"name" -> "value"}. هذا قاموس ثابت للنماذج - وهو شائع في جميع الطلبات وتبقى محتوياته دون تغيير (حتى تتغير محتويات الملفات). هناك واحد آخر - قاموس ديناميكي ، يتم إنشاؤه فارغًا لكل طلب ومليء بمعالج البيانات الديناميكي - على سبيل المثال ، من قاعدة البيانات. من خلال الجمع بين البيانات الثابتة والديناميكية ، يتم تشكيل النتيجة النهائية.

إعلان نموذج مثال:

#NEWSFEED_ITEM:
<div class=NewsHeader>
 <a href='/$LANG_LC/forum/thread/$NEWS_ID'><IF_NEWS_PINNED>[TOP]  </IF_NEWS_PINNED>$NEWS_DATE   $NEWS_TITLE</a>
</div>
<div class=NewsText>$NEWS_TEXT
 <div align=right>
  <a href='/$LANG_LC/forum/thread/$NEWS_ID'>$COMMENTS</a>
 </div>
</div>

هذا قالب ثابت لتغذية الأخبار باسم NEWSFEED_ITEM ، بداخله يحتوي على العديد من القوالب الأخرى ، على سبيل المثال NEWS_TEXT - قالب ديناميكي يحتوي على نص إخباري تم تنزيله من قاعدة البيانات. الترجمة هي أن جميع السلاسل الفرعية للنموذج $ TEMPLATE_NAME يتم استبدالها بشكل متكرر بقيمة هذا النموذج.

هنا يمكنك أيضًا ملاحظة العلامة الزائفة للترجمة الشرطية: <IF_TEMPLATE_NAME> - أثناء الترجمة ، يتم حذف هذه العلامات وترك محتوياتها أو حذفها أيضًا ، اعتمادًا على قيمة النموذج المحدد. اخترت على وجه التحديد تنسيق الشروط هذا - في شكل علامات HTML ، بحيث أنه عند التحرير في محرر نص ، يعمل تسليط الضوء على الأعمال ومن السهل رؤية علامة مقترنة.

يبدو رمز إنشاء الخلاصة الذي يستخدم هذا النموذج شيئًا مثل هذا:


    result:='';
    //       NEWSFEED_ITEM      result
    for i:=0 to n-1 do begin
      id:=StrToIntDef(sa[i*c],0);
      title:=sa[i*c+1];
      cnt:=StrToIntDef(sa[i*c+2],1)-1;
      flags:=StrToIntDef(sa[i*c+3],0);
      //     
      db.Query('SELECT msg,created FROM messages WHERE topic=%d ORDER BY id LIMIT 1', 
        [id]);
      if db.lastErrorCode<>0 then continue;
      text:=db.Next;
      date:=db.NextDate;
      //    ( temp)
      temp.Put('NEWS_ID',id,true);
      temp.Put('NEWS_DATE',FormatDate(date,true),true);
      temp.Put('NEWS_TITLE',title,true);
      temp.Put('NEWS_PINNED',flags and 4>0,true);
      comLink:='$LNK_READ_MORE | ';
      if cnt>0 then comLink:=comLink+inttostr(cnt)+' $LNK_COMMENTS'
        else comLink:=comLink+'$LNK_LEAVE_COMMENT';
      temp.Put('NEWS_TEXT',text,true);
      temp.Put('COMMENTS',comLink,true);
      //   
      result:=result+BuildTemplate('#NEWSFEED_ITEM');
    end;

الموقع


القوالب مناسبة أيضًا للاستخدام في التوطين. للقيام بذلك ، استخدم المتغير الشامل (في سياق الطلب) clientLang. تعمل هذه الطريقة: إذا اكتشف معالج الطلب أن العميل يحتاج إلى صفحة باللغة الروسية ، يكتب القيمة "RU" في clientLang ، وبعد ذلك يحاول مترجم القالب ، بعد أن وجد $ TEMPLATE_NAME في النص ، دائمًا تطبيق $ TEMPLATE_NAME أولاً. وبالتالي ، من أجل الأقلمة ، من الضروري فقط لكل قالب يحتوي على نص إنشاء نسخته للغة أخرى:

#TITLE_NEWS:News
#TITLE_NEWS_RU:

مثال على استخدام إطار العمل


مثال بسيط لرمز الموقع:

program website;
uses SysUtils, SCGI;

//    
function IndexPage:AnsiString; stdcall;
 begin
   result:=FormatHeaders('text/html')+BuildTemplate('#INDEX.HTM');
 end;

begin
 SetCurrentDir(ExtractFileDir(ParamStr(0)));
 SCGI.Initialize; //  
 AddHandler('/',IndexPage); //     '/'
 SCGI.RunServer; //      
end.

مجموع


لقد كتبت الإطار الموصوف في عملية إنشاء الموقع الحقيقي astralheroes.com في نهاية عام 2015. كما يحدث عادة ، ظهر أول فطيرة متكتلة إلى حد ما - تبين أن الرمز فوضوي ومربك إلى حد ما ، الموقع التالي يتحسن. ومع ذلك ، أنا راضٍ عن العملية والنتيجة: يعمل الموقع بشكل جيد ، ويتم تصحيحه وتحديثه بسهولة.

الموجودات:

  • توقعت أنه بالمقارنة مع Perl المضغوط ، فإن كود الموقع منتفخ للغاية ، ولكن لا - نفس الوظيفة المكتوبة في Pascal تستغرق حوالي ضعف الكمية في Perl. لكنها تبدو أكثر وضوحا.
  • ! Perl — , - 100 , , . - - — . Delphi .
  • Perl. -, , , . -, Perl, , .
  • : , , . .
  • . , , ( ), , . , , — . .

    , . — . , :



    , — . , .

?


المصادر على GitHub: github.com/Cooler2/ApusEngineExamples

لاحظ أن هناك وحدة فرعية في المستودع ، لذلك من الأفضل استنساخها مع المعلمة "- المتكررة ".

مشروع الموقع موجود في الملف: "AH-Website \ Backend \ src \ website.dpr"

هذه ليست نسخة كاملة من الموقع الحالي: من الواضح أنه لا يمكنني نشر محتويات قاعدة البيانات مع بيانات اللاعبين ، كما أنني لا أنشر نصوص CGI ، لأنها لا علاقة للموضوع. ومع ذلك ، يتم تجميع المشروع وإطلاقه وتشغيله ، مما يدل على عمل الإطار بشكل كامل.

تم نشر رمز الموقع ، بالإضافة إلى رمز المحرك الذي يستخدمه ، بفضل الدعم الذي تلقيته على Patreon. أعبر عن امتناني لكل من ساندوني وأحثكم على الانضمام - لا يزال هناك الكثير من الأشياء المثيرة للاهتمام في المستقبل :)

شكرا لكم على اهتمامكم!

All Articles