Question on SynchronousHTTPSocket with posting to web service

I found the following article and have run several tests with this class, and it is awesome
https://thezaz.com/blog/urlconnectionsendsync_is_a_per

I have a unique need that I cannot figure out for myself. I am first saving the data I want to send to the web service db to a db table locally. When I push the data to the web service db, I want to delete the records from the local table as they are successfully added.

This is for a desktop app that can be used offline. If the user is offline, I want the data to remain in the temp table and not get deleted. Once they are connected, the app will try the Send method again, and if successful, will delete the records as they are added

Here is the code for this process. Could anyone share how I can accomplish this? This is deleting from the temp table, even when I disconnect from the net

'first save to temp table
dbUser.ExecuteSQL("INSERT INTO XCTempTable (X, Y, Z) VALUES (?, ?, ?)", "X", "Y", "Z")

'get tempID from newly added to delete this one once uploaded
dim sql as String = "SELECT id FROM XCTempTable ORDER BY id DESC"
dim rs as RowSet = dbUser.SelectSQL(sql)

'set property for deleting later
dim tempID as String = rs.Column("id").StringValue

dim bCanDelete as Boolean

'add to server.  if successful, will delete below
try
  dim Socket As New SimpleHTTP.SynchronousHTTPSocket
  Socket.RequestHeader("Cache-Control") = "no-cache"
  Socket.RequestHeader("Connection") = "close"
  
  dim jCode As New JSONItem
  jCode.Value("XXXX") = "XXXX"
  jCode.Value("XXXX") = "XXXX"
  jCode.Value("XXXX") = "XXXX"
  
  dim data as String = jCode.ToString.DefineEncoding(Encodings.UTF8)
  
  Socket.SetRequestContent(data, "application/json")
  
  Socket.Send("POST", "https://XXXX.xojocloud.net/XXXX")
  
  'post added so set to delete 
  bCanDelete = true
  
catch e as NetworkException
  bCanDelete = False
  Return
end try

if bCanDelete = true then
  dbUser.ExecuteSQL("DELETE FROM XCTempTable WHERE id = '" + tempID + "'")
end if

/// I don't think the bCanDelete property is working since it is always deleting from the temp table, even when not connected to the internet

Is there a " HeadersReceived" event or other event following a POST that you could evaluate? That seems like a better place to put the bCanDelete bool and call any subsequent operations.

There wasn’t in the class originally, so i added it. Unfortunately, that didn’t seem to work. Not sure if I needed to add anything else to HeadersReceived, but I just did

bCanDelete = True

Assuming if it was received, this can be set to true. Also, and not sure if this matters, but this class is not part of the window where the POST call is made. There was an example project (couldn’t find it at the moment), but that project also did not include the class on the window, so I did not do this either

I’ll assume that the HeadersReceived will fire as would other related events, but you should be evaluating the HTTPStatus that is passed in to evaluate if it is “200” (aka “OK”) or any of the many many other codes that indicate an error. You would likely only set bCanDelete to true on ‘200’, otherwise handle the other response codes accordingly.

HeadersReceived (URL As String, HTTPStatus As Integer)

Offline sync is not a unique need :slight_smile: Nevertheless it isn’t easy to achieve. I am currently working on a similar functionality.

Note: The only part that is “synchronous” in that class is if you are calling Socket.Send from a Thread. The thread will be paused until the HTTPSocket has received something in the ContentReceived event or the Error event.
If you use Socket.Send on the Main thread, your code will continue execution before the socket got a response.

I had a look at the SynchronousHTTPSocket class and found some errors in your code.

If your code is not running from a Thread, bCandDelete will alway be true in the code you wrote. That’s because it isn’t waiting for the result of Socket.Send

  1. You will either need to call that code from a Thread, then check the HTTPStatus code and response:
Var response As String = Socket.LastContent
If Socket.LastHTTPStatus = 200 Then //And check response if relevant
  bCanDelete = True
End if
  1. Or use AddHandler
AddHandler Socket.ContentReceived, WeakAddressOf mSocket_ContentReceived

And check the HTTPStatus code in mSocket_ContentReceived method you will add to your Window.


(not related to HTTPSocket) if dbUser is a SQLiteDatabase, you could use dbUser.LastRowID instead of this:

1 Like

This, I believe, is my problem. This window is calling .Send directly and not using a thread. I will give this a try tomorrow. For some reason, I thought of only needing to use a thread when wanting to post data from a loop that might take a while. Since this example was only posting one item, I didn’t think it necessary to use a thread. Thanks for this!

Also wasn’t aware of this! This will make it easier to grab the ID I need

Will post back tomorrow if I run into any further issues, but I think this gets me on track

Also that class doesn’t have a ton of utility anymore. URLConnection has a built-in SendSync method now. And you can call it from the main thread, though I strongly suggest you don’t.

But I guess you don’t need it there. Your design seems flawed for the purpose you said.
You should design a flow (in a piece of paper?) before writing the code. :smile:

Looks like you want 2 separated repeating asynchronous tasks running in parallel:

Task 1:   // Send something to the remote db

  Insert the record in the "output queue" db // done

End task 1


Task 2: // dump the queue to the remote endpoint

  Do we have something in the output queue?
    yes: get the oldest record (and its id)
         upload it
         success?
            yes: delete it from the output queue
            no:  continue. maybe sleep a bit 
    no:  continue, sleep a bit, longer than when actively dumping content

End task 2

Adding the Send call and doing all the work in the thread did the trick. Thank you all for teaching me once again. Very much appreciated! Happy holidays!

I think this was your class and example project I found on the forum Thom, yes? I’ve found it to be very helpful. Not sure what you mean by not having a lot of utility. I think it works great. There will be some instances where I’ll use the URLConnection.Send, but I’ll be using your class for other parts. What I liked in the class is that if another call is attempted when this one is running, it doesn’t crash the app with “there’s another process running now”. I noticed that on the URLConnection.Send. With yours, I tested a loop of 100 adds and then started another thread with another loop of 100 adds, and they all added. I don’t think I could’ve gotten that with just the .Send. I’m sure many of you could get that to work with the appropriate sleeps/polls, but that is too advanced for me at this time. Maybe someday :slight_smile:

Yes, it’s definitely mine and I do still use a version of it. https://github.com/thommcgrath/Beacon/blob/master/Project/Modules/SimpleHTTP/SynchronousHTTPSocket.xojo_code

You’re right that it has some advantages. I just meant that it was created at a point in time where such thing wasn’t provided by Xojo. But Xojo now fills that gap, so it’s not a class that really needs to exist anymore.

1 Like

In your blog post The ZAZ: URLConnection.SendSync Is a Performance Nightmare, and What You Can Do About It you say that SendSync is a performance nightmare. Do you know if that was fixed since 2020 (when you wrote the blog post)?

I am thinking of refactoring some of my code to make use of either SendSync (in a thread) or your SynchronousHTTPSocket (in a thread).
If SendSync is still a performance nightmare then your socket still needs to exist :slight_smile:

1 Like

+1!