Using source on other .prgs

mod_harbour is an Apache module that allows to run PRGs directly on the web !!!

Using source on other .prgs

Postby reinaldocrespo » Fri Jul 16, 2021 1:01 pm

Hello Mod-harbourers;

I have started using ModHarbour but so far not so much to build html pages but to trap webhooks. A webhook is a POST request sent to a page from services to notify or transmit certain data.

There is something I still can't figure out about Modharbour. It is the use of other functions and classes on other source files from my Index.prg source.

For example, my code below receives POST data from a service call Twilio. Anytime someone texts my Twilio phone number, this code receives and processes POST data from Twilio that contain all the SMS text information.

Notice how on this code I'm using functions like Connect2DD() and LogData() and ExecuteSQL(). These are my own functions. In order to be able to use them I find I have to include all their source into Index.prg. I want to avoid that.

Is there a better way to link other code, classes, and functions and use them on my Index.prg? Can I use my own created classes like TAdsQuery() that contain many data and methods without having to add all this code into Index.prg?

Code: Select all  Expand view

#include "\harbour\include\fileio.ch"
#include "\harbour\include\ads.ch"


#define CRLF Chr(13)+Chr(10)
#define MAX_LOG_SIZE 65536
#define LOG_DEBUG .T.
#define DEBUGFILE "trace.log"

function Main()
   Local h := AP_PostPairs()
   Local i, cTel, cConfirmCode
   Local cSql, lConfirmed

   LogData( DEBUGFILE, { "Twilio Page hit with", AP_Method() }, MAX_LOG_SIZE )

   For i := 1 To  LEN( h )
      LogData( DEBUGFILE, HGetPairAt( h, i ), MAX_LOG_SIZE )
   Next

   if AP_Method() == "POST" .AND. ;
        hHasKey( h, "MessageSid") .AND. ;
        hHasKey( h, "AccountSid") .AND. ;
        hHasKey( h, "From") .AND. ;
        hHasKey( h, "Body") .AND. ;
        ;//At( ALLTRIM ( h[ "Body "] ),  [1,2] ) > 0  .AND. ;
        ( AdsGetConnectionType() != AE_NO_CONNECTION .OR. Connect2DD() )


      cConfirmCode := AllTrim( hb_ValToStr(  Val(  Left( AllTrim( h[ "Body" ] ), 1 ) ) + 1 ) )
      cTel         := StrTran( AllTrim( h[ 'From'] ), "+1", "" ) //remove +1 from tel numb

      lConfirmed := isConfirmed( cTel )
      //we need to first check if appntment hasnt been confirmed already.
      //patients sometimes send a 1 and then follow with more texts.
      //if appntmnet is already confirmed, should we ignore further replies...?
      //+1 was added to cConfirmCode
      if cConfirmCode != '2' .AND. cConfirmCode != '3' .and. !lconfirmed
            cSql := "INSERT INTO SMSMessages( celnumber, Text ) Values( '$1$', '$2$' ) \n"
            ExecuteSQL( cSql, ADS_ADT, { cTel, "Este sistema automatizado solo entiende 1 para confirmar o 2 para cancelar su cita. Para preguntas marque 787-751-1487" } , LOG_DEBUG )

      elseif lConfirmed //once confirmed stop texting me!  call the office insetad.
         cSql := "INSERT INTO SMSMessages( celnumber, Text ) Values( '$1$', '$2$' ) \n"
         ExecuteSQL( cSql, ADS_ADT, { cTel, "Este sistema automatizado ya tiene su cita confirmada o cancelada previamente. Para preguntas marque 787-751-1487" } , LOG_DEBUG )

      else        //it hasn't been confirmed and a 1 or a 2 was received as expected.

         cSql := ;
               "DECLARE tbl CURSOR ;                  \n"+;
               "OPEN tbl AS SELECT Top 1 guid, service, mrec, StartTime \n"+;
               "              FROM $3$  \n"+;
               "             WHERE tel = '$2$'        \n"+;
               "               AND starttime > Now()  \n"+;
               "               AND ( confirmed is null or confirmed= 1 or confirmed > 3 )\n"+;
               "          ORDER BY StartTime ;        \n"+;
               "                                      \n"+;
               "IF FETCH tbl then                     \n"+;
               "                                      \n"+;
               "   UPDATE $3$              \n"+;
               "      SET confirmed = $1$                \n"+;
               "    WHERE tel = '$2$'                    \n"+;
               "      AND CONVERT( starttime, SQL_DATE ) = convert( tbl.starttime, SQL_DATE );\n"+;
               "                                      \n"+;
               "end;                                  \n"+;
               "CLOSE tbl ; \n"
                   
         ExecuteSQL( cSql, ADS_ADT, { cConfirmCode, cTel,'sfi_msk_appntmnts' }, LOG_DEBUG  )
         ExecuteSQL( cSql, ADS_ADT, { cConfirmCode, cTel,'mo_appntmnts' }, LOG_DEBUG  )
         ExecuteSQL( cSql, ADS_ADT, { cConfirmCode, cTel,'appntmnts' }, LOG_DEBUG  )
         ExecuteSQL( cSql, ADS_ADT, { cConfirmCode, cTel,'degetau_appntmnts' }, LOG_DEBUG  )

         if cConfirmCode = '2'   //.and. !isConfirmed?
            cSql := "INSERT INTO SMSMessages( celnumber, Text ) Values( '$1$', '$2$' ) \n"
            ExecuteSQL( cSql, ADS_ADT, { cTel, "Es importante llegar 15 minutos antes de la hora de su cita." } , LOG_DEBUG )
         endif

      endif

      AdsDisconnect()

   endif

