Browse Source

Queue redone, minor improvements and optimized startup.

tags/v1.4.4
Ivan Bravo Bravo 9 months ago
parent
commit
e90fad2c4c

+ 1
- 1
src/components/Nudity/PhotoRun.vue View File

@@ -89,7 +89,7 @@
</div>

<!-- Maskfin Dialog -->
<dialog ref="maskfinDialog">
<dialog v-if="hasMaskfin" ref="maskfinDialog">
<div class="dialog__content dialog__maskfin">
<div class="maskfin__preview">
<img :src="run.maskfinFile.path">

+ 1
- 0
src/components/UI/AppPhoto.vue View File

@@ -42,6 +42,7 @@ export default {
img {
@apply w-full rounded-t shadow-md;
height: auto;
max-height: 300px;
}

.photo__label {

+ 1
- 1
src/components/UI/AppUpdate.vue View File

@@ -14,7 +14,7 @@

<!-- Update available -->
<box-item
v-else-if="!updater.update.active"
v-else
:label="`${projectTitle} ${updater.latest.tag_name} available.`"
icon="fire-alt"
class="update-item"

+ 4
- 0
src/modules/config/cli-errors.json View File

@@ -54,5 +54,9 @@
{
"query": "file not a supported format",
"message": "There was a problem loading the photo, please make sure it is not corrupt and is of a valid format."
},
{
"query": "The final result is not a valid image file",
"message": "The photo has been transformed but could not be saved. Please make sure you have enough disk space and that DreamTime can write to it."
}
]

+ 1
- 1
src/modules/file.js View File

@@ -127,6 +127,7 @@ export class File {
}

const metadata = await getMetadata(filepath)

return this.setMetadata(metadata)
}

