XMLRPC clients and servers can be easily written in purebasic without the use of components. The advantage is that only 1 executable has to be installed and no dll's or com's. I wrote a small OOish includefile that can be used to program XMLTPC clients or servers. The design is not fully OO and therefor the programmer should be aware of what he is doing (no errors are returned if methods are nit used in the intended order). The following files are in this message :
OO_XMLRPC.pb ---- The XIncludeFile
TimeServer.pb ---- a server that returns the current time
usage : TimeServer <portnr>
example : TimeServer 8000
TimeClient.pb ---- a client that retrieves the current time
usage : TimeClient <URL> <portnr>
example : TimeClient
www.xmlrpc.com 80
example : TimeClient localhost 8000
TotalServer.pb ---- a server that totalises an array of floating point numbers
usage : TotalServer <portnr>
example : TotalServer 8000
TotalClient.pb ---- a client that receives the total
usage : TotalClient <URL> <portnr>
example : TotalClient localhost 8000
The software is not extensively tested against XMLRPC servers on the Web so that there still some shortcomings but the idea works.
The XIncludeFile
Code: Select all
;****************************************
;
; XML-RPC inclidefile OO_XMLRPC
; Author : Leo Mijnders
; Date : Nov 2004
;
;****************************************
; TAG Definitions
;****************************************
#CRF = Chr(13)
#HTF = Chr(9)
#LFF = Chr(10)
#CRLF = Chr(13)+Chr(10)
#MAXDEPTH = 20
#POST = "POST "
#HTTP = "HTTP 1.0"
#USERAGENT = "User-Agent: "
#HOST = "Host: "
#CONTENTTYPE = "Content-Type: text/html"
#CONTENTLENGTH = "Content-length: "
#PARAM_TAG = "<param>"
#PARAM_ETAG = "</param>"
#VALUE_TAG = "<value>"
#VALUE_ETAG = "</value>"
#BOOLEAN_TAG = "<boolean>"
#BOOLEAN_ETAG = "</boolean>"
#DOUBLE_TAG = "<double>"
#DOUBLE_ETAG = "</double>"
#INT_TAG = "<int>"
#INT_ETAG = "</int>"
#I4_TAG = "<i4>"
#I4_ETAG = "</i4>"
#STRING_TAG = "<string>"
#STRING_ETAG = "</string>"
#DATETIME_TAG = "<dateTime.iso8601>"
#DATETIME_ETAG = "</dateTime.iso8601>"
#BASE64_TAG = "<base64>"
#BASE64_ETAG = "</base64>"
#NIL_TAG = "<nil/>"
#ARRAY_TAG = "<array>"
#DATA_TAG = "<data>"
#DATA_ETAG = "</data>"
#ARRAY_ETAG = "</array>"
#STRUCT_TAG = "<struct>"
#MEMBER_TAG = "<member>"
#NAME_TAG = "<name>"
#NAME_ETAG = "</name>"
#MEMBER_ETAG = "</member>"
#STRUCT_ETAG = "</struct>"
;****************************************
; XMLRPCSend
;****************************************
Interface XMLRPCSend
AddBase64(Addr.l, Long.l)
AddBoolean(Boolean.b)
AddDateTime(Seconds.l)
AddDouble(Float.f, Decimals.l)
AddInteger(Integer.l)
AddString(String.s)
AddNil()
OpenArray()
CloseArray()
OpenStruct()
CloseStruct()
OpenMember(Name.s)
CloseMember()
Submit.s(Caddr.l)
EndInterface
Structure XMLRPCSendInstance
vTable.l
Functions.l[SizeOf(XMLRPCSend)/4]
HostName.s
HostPort.l
HostUri.s
MethodName.s
Server.s
UserAgent.s
XMLBody.s
Nested.b
Fault.b
EndStructure
Procedure AddBase64(*self.XMLRPCSendInstance, Addr.l, Long.l)
*self\XMLBody+Space(2 * *self\Nested)
*OutputBuffer=AllocateMemory(2*Long+64)
Base64Encoder(Addr, Long, *OutputBuffer, 2*Long+64)
If *self\Nested | *self\Fault = 0
*self\XMLBody+#PARAM_TAG
EndIf
*self\XMLBody+#VALUE_TAG+#BASE64_TAG
*self\XMLBody+PeekS(*OutputBuffer)
*self\XMLBody+#BASE64_ETAG+#VALUE_ETAG
FreeMemory(*OutputBuffer)
If *self\Nested | *self\Fault = 0
*self\XMLBody+#PARAM_ETAG
EndIf
*self\XMLBody+#CRLF
EndProcedure
Procedure AddBoolean(*self.XMLRPCSendInstance, Boolean.b)
*self\XMLBody+Space(2 * *self\Nested)
If *self\Nested | *self\Fault = 0
*self\XMLBody+#PARAM_TAG
EndIf
*self\XMLBody+#VALUE_TAG+#BOOLEAN_TAG
*self\XMLBody+Str(Boolean)
*self\XMLBody+#BOOLEAN_ETAG+#VALUE_ETAG
If *self\Nested | *self\Fault = 0
*self\XMLBody+#PARAM_ETAG
EndIf
*self\XMLBody+#CRLF
EndProcedure
Procedure AddDateTime(*self.XMLRPCSendInstance, Seconds.l)
*self\XMLBody+Space(2 * *self\Nested)
If *self\Nested | *self\Fault = 0
*self\XMLBody+#PARAM_TAG
EndIf
*self\XMLBody+#VALUE_TAG+#DATETIME_TAG
*self\XMLBody+FormatDate("%yyyy%mm%ddT%hh:%ii:%ss",Seconds)
*self\XMLBody+#DATETIME_ETAG+#VALUE_ETAG
If *self\Nested | *self\Fault = 0
*self\XMLBody+#PARAM_ETAG
EndIf
*self\XMLBody+#CRLF
EndProcedure
Procedure AddDouble(*self.XMLRPCSendInstance, Float.f, Decimals.l)
*self\XMLBody+Space(2 * *self\Nested)
If *self\Nested | *self\Fault = 0
*self\XMLBody+#PARAM_TAG
EndIf
*self\XMLBody+#VALUE_TAG+#DOUBLE_TAG
*self\XMLBody+StrF(Float, Decimals)
*self\XMLBody+#DOUBLE_ETAG+#VALUE_ETAG
If *self\Nested | *self\Fault = 0
*self\XMLBody+#PARAM_ETAG
EndIf
*self\XMLBody+#CRLF
EndProcedure
Procedure AddInteger(*self.XMLRPCSendInstance, Long.l)
*self\XMLBody+Space(2 * *self\Nested)
If *self\Nested | *self\Fault = 0
*self\XMLBody+#PARAM_TAG
EndIf
*self\XMLBody+#VALUE_TAG+#I4_TAG
*self\XMLBody+Str(Long)
*self\XMLBody+#I4_ETAG+#VALUE_ETAG
If *self\Nested | *self\Fault = 0
*self\XMLBody+#PARAM_ETAG
EndIf
*self\XMLBody+#CRLF
EndProcedure
Procedure AddString(*self.XMLRPCSendInstance, String.s)
*self\XMLBody+Space(2 * *self\Nested)
If *self\Nested | *self\Fault = 0
*self\XMLBody+#PARAM_TAG
EndIf
*self\XMLBody+#VALUE_TAG+#STRING_TAG
*self\XMLBody+String
*self\XMLBody+#STRING_ETAG+#VALUE_ETAG
If *self\Nested | *self\Fault = 0
*self\XMLBody+#PARAM_ETAG
EndIf
*self\XMLBody+#CRLF
EndProcedure
Procedure AddNil(*self.XMLRPCSendInstance)
*self\XMLBody+Space(2 * *self\Nested)
If *self\Nested | *self\Fault = 0
*self\XMLBody+#PARAM_TAG
EndIf
*self\XMLBody+#VALUE_TAG+#NIL_TAG+#VALUE_ETAG
If *self\Nested | *self\Fault = 0
*self\XMLBody+#PARAM_ETAG
EndIf
*self\XMLBody+#CRLF
EndProcedure
Procedure OpenArray(*self.XMLRPCSendInstance)
*self\XMLBody+Space(2 * *self\Nested)
If *self\Nested | *self\Fault = 0
*self\XMLBody+#PARAM_TAG
EndIf
*self\XMLBody+#VALUE_TAG+#ARRAY_TAG+#DATA_TAG
*self\XMLBody+#CRLF
*self\Nested+1
EndProcedure
Procedure CloseArray(*self.XMLRPCSendInstance)
*self\XMLBody+Space(2 * *self\Nested)
*self\XMLBody+#DATA_ETAG+#ARRAY_ETAG+#VALUE_ETAG
If *self\Nested = 1 And *self\Fault=0
*self\XMLBody+#PARAM_ETAG
EndIf
*self\XMLBody+#CRLF
*self\Nested-1
EndProcedure
Procedure OpenStruct(*self.XMLRPCSendInstance)
*self\XMLBody+Space(2 * *self\Nested)
If *self\Nested | *self\Fault = 0
*self\XMLBody+#PARAM_TAG
EndIf
*self\XMLBody+#VALUE_TAG+#STRUCT_TAG
*self\XMLBody+#CRLF
*self\Nested+1
EndProcedure
Procedure CloseStruct(*self.XMLRPCSendInstance)
*self\XMLBody+Space(2 * *self\Nested)
*self\XMLBody+#STRUCT_ETAG+#VALUE_ETAG
If *self\Nested = 1 And *self\Fault = 0
*self\XMLBody+#PARAM_ETAG
EndIf
*self\XMLBody+#CRLF
*self\Nested-1
EndProcedure
Procedure OpenMember(*self.XMLRPCSendInstance, Name.s)
*self\XMLBody+Space(2 * *self\Nested)
*self\XMLBody+#MEMBER_TAG+#CRLF+Space(2* *self\Nested)+#NAME_TAG+Name+#NAME_ETAG
*self\XMLBody+#CRLF
EndProcedure
Procedure CloseMember(*self.XMLRPCSendInstance)
*self\XMLBody+Space(2 * *self\Nested)
*self\XMLBody+#MEMBER_ETAG
*self\XMLBody+#CRLF
EndProcedure
Procedure.s Submit(*self.XMLRPCSendInstance, caddr.l)
If *self\Fault
*self\Nested=1
EndIf
ReturnString.s=""
If *self\Server=""
naddr.l=OpenNetworkConnection(*self\HostName,*self\HostPort)
Else
naddr.l=caddr
EndIf
If naddr
xml.s="<?xml version="+Chr(34)+"1.0"+Chr(34)+"?>"+#CRLF
If *self\Server=""
xml+"<methodCall>"
Else
xml+"<methodResponse>"
EndIf
xml+#CRLF
If *self\Server=""
xml+"<methodName>"+*self\MethodName+"</methodName>"+#CRLF
EndIf
If *self\Fault
xml+"<fault>"+#CRLF
Else
xml+"<params>"+#CRLF
EndIf
xml+*self\XMLBody
If *self\Fault
xml+"</fault>"+#CRLF
Else
xml+"</params>"+#CRLF
EndIf
If *self\Server=""
xml+"</methodCall>"
Else
xml+"</methodResponse>"
EndIf
xml+#CRLF
If *self\Server=""
com$="POST /RPC2 HTTP/1.0"+#CRLF
com$=com$+"User-Agent: HTTP-For-PureBasic"+#CRLF
com$=com$+"Host: "+*self\HostName+#CRLF
com$=com$+"Content-Type: text/html"+#CRLF
com$=com$+"Content-Length: "+Str(Len(xml))+#CRLF
com$=com$+ #CRLF
com$+xml
Else
com$="HTTP/1.1 200 OK"+#CRLF
com$+"Connection: close"+#CRLF
com$+"Content-Length: "+Str(Len(xml))+#CRLF
com$+"Content-Type: text/html"+#CRLF
com$+"Date: "+"To do"+#CRLF
com$+"Server: "+*self\Server+#CRLF
com$+ #CRLF
com$+xml
EndIf
SendNetworkString(naddr,com$)
If *self\Server=""
Buffer.s=Space(4999)
Repeat
result=ReceiveNetworkData(naddr,@Buffer,Len(Buffer))
ReturnString+Left(PeekS(@Buffer),result)
Until result=0
CloseNetworkConnection(naddr)
EndIf
EndIf
ProcedureReturn ReturnString
EndProcedure
Procedure.l CreateInstance_XMLRPCSend()
*Instance.XMLRPCSendInstance = AllocateMemory(SizeOf(XMLRPCSendInstance))
*Instance\vTable = *Instance + OffsetOf(XMLRPCSendInstance, Functions)
*Instance\Functions[0] = @AddBase64()
*Instance\Functions[1] = @AddBoolean()
*Instance\Functions[2] = @AddDateTime()
*Instance\Functions[3] = @AddDouble()
*Instance\Functions[4] = @AddInteger()
*Instance\Functions[5] = @AddString()
*Instance\Functions[6] = @AddNil()
*Instance\Functions[7] = @OpenArray()
*Instance\Functions[8] = @CloseArray()
*Instance\Functions[9] = @OpenStruct()
*Instance\Functions[10] = @CloseStruct()
*Instance\Functions[11] = @OpenMember()
*Instance\Functions[12] = @CloseMember()
*Instance\Functions[13] = @Submit()
*Instance\HostName = ""
*Instance\HostPort = 0
*Instance\HostUri = ""
*Instance\MethodName = ""
*Instance\XMLBody = ""
*Instance\Server = ""
*Instance\Nested = 0
*Instance\Fault = 0
ProcedureReturn *Instance
EndProcedure
;****************************************
; XMLRPCRecieve
;****************************************
Interface XMLRPCRecieve
FirstContent()
NextContent()
CheckWellFormed()
GetCurrentPos.l()
EndInterface
Structure ParseStructure
Tag.s
Nr.l
EndStructure
Structure XMLRPCRecieveInstance
vTable.l
Functions.l[SizeOf(XMLRPCRecieve)/4]
Response.s
Header.s
XMLBody.s
Content.s
ContentPresent.b
ContentLevel.l
StringFieldNr.l
Parse.ParseStructure[#MaxDepth]
XMLVersion.s
XMLWellFormed.b
EndStructure
Procedure Content(*self.XMLRPCRecieveInstance, StringFieldNr.l)
i=StringFieldNr
Repeat
Tag.s=StringField(*self\XMLBody,i,#CRF)
*self\ContentPresent=0
*self\XMLWellFormed=1
If Tag="" ; end of XML
*self\StringFieldNr=i+1
ProcedureReturn
ElseIf Trim(Tag)="" ; space
*self\StringFieldNr=i+1
ElseIf Left(Tag,1)="<" And Right(Tag,1)<>">"
*self\XMLWellFormed=0
*self\StringFieldNr=i
ProcedureReturn
ElseIf Left(Tag,1)<>"<" And Right(Tag,1)=">"
*self\XMLWellFormed=0
*self\StringFieldNr=i
ProcedureReturn
ElseIf Left(Tag,13)="<?xml version" ; set XML version
*self\XMLVersion=Tag
ElseIf Left(Tag,2)="<?" ; ignore comment tags
ElseIf Left(Tag,3)="</>" ; handle the NIL Tag
*self\ContentLevel-1
*self\Content=""
*self\ContentPresent=1
ElseIf Left(Tag,2)="</" ; handle end tag
*self\ContentLevel-1
If *self\Parse[*self\ContentLevel]\Tag <> ReplaceString(Tag,"</","<")
*self\XMLWellFormed=0
*self\StringFieldNr=i
ProcedureReturn
EndIf
ElseIf Left(Tag,1)="<" ; handle tag
*self\Parse[*self\ContentLevel]\Tag=Tag
*self\Parse[*self\ContentLevel]\Nr+1
*self\ContentLevel+1
*self\Parse[*self\ContentLevel]\Nr=0
Else ; handle content
*self\Content=Tag
*self\ContentPresent=1
EndIf
i+1
Until *self\ContentPresent=1
*self\StringFieldNr=i
EndProcedure
Procedure FirstContent(*self.XMLRPCRecieveInstance)
Content(*self,1)
EndProcedure
Procedure NextContent(*self.XMLRPCRecieveInstance)
Content(*self,*self\StringFieldNr)
EndProcedure
Procedure CheckWellFormed(*self.XMLRPCRecieveInstance)
*self\StringFieldNr=1
Repeat
Content(*self,*self\StringFieldNr)
Until *self\ContentPresent=0 Or *self\XMLWellFormed=0
EndProcedure
Procedure.l GetCurrentPos(*self.XMLRPCRecieveInstance)
For i=1 To *self\StringFieldNr
Tag.s =StringField(*self\XMLBody, i, #CRF)
StartPos.l=1
If Tag="</>"
ElseIf Left(Tag,1)="<"
StartPos=FindString(*self\Response, Tag, StartPos)
EndIf
Next
ProcedureReturn StartPos
EndProcedure
Procedure.l CreateInstance_XMLRPCRecieve(Response.s)
*Instance.XMLRPCRecieveInstance = AllocateMemory(SizeOf(XMLRPCRecieveInstance))
*Instance\vTable = *Instance + OffsetOf(XMLRPCRecieveInstance, Functions)
*Instance\Functions[0] = @FirstContent()
*Instance\Functions[1] = @NextContent()
*Instance\Functions[2] = @CheckWellFormed()
*Instance\Functions[3] = @GetCurrentPos()
*Instance\Response = Response
ContentLength=Val(Mid(Response,FindString(Response,"Content-Length:",1)+15,10))
*Instance\Header = Left(Response,Len(Response)-ContentLength)
Temp.s=Right(Response, ContentLength)
Temp=ReplaceString(Temp,"/>","></>")
Temp=ReplaceString(Temp,#CRF,"")
Temp=ReplaceString(Temp,#LFF,"")
Temp=ReplaceString(Temp,#HTF,"")
Temp=ReplaceString(Temp,"<",#CRF+"<")
Temp=ReplaceString(Temp,">",">"+#CRF)
Temp=ReplaceString(Temp,#CRF+#CRF,#CRF)
*Instance\XMLBody=Right(Temp,Len(Temp)-FindString(Temp,"<",1)+1)
*Instance\Content=""
*Instance\ContentPresent=0
*Instance\ContentLevel=0
*Instance\StringFieldNr=0
*Instance\XMLVersion=""
*Instance\XMLWellFormed=0
ProcedureReturn *Instance
EndProcedure
The Examples
Code: Select all
;****************************************
;
; XML-RPC example TimeServer
; Author : Leo Mijnders
; Date : Nov 2004
;
;****************************************
XIncludeFile "OO_XMLRPC.pb"
Enumeration
#NOTWELLFORMED
#UNKNOWNMETHOD
#NOMETHODNAMETAG
#NOCONTENT
#TOMUCHPARAMETERS
#LASTENUM
EndEnumeration
; Global Errors.s
Dim Errors.s(#LASTENUM)
Errors(#NOTWELLFORMED)="XML not well formed"
Errors(#UNKNOWNMETHOD)="The methodName is unknown"
Errors(#NOMETHODNAMETAG)="There is no methodName tag"
Errors(#NOCONTENT)="There is no content"
Errors(#TOMUCHPARAMETERS)="This method has to much parameters"
Procedure FaultHandling(Error.l,ClientNaddr.l)
Response.XMLRPCSend=CreateInstance_XMLRPCSend()
*Response.XMLRPCSendInstance=Response
*Response\Server="Leo's TimeServer"
*Response\Fault=1
Response\OpenStruct()
Response\OpenMember("faultCode")
Response\AddInteger(Error)
Response\CloseMember()
Response\OpenMember("faultString")
Response\AddString(Errors(Error))
Response\CloseMember()
Response\CloseStruct()
Response\Submit(ClientNaddr)
FreeMemory(*Response)
CloseNetworkConnection(ClientNaddr)
EndProcedure
Procedure ProcessRequest(Buffer.l, Length.l, ClientNaddr.l)
Request.XMLRPCRecieve=CreateInstance_XMLRPCRecieve(Left(PeekS(Buffer),Length))
*Request.XMLRPCRecieveInstance=Request
Request\CheckWellFormed()
If *Request\XMLWellFormed
; MessageRequester("","Well Formed",0)
Request\FirstContent()
If *Request\ContentPresent
If *Request\Parse[1]\Tag="<methodName>"
If *Request\Content="currentTime.getCurrentTime"
Else
FaultHandling(#UNKNOWNMETHOD, ClientNaddr)
FreeMemory(*Request)
ProcedureReturn
EndIf
Else
FaultHandling(#NOMETHODNAMETAG, ClientNaddr)
FreeMemory(*Request)
ProcedureReturn
EndIf
Else
FaultHandling(#NOCONTENT, ClientNaddr)
FreeMemory(*Request)
ProcedureReturn
EndIf
Request\NextContent()
If *Request\ContentPresent
FaultHandling(#TOMUCHPARAMETERS, ClientNaddr)
FreeMemory(*Request)
ProcedureReturn
Else
FreeMemory(*Request)
Response.XMLRPCSend=CreateInstance_XMLRPCSend()
*Response.XMLRPCSendInstance=Response
*Response\Server="Leo's TimeServer"
Response\AddString(FormatDate("%yyyy%mm%ddT%hh:%ii:%ss",Date()))
Response\Submit(ClientNaddr)
FreeMemory(*Response)
CloseNetworkConnection(ClientNaddr)
EndIf
Else
FaultHandling(#NOTWELLFORMED, ClientNaddr)
FreeMemory(*Request)
ProcedureReturn
EndIf
EndProcedure
If InitNetwork() = 0
MessageRequester("Error", "Can't initialize the network !", 0)
End
EndIf
Port = Val(ProgramParameter())
Buffer = AllocateMemory(5000)
OpenConsole() ; First we must open a console
ConsoleTitle ("PureBasic - XML-RPC Server at port "+Str(Port)) ; Now we can give the opened console a Titlename ;)
Print("Press Esc to shut down the server !")
If CreateNetworkServer(Port)
Repeat
SEvent.l = NetworkServerEvent()
If SEvent
ClientID = NetworkClientID()
Select SEvent
Case 1
; MessageRequester("PureBasic - Server", "A new client has connected !", 0)
Case 2
; MessageRequester("PureBasic - Server", "Client "+Str(ClientID)+" has send a packet !", 0)
Length.l=ReceiveNetworkData(ClientID, Buffer, 5000)
; MessageRequester("Info", "String: "+PeekS(Buffer), 0)
ProcessRequest(Buffer, Length, ClientID)
Case 3
; MessageRequester("PureBasic - Server", "Client "+Str(ClientID)+" has send a file via the network !", 0)
; ReceiveNetworkFile(ClientID, "C:\TEST_Network.ftp3")
Case 4
; MessageRequester("PureBasic - Server", "Client "+Str(ClientID)+" has closed the connexion...", 0)
; Quit = 1
EndSelect
EndIf
EscPressed.s=Inkey()
If Asc(EscPressed)=27
Quit=1
EndIf
Until Quit = 1
; MessageRequester("PureBasic - Server", "Click to quit the server.", 0)
CloseNetworkServer()
Else
MessageRequester("Error", "Can't create the server (port in use ?).", 0)
EndIf
CloseConsole()
End
Code: Select all
;****************************************
;
; XML-RPC example TimeClient
; Author : Leo Mijnders
; Date : Nov 2004
;
;****************************************
XIncludeFile "OO_XMLRPC.pb"
InitNetwork()
Request.XMLRPCSend=CreateInstance_XMLRPCSend()
*Request.XMLRPCSendInstance=Request
;*Request\HostName="time.xmlrpc.com"
;*Request\HostPort=80
;*Request\HostName="localhost"
;*Request\HostPort=8000
*Request\HostName=ProgramParameter()
*Request\HostPort=Val(ProgramParameter())
*Request\HostUri="/RPC2"
*Request\MethodName="currentTime.getCurrentTime"
*Request\UserAgent="XML-RPC-For-PureBasic"
Result.s=Request\Submit(0)
If Result=""
MessageRequester("","No Response, possibly network error",0)
End
EndIf
Response.XMLRPCRecieve=CreateInstance_XMLRPCRecieve(Result)
*Response.XMLRPCRecieveInstance=Response
;MessageRequester("Response",*Response\Header,0)
;MessageRequester("Response",*Response\XMLBody,0)
Response\CheckWellFormed()
;MessageRequester("", Str(*Response\XMLWellFormed),0)
Response\FirstContent()
MessageRequester("Response",*Response\Content,0)
;MessageRequester("Response",Str(*Response\ContentLevel),0)
;MessageRequester("Response",*Response\Parse[*Response\ContentLevel-1]\Tag,0)
Repeat
Response\NextContent()
If *Response\ContentPresent=0
Break
EndIf
MessageRequester("Response", "Content : "+*Response\Content,0)
; MessageRequester("Response","ContentLevel : "+Str(*Response\ContentLevel),0)
; MessageRequester("Response","Content Tag : "+*Response\Parse[*Response\ContentLevel-1]\Tag,0)
Until #FALSE
MessageRequester("Response","No more Contents",0)
FreeMemory(*Request)
FreeMemory(*Response)
Code: Select all
;****************************************
;
; XML-RPC example TotalServer
; Author : Leo Mijnders
; Date : Nov 2004
;
;****************************************
XIncludeFile "OO_XMLRPC.pb"
Enumeration
#NOTWELLFORMED
#UNKNOWNMETHOD
#NOMETHODNAMETAG
#NOCONTENT
#NONAMEPARAMETER
#WRONGPARAMETER
#NOTHINGTOTOTALIZE
#LASTENUM
EndEnumeration
; Global Errors.s
Dim Errors.s(#LASTENUM)
Errors(#NOTWELLFORMED)="XML not well formed"
Errors(#UNKNOWNMETHOD)="The methodName is unknown"
Errors(#NOMETHODNAMETAG)="There is no methodName tag"
Errors(#NOCONTENT)="There is no content"
Errors(#NONAMEPARAMETER)="The name parameter is missing"
Errors(#WRONGPARAMETER)="The parameter is not allowed "
Errors(#NOTHINGTOTOTALIZE)="There is nothing to totalize"
Procedure FaultHandling(Error.l,ClientNaddr.l)
Response.XMLRPCSend=CreateInstance_XMLRPCSend()
*Response.XMLRPCSendInstance=Response
*Response\Server="Leo's TimeServer"
*Response\Fault=1
Response\OpenStruct()
Response\OpenMember("faultCode")
Response\AddInteger(Error)
Response\CloseMember()
Response\OpenMember("faultString")
Response\AddString(Errors(Error))
Response\CloseMember()
Response\CloseStruct()
Response\Submit(ClientNaddr)
FreeMemory(*Response)
CloseNetworkConnection(ClientNaddr)
EndProcedure
Procedure ProcessRequest(Buffer.l, Length.l, ClientNaddr.l)
Request.XMLRPCRecieve=CreateInstance_XMLRPCRecieve(Left(PeekS(Buffer),Length))
*Request.XMLRPCRecieveInstance=Request
Request\CheckWellFormed()
If *Request\XMLWellFormed
Request\FirstContent()
If *Request\ContentPresent
If *Request\Parse[1]\Tag="<methodName>"
If *Request\Content="CalculateTotal"
Else
FaultHandling(#UNKNOWNMETHOD, ClientNaddr)
FreeMemory(*Request)
ProcedureReturn
EndIf
Else
FaultHandling(#NOMETHODNAMETAG, ClientNaddr)
FreeMemory(*Request)
ProcedureReturn
EndIf
Else
FaultHandling(#NOCONTENT, ClientNaddr)
FreeMemory(*Request)
ProcedureReturn
EndIf
Name.s=""
Total.f=0.0
Nr.l=0
Repeat
Request\NextContent()
If *Request\ContentPresent=0
Break
ElseIf *Request\Parse[*Request\ContentLevel-1]\Tag="<name>"
Name=*Request\Content
ElseIf *Request\Parse[*Request\ContentLevel-1]\Tag="<double>"
Total+ValF(*Request\Content)
Nr+1
Else
FaultHandling(#WRONGPARAMETER, ClientNaddr)
FreeMemory(*Request)
ProcedureReturn
EndIf
Until #FALSE
If Name=""
FaultHandling(#NONAMEPARAMETER, ClientNaddr)
FreeMemory(*Request)
ProcedureReturn
EndIf
If Nr=0
FaultHandling(#NOTHINGTOTOTALIZE, ClientNaddr)
FreeMemory(*Request)
ProcedureReturn
EndIf
FreeMemory(*Request)
Response.XMLRPCSend=CreateInstance_XMLRPCSend()
*Response.XMLRPCSendInstance=Response
*Response\Server="Leo's TimeServer"
Response\OpenStruct()
Response\OpenMember("Total "+Name)
Response\AddDouble(Total,2)
Response\CloseMember()
Response\CloseStruct()
Response\Submit(ClientNaddr)
FreeMemory(*Response)
CloseNetworkConnection(ClientNaddr)
Else
FaultHandling(#NOTWELLFORMED, ClientNaddr)
FreeMemory(*Request)
ProcedureReturn
EndIf
EndProcedure
If InitNetwork() = 0
MessageRequester("Error", "Can't initialize the network !", 0)
End
EndIf
Port = Val(ProgramParameter())
Buffer = AllocateMemory(5000)
OpenConsole() ; First we must open a console
ConsoleTitle ("PureBasic - XML-RPC Server at port "+Str(Port)) ; Now we can give the opened console a Titlename ;)
Print("Press Esc to shut down the server !")
If CreateNetworkServer(Port)
Repeat
SEvent.l = NetworkServerEvent()
If SEvent
ClientID = NetworkClientID()
Select SEvent
Case 1
; MessageRequester("PureBasic - Server", "A new client has connected !", 0)
Case 2
; MessageRequester("PureBasic - Server", "Client "+Str(ClientID)+" has send a packet !", 0)
Length.l=ReceiveNetworkData(ClientID, Buffer, 5000)
; MessageRequester("Info", "String: "+PeekS(Buffer), 0)
ProcessRequest(Buffer, Length, ClientID)
Case 3
; MessageRequester("PureBasic - Server", "Client "+Str(ClientID)+" has send a file via the network !", 0)
; ReceiveNetworkFile(ClientID, "C:\TEST_Network.ftp3")
Case 4
; MessageRequester("PureBasic - Server", "Client "+Str(ClientID)+" has closed the connexion...", 0)
; Quit = 1
EndSelect
EndIf
EscPressed.s=Inkey()
If Asc(EscPressed)=27
Quit=1
EndIf
Until Quit = 1
; MessageRequester("PureBasic - Server", "Click to quit the server.", 0)
CloseNetworkServer()
Else
MessageRequester("Error", "Can't create the server (port in use ?).", 0)
EndIf
CloseConsole()
End
Code: Select all
;****************************************
;
; XML-RPC example TotalClient
; Author : Leo Mijnders
; Date : Nov 2004
;
;****************************************
XIncludeFile "OO_XMLRPC.pb"
InitNetwork()
Request.XMLRPCSend=CreateInstance_XMLRPCSend()
*Request.XMLRPCSendInstance=Request
Request\OpenStruct()
Request\OpenMember("Prices")
Request\OpenArray()
Request\AddDouble(14.2,2)
Request\AddDouble(16.7,2)
Request\AddDouble(13.8,2)
Request\AddDouble(17.1,2)
Request\CloseArray()
Request\CloseMember()
Request\CloseStruct()
*Request\HostName=ProgramParameter()
*Request\HostPort=Val(ProgramParameter())
*Request\HostUri="/RPC2"
*Request\MethodName="CalculateTotal"
*Request\UserAgent="XML-RPC-For-PureBasic"
Result.s=Request\Submit(0)
If Result=""
MessageRequester("","No Response, possibly network error",0)
End
EndIf
Response.XMLRPCRecieve=CreateInstance_XMLRPCRecieve(Result)
*Response.XMLRPCRecieveInstance=Response
;MessageRequester("Response",*Response\Header,0)
;MessageRequester("Response",*Response\XMLBody,0)
Response\CheckWellFormed()
;MessageRequester("", Str(*Response\XMLWellFormed),0)
Response\FirstContent()
MessageRequester("Response",*Response\Content,0)
;MessageRequester("Response",Str(*Response\ContentLevel),0)
;MessageRequester("Response",*Response\Parse[*Response\ContentLevel-1]\Tag,0)
Repeat
Response\NextContent()
If *Response\ContentPresent=0
Break
EndIf
MessageRequester("Response", "Content : "+*Response\Content,0)
; MessageRequester("Response","ContentLevel : "+Str(*Response\ContentLevel),0)
; MessageRequester("Response","Content Tag : "+*Response\Parse[*Response\ContentLevel-1]\Tag,0)
Until #FALSE
MessageRequester("Response","No more Contents",0)
FreeMemory(*Request)
FreeMemory(*Response)