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
// rapids.prg
#include "hbclass.ch"
#include "rapids.ch"
#include "DBEmphasis.ch"
#define wa_KEY_ALLOCATOR 201 // work area for primary key allocation functionality
PROCEDURE 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()
RETURN
FUNCTION CheckParameter( str_Parameter )
LOCAL str_UParameter
LOCAL str_TimeOut
str_UParameter := Left( Upper( str_Parameter ), 2 )
// check for -D<data-directory> option
IF 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 nil
ENDIF
// check for -Q (quiet) option
IF str_UParameter = "-Q"
log_Verbose := .F.
AAdd( arr_Info, "-Q: set to Quiet mode" )
// ? "quiet"
RETURN nil
ENDIF
// check for -P<port-number> option
IF 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 nil
ENDIF
// check for -T<time-out> option
IF 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 nil
ENDIF
RETURN nil
FUNCTION 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