A while ago, in response to a post about data bases, I mentioned my Harbour based client-server architecture data base. I promised to post in response to a request and this thread will fulfill that promise, albeit a bit later than I originally promised.
Herewith is the main .prg file. It really only implements two things:
command line processing
the main server loop
Code: Select all | Expand
// rapids.prg#include "hbclass.ch"#include "rapids.ch"#include "DBEmphasis.ch"#define wa_KEY_ALLOCATOR 201 // work area for primary key allocation functionalityPROCEDURE Main( ... ) LOCAL ptr_Server // pointer returned by INetServer() LOCAL ptr_Client // pointer returned by INetAccept() LOCAL arr_Parameters // array holding command line parameters LOCAL int_ParamCount // command line parameter count LOCAL log_Continue // controls main server loop LOCAL int_LoopCounter PUBLIC log_Verbose // If .T. then "diagnostic" information is sent to the terminal [defaults to .T.] PUBLIC str_Port // Port number to use (as a string) [defaults to "1800"] PUBLIC int_Port // Port number to use as an integer PUBLIC int_TimeOut // Timeout to use (in thousandths of a second) PUBLIC arr_Info // array to hold information about command line processing (so its output can be supressed via the command line) PUBLIC str_DataDir // Path to data files PUBLIC arr_DBQueries := Array( query_LAST ) // array holding the "compiled" query objects PUBLIC int_MaxDBQuery := query_LAST // length of above array PUBLIC arr_Select := Array( select_LAST ) // array holding field selection objects PUBLIC str_User // ID of user (this functionality not yet fully implemented) PUBLIC obj_DateTime // Date-Time object PUBLIC arr_Xfer // array used for transfer of sub-query data arr_Parameters := HB_AParams() int_ParamCount := LEN( arr_Parameters ) ? ? "RAPIDS - xBase Client Server Data Base Server - Version 1.00.03" ? "---------------------------------------------------------------" ? ? "(c) Finalysis Pty. Ltd. 2008 - 2011" ? ? "Max Query ID is:", int_MaxDBQuery // set default values for items that can also be set via the command line log_Verbose := .T. int_Port := 1800 int_TimeOut := 100 str_DataDir := "/" + CurDir() + "/" // process any command line options arr_Info := { "Checking command line" } AAdd( arr_Info, ALLTRIM( STR( int_ParamCount ) ) + " command line parameter(s) found" ) IF int_ParamCount > 0 FOR int_LoopCounter = 1 TO int_ParamCount CheckParameter( arr_Parameters[int_LoopCounter] ) NEXT ENDIF OpenDataFiles() OpenKeyAllocation() SetUpQueryFormats() SetUpQueries() IF log_Verbose ? ? "Setting Up Server Query Object" ENDIF obj_Query := TServerQuery():New() obj_DateTime := TDateTime():New() IF log_Verbose ? ? "Setting up sockets" ENDIF HB_INetInit() ptr_Server := HB_INetServer( Val( str_Port ) ) HB_INetTimeout( ptr_Server, 100 ) ? "Server listening on port", str_Port, "for requests Press [Esc] to quit" log_Continue := .T. DO WHILE InKey( 0.1 ) != 27 // wait for incoming connection requests ptr_Client := HB_INetAccept( ptr_Server ) IF HB_INetErrorCode( ptr_Server ) == 0 // process client request // possibly in a future version in a separate thread // ServeClient( pClient ) obj_Query:Request( ptr_Client ) ENDIF ENDDO // WaitForThreads() would go here in a threaded version // close socket and cleanup memory HB_INetClose( ptr_Server ) HB_INetCleanup()RETURNFUNCTION CheckParameter( str_Parameter )LOCAL str_UParameterLOCAL str_TimeOutstr_UParameter := Left( Upper( str_Parameter ), 2 )// check for -D<data-directory> optionIF str_UParameter = "-D" str_DataDir := SUBSTR( str_Parameter, 3 ) IF EMPTY( str_DataDir ) ? "ERROR: -D option specified but no data directory given" QUIT ENDIF AAdd( arr_Info, "-D: data directory set to " + str_DataDir ) RETURN nilENDIF// check for -Q (quiet) optionIF str_UParameter = "-Q" log_Verbose := .F. AAdd( arr_Info, "-Q: set to Quiet mode" ) // ? "quiet" RETURN nilENDIF// check for -P<port-number> optionIF str_UParameter = "-P" ? "Port option specified" str_Port := SUBSTR( str_Parameter, 3 ) ? "str_Port is:", str_Port IF EMPTY( str_Port ) ? "ERROR: -P option specified but no port number given" QUIT ENDIF int_Port := VAL( str_Port ) AAdd( arr_Info, "-P: port set to " + str_Port ) RETURN nilENDIF// check for -T<time-out> optionIF str_UParameter = "-T" str_TimeOut := SUBSTR( str_Parameter, 3 ) IF EMPTY( str_TimeOut ) ? "ERROR: -T option specified but no port timeout value given" QUIT ENDIF int_Port := VAL( str_TimeOut ) AAdd( arr_Info, "-T: timeout set to " + str_TimeOut ) RETURN nilENDIF RETURN nilFUNCTION OpenKeyAllocation() LOCAL int_Info LOCAL int_LoopCounter // first display information about command line processing if in "verbose" mode IF log_Verbose ? int_Info := Len( arr_Info ) FOR int_LoopCounter = 1 TO int_Info ? arr_Info[int_LoopCounter] NEXT ? ? "Opening Data Files" ENDIF SELECT wa_KEY_ALLOCATOR USE ( str_DataDir + "KY_KEY" ) SHARED RETURN nil