mirror of
https://github.com/flynx/ImageGrid.git
synced 2025-10-29 02:10:08 +00:00
new task manager working...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
d59b62c39f
commit
7f086b289b
@ -2358,89 +2358,6 @@ function(func){
|
||||
return func }
|
||||
|
||||
|
||||
//
|
||||
// action: ['Path/To/Action',
|
||||
// abortablePromise('abort-id', function(abort, ...args){
|
||||
//
|
||||
// abort.cleanup(function(reason, res){
|
||||
// if(reason == 'done'){
|
||||
// // ...
|
||||
// }
|
||||
// if(reason == 'aborted'){
|
||||
// // ...
|
||||
// }
|
||||
// })
|
||||
//
|
||||
// return new Promise(function(resolve, reject){
|
||||
// // ...
|
||||
//
|
||||
// if(abort.isAborted){
|
||||
// // handle abort...
|
||||
// }
|
||||
//
|
||||
// // ...
|
||||
// }) })],
|
||||
//
|
||||
//
|
||||
// NOTE: if the returned promise is not resolved .cleanup(..) will not
|
||||
// be called even if the appropriate .abort(..) as called...
|
||||
//
|
||||
// XXX is the abort api an overkill??
|
||||
// ...can this be solved/integrated with tasks???
|
||||
// essentially this creates an abortable task, for full blown tasks
|
||||
// it would be nice to also be able to:
|
||||
// - pause/resume (abort is done)
|
||||
// - serialize/restore
|
||||
// - list/sort/prioritize
|
||||
// - remote (peer/worker)
|
||||
// XXX docs...
|
||||
// XXX LEGACY...
|
||||
var abortablePromise =
|
||||
module.abortablePromise =
|
||||
function(title, func){
|
||||
return Object.assign(
|
||||
Task(function(...args){
|
||||
var that = this
|
||||
|
||||
var abort = object.mixinFlat(
|
||||
this.abortable(title, function(){
|
||||
that.clearAbortable(title, abort)
|
||||
return abort }),
|
||||
{
|
||||
get isAborted(){
|
||||
return !((that.__abortable || new Map())
|
||||
.get(title) || new Set())
|
||||
.has(this) },
|
||||
|
||||
__cleanup: null,
|
||||
cleanup: function(func){
|
||||
var args = [...arguments]
|
||||
var reason = this.isAborted ?
|
||||
'aborted'
|
||||
: 'done'
|
||||
typeof(func) == 'function' ?
|
||||
// register handler...
|
||||
(this.__cleanup = this.__cleanup
|
||||
|| new Set()).add(func)
|
||||
// call cleanup handlers...
|
||||
: [...(this.__cleanup || [])]
|
||||
.forEach(function(f){
|
||||
f.call(that, reason, ...args) })
|
||||
return this },
|
||||
})
|
||||
|
||||
return func.call(this, abort, ...args)
|
||||
.then(function(res){
|
||||
abort.cleanup(res)()
|
||||
return res })
|
||||
.catch(function(res){
|
||||
abort.cleanup(res)() }) }),
|
||||
{
|
||||
toString: function(){
|
||||
return `core.abortablePromise('${ title }', \n${ func.toString() })` },
|
||||
}) }
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Task action action helpers...
|
||||
//
|
||||
@ -2473,6 +2390,7 @@ function(title, func){
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
// XXX add a task manager UI...
|
||||
var TaskActions = actions.Actions({
|
||||
config: {
|
||||
},
|
||||
@ -2504,103 +2422,6 @@ var TaskActions = actions.Actions({
|
||||
// session tasks are stopped when the index is cleared...
|
||||
get sessionTasks(){
|
||||
return this.tasks.titled(...this.sessionTaskActions) },
|
||||
|
||||
|
||||
|
||||
// XXX LEGACY -- remove after migrating sharp.js and abortablePromise(..)
|
||||
//
|
||||
// Abortable...
|
||||
//
|
||||
// Format:
|
||||
// Map({
|
||||
// title: Set([ func, ... ]),
|
||||
// ...
|
||||
// })
|
||||
//
|
||||
// XXX rename...
|
||||
// XXX extend to support other task operations...
|
||||
__abortable: null,
|
||||
|
||||
abortable: ['- System/Register abort handler',
|
||||
doc`Register abortable action
|
||||
|
||||
.abortable(title, func)
|
||||
-> func
|
||||
|
||||
`,
|
||||
function(title, callback){
|
||||
// reserved titles...
|
||||
if(title == 'all' || title == '*'){
|
||||
throw new Error('.abortable(..): can not set reserved title: "'+ title +'".') }
|
||||
|
||||
var abortable = this.__abortable = this.__abortable || new Map()
|
||||
var set = abortable.get(title) || new Set()
|
||||
abortable.set(title, set)
|
||||
set.add(callback)
|
||||
|
||||
return actions.ASIS(callback) }],
|
||||
clearAbortable: ['- System/Clear abort handler(s)',
|
||||
doc`Clear abort handler(s)
|
||||
|
||||
Clear abort handler...
|
||||
.clearAbortable(title, callback)
|
||||
|
||||
Clear all abort handlers for title...
|
||||
.clearAbortable(title)
|
||||
.clearAbortable(title, 'all')
|
||||
|
||||
Clear all abort handlers...
|
||||
.clearAbortable('all')
|
||||
|
||||
`,
|
||||
function(title, callback){
|
||||
callback = callback || '*'
|
||||
|
||||
// clear all...
|
||||
if(title == '*' || title == 'all'){
|
||||
delete this.__abortable }
|
||||
|
||||
var set = ((this.__abortable || new Map()).get(title) || new Set())
|
||||
// clear specific handler...
|
||||
callback != '*'
|
||||
&& callback != 'all'
|
||||
&& set.delete(callback)
|
||||
// cleanup / clear title...
|
||||
;(set.size == 0
|
||||
|| callback == '*'
|
||||
|| callback == 'all')
|
||||
&& (this.__abortable || new Set()).delete(title)
|
||||
// cleanup...
|
||||
this.__abortable
|
||||
&& this.__abortable.size == 0
|
||||
&& (delete this.__abortable) }],
|
||||
abort: ['- System/Abort task(s)',
|
||||
doc`
|
||||
|
||||
.abort(title)
|
||||
.abort([title, .. ])
|
||||
|
||||
.abort('all')
|
||||
|
||||
`,
|
||||
function(title, task='all'){
|
||||
title = title == '*' || title == 'all' ?
|
||||
[...(this.__abortable || new Map()).keys()]
|
||||
: title instanceof Array ?
|
||||
title
|
||||
: [title]
|
||||
|
||||
this.__abortable
|
||||
&& title
|
||||
.forEach(function(title){
|
||||
[...(this.__abortable || new Map()).get(title) || []]
|
||||
.forEach(function(f){ f() })
|
||||
this.__abortable
|
||||
&& this.__abortable.delete(title) }.bind(this))
|
||||
// cleanup...
|
||||
this.__abortable
|
||||
&& this.__abortable.size == 0
|
||||
&& (delete this.__abortable) }],
|
||||
})
|
||||
|
||||
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
(function(require){ var module={} // make module AMD/node compatible...
|
||||
/*********************************************************************/
|
||||
|
||||
var array = require('lib/types/Array')
|
||||
|
||||
var actions = require('lib/actions')
|
||||
var features = require('lib/features')
|
||||
|
||||
@ -248,21 +246,36 @@ var SharpActions = actions.Actions({
|
||||
NOTE: all options are optional.
|
||||
NOTE: this will not overwrite existing images.
|
||||
`,
|
||||
core.abortablePromise('makeResizedImage', function(abort, images, size, path, options={}){
|
||||
core.taskAction('makeResizedImage', function(ticket, images, size, path, options={}){
|
||||
var that = this
|
||||
|
||||
// sanity check...
|
||||
if(arguments.length < 3){
|
||||
if(arguments.length < 4){
|
||||
ticket.reject()
|
||||
throw new Error('.makeResizedImage(..): '
|
||||
+'need at least images, size and path.') }
|
||||
|
||||
var CHUNK_SIZE = 4
|
||||
|
||||
abort.cleanup(function(reason, res){
|
||||
// setup runtime interactions...
|
||||
//
|
||||
// NOTE: we will resolve the ticket when we are fully done
|
||||
// and not on stop...
|
||||
var STOP = false
|
||||
ticket
|
||||
.onmessage('stop', function(){
|
||||
STOP = true })
|
||||
.then(function(){
|
||||
// close progress bar...
|
||||
// NOTE: if we have multiple tasks let the last one
|
||||
// close the progress bar...
|
||||
if(that.tasks.titled(ticket.title).length == 0){
|
||||
logger
|
||||
&& logger.emit('done')
|
||||
&& reason == 'aborted'
|
||||
&& logger.emit(res) })
|
||||
&& logger.emit('close') }
|
||||
// cleanup...
|
||||
delete that.__cache_metadata_reading })
|
||||
var abort = function(){
|
||||
that.tasks.stop(ticket.title) }
|
||||
|
||||
var CHUNK_SIZE = 4
|
||||
|
||||
// get/normalize images...
|
||||
//images = images || this.current
|
||||
@ -316,7 +329,8 @@ var SharpActions = actions.Actions({
|
||||
logger = logger !== false ?
|
||||
(logger || this.logger)
|
||||
: false
|
||||
logger = logger && logger.push('Resize', {onclose: abort})
|
||||
logger = logger
|
||||
&& logger.push('Resize', {onclose: abort})
|
||||
|
||||
// backup...
|
||||
// XXX make backup name pattern configurable...
|
||||
@ -328,8 +342,8 @@ var SharpActions = actions.Actions({
|
||||
|
||||
return images
|
||||
.mapChunks(CHUNK_SIZE, function(gid){
|
||||
if(abort.isAborted){
|
||||
throw array.STOP('aborted') }
|
||||
if(STOP){
|
||||
throw Array.STOP('aborted') }
|
||||
|
||||
// skip non-images...
|
||||
if(!['image', null, undefined]
|
||||
@ -413,13 +427,13 @@ var SharpActions = actions.Actions({
|
||||
&& logger.emit('done', to)
|
||||
return img }) }) }) })
|
||||
.then(function(res){
|
||||
ticket.resolve(res)
|
||||
return res == 'aborted' ?
|
||||
Promise.reject('aborted')
|
||||
: res }) })],
|
||||
|
||||
// XXX this does not update image.base_path -- is this correct???
|
||||
// XXX add support for offloading the processing to a thread/worker...
|
||||
// XXX should we use task.Queue()???
|
||||
makePreviews: ['Sharp|File/Make image $previews',
|
||||
core.doc`Make image previews
|
||||
|
||||
@ -447,27 +461,43 @@ var SharpActions = actions.Actions({
|
||||
NOTE: if base_path is given .images will not be updated with new
|
||||
preview paths...
|
||||
`,
|
||||
core.abortablePromise('makePreviews', function(abort, images, sizes, base_path, logger){
|
||||
core.taskAction('makePreviews', function(ticket, images, sizes, base_path, logger){
|
||||
var that = this
|
||||
|
||||
var CHUNK_SIZE = 4
|
||||
|
||||
abort.cleanup(function(reason, res){
|
||||
// setup runtime interactions...
|
||||
//
|
||||
// NOTE: we will resolve the ticket when we are fully done
|
||||
// and not on stop...
|
||||
var STOP = false
|
||||
ticket
|
||||
.onmessage('stop', function(){
|
||||
STOP = true })
|
||||
.then(function(){
|
||||
// close progress bar...
|
||||
// NOTE: if we have multiple tasks let the last one
|
||||
// close the progress bar...
|
||||
if(that.tasks.titled(ticket.title).length == 0){
|
||||
gid_logger
|
||||
&& gid_logger.emit('done')
|
||||
&& reason == 'aborted'
|
||||
&& gid_logger.emit(res)
|
||||
&& gid_logger.emit('close')
|
||||
logger
|
||||
&& logger.emit('done')
|
||||
&& reason == 'aborted'
|
||||
&& logger.emit(res) })
|
||||
&& logger.emit('close') }
|
||||
// cleanup...
|
||||
delete that.__cache_metadata_reading })
|
||||
var abort = function(){
|
||||
that.tasks.stop(ticket.title) }
|
||||
|
||||
var CHUNK_SIZE = 4
|
||||
|
||||
var logger_mode = this.config['preview-progress-mode'] || 'gids'
|
||||
logger = logger !== false ?
|
||||
(logger || this.logger)
|
||||
: false
|
||||
var gid_logger = logger && logger.push('Images', {onclose: abort})
|
||||
logger = logger && logger.push('Previews', {onclose: abort})
|
||||
var gid_logger = logger
|
||||
&& logger.push('Images',
|
||||
{onclose: abort})
|
||||
logger = logger
|
||||
&& logger.push('Previews',
|
||||
{onclose: abort})
|
||||
|
||||
// get/normalize images...
|
||||
images = images
|
||||
@ -506,8 +536,8 @@ var SharpActions = actions.Actions({
|
||||
|
||||
return images
|
||||
.mapChunks(CHUNK_SIZE, function(gid){
|
||||
if(abort.isAborted){
|
||||
throw array.STOP('aborted') }
|
||||
if(STOP){
|
||||
throw Array.STOP('aborted') }
|
||||
|
||||
var img = that.images[gid]
|
||||
var base = base_path
|
||||
@ -516,8 +546,8 @@ var SharpActions = actions.Actions({
|
||||
|
||||
return sizes
|
||||
.map(function(size, i){
|
||||
if(abort.isAborted){
|
||||
throw array.STOP('aborted') }
|
||||
if(STOP){
|
||||
throw Array.STOP('aborted') }
|
||||
|
||||
var name = path = path_tpl
|
||||
.replace(/\$RESOLUTION|\$\{RESOLUTION\}/g, parseInt(size))
|
||||
@ -548,12 +578,12 @@ var SharpActions = actions.Actions({
|
||||
|
||||
return [gid, size, name] }) }) })
|
||||
.then(function(res){
|
||||
ticket.resolve(res)
|
||||
return res == 'aborted' ?
|
||||
Promise.reject('aborted')
|
||||
: res.flat() }) })],
|
||||
|
||||
// XXX add support for offloading the processing to a thread/worker...
|
||||
// XXX should we use task.Queue()???
|
||||
__cache_metadata_reading: null,
|
||||
cacheMetadata: ['- Sharp|Image/',
|
||||
core.doc`Cache metadata
|
||||
@ -602,21 +632,38 @@ var SharpActions = actions.Actions({
|
||||
NOTE: this will effectively update metadata format to the new spec...
|
||||
NOTE: for info on full metadata format see: .readMetadata(..)
|
||||
`,
|
||||
core.abortablePromise('cacheMetadata', function(abort, images, logger){
|
||||
core.sessionTaskAction('cacheMetadata', function(ticket, images, logger){
|
||||
var that = this
|
||||
|
||||
var CHUNK_SIZE = 4
|
||||
|
||||
// XXX this seems to be called prematurely...
|
||||
abort.cleanup(function(reason, res){
|
||||
console.log('### ABORT:\n ',
|
||||
logger && logger.log.length,
|
||||
reason, res)
|
||||
// setup runtime interactions...
|
||||
//
|
||||
// NOTE: we will resolve the ticket when we are fully done
|
||||
// and not on stop...
|
||||
var STOP = false
|
||||
ticket
|
||||
.onmessage('stop', function(){
|
||||
STOP = true })
|
||||
.then(function(){
|
||||
// close progress bar...
|
||||
// NOTE: if we have multiple tasks let the last one
|
||||
// close the progress bar...
|
||||
if(that.tasks.titled(ticket.title).length == 0){
|
||||
logger
|
||||
&& logger.emit('close')
|
||||
&& reason == 'aborted'
|
||||
&& logger.emit(res)
|
||||
&& logger.emit('close') }
|
||||
that.off('clear', on_close)
|
||||
// cleanup...
|
||||
delete that.__cache_metadata_reading })
|
||||
// clear the progress bar for the next session...
|
||||
var on_close
|
||||
this.one('clear', on_close = function(){
|
||||
logger && logger.emit('close') })
|
||||
|
||||
// universal task abort...
|
||||
// NOTE: this will abort all the tasks of this type...
|
||||
var abort = function(){
|
||||
that.tasks.stop(ticket.title) }
|
||||
|
||||
var CHUNK_SIZE = 4
|
||||
|
||||
// handle logging and processing list...
|
||||
// NOTE: these will maintain .__cache_metadata_reading helping
|
||||
@ -688,8 +735,8 @@ var SharpActions = actions.Actions({
|
||||
return images
|
||||
.mapChunks(CHUNK_SIZE, function(gid){
|
||||
// abort...
|
||||
if(abort.isAborted){
|
||||
throw array.STOP('aborted') }
|
||||
if(STOP){
|
||||
throw Array.STOP('aborted') }
|
||||
|
||||
var img = cached_images[gid]
|
||||
var path = img && that.getImagePath(gid)
|
||||
@ -770,9 +817,12 @@ var SharpActions = actions.Actions({
|
||||
|
||||
return done(gid) }) })
|
||||
.then(function(res){
|
||||
ticket.resolve(res)
|
||||
// XXX do we need this???
|
||||
return res == 'aborted' ?
|
||||
Promise.reject('aborted')
|
||||
: res }) })],
|
||||
: res
|
||||
}) })],
|
||||
cacheAllMetadata: ['- Sharp|Image/',
|
||||
core.doc`Cache all metadata
|
||||
NOTE: this is a shorthand to .cacheMetadata('all', ..)`,
|
||||
@ -781,12 +831,13 @@ var SharpActions = actions.Actions({
|
||||
|
||||
// shorthands...
|
||||
// XXX do we need these???
|
||||
// ...better have a task manager UI...
|
||||
abortMakeResizedImage: ['- Sharp/',
|
||||
'abort: "makeResizedImage"'],
|
||||
'tasks.stop: "makeResizedImage"'],
|
||||
abortMakePreviews: ['- Sharp/',
|
||||
'abort: "makePreviews"'],
|
||||
'tasks.stop: "makePreviews"'],
|
||||
abortCacheMetadata: ['- Sharp/',
|
||||
'abort: "cacheMetadata"'],
|
||||
'tasks.stop: "cacheMetadata"'],
|
||||
})
|
||||
|
||||
|
||||
@ -806,15 +857,6 @@ module.Sharp = core.ImageGridFeatures.Feature({
|
||||
isApplicable: function(){ return !!sharp },
|
||||
|
||||
handlers: [
|
||||
// XXX
|
||||
['load.pre',
|
||||
function(){
|
||||
this.abort([
|
||||
'makeResizedImage',
|
||||
'makePreviews',
|
||||
'cacheMetadata',
|
||||
]) }],
|
||||
|
||||
//* XXX this needs to be run in the background...
|
||||
// XXX this is best done in a thread + needs to be abortable (on .load(..))...
|
||||
[['loadImages',
|
||||
|
||||
8
Viewer/package-lock.json
generated
8
Viewer/package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ImageGrid.Viewer.g4",
|
||||
"version": "4.0.0-a",
|
||||
"version": "4.0.0a",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -1110,9 +1110,9 @@
|
||||
"integrity": "sha512-9kZM80Js9/eTwXN9VXwLDC1wDJ7gIAdYU9GIzb5KJmNcLAMaW+zhgFrwFFMrcSfggUuadgnqSrS41E4XLe8JZw=="
|
||||
},
|
||||
"ig-types": {
|
||||
"version": "5.0.14",
|
||||
"resolved": "https://registry.npmjs.org/ig-types/-/ig-types-5.0.14.tgz",
|
||||
"integrity": "sha512-j4oyqZP+xasNYMyWllcZz5kT8vscB58P6smehoBEHxNRPlKMqfZTP4MlxQVZpyAgPH8HCCwGjEYZ7c63FokWFA==",
|
||||
"version": "5.0.17",
|
||||
"resolved": "https://registry.npmjs.org/ig-types/-/ig-types-5.0.17.tgz",
|
||||
"integrity": "sha512-A4qzL3t+usOnPx7tu+ieUDQIDUBEocouv7O6aBbLTcleDM5VNDOrdswfThNk3PSoP1bTSLmQV9LWsBRG1qVXiA==",
|
||||
"requires": {
|
||||
"ig-object": "^5.4.12",
|
||||
"object-run": "^1.0.1"
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
"ig-argv": "^2.15.0",
|
||||
"ig-features": "^3.4.2",
|
||||
"ig-object": "^5.4.12",
|
||||
"ig-types": "^5.0.14",
|
||||
"ig-types": "^5.0.17",
|
||||
"moment": "^2.29.1",
|
||||
"object-run": "^1.0.1",
|
||||
"requirejs": "^2.3.6",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user