@@ -174,7 +175,6 @@ export class File {
* @param {string} data
*/
async writeDataURL(data) {
console.log('writeDataURL', this.path, this)
fs.writeDataURL(this.path, data)
await this.open()


+ 2
- 2
src/modules/nudify/photo-run.js View File

@@ -246,7 +246,7 @@ export class PhotoRun {

this.process.on('fail', (fileError) => {
if (fileError) {
def.reject(new Warning(`Run ${this.id} failed!`, 'DreamPower has transformed the photo but could not save it.', fileError))
def.reject(new Warning(`Run ${this.id} has failed!`, 'The photo has been transformed but could not be saved. Please make sure you have enough disk space and that DreamTime can write to it.', fileError))
} else {
def.reject(this.getPowerError())
}
@@ -328,7 +328,7 @@ export class PhotoRun {
return null
}

const title = `Run ${this.id} has failed.`
const title = `Run ${this.id} has failed!`

const extra = {
terminal: this.cli.lines.map((item) => item.text),

+ 35
- 50
src/modules/nudify/photo.js View File

@@ -10,8 +10,7 @@
import {
cloneDeep, isNil, merge, isError,
} from 'lodash'
import Queue from 'better-queue'
import MemoryStore from 'better-queue-memory'
import { Queue } from '@dreamnet/queue'
import EventBus from 'js-event-bus'
import { settings } from '../system'
import { Consola, handleError } from '../consola'
@@ -333,58 +332,62 @@ export class Photo {
*
*/
setupQueue() {
/*
let maxTimeout = settings.processing.device === 'GPU' ? (3 * 60 * 1000) : (20 * 60 * 1000)

if (this.file.mimetype === 'image/gif') {
maxTimeout += (30 * 60 * 1000)
}
*/

this.queue = new Queue(this.queueTicket, {
maxTimeout,
afterProcessDelay: 500,
batchSize: 1,
concurrent: 1,
store: new MemoryStore,
})
this.queue = new Queue(this.worker)

this.queue.on('finished', () => {
if (this.runs.length === 0) {
this.status = 'pending'
} else {
this.onFinish()
}

this.queue.on('drain', () => {
this.onFinish()
this.consola.debug('Runs finished.')
this.consola.debug('🏁 Runs finished. 🏁')
})

this.queue.on('task_queued', (runId) => {
const run = this.getRunById(runId)
this.queue.on('task_added', (run) => {
run.onQueue()

this.onQueueRun()

this.consola.debug(`Run added: #${runId}`)
this.consola.debug(`📷 Run added: #${run.id}`)
})

this.queue.on('task_started', (runId) => {
const run = this.getRunById(runId)
this.queue.on('task_started', (run) => {
run.onStart()

this.consola.debug(`Run started: #${runId}`)
this.consola.debug(`🚗 Run started: #${run.id}`)
})

this.queue.on('task_finish', (runId) => {
const run = this.getRunById(runId)
this.queue.on('task_finished', (run) => {
run.onFinish()

this.consola.debug(`Run finished: #${runId}`)
this.consola.debug(`🏁 Run finished: #${run.id}`)
})

this.queue.on('task_failed', (runId, error) => {
const run = this.getRunById(runId)
this.queue.on('task_failed', (run, error) => {
run.onFail()

this.consola.warn(`Run failed: #${runId} ${error}`)
this.consola.warn(`💥 Run failed: #${run.id} ${error}`)

if (isError(error)) {
handleError(error)
}
})

this.queue.on('task_dropped', (run) => {
run.stop()
run.onFinish()

this.consola.debug(`⛔ Run dropped: ${run.id}`)
})
}

/**
@@ -407,10 +410,6 @@ export class Photo {
*/
cancel() {
NudifyQueue.cancel(this)

if (this.waiting) {
this.status = 'pending'
}
}

/**
@@ -440,11 +439,11 @@ export class Photo {
const run = new PhotoRun(it, this)

this.runs.push(run)
this.queue.push(run)
this.queue.add(run)
}

await new Promise((resolve) => {
this.queue.on('drain', () => {
this.queue.on('finished', () => {
resolve()
})
})
@@ -455,9 +454,7 @@ export class Photo {
* This should only be called from the queue.
*/
stop() {
this.runs.forEach((run) => {
this.cancelRun(run)
})
this.queue.clear()
}

/**
@@ -465,7 +462,7 @@ export class Photo {
* @param {PhotoRun} run
*/
addRun(run) {
this.queue.push(run)
this.queue.add(run)
}

/**
@@ -473,27 +470,15 @@ export class Photo {
* @param {PhotoRun} run
*/
cancelRun(run) {
this.queue.cancel(run.id)
this.queue.drop(run)
}

/**
*
* @param {PhotoRun} run
* @param {Function} done
*/
queueTicket(run, done) {
run.start().then(() => {
done()
return true
}).catch((error) => {
done(error)
})

return {
cancel() {
run.stop()
},
}
*/
worker(run) {
return run.start()
}

/**

+ 20
- 39
src/modules/nudify/queue.js View File

@@ -8,8 +8,7 @@
// Written by Ivan Bravo Bravo <ivan@dreamnet.tech>, 2020.

import { isError } from 'lodash'
import Queue from 'better-queue'
import MemoryStore from 'better-queue-memory'
import { Queue } from '@dreamnet/queue'
import { Consola, handleError } from '../consola'

const consola = Consola.create('queue')
@@ -28,67 +27,49 @@ export const NudifyQueue = {
*
*/
setup() {
this.queue = new Queue(this.queueTicket, {
maxTimeout: (3 * 60 * 60 * 1000), // 3 hours.
afterProcessDelay: 1000,
batchSize: 1,
concurrent: 1,
store: new MemoryStore,
})

const { Nudify } = require('./nudify')
this.queue = new Queue(this.worker)

this.queue.on('task_queued', (photoId) => {
const photo = Nudify.getPhotoById(photoId)
this.queue.on('task_added', (photo) => {
photo.onQueue()

consola.debug(`Photo added: ${photoId}`)
consola.debug(`📷 Photo added: ${photo.file.fullname}`)
})

this.queue.on('task_started', (photoId) => {
const photo = Nudify.getPhotoById(photoId)
this.queue.on('task_started', (photo) => {
photo.onStart()

consola.debug(`Photo started: #${photoId}`)
consola.debug(`🚗 Photo started: ${photo.file.fullname}`)
})

this.queue.on('task_finish', (photoId) => {
// const photo = Nudify.getPhotoById(photoId)
this.queue.on('task_finished', (photo) => {
// photo.onFinish()

consola.debug(`Photo transformed: ${photoId}`)
consola.debug(`🏁 Photo finished: ${photo.file.fullname}`)
})

this.queue.on('task_failed', (photoId, error) => {
const photo = Nudify.getPhotoById(photoId)
this.queue.on('task_failed', (photo, error) => {
photo.onFinish()

consola.debug(`Photo failed: ${photoId} ${error}`)
consola.debug(`💥 Photo failed: ${photo.file.fullname} ${error}`)

if (isError(error)) {
handleError(error)
}
})

this.queue.on('task_dropped', (photo) => {
photo.stop()

consola.debug(`⛔ Photo dropped: ${photo.id}`)
})
},

/**
*
* @param {Photo} photo
* @param {Function} done
*/
queueTicket(photo, done) {
photo.start().then(() => {
done()
return true
}).catch((error) => {
done(error)
})

return {
cancel() {
photo.stop()
},
}
worker(photo) {
return photo.start()
},

/**
@@ -96,7 +77,7 @@ export const NudifyQueue = {
* @param {Photo} photo
*/
add(photo) {
this.queue.push(photo)
this.queue.add(photo)
},

/**
@@ -104,6 +85,6 @@ export const NudifyQueue = {
* @param {Photo} photo
*/
cancel(photo) {
this.queue.cancel(photo.id)
this.queue.drop(photo)
},
}

+ 7
- 2
src/modules/services/logrocket.js View File

@@ -34,7 +34,7 @@ class LogRocketService extends BaseService {
* @type {boolean}
*/
get can() {
return isString(this.accessToken) && settings.telemetry.dom && process.env.name === 'production'
return isString(this.accessToken) && process.env.name === 'production'
}

/**
@@ -51,7 +51,11 @@ class LogRocketService extends BaseService {
return {
release: this.release,
shouldCaptureIP: false,
console: {
isEnabled: true,
},
network: {
isEnabled: true,
requestSanitizer(request) {
// the user does not want to send private dom.
privateExtensions.forEach((extension) => {
@@ -67,7 +71,8 @@ class LogRocketService extends BaseService {
},
},
dom: {
baseHref: $provider.ngrok.getAddress() || nucleus.urls?.internal?.cdn || null,
isEnabled: settings.telemetry?.dom || true,
baseHref: $provider.ngrok.getAddress() || nucleus.urls?.internal?.cdn,
},
}
}

+ 0
- 1
src/modules/timer.js View File

@@ -7,7 +7,6 @@
//
// Written by Ivan Bravo Bravo <ivan@dreamnet.tech>, 2020.

import { isNil } from 'lodash'
import dayjs from 'dayjs'
import { Consola } from './consola'


+ 37
- 33
src/modules/updater/base.js View File

@@ -43,12 +43,12 @@ export class BaseUpdater {
/**
* @type {Consola}
*/
_consola
consola

/**
* @type {axios.AxiosInstance}
*/
_http
http

/**
* @type {Object}
@@ -63,7 +63,11 @@ export class BaseUpdater {
/**
* @type {string}
*/
_currentVersion
_currentVersion = 'v0.0.0'

get currentVersion() {
return this._currentVersion
}

/**
* @type {Array}
@@ -71,9 +75,9 @@ export class BaseUpdater {
downloadUrls = []

/**
* @type {import('js-event-bus')}
* @type {EventEmitter}
*/
_downloadBus
downloadEvents

/**
* @type {Object}
@@ -123,17 +127,14 @@ export class BaseUpdater {
return this.latestCompatible?.tag_name || 'v0.0.0'
}

/**
* @type {string}
*/
get currentVersion() {
return this._currentVersion
}

/**
* @type {boolean}
*/
get available() {
if (!this.enabled) {
return false
}

return compareVersions.compare(this.latestCompatibleVersion, this.currentVersion, '>')
}

@@ -177,8 +178,11 @@ export class BaseUpdater {
})
}

/**
*
*/
constructor() {
this._consola = Consola.create(`updater:${this.name}`)
this.consola = Consola.create(`updater:${this.name}`)
}

/**
@@ -188,28 +192,28 @@ export class BaseUpdater {
this.enabled = false

if (!system.online) {
this._consola.warn('No internet connection.')
this.consola.warn('No internet connection.')
return
}

if (!nucleus.enabled) {
this._consola.warn('No connection with Nucleus.')
this.consola.warn('No connection with Nucleus.')
return
}

if (!this.can) {
this._consola.warn('Disabled.')
this.consola.warn('Disabled.')
return
}

try {
this._http = axios.create({
this.http = axios.create({
baseURL: `${GITHUB_API}/${this.githubRepo}`,
timeout: 3000,
})

await this._fetchReleases()
this._consola.info(`Current: ${this.currentVersion} - Latest Compatible: ${this.latestCompatibleVersion}`)
this.consola.info(`Current: ${this.currentVersion} - Latest Compatible: ${this.latestCompatibleVersion}`)

this.refresh()

@@ -219,7 +223,7 @@ export class BaseUpdater {
this.sendNotification()
}
} catch (err) {
this._consola.warn('Unable to fetch the latest version information.', err)
this.consola.warn('Unable to fetch the latest version information.', err)
}
}

@@ -303,7 +307,7 @@ export class BaseUpdater {
*
*/
async _fetchReleases() {
const response = await this._http.get('/releases')
const response = await this.http.get('/releases')

// only final releases
const releases = filter(response.data, {
@@ -366,7 +370,7 @@ export class BaseUpdater {

await this.install(filepath)
} catch (err) {
throw new Exception('The installation failed.', err)
throw new Exception('The installation failed.', 'There was a problem trying to install the downloaded file, please try again.', err)
}
}

@@ -395,7 +399,7 @@ export class BaseUpdater {

return filepath
} catch (err) {
this._consola.warn(`Unable to download update from: ${url}`, err).report()
this.consola.warn(`Unable to download update from: ${url}`, err).report()
continue
}
}
@@ -408,25 +412,25 @@ export class BaseUpdater {
* @param {string} url
*/
_downloadFrom(url) {
this._consola.info(`Downloading update from: ${url}`)
this.consola.info(`Downloading update from: ${url}`)
const def = deferred()

this._downloadBus = download(url, {
this.downloadEvents = download(url, {
filename: this.filename,
})

this._downloadBus.on('progress', (payload) => {
this.downloadEvents.on('progress', (payload) => {
this.update.progress = (payload.progress * 100).toFixed(2)
this.update.total = payload.total
this.update.written = payload.written
})

this._downloadBus.on('error', (err) => {
this._downloadBus = null
this.downloadEvents.on('error', (err) => {
this.downloadEvents = null
def.reject(err)
})

this._downloadBus.on('finish', (filepath) => {
this.downloadEvents.on('finish', (filepath) => {
const stats = statSync(filepath)
const size = filesize(stats.size, { exponent: 2, output: 'object' })

@@ -435,12 +439,12 @@ export class BaseUpdater {
def.reject(new Warning('Unable to download update.', 'The file is corrupt.'))
}

this._downloadBus = null
this.downloadEvents = null
def.resolve(filepath)
})

this._downloadBus.on('cancelled', () => {
this._downloadBus = null
this.downloadEvents.on('cancelled', () => {
this.downloadEvents = null
def.resolve()
})

@@ -451,11 +455,11 @@ export class BaseUpdater {
*
*/
cancel() {
if (isNil(this._downloadBus)) {
if (isNil(this.downloadEvents)) {
return
}

this._downloadBus.emit('cancel')
this.downloadEvents.emit('cancel')
}

/**

+ 1
- 1
src/nuxt.config.js View File

@@ -106,7 +106,7 @@ module.exports = {
/*
** Customize the progress-bar color
*/
loading: { color: '#fff' },
loading: { color: '#D67411' },

/*
** Global CSS

+ 2
- 2
src/package.json View File

@@ -53,6 +53,7 @@
"dependencies": {
"7zip-bin": "^5.0.3",
"@dreamnet/logplease": "^1.0.0",
"@dreamnet/queue": "^0.1.0",
"@fortawesome/fontawesome-svg-core": "^1.2.25",
"@fortawesome/free-brands-svg-icons": "^5.11.2",
"@fortawesome/free-regular-svg-icons": "^5.11.2",
@@ -60,7 +61,6 @@
"@fortawesome/vue-fontawesome": "^0.1.8",
"@sweetalert2/theme-dark": "^3.1.0",
"axios": "^0.19.0",
"better-queue": "^3.8.10",
"better-queue-memory": "^1.0.4",
"caller-callsite": "^4.1.0",
"combokeys": "^3.0.1",
@@ -155,4 +155,4 @@
"tailwindcss-alpha": "hacknug/tailwindcss-alpha#feature/tests",
"worker-loader": "^2.0.0"
}
}
}

+ 16
- 0
src/pages/wizard/power.vue View File

@@ -50,6 +50,7 @@

<div class="box__content">
<box-item
v-if="!isMacOS"
label="Device."
description="Device that will be used to transform photos and choose the appropriate version of DreamPower.">
<select v-model="$settings.processing.device" class="input">
@@ -62,6 +63,17 @@
</select>
</box-item>

<box-item
v-else
label="Device."
description="GPU is not available in macOS.">
<select v-model="$settings.processing.device" class="input" disabled>
<option value="CPU">
CPU
</option>
</select>
</box-item>

<box-item
label="Location."
description="Folder where DreamPower will be installed.">
@@ -110,6 +122,10 @@ export default {
}),

computed: {
isMacOS() {
return process.platform === 'darwin'
},

power() {
return nucleus.v1?.projects?.dreampower.about || {
title: 'DreamPower',

+ 8
- 2
src/plugins/binds.js View File

@@ -13,10 +13,16 @@ import {
} from '~/modules/consola'

const { getPath } = $provider.paths
const { fs } = $provider

// logger setup.
const logDate = new Date().toJSON().slice(0, 10)

const logDir = getPath('userData', 'logs', logDate)
fs.ensureDirSync(logDir)

Logger.setOptions({
filename: getPath('userData', 'logs', new Date().toJSON().slice(0, 10), 'renderer.log'),
filename: getPath('userData', 'logs', logDate, 'renderer.log'),
logLevel: process.env.LOG || 'debug',
})

@@ -32,6 +38,6 @@ window.LogEvent = LogEvent
window.Warning = Warning
window.Exception = Exception

export default ({ redirect, router }) => {
export default ({ redirect }) => {
window.$redirect = redirect
}

+ 22
- 13
src/plugins/boot.js View File

@@ -15,33 +15,42 @@ import { handleError } from '~/modules/consola'

// eslint-disable-next-line no-unused-vars
export default async ({ app }, inject) => {
// catch errors.
// Error Handlers.
window.addEventListener('error', (event) => handleError(event))

window.addEventListener('unhandledrejection', (rejection) => handleError(rejection.reason))

Vue.config.errorHandler = (err) => handleError(err)

// analytics.
// Analytics.
await nucleus.setup()

// bug and session tracking.
await Promise.all([
// Bug/Session tracking.
Promise.all([
rollbar.setup(),
logrocket.setup(),
])

// app requirements.
// Requirements check.
await requirements.setup()

// update providers.
await Promise.all([
dreamtime.setup(),
dreampower.setup(),
checkpoints.setup(),
])

// shortcuts.
// Update providers.
if (!requirements.power.installed || !requirements.power.checkpoints) {
// This information is needed for the wizard.
await Promise.all([
dreamtime.setup(),
dreampower.setup(),
checkpoints.setup(),
])
} else {
Promise.all([
dreamtime.setup(),
dreampower.setup(),
checkpoints.setup(),
])
}

// Shortcuts.
inject('provider', $provider)
inject('nucleus', nucleus)
}

+ 5
- 6
src/plugins/setup.js View File

@@ -32,24 +32,23 @@ export default ({ app }, inject) => {
const { Nudify, NudifyStore } = require('~/modules/nudify')
const { settings } = require('~/modules/system')

// settings.
// User settings.
app.$settings = settings
inject('settings', settings)

// dreamtime.
// DreamTime.
app.$dream = dream
inject('dream', dream)

// nudify.
// Nudification/Queue.
Nudify.setup()

// nudify store.
// Nudify store.
NudifyStore.setup()
inject('nudify', NudifyStore)

// achievements!
// Achievements.
achievements.setup()

// ready
consola.info('The front-end is ready!')
}

Loading…
Cancel
Save