Restructured EEPROM client js.

This commit is contained in:
flash 2022-07-05 19:07:24 +00:00
parent 6ee8738686
commit d5d4096dc3
5 changed files with 338 additions and 193 deletions

View file

@ -14,7 +14,7 @@ $semaphore = sem_get($ftok, 1);
if(!sem_acquire($semaphore)) if(!sem_acquire($semaphore))
die('Failed to acquire semaphore.' . PHP_EOL); die('Failed to acquire semaphore.' . PHP_EOL);
require_once __DIR__ . '/startup.php'; require_once __DIR__ . '/eeprom.php';
// Mark expired as deleted // Mark expired as deleted
$expired = Upload::expired(); $expired = Upload::expired();

185
eeprom.js
View file

@ -1,185 +0,0 @@
var EEPROM = function(srcId, endpoint, authorization) {
this.srcId = parseInt(srcId);
this.setEndpoint(endpoint);
this.setAuthorization(authorization);
};
EEPROM.prototype.setEndpoint = function(endpoint) {
this.endpoint = endpoint.toString();
};
EEPROM.prototype.setAuthorization = function(authorization) {
this.authorization = authorization.toString();
};
EEPROM.prototype.deleteUpload = function(fileInfo) {
return new EEPROM.EEPROMDeleteTask(
this.authorization,
fileInfo
);
};
EEPROM.prototype.createUpload = function(file) {
return new EEPROM.EEPROMUploadTask(
this.srcId,
this.endpoint,
this.authorization,
file
);
};
EEPROM.ERR_GENERIC = 'generic'; // Generic error, no further details
EEPROM.ERR_INVALID = 'invalid'; // Request is invalid
EEPROM.ERR_AUTH = 'auth'; // Auth token expired
EEPROM.ERR_ACCESS = 'access'; // Barred from uploading
EEPROM.ERR_DMCA = 'dmca'; // DMCA takedown
EEPROM.ERR_GONE = 'gone'; // Invalid endpoint
EEPROM.ERR_SERVER = 'server'; // Server error
EEPROM.ERR_SIZE = 'size'; // Too large
EEPROM.EEPROMFile = function(fileInfo) {
// A merge operation woulda been neat.
this.id = (fileInfo.id || '').toString();
this.url = (fileInfo.url || '').toString();
this.urlf = (fileInfo.urlf || '').toString();
this.thumb = (fileInfo.thumb || '').toString();
this.name = (fileInfo.name || '').toString();
this.type = (fileInfo.type || '').toString();
this.size = parseInt(fileInfo.size || 0);
this.user = parseInt(fileInfo.user || 0);
this.hash = (fileInfo.hash || '').toString();
this.created = (fileInfo.created || null);
this.accessed = (fileInfo.accessed || null);
this.expires = (fileInfo.expires || null);
this.deleted = (fileInfo.deleted || null);
this.dmca = (fileInfo.dmca || null);
};
EEPROM.EEPROMFile.prototype.isImage = function() { return this.type.indexOf('image/') === 0; };
EEPROM.EEPROMFile.prototype.isAudio = function() { return this.type.indexOf('audio/') === 0; };
EEPROM.EEPROMFile.prototype.isVideo = function() { return this.type.indexOf('video/') === 0; };
EEPROM.EEPROMDeleteTask = function(authorization, fileInfo) {
var _self = this;
this.authorization = authorization;
this.fileInfo = fileInfo;
this.xhr = new XMLHttpRequest;
this.xhr.addEventListener('readystatechange', function() {
if(this.readyState !== 4)
return;
if(this.status !== 204) {
_self.errorCode = EEPROM.ERR_GENERIC;
switch(this.status) {
case 401:
_self.errorCode = EEPROM.ERR_AUTH;
break;
case 403:
_self.errorCode = EEPROM.ERR_ACCESS;
break;
case 404:
case 410:
_self.errorCode = EEPROM.ERR_GONE;
break;
case 500:
case 503:
_self.errorCode = EEPROM.ERR_SERVER;
break;
}
if(_self.onFailure)
_self.onFailure(_self.errorCode);
return;
}
if(_self.onSuccess)
_self.onSuccess();
});
};
EEPROM.EEPROMDeleteTask.prototype.onSuccess = undefined;
EEPROM.EEPROMDeleteTask.prototype.onFailure = undefined;
EEPROM.EEPROMDeleteTask.prototype.start = function() {
this.xhr.open('DELETE', this.fileInfo.urlf);
this.xhr.setRequestHeader('Authorization', this.authorization);
this.xhr.send();
};
EEPROM.EEPROMUploadTask = function(srcId, endpoint, authorization, file) {
var _self = this;
this.aborted = false;
this.endpoint = endpoint;
this.authorization = authorization;
this.xhr = new XMLHttpRequest;
this.formData = new FormData;
this.formData.append('src', srcId);
this.formData.append('file', file);
var reportUploadProgress = function(ev) {
if(_self.onProgress)
_self.onProgress(new EEPROM.EEPROMUploadTask.EEPROMUploadTaskProgress(ev.loaded, ev.total));
};
this.xhr.upload.addEventListener('loadstart', reportUploadProgress);
this.xhr.upload.addEventListener('progress', reportUploadProgress);
this.xhr.upload.addEventListener('load', reportUploadProgress);
this.xhr.addEventListener('readystatechange', function() {
if(this.readyState !== 4)
return;
if(this.status !== 201) {
_self.failureResponse = {
userAborted: _self.aborted,
error: EEPROM.ERR_GENERIC,
};
switch(this.status) {
case 400:
case 405:
_self.failureResponse.error = EEPROM.ERR_INVALID;
break;
case 401:
_self.failureResponse.error = EEPROM.ERR_AUTH;
break;
case 403:
_self.failureResponse.error = EEPROM.ERR_ACCESS;
break;
case 404:
case 410:
_self.failureResponse.error = EEPROM.ERR_GONE;
break;
case 451:
_self.failureResponse.error = EEPROM.ERR_DMCA;
break;
case 413:
_self.failureResponse.error = EEPROM.ERR_SIZE;
_self.failureResponse.maxSize = parseInt(this.getResponseHeader('X-EEPROM-Max-Size'));
break;
case 500:
case 503:
_self.failureResponse.error = EEPROM.ERR_SERVER;
break;
}
if(_self.onFailure)
_self.onFailure(_self.failureResponse);
return;
}
_self.fileInfo = new EEPROM.EEPROMFile(JSON.parse(this.responseText));
if(_self.onComplete)
_self.onComplete(_self.fileInfo);
});
};
EEPROM.EEPROMUploadTask.EEPROMUploadTaskProgress = function(loaded, total) {
this.progress = Math.ceil(((this.loaded = loaded) / (this.total = total)) * 100);
};
EEPROM.EEPROMUploadTask.prototype.onComplete = undefined;
EEPROM.EEPROMUploadTask.prototype.onFailure = undefined;
EEPROM.EEPROMUploadTask.prototype.onProgress = undefined;
EEPROM.EEPROMUploadTask.prototype.abort = function() {
this.aborted = true;
this.xhr.abort();
};
EEPROM.EEPROMUploadTask.prototype.start = function() {
this.xhr.open('POST', this.endpoint);
this.xhr.setRequestHeader('Authorization', this.authorization);
this.xhr.send(this.formData);
};

