///|
/// Framework-neutral protocol façade. It accepts plain values and owns only a
/// reference store; network I/O, authentication and persistence stay outside.
pub struct TusEngine {
priv store : MemoryStore
config : TusConfig
}
///|
pub fn TusEngine::new(
config? : TusConfig = TusConfig::default(),
store? : MemoryStore = MemoryStore::new(),
) -> Result[TusEngine, TusError] {
match validate_config(config) {
Err(error) => Err(error)
Ok(_) => Ok({ store, config, })
}
}
///|
pub fn TusEngine::handle(self : TusEngine, request : TusRequest) -> TusResponse {
let request = match apply_method_override(request) {
Err(error) =>
return failure_response(error, headers=version_response_headers())
Ok(request) => request
}
match request.http_method {
Options => self.handle_options(request)
Post => handle_creation(request, self.store, self.config)
Head => handle_head(request, self.store, self.config)
Patch => handle_patch(request, self.store, self.config)
Other(value) => unsupported_method_response(value)
}
}
///|
pub fn TusEngine::snapshot(
self : TusEngine,
identifier : String,
) -> Result[UploadRecord, TusError] {
self.store.get(identifier)
}
///|
pub fn TusEngine::uploads(self : TusEngine) -> Array[UploadRecord] {
self.store.list()
}
///|
pub fn TusEngine::upload_count(self : TusEngine) -> Int {
self.store.count()
}
///|
fn TusEngine::handle_options(
self : TusEngine,
request : TusRequest,
) -> TusResponse {
match validate_request(request, self.config) {
Err(error) =>
return failure_response(error, headers=version_response_headers())
Ok(_) => ()
}
let extensions = supported_extensions(self.config)
let headers = Headers::empty()
.add("Tus-Version", TUS_VERSION)
.add("Tus-Resumable", TUS_VERSION)
.add("Tus-Max-Size", self.config.limits.max_upload_size.to_string())
.add("Allow", "OPTIONS, POST, HEAD, PATCH")
let headers = if extensions.length() == 0 {
headers
} else {
headers.add("Tus-Extension", join_ascii(extensions, ","))
}
success_response(204, headers~, trace=[
trace(
"options.capabilities.reported", "server capabilities were derived from active configuration",
"tus-1.0.0/core",
),
])
}
///|
pub fn supported_extensions(config : TusConfig) -> Array[String] {
let extensions : Array[String] = []
if config.allow_creation {
extensions.push("creation")
if config.allow_deferred_length {
extensions.push("creation-defer-length")
}
}
extensions
}
///|
fn unsupported_method_response(http_method : String) -> TusResponse {
failure_response(
invalid_method(http_method),
headers=version_response_headers().add(
"Allow", "OPTIONS, POST, HEAD, PATCH",
),
)
}
///|
fn join_ascii(values : Array[String], separator : String) -> String {
let output = StringBuilder()
for index, value in values {
if index > 0 {
output.write_string(separator)
}
output.write_string(value)
}
output.to_string()
}