[quote=306618:@Michel Bujardet]I use Instant Payment Notification with a Xojo Web app as listener, which receives notifications from Paypal and deliver instructions for download.
The trick is to have Paypal hit HandleURL or HandleSpecialURL, and to post back using Xojo.Core.HTTPSocket in secure mode, because it supports http 1.1.
Another option would be to use CURL (most samples they show use it), but I don’t know if MBS CURL is able to do http 1.1 required by Paypal.[/quote]
Paypal summary of Steps 1-3:
Your listener listens for the HTTP POST IPN messages that PayPal sends with each event.
After receiving the IPN message from PayPal, your listener returns an empty HTTP 200 response to PayPal. Otherwise, PayPal resends the IPN message.
Your listener sends the complete message back to PayPal using HTTPS POST.
I think I am in pretty good shape with step #1 - I have implemented a listener in HandleURL event of my listener app.
At the end of my receiving the IPN message in step #1 above, I end the routine with:
Request.Status = 200
Return True
… which I believe satisfies step #2 above?
Here’s where I am asking for guidance… Since I have exited the HandleURL routine as described above (Request.Status = 200; Return True), then I need to trigger the routine to address step #3 above. Is that correct that this needs to happen outside the HandleURL event - since I need to return 200 BEFORE I execute on step #3? And if that is correct, how do you trigger the step #3 process - do you just set up a timer or something like that to invoke the step #3 process?
And therefore, I run the thread before getting to the “Return True” statement - and I don’t think that sequence would work.
So I think I need to do this:
We do a bit of database work as part of Step 3 so returning the message to PayPal occurs after Step 2 or they have been indifferent to the sequence. A delay should ensure the order of the sequence but for the past couple of years, it’s worked for us without a delay.
I’m not a communications expert -
I have set up my socket as follows - please let me know if you see something not right.
responseSocket = New HTTPSecureSocket
responseSocket.Secure = True
responseSocket.connectiontype = responseSocket.TLSv12
After receiving the IPN from paypal, I set up the socket as above and send back to paypal the verify command with their payload.
My socket show it connects, but I don’t receive any other events such as page received or error.
That is the whole point : each handleURL has its own thread, so it can be tapped into without disturbing the rest of the program.
Mark : You cannot use the request object directly, or the old HTTPSocket, because Xojo Web does not support the required HTTP 1.1.
That is why I use a Xojo.Net.HTTPSocket to post back.
[code] // Set dictionary
dim entity as string
if debugbuild then
entity = “payment_type=instant&payment_date=Sun%20Feb%2028%202016%2022%3A24%3A42%20GMT%2B0100%20%28CET%29&payment_status=Completed&address_status=confirmed&payer_status=verified&first_name=Ginette&last_name=Smith&payer_email=michel@fontmenu.com&payer_id=TESTBUYERID01&address_name=John%20Smith&address_country=United%20States&address_country_code=US&address_zip=95131&address_state=CA&address_city=San%20Jose&address_street=123%20any%20street&business=seller%40paypalsandbox.com&receiver_email=paypal-fonts@fontmenu.com&receiver_id=seller%40paypalsandbox.com&residence_country=US&item_name=something&item_number=AK-1234&quantity=1&shipping=3.04&tax=2.02&mc_currency=USD&mc_fee=0.44&mc_gross=12.34&mc_gross_1=9.34&txn_type=web_accept&txn_id=580373057¬ify_version=2.1&custom=AB776E2678FD3B695A3C2E8129571F2AEB463D13A764EC09EEF28172181AC2D189DDA6D0&invoice=abc1234&test_ipn=1&verify_sign=AFcWxV21C7fd0v3bYYYRCpSSRl31AvuP1FzfXF7VqgkW9eYfB4k4P09J”
else
entity = Request.Entity
end if
logme = logme + request.Entity+EndOfLine
dim s as string = DecodeURLComponent(entity)
s = s.ReplaceAll("+", " ")
logme = logme + "s : "+s+EndOfLine
dim args() as string = split(s, "&")
logme = logme + "args ubound : "+str(args.Ubound)+EndOfLine
if args.Ubound > 0 then
' Simple data in a Dictionary
Dim info As New Xojo.Core.Dictionary
mySocket = New xojo.Net.HTTPSocket
logme = logme + "loading dictionary"+EndOfLine
for i as integer = 0 to args.Ubound-1
dim paire() as string = split(args(i),"=")
dico.value(paire(0)) = paire(1)
next
logme = logme + "dictionary :"+str(dico.Count)+EndOfLine
' Convert to JSON text
Dim json As Text
json = Xojo.Data.GenerateJSON(info)
' Convert to MemoryBlock
Dim data As Xojo.Core.MemoryBlock
data = Xojo.Core.TextEncoding.UTF8.ConvertTextToData(json)
mySocket.SetRequestContent(data, "application/x-www-form-urlencoded")
mySocket.Send("POST", "https://ipnpb.paypal.com/cgi-bin/webscr")[/code]
Pardon my ignorance here. The only way I know how to do this is:
request.status = 200
return true
Am I correct in assuming the 200 status is only sent upon the return true statement?
Because if that is the case, then you have exited the HandleURL event without the opportunity to execute your code above.
And if I am not correct, then how do you: [quote=314094:]return 200 through Request before the code I posted[/quote] ?
By the way - I do appreciate your willingness to be helpful - so, thank you.
[quote=314203:@Mark Pastor]Pardon my ignorance here. The only way I know how to do this is:
request.status = 200
return true
[/quote]
The return true will send it that very instant. If you add code that processes things between request.status and return true that code will process and your status will still be whatever you set it when the method completes.
So, if the code for step 3 processes in the HandleURL event before the return true statement, then step 3 will happen before step 2 completes. That is the clarity I am looking for.
It’s the start of a race condition. Your web app will begin the process of the third step before it returns the HTTP status code of 200. Chances are it will complete HandleURL (and return the status) before being able to send out the request for verification, but who knows, the race is on!
Request entity may contain space, encoded as “+”. So I replace them by space. The same result would be attained with DecodeURLComponent. I don’t remember why I used replaceAll instead.