View file

@ -5,15 +5,11 @@ define('PRM_STARTUP', microtime(true));
define('PRM_ROOT', __DIR__); define('PRM_ROOT', __DIR__);
define('PRM_CLI', PHP_SAPI === 'cli'); define('PRM_CLI', PHP_SAPI === 'cli');
define('PRM_DEBUG', is_file(PRM_ROOT . '/.debug')); define('PRM_DEBUG', is_file(PRM_ROOT . '/.debug'));
define('PRM_PHP_MIN_VER', '7.4.0');
define('PRM_PUBLIC', PRM_ROOT . '/public'); define('PRM_PUBLIC', PRM_ROOT . '/public');
define('PRM_SOURCE', PRM_ROOT . '/src'); define('PRM_SOURCE', PRM_ROOT . '/src');
define('PRM_UPLOADS', PRM_PUBLIC . '/data'); define('PRM_UPLOADS', PRM_PUBLIC . '/data');
define('PRM_THUMBS', PRM_PUBLIC . '/thumb'); define('PRM_THUMBS', PRM_PUBLIC . '/thumb');
if(version_compare(PHP_VERSION, PRM_PHP_MIN_VER, '<'))
die('EEPROM required at least PHP ' . PRM_PHP_MIN_VER . '.');
error_reporting(PRM_DEBUG ? -1 : 0); error_reporting(PRM_DEBUG ? -1 : 0);
ini_set('display_errors', PRM_DEBUG ? 'On' : 'Off'); ini_set('display_errors', PRM_DEBUG ? 'On' : 'Off');

