Perlbalを使ったUploadプログレス表示

Webでファイルアップロードの仕組みって結構つかわれてますが、
大きなファイルをアップロードしている時、プログレスバーとかを
表示したかったりしますが、Perlbalでは簡単にできました。

Perlbalの設定ファイルには↓見たいに設定
肝は
CREATE SERVICE uptrack

SET upload_status_listeners = 127.0.0.1:7002, 10.54.0.1:7001
あとは普通のPerlbalの設定と同様

CREATE POOL nekokak_pool
    POOL nekokak_pool ADD 192.168.200.100:8000

CREATE SERVICE uptrack
  SET role = upload_tracker
  SET listen = 127.0.0.1:7002
ENABLE uptrack

CREATE SERVICE nekokak
    SET role            = reverse_proxy
    SET upload_status_listeners = 127.0.0.1:7002, 10.54.0.1:7001
    SET pool            = nekokak_pool
ENABLE nekokak

CREATE SERVICE http_server
    SET listen          = 0.0.0.0:80
    SET role            = selector
    SET plugins         = UrlGroup

    GROUP *.example.com = nekokak

ENABLE http_server

ServerSideのプログラムは特にプログレス用の変更とかせずに
普通にファイルアップロードを処理するプログラムでおk

HTML側ではXmlHttpRequestを使うので大体↓見たいな感じになります

                      <div class="maincolumn">
<script>

////// public interface:

function UploadTracker (formele, cb) {
    this.form      = formele;
    this.callback = cb;
    this.session  = UploadTracker._generateSession();
    this.stopped  = false;

    var action = this.form.action;
    if (action.match(/\bclient_up_sess=(\w+)/)) {
        action = action.replace(/\bclient_up_sess=(\w+)/, "client_up_sess=" + this.session);
    } else {
        action += (action.match(/\?/) ? "&" : "?");
        action += "client_up_sess=" + this.session;
    }
    this.form.action = action;

    this._startCheckStatus();
}


// method to stop tracking a form's upload status
UploadTracker.prototype.stopTracking = function () {
    this.stopped = true;
};


// private implementation details:
UploadTracker._XTR = function () {
    var xtr;
    var ex;

    if (typeof(XMLHttpRequest) != "undefined") {
        xtr = new XMLHttpRequest();
    } else {
        try {
            xtr = new ActiveXObject("Msxml2.XMLHTTP.4.0");
        } catch (ex) {
            try {
                xtr = new ActiveXObject("Msxml2.XMLHTTP");
            } catch (ex) {
            }
        }
    }

    // let me explain this.  Opera 8 does XMLHttpRequest, but not setRequestHeader.
    // no problem, we thought:  we'll test for setRequestHeader and if it's not present
    // then fall back to the old behavior (treat it as not working).  BUT --- IE6 won't
    // let you even test for setRequestHeader without throwing an exception (you need
    // to call .open on the .xtr first or something)
    try {
        if (xtr && ! xtr.setRequestHeader)
            xtr = null;
    } catch (ex) { }

    return xtr;
};


UploadTracker._generateSession = function () {
    var str = Math.random() + "";
    return curSession = str.replace(/[^\d]/, "");
};


UploadTracker.prototype._startCheckStatus = function () {
    var uptrack = this;
    if (uptrack.stopped) return true;

    var xtr = UploadTracker._XTR();
    if (!xtr) return;

    var callback = function () {
        if (xtr.readyState != 4) return;
        if (uptrack.stopped)     return;

        if (xtr.status == 200) {
            var val;
            eval("val = " + xtr.responseText + ";");
            uptrack.callback(val);
        }
        setTimeout(function () { uptrack._startCheckStatus(); }, 1000);
    };

    xtr.onreadystatechange = callback;
    xtr.open("GET", "/__upload_status?client_up_sess=" + uptrack.session + "&rand=" + Math.random());
    xtr.send(null);
}

var uptrack; // our Perlbal upload tracker object, if defined

// called from iframe's content on complete, with a URL of where we should go:
function onUploadComplete (destURL) {
    window.location = destURL;
}

// called by the perlbal upload tracker library:  (we pass it this function below)
function uploadCallback (data) {
    if (! (data && data.total)) return;
    var percent = Math.floor(data.done * 100 / data.total);
    document.getElementById("UploadBarInside").style.width = percent + "%";
    var status = Math.floor(data.done / 1024) + " kB / " + 
    Math.floor(data.total / 1024) + " kB, " + percent + "% complete";
    document.getElementById("UploadStatus").innerHTML = status;
}

function submitForm () {
    if (uptrack) uptrack.stopTracking();

    var frm = document.getElementById("WebUpload");

    frm.target = "upiframe"; // change target to our iframe

    // create the actual Perlbal upload tracker object:
    uptrack = new UploadTracker(frm, uploadCallback);

    document.getElementById("UploadStatus").innerHTML = "Uploading, please wait...";
    document.getElementById("UploadBar").style.display = "block";
    return true;
}

</script>

<iframe name="upiframe" id="upiframe" height="0" width="0">
</iframe>
<div name="UploadBarInside" id="UploadBarInside"></div>
<div name="UploadStatus" id="UploadStatus"></div>
<div name="UploadBar" id="UploadBar"></div>

                <form action="/upload/" method="post" name="WebUpload" id="WebUpload" enctype="multipart/form-data" onSubmit="submitForm()">
                    <input name="file" type="file" />
                    <input name="upload" type="submit" />
                </form>
                
</div>

これで、ファイルをアップロードすると、プログレスが表示されます。
もう少し手を加えればもとおされにプログレス表示したりもできますね。

こういうのはサンプルのサイトがあったほうがいいなぁ。
来週の時間のあるときにでも用意するかもです。

参考)http://brad.livejournal.com/2171184.html