samples/Backend on AOLserver and OpenACS.md
# AOLserver and OpenACS
[@steffentchr](http://twitter.com/steffentchr)
Our upload managers are using [AOLserver](http://www.aolserver.com/) and [OpenACS](http://www.openacs.com/).
Generally, all Resumable.js request are handled through a single method:
ad_proc handle_resumable_file {
{-file_parameter_name "file"}
{-folder "/tmp"}
-check_video:boolean
{-max_file_size ""}
} {} {
# Check parameter to see if this is indeed a resumable
ad_page_contract {} {
{resumableChunkNumber:integer "0"}
{resumableChunkSize:integer "0"}
{resumableTotalSize:integer "0"}
{resumableIdentifier ""}
{resumableFilename ""}
}
# Clean up the identifier
regsub -all {[^0-9A-Za-z_-]} $resumableIdentifier "" resumableIdentifier
# Check if the request is sane
if { $resumableChunkNumber==0 || $resumableChunkSize==0 || $resumableTotalSize==0 || $resumableIdentifier eq "" } {
return "non_resumable_request"
}
set number_of_chunks [expr int(floor($resumableTotalSize/($resumableChunkSize*1.0)))]
if { $number_of_chunks==0 } {set number_of_chunks 1}
if { $resumableChunkNumber>$number_of_chunks } {
return "invalid_resumable_request"
}
# What would the file name be?
set filename [file join $folder "resumable-${resumableIdentifier}.${resumableChunkNumber}"]
# If this is a GET request, we should tell the uploader if the file is already in place or not
if { [ns_conn method] eq "GET" } {
if { [file exists $filename] && [file size $filename]==$resumableChunkSize } {
doc_return 200 text/plain "ok"
} else {
doc_return 204 text/plain "not found"
}
ad_script_abort
}
# Assign a tmp file
ad_page_contract {} [list "${file_parameter_name}:trim" "${file_parameter_name}.tmpfile:tmpfile"]
set tmp_filename [set "${file_parameter_name}.tmpfile"]
if { $resumableFilename ne "" } {
set original_filename $resumableFilename
} else {
set original_filename [set $file_parameter_name]
}
# Check data size
if { $max_file_size ne "" && $resumableTotalSize>$max_file_size } {
return [list "invalid_resumable_request" "The file is too large" $original_filename]
} elseif { $resumableChunkNumber<$number_of_chunks && [file size $tmp_filename]!=$resumableChunkSize } {
return [list "invalid_resumable_request" "Wrong data size" $original_filename]
} elseif { $number_of_chunks>1 && $resumableChunkNumber==$number_of_chunks && [file size $tmp_filename] != [expr ($resumableTotalSize % $resumableChunkSize) + $resumableChunkSize] } {
return [list "invalid_resumable_request" "Wrong data size" $original_filename]
} elseif { $number_of_chunks==1 && [file size $tmp_filename] != $resumableTotalSize } {
return [list "invalid_resumable_request" "Wrong data size" $original_filename]
}
# Save the chunk
file mkdir $folder
file copy -force $tmp_filename $filename
# Try collating the first and last chunk -- and identify
if { $check_video_p && ($resumableChunkNumber==1 || $resumableChunkNumber==$number_of_chunks) } {
## (Here you can do check on first and last chunk if needed
## For example, we will check if this is a support video file.)
}
# Check if all chunks have come in
set chunk_num 1
set chunk_files [list]
while { $chunk_num<=$number_of_chunks } {
set chunk_filename [file join $folder "resumable-${resumableIdentifier}.${chunk_num}"]
if { ![file exists $chunk_filename] } {
return [list "partly_done" $filename $original_filename]
}
lappend chunk_files $chunk_filename
incr chunk_num
}
# We've come this far, meaning that all the pieces are in place
set output_filename [file join $folder "resumable-${resumableIdentifier}.final"]
foreach file $chunk_files {
exec cat $file >> $output_filename
catch {
file delete $file
}
}
return [list "done" $output_filename $original_filename $resumableIdentifier]
}
After this, all Resumable.js cases can be handled easily, including
fallback to non-resumable requests.
# Is this a file from Resumable.js?
lassign [handle_resumable_file] resumable_status resumable_context resumable_original_filename resumable_identifier
if { $resumable_status ne "non_resumable_request" } {
# Yes, it is
switch -exact $resumable_status {
partly_done {
doc_return 200 text/plain ok
ad_script_abort
}
done {
# All the pieces are in place
ad_page_contract {} {
{file:trim "unknown"}
}
set "file.tmpfile" $resumable_context
set file $resumable_identifier
}
invalid_resumable_request -
default {
doc_return 500 text/plain $resumable_context
ad_script_abort
}
}
} else {
# Nope, it's just a straight-forward HTTP request
ad_page_contract {} {
file:trim
file.tmpfile:tmpfile
}
}