Briliant, thanks a lot ! Looks like I misunderstood Adam's reply, sorry about that !

I tried different things but I didn't think of calling invoke from within the worker thread, that solved the freezing problem. I ended up using the Thread class; spawn complained about the mutability of the given arguments. I realize what I did may be an ugly solution for the problem at hand, so I'll try to modify the code in order to avoid giving the thread UI elements altogether, thus being able to take advantage of more.. modern techniques like std.concurrency.

I'm using the Timer trick on another part of the project. Right now I'm running instances of a "Downloader" class in the background, a class that extends Thread and provides some useful functionality : a way to track the progress, to set rate limits, to abort the download, etc. It seems to be working fine, I'm using the (incomplete) program to download Visual Studio as we speak.

I set up a timer to periodically retrieve the progress of a download from the instances then update the ListView accordingly. Right now I'm hesitating between continuing with this approach vs using std.concurrency or even std.parallelism since the downloads are supposed to run in parallel without communicating with one another, but the only way I see would be to place the message handling code inside a loop, which for some reason doesn't sit right with me. I'm still learning concurrency (courtesy of Ali Çehreli and his book), so maybe my doubts are unfounded. Here's what I'll probably end up using, minus the error handling :

void dlWorker(HTTP client, string local, string remote, bool resume = true)
{
        auto fh = File(local, resume ? "a" : "w");
        scope(exit)
                fh.close;
        size_t size;
        size_t progress;
client.onProgress = (size_t dlTotal, size_t dlNow, size_t ulTotal, size_t ulNow) {
                size = dlTotal;
                progress = dlNow;
        };
        client.onReceive = (ubyte[] data) {
                fh.rawWrite(data);
                return data.length;
        };      
        client.perform;
        while(!client.isStopped)
        {
                auto msg = receiveOnly!(MsgType, int)();
                switch(msg[0])
                {
                        case MsgType.progress: send(ownerTid, progress); break;
                        case MsgType.size: send(ownerTid, size); break;
                        case MsgType.abort:
                                client.shutdown;
                                send(ownerTid, 1);
                        break;
                        default:
                                
client.handle.set(CurlOption.recv_rate_speed_large, msg[1]);
                                send(ownerTid, 1);
                        break;
                }
        }
}

enum MsgType
{
        progress, size, abort, limit;
}

Though I'm not entirely sure how I would tie the ListView rows to their respective workers. But I'll cross that bridge when I get to it.

Again, thanks for all the help. You guys are definitely going to be mentioned in the "About" section of the finished product.

Reply via email to