reworked core.Tasks, almost ready to remove legacy code...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2020-11-26 00:44:46 +03:00
parent d3e54c83ac
commit e9a3192335
6 changed files with 119 additions and 249 deletions

View File

@ -51,6 +51,8 @@
// XXX
var DEBUG = typeof(DEBUG) != 'undefined' ? DEBUG : true
var types = require('lib/types')
var runner = require('lib/types/runner')
var util = require('lib/util')
var object = require('lib/object')
var actions = require('lib/actions')
@ -59,6 +61,7 @@ var toggler = require('lib/toggler')
/*********************************************************************/
// NOTE: if no toggler state is set this assumes that the first state
@ -964,9 +967,7 @@ var LifeCycleActions = actions.Actions({
evt.indexOf('stopped.pre'),
evt.indexOf('stopped.post')) >= 0
&& this.isStopped()
&& func.call(this)
}
}],
&& func.call(this) } }],
// helpers...
restart: ['System/Soft restart',
@ -2350,8 +2351,8 @@ module.Workspace = ImageGridFeatures.Feature({
// XXX should this be a separate module???
//var tasks = require('lib/tasks')
var task =
module.tast =
var Task =
module.Tast =
function(func){
func.__task__ = true
return func }
@ -2393,11 +2394,12 @@ function(func){
// - list/sort/prioritize
// - remote (peer/worker)
// XXX docs...
// XXX LEGACY...
var abortablePromise =
module.abortablePromise =
function(title, func){
return Object.assign(
task(function(...args){
Task(function(...args){
var that = this
var abort = object.mixinFlat(
@ -2440,96 +2442,33 @@ function(title, func){
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
var Task =
module.Task =
object.Constructor('Task', {
})
// XXX
var events = require('lib/types/event')
// Task action action helpers...
//
// NOTE: for examples see:
// features/examples.js:
// ExampleActions.exampleTask(..)
// ExampleActions.exampleSessionTask(..)
var taskAction =
module.taskAction =
function(title, func){
var action
return (action = Object.assign(
task(function(...args){
var that = this
// XXX
var ticket = events.EventMixin({
// can be:
// - ready
// - running
// - done
state: null,
start: events.Event('start', function(handle, ...args){
if(this.state == 'ready'){
that.resumeTask(title, action)
handle(...args) } }),
pause: events.Event('pause', function(handle, ...args){
if(this.state == 'running'){
that.pauseTask(title, action)
handle(...args) } }),
abort: events.Event('abort', function(handle, ...args){
if(!this.state != 'done'){
that.abortTask(title, action)
handle(...args) } }),
})
// XXX
return func.call(this, ticket, ...args) }),
return (action = object.mixin(
Task(function(...args){
return this.tasks.Task(title, func.bind(this), ...args) }),
{
__task_title__: title,
toString: function(){
return `core.taskAction('${ title }', \n${ func.toString() })` },
return `core.taskAction('${ title }', \n\t${
object.normalizeIndent('\t'+func.toString()) })` },
})) }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
var makeTaskAction =
function(name, from, to, callback){
return function(title, task='all'){
title = title == '*' || title == 'all' ?
[...(this.__running_tasks || new Map()).keys()]
: title instanceof Array ?
title
: [title]
this.__running_tasks
&& title
.forEach(function(title){
[...(this.__running_tasks || new Map()).get(title) || []]
.forEach(function(t){
// filter task...
;(task == 'all'
|| task == '*'
|| task === t
|| (task instanceof Array
&& task.includes(t)))
// filter states...
&& (from == '*'
|| from == 'all'
|| t.state == from)
// XXX do we retrigger???
//&& t.state != to
// call handler...
&& t[name]
&& t[name]() !== false
// state...
&& to
&& (t.state = to) })
callback
&& callback.call(this, title, task) }.bind(this))
// cleanup...
this.__running_tasks
&& this.__running_tasks.size == 0
&& (delete this.__running_tasks) } }
var sessionTaskAction =
module.sessionTaskAction =
function(title, func){
return object.mixin(
taskAction(...arguments),
{ __session_task__: true }) }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -2538,120 +2477,30 @@ var TaskActions = actions.Actions({
config: {
},
// Format:
// Map({
// title: Set([
// {
// state: ...,
// abort: func,
// pause: func,
// resume: func,
// ...
// },
// ...
// ]),
// ...
// })
// actions that generate tasks...
//
__running_tasks: null,
// XXX cache these???
get taskActions(){
return this.actions
.filter(function(action){
return !!this.getActionAttr(action, '__task__') }.bind(this)) },
get sessionTaskActions(){
return this.actions
.filter(function(action){
return !!this.getActionAttr(action, '__session_task__') }.bind(this)) },
// XXX should this .resume(..)???
// XXX might be a good idea to make this compatible with tasks.Queue(..)
// ...and return a queue if not task is given??
Task: ['- System/',
doc`
`,
function(title, task){
// reserved titles...
if(title == 'all' || title == '*'){
throw new Error('.abortable(..): can not set reserved title: "'+ title +'".') }
var tasks = this.__running_tasks = this.__running_tasks || new Map()
var set = tasks.get(title) || new Set()
tasks.set(title, set)
set.add(task)
task.state = 'running'
return task }],
getTasks: ['- System/',
function(title='all', state='all'){
var normArg = function(arg){
return !arg ?
'all'
: arg == 'all' || arg == '*' ?
arg
: arg instanceof Array ?
new Set(arg)
: new Set([arg]) }
title = normArg(title)
state = normArg(state)
return this.__running_tasks ?
[...this.__running_tasks.entries()]
.reduce(function(res, [t, set]){
if(title != 'all'
&& title != '*'
&& !title.has(t)){
return res }
var l = [...set]
.filter(function(t){
return state == 'all'
|| state == '*'
|| state.has(t.state) })
l.length > 0
&& (res[t] = l)
return res }, {})
: {} }],
// XXX should this abort the cleared tasks???
// ...if not would be logical to rename this to ._clearTask(..)
clearTask: ['- System/',
function(title, task='all'){
// clear all...
if(title == '*' || title == 'all'){
delete this.__running_tasks }
var set = ((this.__running_tasks || new Map()).get(title) || new Set())
// clear specific handler...
task != '*'
&& task != 'all'
&& set.delete(task)
// cleanup / clear title...
;(set.size == 0
|| task == '*'
|| task == 'all')
&& (this.__running_tasks || new Set()).delete(title)
// cleanup...
this.__running_tasks
&& this.__running_tasks.size == 0
&& (delete this.__running_tasks) }],
// XXX cache???
// task manager...
//
__task_manager__: runner.TaskManager,
__tasks: null,
get tasks(){
return this.actions.filter(function(action){
return !!this.getActionAttr(action, '__task__') }.bind(this)) },
return (this.__tasks =
this.__tasks
|| this.__task_manager__()) },
// session tasks are stopped when the index is cleared...
get sessionTasks(){
return this.tasks.titled(...this.sessionTaskActions) },
get tasksActive(){
return this.getTasks() },
get tasksRunning(){
return this.getTasks('all', 'running') },
get tasksPaused(){
return this.getTasks('all', 'paused') },
pauseTask: ['- System/',
makeTaskAction('pause', 'running', 'paused')],
resumeTask: ['- System/',
makeTaskAction('resume', 'paused', 'running')],
abortTask: ['- System/',
makeTaskAction('abort', 'all', null,
function(title, task='all'){
this.__running_tasks
&& (task == 'all'
|| task == '*'
|| this.__running_tasks.get(title).size == 0)
&& this.__running_tasks.delete(title) })],
// XXX LEGACY -- remove after migrating sharp.js and abortablePromise(..)
@ -2748,25 +2597,6 @@ var TaskActions = actions.Actions({
this.__abortable
&& this.__abortable.size == 0
&& (delete this.__abortable) }],
/* XXX LEGACY...
get jobs(){
return this.__jobs },
getJob: ['- Jobs/',
function(name){
name = name || this.data.newGID()
// get/init task dict...
var t = this.__jobs = this.__jobs || {}
// get/init task...
var job = t[name] = t[name] || tasks.Queue()
job.name = name
return job
}],
//*/
})
@ -2781,6 +2611,8 @@ module.Tasks = ImageGridFeatures.Feature({
actions: TaskActions,
handlers: [
['clear',
'sessionTasks.stop'],
],
})

View File

@ -267,14 +267,41 @@ var ExampleActions = actions.Actions({
// XXX inner/outer action...
// NOTE: action name and task name should be the same to avoid
// confusion...
// XXX it would be quite complicated to support both and
// confusing to support either...
exampleTask: ['- Test/',
core.taskAction('Example task', function(ticket, ...args){
core.taskAction('exampleTask',
function(ticket, ...args){
console.log('###', ticket.title+':', 'START:', ...args,
'\n\t\t(supported messages: "stop", "break", "error", ...)')
ticket.onmessage(function(msg, ...args){
// stop...
if(msg == 'stop'){
console.log('###', ticket.title+':', 'STOP')
ticket.resolve(...args)
// XXX
console.log('>>>>', ticket, ...args)
// break...
} else if(msg == 'break'){
console.log('###', ticket.title+':', 'BREAK')
ticket.reject(...args)
return Promise.cooperative()
})],
// error...
} else if(msg == 'error'){
console.log('###', ticket.title+':', 'ERROR')
throw new Error('Task error')
// other...
} else {
console.log('###', ticket.title+':', 'Got message:', msg, ...args) } }) })],
exampleSessionTask: ['- Test/',
core.sessionTaskAction('exampleSessionTask',
function(ticket, ...args){
console.log('###', ticket.title+':', 'START:', ...args)
ticket.onmessage('stop', function(){
console.log('###', ticket.title+':', 'STOP:', ...args)
ticket.resolve(...args) }) })],
})
var Example =

View File

@ -411,7 +411,11 @@ var SharpActions = actions.Actions({
.then(function(){
logger
&& logger.emit('done', to)
return img }) }) }) }) })],
return img }) }) }) })
.then(function(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...
@ -544,7 +548,9 @@ var SharpActions = actions.Actions({
return [gid, size, name] }) }) })
.then(function(res){
return res.flat() }) })],
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()???
@ -762,7 +768,11 @@ var SharpActions = actions.Actions({
that.ribbons
&& that.ribbons.updateImage(gid)
return done(gid) }) }) })],
return done(gid) }) })
.then(function(res){
return res == 'aborted' ?
Promise.reject('aborted')
: res }) })],
cacheAllMetadata: ['- Sharp|Image/',
core.doc`Cache all metadata
NOTE: this is a shorthand to .cacheMetadata('all', ..)`,

View File

@ -90,6 +90,7 @@ var ProgressActions = actions.Actions({
// XXX multiple containers...
// XXX shorten the nested css class names...
// XXX revise styles...
// XXX make the "X" bigger -- finger usable...
__progress_cache: null,
showProgress: ['- Interface/Show progress bar...',
core.doc`Progress bar widget...
@ -201,7 +202,7 @@ var ProgressActions = actions.Actions({
.append($('<progress/>'))
// events...
.on('progressClose', function(){
widget
$(this)
.fadeOut(that.config['progress-fade-duration'] || 200, function(){
var cache = (that.__progress_cache || {})[text]
cache.timeout

View File

@ -1,6 +1,6 @@
{
"name": "ImageGrid.Viewer.g4",
"version": "4.0.0a",
"version": "4.0.0-a",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -549,9 +549,9 @@
}
},
"debug": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
"integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"requires": {
"ms": "2.1.2"
}
@ -636,9 +636,9 @@
}
},
"electron": {
"version": "9.3.4",
"resolved": "https://registry.npmjs.org/electron/-/electron-9.3.4.tgz",
"integrity": "sha512-OHP8qMKgW8D8GtH+altB22WJw/lBOyyVdoz5e8D0/iPBmJU3Jm93vO4z4Eh/9DvdSXlH8bMHUCMLL9PVW6f+tw==",
"version": "9.3.5",
"resolved": "https://registry.npmjs.org/electron/-/electron-9.3.5.tgz",
"integrity": "sha512-EPmDsp7sO0UPtw7nLD1ufse/nBskP+ifXzBgUg9psCUlapkzuwYi6pmLAzKLW/bVjwgyUKwh1OKWILWfOeLGcQ==",
"requires": {
"@electron/get": "^1.0.1",
"@types/node": "^12.0.12",
@ -646,9 +646,9 @@
},
"dependencies": {
"@types/node": {
"version": "12.19.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.4.tgz",
"integrity": "sha512-o3oj1bETk8kBwzz1WlO6JWL/AfAA3Vm6J1B3C9CsdxHYp7XgPiH7OEXPUbZTndHlRaIElrANkQfe6ZmfJb3H2w=="
"version": "12.19.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.6.tgz",
"integrity": "sha512-U2VopDdmBoYBmtm8Rz340mvvSz34VgX/K9+XCuckvcLGMkt3rbMX8soqFOikIPlPBc5lmw8By9NUK7bEFSBFlQ=="
}
}
},
@ -1073,9 +1073,9 @@
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
},
"ig-actions": {
"version": "3.24.13",
"resolved": "https://registry.npmjs.org/ig-actions/-/ig-actions-3.24.13.tgz",
"integrity": "sha512-x7+37fJ1wsdSl/VNb4W569IHiUx2SKtEr76PI6LxXOW3fRkv6/9KnDXJK8pL+XVO012oj096WatYK80aPUlLPQ==",
"version": "3.24.15",
"resolved": "https://registry.npmjs.org/ig-actions/-/ig-actions-3.24.15.tgz",
"integrity": "sha512-fhMZ1F34nPm/Hir1Is+3hKPJpshgwbxjnQRJb5M+/fs52FfoG7TMbDYWzbKKe6qtwfyrcVD2rPRidjCl6779zQ==",
"requires": {
"ig-object": "^5.0.2"
}
@ -1105,16 +1105,16 @@
}
},
"ig-object": {
"version": "5.4.11",
"resolved": "https://registry.npmjs.org/ig-object/-/ig-object-5.4.11.tgz",
"integrity": "sha512-WPPQ5C41c6q3tPfa2fBbWE2xcLF7LoGRu2E6Wr/aoA5oxAyl8lAuE7Kqt4TyPwfW9jVI0+ifBztg9e1tR5mG1Q=="
"version": "5.4.12",
"resolved": "https://registry.npmjs.org/ig-object/-/ig-object-5.4.12.tgz",
"integrity": "sha512-9kZM80Js9/eTwXN9VXwLDC1wDJ7gIAdYU9GIzb5KJmNcLAMaW+zhgFrwFFMrcSfggUuadgnqSrS41E4XLe8JZw=="
},
"ig-types": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/ig-types/-/ig-types-4.1.2.tgz",
"integrity": "sha512-IYnuBWw7m7qvtW21ggoodFA++v+bHwNMqGRvo9w2IwfI3leVPbOORUC5CjUKb4q/ffGlCcT3gC7w+E/aO8BOTw==",
"version": "5.0.14",
"resolved": "https://registry.npmjs.org/ig-types/-/ig-types-5.0.14.tgz",
"integrity": "sha512-j4oyqZP+xasNYMyWllcZz5kT8vscB58P6smehoBEHxNRPlKMqfZTP4MlxQVZpyAgPH8HCCwGjEYZ7c63FokWFA==",
"requires": {
"ig-object": "^5.4.11",
"ig-object": "^5.4.12",
"object-run": "^1.0.1"
}
},

View File

@ -20,7 +20,7 @@
"dependencies": {
"app-module-path": "^1.0.6",
"async-json": "0.0.2",
"electron": "^9.3.4",
"electron": "^9.3.5",
"exif-reader": "^1.0.3",
"exiftool": "^0.0.3",
"fs-extra": "^7.0.1",
@ -28,11 +28,11 @@
"generic-walk": "^1.4.0",
"glob": "^7.1.6",
"guarantee-events": "^1.0.0",
"ig-actions": "^3.24.13",
"ig-actions": "^3.24.15",
"ig-argv": "^2.15.0",
"ig-features": "^3.4.2",
"ig-object": "^5.4.11",
"ig-types": "^4.1.2",
"ig-object": "^5.4.12",
"ig-types": "^5.0.14",
"moment": "^2.29.1",
"object-run": "^1.0.1",
"requirejs": "^2.3.6",