Threaded XMLHttpRequest In Shoes

hackety org From hackety org, 3 months ago, 0 views

Threads can be tough and don’t suit beginners very well. And, well, Ruby threads can tie up the main app thread.

So, Shoes steals the underpinnings of Ajax to give you asynchronous downloads without needing to get into threading. Many of the young Sneakers are building Twitter and Flickr apps; it seemed the morally upright thing to do. In addition, I was able to use these HTTP threads to load remote images in the background. So, in Shoes, images loaded from the web will appear as they load.

Here’s the simple-downloader.rb from the samples that come with Shoes:

To achieve this, Shoes uses platform code for both threading and HTTP. On Windows, CreateThread and WinHTTP. On Linux, pthread and curl. And, on OS X, NSDownload and NSThread.

Downloading is reduced to a single line:

Shoes.app { download "http://shoooes.net/shoes.png", :save => "shoes.png" }

This happens asynchronously, so shoes.png won’t be there yet when this method ends. It might be huge. It might appear an hour later. You can attach a finish event to be notified when the download is complete.

Shoes.app do
  download "http://shoooes.net/shoes.png", :save => "shoes.png" do |dl|
    alert "Scuse me. Your shoes.png has arrived."
  end
end

Omit the :save option and you can get back the download as a string.

Shoes.app do
  download "http://hacketyhack.net/pkg/osx/shoes" do |dl|
    alert "The latest OS X download is: #{dl.response.body}"
  end
end

You can also attach :method, :headers and :body options to the download, if you want to customize the request beyond that. I studied XMLHttpRequest closely and tried to be sure the same things could be done with this.


As for events, you get four of them: start, progress, finish and error. You can either pass proc objects in as options:

Shoes.app do
  url = "http://shoooes.net/dist/shoes-0.r905.exe"
  status = para "Downloading #{url}"

  download url, :save => "shoes.exe",
    :start => proc { |dl| status.text = "Connecting..." },
    :progress => proc { |dl| status.text = "#{dl.percent}% complete" },
    :finish => proc { |dl| status.text = "Download finished" },
    :error => proc { |dl, err| status.text = "Error: #{err}" }
end

Or, use the method syntax:

Shoes.app do
  url = "http://shoooes.net/dist/shoes-0.r905.exe"
  status = para "Downloading #{url}"

  get = download url, :save => "shoes.exe"
  get.start { |dl| status.text = "Connecting..." }
  get.progress { |dl| status.text = "#{dl.percent}% complete" }
  get.finish { |dl| status.text = "Download finished" }
  get.error { |dl, err| status.text = "Error: #{err}" }
end

The last thing I will mention is that every queued download is attached to the window containing it. When you close the window, the download stops. So, if you’re queueing a download from a temporary popup, be sure to queue it on the main app window.

comments

No comments yet.

You must be logged in to add your own comment.