212
js/eeprom-v1.0.js Normal file
View file

@ -0,0 +1,212 @@
var EEPROM = function(srcId, endpoint, authorization) {
var obj = {
srcId: parseInt(srcId),
endpoint: endpoint,
authorization: authorization,
};
console.log(obj);
obj.setEndpoint = function(endpoint) {
obj.endpoint = (endpoint || '').toString();
};
obj.setAuthorization = function(authorization) {
obj.authorization = (authorization || '').toString();
};
obj.deleteUpload = function(fileInfo) {
return new EEPROM.EEPROMDeleteTask(
obj.authorization,
fileInfo
);
};
obj.createUpload = function(file) {
return new EEPROM.EEPROMUploadTask(
obj.srcId,
obj.endpoint,
obj.authorization,
file
);
};
return obj;
};
EEPROM.ERR_GENERIC = 'generic';
EEPROM.ERR_INVALID = 'invalid';
EEPROM.ERR_AUTH = 'auth';
EEPROM.ERR_ACCESS = 'access';
EEPROM.ERR_DMCA = 'dmca';
EEPROM.ERR_GONE = 'gone';
EEPROM.ERR_SERVER = 'server';
EEPROM.ERR_SIZE = 'size';
EEPROM.EEPROMFile = function(fileInfo) {
var obj = {
id: (fileInfo.id || '').toString(),
url: (fileInfo.url || '').toString(),
urlf: (fileInfo.urlf || '').toString(),
thumb: (fileInfo.thumb || '').toString(),
name: (fileInfo.name || '').toString(),
type: (fileInfo.type || '').toString(),
size: parseInt(fileInfo.size || 0),
user: parseInt(fileInfo.user || 0),
hash: (fileInfo.hash || '').toString(),
created: (fileInfo.created || null),
accessed: (fileInfo.accessed || null),
expires: (fileInfo.expires || null),
deleted: (fileInfo.deleted || null),
dmca: (fileInfo.dmca || null),
};
obj.isImage = function() { return obj.type.indexOf('image/') === 0; };
obj.isAudio = function() { return obj.type.indexOf('audio/') === 0; };
obj.isVideo = function() { return obj.type.indexOf('video/') === 0; };
return obj;
};
EEPROM.EEPROMDeleteTask = function(authorization, fileInfo) {
var obj = {
authorization: authorization,
fileInfo: fileInfo,
onSuccess: undefined,
onFailure: undefined,
};
var xhr = obj.xhr = new XMLHttpRequest;
obj.xhr.addEventListener('readystatechange', function() {
if(xhr.readyState !== 4)
return;
if(xhr.status !== 204) {
obj.errorCode = EEPROM.ERR_GENERIC;
switch(xhr.status) {
case 401:
obj.errorCode = EEPROM.ERR_AUTH;
break;
case 403:
obj.errorCode = EEPROM.ERR_ACCESS;
break;
case 404:
case 410:
obj.errorCode = EEPROM.ERR_GONE;
break;
case 500:
case 503:
obj.errorCode = EEPROM.ERR_SERVER;
break;
}
if(obj.onFailure)
obj.onFailure(obj.errorCode);
return;
}
if(obj.onSuccess)
obj.onSuccess();
});
obj.start = function() {
xhr.open('DELETE', obj.fileInfo.urlf);
xhr.setRequestHeader('Authorization', obj.authorization);
xhr.send();
};
return obj;
};
EEPROM.EEPROMUploadTask = function(srcId, endpoint, authorization, file) {
var obj = {
aborted: false,
endpoint: endpoint,
authorization: authorization,
onComplete: undefined,
onFailure: undefined,
onProgress: undefined,
failureResponse: undefined,
};
var xhr = obj.xhr = new XMLHttpRequest,
fd = obj.formData = new FormData;
fd.append('src', srcId);
fd.append('file', file);
var reportUploadProgress = function(ev) {
if(obj.onProgress)
obj.onProgress({
loaded: ev.loaded,
total: ev.total,
progress: Math.ceil((ev.loaded / ev.total) * 100),
});
};
xhr.upload.addEventListener('loadstart', reportUploadProgress);
xhr.upload.addEventListener('progress', reportUploadProgress);
xhr.upload.addEventListener('load', reportUploadProgress);
xhr.addEventListener('readystatechange', function() {
if(this.readyState !== 4)
return;
if(this.status !== 201) {
obj.failureResponse = {
userAborted: obj.aborted,
error: EEPROM.ERR_GENERIC,
};
switch(this.status) {
case 400:
case 405:
obj.failureResponse.error = EEPROM.ERR_INVALID;
break;
case 401:
obj.failureResponse.error = EEPROM.ERR_AUTH;
break;
case 403:
obj.failureResponse.error = EEPROM.ERR_ACCESS;
break;
case 404:
case 410:
obj.failureResponse.error = EEPROM.ERR_GONE;
break;
case 451:
obj.failureResponse.error = EEPROM.ERR_DMCA;
break;
case 413:
obj.failureResponse.error = EEPROM.ERR_SIZE;
obj.failureResponse.maxSize = parseInt(this.getResponseHeader('X-EEPROM-Max-Size'));
break;
case 500:
case 503:
obj.failureResponse.error = EEPROM.ERR_SERVER;
break;
}
if(obj.onFailure)
obj.onFailure(obj.failureResponse);
return;
}
obj.fileInfo = new EEPROM.EEPROMFile(JSON.parse(this.responseText));
if(obj.onComplete)
obj.onComplete(obj.fileInfo);
});
obj.abort = function() {
obj.aborted = true;
xhr.abort();
};
obj.start = function() {
xhr.open('POST', obj.endpoint);
xhr.setRequestHeader('Authorization', obj.authorization);
xhr.send(fd);
};
return obj;
};