return nil

 
User avatar
reinaldocrespo
 
Posts: 979
Joined: Thu Nov 17, 2005 5:49 pm
Location: Fort Lauderdale, FL

Re: Using source on other .prgs

Postby Antonio Linares » Sat Jul 17, 2021 10:05 pm

Dear Reinaldo,

mod_harbour provides "meta commands" which are instructions that will be executed before running the requested PRG

In example:

Your code ...

at the bottom of it:
// {% LoadPrg( "extra1.prg" ) %}
// {% LoadPrg( "extra2.prg" ) %}

Such code will be identified by mod_harbour and macro expanded. function LoadPrg() is quite simple:

Code: Select all  Expand view
static aPRGs := {}

function LoadPrg( cPrgName )

   local cCode := MemoRead( hb_GetEnv( "PRGPATH" ) + cPrgName )
   local nLen  := Len( hb_ATokens( cCode, Chr( 10 ) ) )
   local nAt

   if Len( aPRGs ) == 0
      AAdd( aPRGs, { AP_FileName(), ProcLine( 2 ) } )
   endif  

   if AScan( aPRGs, { | aPRG | cPrgName == aPRG[ 1 ] } ) == 0
      AAdd( aPRGs, { cPrgName, ATail( aPRGs )[ 2 ] + nLen } )
   else
      cCode = ""  
   endif  

return cCode

function GetPrg( nLine )

   local aPrg := { AP_FileName(), ProcLine( 2 ) }

   if Len( aPrgs ) > 0
      nAt = AScan( aPRGs, { | aPrg | nLine <= aPrg[ 2 ] } )
      if nAt != 0
         aPrg = aPrgs[ nAt ]
      endif  
   endif    

   aPRGs = {}

return aPrg


The above code must be included into mod_harbour. If you don't want to rebuild mod_harbour then do it this way:

// {% hb_MemoRead( hb_GetEnv( "PRGPATH" ) + "extra1.prg" ) %}

The advantage of using LoadPrg() is that GetPrg( nLine ) will provide you the right PRG name when there is an error in your code
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42084
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Using source on other .prgs

Postby reinaldocrespo » Sun Jul 18, 2021 2:47 pm

Hello Antonio and all other Mod_harbour'ers;

If I am to rebuild mod_harbour; would it make sense to also include some of my most frequently used code as libs linked to libharbour.dll?

Should I be concerned about speed degradation if I do that?

Thank you,
User avatar
reinaldocrespo
 
Posts: 979
Joined: Thu Nov 17, 2005 5:49 pm
Location: Fort Lauderdale, FL

Re: Using source on other .prgs

Postby Antonio Linares » Sun Jul 18, 2021 3:11 pm

Reinaldo,

> If I am to rebuild mod_harbour; would it make sense to also include some of my most frequently used code as libs linked to libharbour.dll?

Yes, you can include any library in modharbour.hbp just remember to add this code in apache.prg for each library that you want to include:

#define __HBEXTERN__HBTIP__REQUEST // replace HBTIP with your lib name
#include "../../harbour/contrib/hbtip/hbtip.hbx" // generated by hbmk2

hbx files are generated by hbmk2 when you build your lib using hbmk2:
-hbx=yourlib.hbx

This asures that all the symbols in each library will be linked and fully available from mod_harbour.
Please review any hbx file like "../../harbour/contrib/hbtip/hbtip.hbx" as you can also create them manually using your source code editor.

> Should I be concerned about speed degradation if I do that?

not at all. Speed will be practically the same.
Just a very large libharbour.dll could slow down just a little bit because it is copied on each request. But for a few libs it is not noticeable :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42084
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain


Return to mod_harbour

Who is online

Users browsing this forum: No registered users and 4 guests