SkylarkUpload
Skylark upload with ajax progress bar
SkylarkUpload.h
#ifndef _SkylarkUpload_SkylarkUpload_h_
#define _SkylarkUpload_SkylarkUpload_h_
#include <Skylark/Skylark.h>
using namespace Upp;
class SkylarkUpload : public SkylarkApp
{
private:
// root path for saving files
String rootPath;
protected:
public:
// constructor
SkylarkUpload(String const &rPath);
// get root path
String const &GetRootPath(void) { return rootPath; }
};
SkylarkUpload &Upload();
#endif
SkylarkUpload.cpp
#include "SkylarkUpload.h"
SkylarkUpload &Upload()
{
return (SkylarkUpload &)SkylarkApp::TheApp();
}
SkylarkUpload::SkylarkUpload(String const &rPath)
{
root = "server";
rootPath = rPath;
RealizeDirectory(rootPath);
#ifdef _DEBUG
prefork = 0;
use_caching = false;
#endif
}
CONSOLE_APP_MAIN
{
#ifdef _DEBUG
StdLogSetup(LOG_FILE|LOG_COUT);
Ini::skylark_log = true;
#endif
SkylarkUpload upload(AppendFileName(GetHomeDirectory(), "UPLOAD/"));
upload.Run();
}
Handlers.icpp
#include "SkylarkUpload.h"
int ProgressHandler(int reason, Http &http, int size)
{
// get the upload unique identifier
String id = http["uploadid"];
String currentId = "." + id + ".currentSize";
String totalId = "." + id + ".totalSize";
// must be reentrant
INTERLOCKED {
switch(reason)
{
// got headers ?
case PROGRESS_HEADER:
{
http
.SessionSet(currentId, 0)
.SessionSet(totalId, size)
;
break;
}
// reading contents ?
case PROGRESS_CONTENT:
{
int oldPercent = http[currentId];
int total = http[totalId];
// take care to NOT return 100% up to upload ended really
int percent = min(99, (int)(100.0 * size / total));
// avoid unnnedded session storing
if(oldPercent != percent)
http.SessionSet(currentId, percent);
break;
}
// finished reading contents ?
case PROGRESS_END:
{
// signals end by resetting total size
http.SessionSet(totalId, 0);
break;
}
// default, used by query handler
default: // PROGRESS_QUERY
{
// check if key is there --> upload started
int total = http[totalId];
if(!IsNull(total))
{
if(total)
// if upload not ended, return the progress %
return http[currentId];
else
{
// upload ended, nullify session variables and return 100%
http
.SessionSet(currentId, Null)
.SessionSet(totalId, Null)
;
return 100;
}
}
else
// upload still not started, return 0 progress
return 0;
}
}
}
return true;
}
SKYLARK(Home, "home")
{
// we need a session variable for upload id
if(http["@__skylark_session_cookie__"].IsNull())
http.NewSessionId();
// show rootpath in html page
http("UploadFolder", Upload().GetRootPath());
http.RenderResult("SkylarkUpload/SkylarkUpload");
}
SKYLARK(Default, "**")
{
http.Redirect(Home);
}
SKYLARK_PROGRESS(PostUpload, "upload:POST", &ProgressHandler)
{
String fileName = AppendFileName(Upload().GetRootPath(), (String)http["filename"]);
Value const &contents = http["filestoupload[]"];
Value const &filenames = http["filestoupload.filename[]"];
if(contents.IsNull() || filenames.IsNull())
return;
for(int i = 0; i < contents.GetCount(); i++)
SaveFile(AppendFileName(Upload().GetRootPath(), (String)filenames[i]), contents[i]);
}
SKYLARK(Progress,"progress")
{
int p = ProgressHandler(PROGRESS_QUERY, http, 0);
http.Content("text/plain", Format("%d", p));
http.Response(200, "OK");
}
SkylarkUpload.witz
<html>
<head>
<title>File Upload Progress Bar</title>
<link rel='stylesheet' type='text/css' href='static/SkylarkUpload/SkylarkUpload.css'>
<!-- this script does all the upload magics -->
<script type='text/javascript' src='static/SkylarkUpload/upload.js'></script>
</head>
<body>
<div id='bodyContainer'>
<div id='header'>
Skylark file upload demo
</div>
<br>
<br>
This demo supports uploading multiple files at once
<br>
Files will be uploaded in '$UploadFolder' folder on server
<br>
<br>
<!--
POST URL -- javascript code will read it and build the 'action' of following form
You MUST insert in 'value' field the upload url (here 'upload')
-->
<input type='hidden' id='uploadurl' value='upload'>
<!--
progress handler URL -- javascript will use it to make periodic calls on server
querying upload progress and showing it in progress bar
You MUST insert in 'value' field the progress url (here 'progress')
-->
<input type='hidden' id='progressurl' value='progress'>
<!--
POST form
action is a dummy value, will be filled by javascript code
which sets the POST
-->
<form action='xxxxxx' method='POST' id='myForm' enctype='multipart/form-data' target='hidden_iframe' onsubmit='startUpload(this);'>
<!--
ending [] in filestoupload[] makes a ValueArray of multipart data
in Skylark arrays will be :
filestoupload[] a ValueArray with file contents
filestoupload.content_type[] a ValueArray with file content types
filestoupload.filename[] a ValueArray with filenames
The 'multiple' field allows select and upload more files at once
-->
<input type='file' name='filestoupload[]' multiple=''>
<br><br>
<input type='submit' value='Start Upload'>
<br>
</form>
<!-- Progress bar -->
<div id='progress_container'>
<div id='progress'></div>
</div>
<!--
hidden frame doing the upload process
it's used to 'free' the browser window during upload phase
-->
<iframe id='hidden_iframe' name='hidden_iframe' src='about:blank'></iframe>
<!--
these fields are used to build an unique identifier of this upload job
in order to allow progress handler to identify correctly its related upload job
(we need it because we can have more upload jobs calls on server
-->
<input type='hidden' id='session' value='$@__skylark_session_cookie__'>
<input type='hidden' id='submittime' value=''>
</div>
</body>
</html>
|