Is there someone that can tell me how to avoid a “socket already in use” error using Xojo.Net.HttpSocket ?
I’m having a hard time to figure out how to make multiple (small) JSON requests.
Can i reuse the socket or do i have to create another socket object?
Sockets Subclass are on my views. just like the iOS httpsocket example
In iOS, HTTPSocket executes asynchronously and it is kept alive until it finishes executing. So to make multiple requests I instantiate a new instance of the HTTPSocket for each request.
I use the new Timer.calllater mechanism which allows me to reuse the socket.
Don’t know how that works can you explain?
You create a method that will sequentially request your data. At the end of the page received event you add a xojo.Core.Timer.CallLater(1, AddressOf )
This creates a singleshot timer that calls your method to get the next data. Have a look at http://developer.xojo.com/xojo-core-timer$CallLater
[quote=200412:@Wayne Golding]You create a method that will sequentially request your data. At the end of the page received event you add a xojo.Core.Timer.CallLater(1, AddressOf )
This creates a singleshot timer that calls your method to get the next data. Have a look at http://developer.xojo.com/xojo-core-timer$CallLater[/quote]
Just wanted to thank you guys for this thread!
I’m working with an API that requires the use of offsets when large result sets are returned, and reusing the socket using this method did the trick.
[quote=207877:@Tim Dietrich]Just wanted to thank you guys for this thread!
I’m working with an API that requires the use of offsets when large result sets are returned, and reusing the socket using this method did the trick.[/quote]
It’s very easy actually once you get used to it.
I’m currently using sockets in a local scope with subclassed socket. It will be cleared once the request is completely done.
Trying to wrap my head around TimerCallLater
The first loop posts ok then the socket is in use.
[code] dim i As Integer
Dim jsonText As Text
Dim jsonData As xojo.Core.MemoryBlock
Dim nameDict As new Xojo.Core.Dictionary
Dim artistDict As Xojo.Core.Dictionary
dim a As AirTableItem
for i=0 to 3
'fill with values below
artistDict= new xojo.Core.Dictionary
nameDict.Value(“Handle”) = a.Handle +str(i)
nameDict.Value(“Title”) = a.Title
nameDict.Value(“Body (HTML)”) = a.Body
artistDict.Value("fields") = nameDict
jsonText = Xojo.Data.GenerateJSON(artistDict)
jsonData = Xojo.Core.TextEncoding.UTF8.ConvertTextToData(jsonText, False)
self.RequestHeader("Authorization") = "Bearer " + App.kAPIKey
'Self.Send("PATCH", "https://api.airtable.com/v0/" + App.kAppID + "/Artists/" + a.ID)
self.Send("POST", "https://api.airtable.com/v0/" + App.kAppID + "/Shop%20Template/" )
In page received
xojo.core.Timer.CallLater(1, AddressOf postToAirTable)
The way I read this code is you need to make 4 sequential calls to api.airtable.com in which case you’re going to need to write a state engine. You need to change your handle after receiving each response, not make 4 calls one after the other.
I must be missing something. There must be a way to see if the socket is in use without tripping this error isn’t there?
I’d like to have a timer set to check ever x period and when the socket is all done, then I’d make a subsequent call.
If you don’t need to do the requests in order, you can just create a new socket each time. That’s what I do. The socket will be destroyed automatically after it has completed (or timed out). That way your app isn’t bottlenecked with every async request sitting behind a single socket awaiting completion.
I thought of that too, however my initial design anticipated this wiring differently. I can always refactor, but it’s non-trivial at this point.
So I have a sub-class of the socket dragged into the window, and I’m making use of my own events to drive behavior.
I suppose I could do it the other way, where I create a socket, pass it the object that initially was housing it (a custom listbox row). Then I have to worry about what happens if someone closes that view and the reference for output goes away.
So if you create new sockets, where do you store them? In the past I’ve done this in an array, but I’ve been able to tell when they are “all done” so I could remove them and let Xojo do whatever it does to dispose.
I have an “API” class based on HTTPSocket but I don’t store the instance variables. When I need to call a web service, I just create a new, local variable in the method that is doing the calling of the same type as my class and pass it the route and payload in the constructor and then I just let the method finish. Even though the variable goes out of scope, it stays alive until the request either completes or times out, which is cool. If it’s a GET request, sometimes I pass in a callback (delegate) and the API instance calls back into the calling view to let it know it has retrieved some data or completed a process.
I do have one situation where I need to “rate limit” the requests to ensure only one is completed at a time, but that’s quite easy with a Shared Property in the class which stores an array of requests and then just does them from oldest to newest. Then I use the CallLater method as described earlier in this thread to launch the next one after each finishes. But I still don’t need to retain a reference to my HTTPSocket-based API class anywhere.
hmmm. I need to do some refactoring.
Just following up with success.
I refactored the entire app to work with sockets exactly as Jason recommended.
It’s been rock solid, and easier to maintain.
It was simply a poor implementation on my part at the beginning. I tried to cut corners that didn’t need cutting.
Thanks for the direction Jason.
Youre welcome Chris. Im always doing this sort of thing myself. A wise old developer once told me that its good practice to continuously refactor small pieces as you learn new things. I think he could have been right.
Jason, so I did find a problem where an impatient user could get a second, third, and so on, socket trying to perform the same action.
To overcome I created a shared property that is a Text array of action identifiers.
Then before I start a new socket, I test if one is already out there doing this. If not, I start it up and register the identifier.
In the destructor I remove the identifier.
Seems to work very well, but I’m curious how others have overcome the same issue.
Did you see any of this?
Hey Chris. Ive generally tried not to enforce the service calls to be synchronous as for most of my app it isnt a problem if, for example, the user goes into a view which causes a bunch of service calls to download images and then goes back out and then goes back into the same view, causing the same calls. Mostly the calls either complete quickly anyway and then the images are in my cache so the view loads faster next time or, if not, it just doesnt cause any harm.
However sometimes I do want the calls to be synchronous, such as for my login/authentication code which requires about five different services to be called one after the other, in the same order. In this case I pass a synchronous = True property to the main services entry point and my code will only pop the oldest service off the stack (array of services) and wait for that to finish or time out before moving on to the next one.