View file

@ -1,7 +1,7 @@
<?php <?php
namespace EEPROM; namespace EEPROM;
require_once __DIR__ . '/../startup.php'; require_once __DIR__ . '/../eeprom.php';
$reqMethod = $_SERVER['REQUEST_METHOD']; $reqMethod = $_SERVER['REQUEST_METHOD'];
$reqPath = '/' . trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/'); $reqPath = '/' . trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/');
@ -159,9 +159,131 @@ if(preg_match('#^/uploads/([a-zA-Z0-9-_]{32})\.json/?$#', $reqPath, $matches)) {
return; return;
} }
if($reqPath === '/eeprom.js' && is_file(PRM_ROOT . '/eeprom.js')) { if($reqPath === '/eeprom.js') {
header('Content-Type: application/javascript; charset=utf-8'); header('Content-Type: application/javascript; charset=utf-8');
echo file_get_contents(PRM_ROOT . '/eeprom.js'); echo file_get_contents(PRM_ROOT . '/js/eeprom-v1.0.js');
return;
}
if($reqPath === '/test-v1.0.html' && PRM_DEBUG) {
header('Content-Type: text/html; charset=utf-8');
$cookie = htmlspecialchars((string)filter_input(INPUT_COOKIE, 'msz_auth'));
echo <<<TEST
<!doctype html>
<input type="file" id="-eeprom-file"/> <button id="-eeprom-abort">Abort</button> <progress id="-eeprom-progress" min="0" max="100" value="0"></progress> <span id="-eeprom-progress-done"></span> <span id="-eeprom-progress-total"></span><br/>
<div id="-eeprom-history"></div>
<script src="/eeprom.js" type="text/javascript"></script>
<script type="text/javascript">
var eFile = document.getElementById('-eeprom-file'),
eAbort = document.getElementById('-eeprom-abort'),
eProgress = document.getElementById('-eeprom-progress'),
eProgressD = document.getElementById('-eeprom-progress-done'),
eProgressT = document.getElementById('-eeprom-progress-total'),
eHistory = document.getElementById('-eeprom-history'),
eTask = undefined;
eAbort.onclick = function() {
if(eTask)
eTask.abort();
};
var eClient = new EEPROM(1, '/uploads', 'Misuzu {$cookie}');
eFile.onchange = function() {
var task = eTask = eClient.createUpload(this.files[0]);
task.onProgress = function(progressInfo) {
eProgress.value = progressInfo.progress;
eProgressD.textContent = progressInfo.loaded;
eProgressT.textContent = progressInfo.total;
};
task.onFailure = function(errorInfo) {
if(!errorInfo.userAborted) {
var errorText = 'Was unable to upload file.';
switch(errorInfo.error) {
case EEPROM.ERR_INVALID:
errorText = 'Upload request was invalid.';
break;
case EEPROM.ERR_AUTH:
errorText = 'Upload authentication failed, refresh and try again.';
break;
case EEPROM.ERR_ACCESS:
errorText = 'You\'re not allowed to upload files.';
break;
case EEPROM.ERR_GONE:
errorText = 'Upload client has a configuration error or the server is gone.';
break;
case EEPROM.ERR_DMCA:
errorText = 'This file has been uploaded before and was removed for copyright reasons, you cannot upload this file.';
break;
case EEPROM.ERR_SERVER:
errorText = 'Upload server returned a critical error, try again later.';
break;
case EEPROM.ERR_SIZE:
if(errorInfo.maxSize < 1)
errorText = 'Selected file is too large.';
else {
var _t = ['bytes', 'KB', 'MB', 'GB', 'TB'],
_i = parseInt(Math.floor(Math.log(errorInfo.maxSize) / Math.log(1024))),
_s = Math.round(errorInfo.maxSize / Math.pow(1024, _i), 2);
errorText = 'Upload may not be larger than %1 %2.'.replace('%1', _s).replace('%2', _t[_i]);
}
break;
}
alert(errorText);
}
};
task.onComplete = function(fileInfo) {
eTask = undefined;
var elem = document.createElement('div');
elem.id = fileInfo.id;
var link = document.createElement('a');
link.textContent = fileInfo.id;
link.href = fileInfo.url;
link.target = '_blank';
elem.appendChild(link);
elem.appendChild(document.createTextNode(' '));
var del = document.createElement('button');
del.textContent = 'Delete';
del.onclick = function() {
var dTask = eClient.deleteUpload(fileInfo);
dTask.onFailure = function(reason) {
alert('Delete failed: ' + reason);
};
dTask.onSuccess = function() {
eHistory.removeChild(elem);
};
dTask.start();
};
elem.appendChild(del);
elem.appendChild(document.createTextNode(' '));
var json = document.createElement('code');
json.textContent = JSON.stringify(fileInfo);
elem.appendChild(json);
eHistory.appendChild(elem);
};
task.start();
};
</script>
TEST;
return; return;
} }