Refactored http timeout handling.
This commit is contained in:
		
							parent
							
								
									36a8adbd8c
								
							
						
					
					
						commit
						336b91c872
					
				|  | @ -50,6 +50,20 @@ | ||||||
| 						icon="question2" | 						icon="question2" | ||||||
| 					/> | 					/> | ||||||
| 				</h2> | 				</h2> | ||||||
|  | 
 | ||||||
|  | 				<Icon | ||||||
|  | 					v-show="me && isStashed" | ||||||
|  | 					icon="heart7" | ||||||
|  | 					class="stash stashed noselect" | ||||||
|  | 					@click="unstashScene" | ||||||
|  | 				/> | ||||||
|  | 
 | ||||||
|  | 				<Icon | ||||||
|  | 					v-show="me && !isStashed" | ||||||
|  | 					icon="heart8" | ||||||
|  | 					class="stash unstashed noselect" | ||||||
|  | 					@click="stashScene" | ||||||
|  | 				/> | ||||||
| 			</div> | 			</div> | ||||||
| 
 | 
 | ||||||
| 			<div class="row associations"> | 			<div class="row associations"> | ||||||
|  | @ -223,7 +237,7 @@ import Actor from '../actors/tile.vue'; | ||||||
| import Releases from './releases.vue'; | import Releases from './releases.vue'; | ||||||
| import Scroll from '../scroll/scroll.vue'; | import Scroll from '../scroll/scroll.vue'; | ||||||
| 
 | 
 | ||||||
| async function fetchRelease() { | async function fetchRelease(scroll = true) { | ||||||
| 	if (this.$route.name === 'scene') { | 	if (this.$route.name === 'scene') { | ||||||
| 		this.release = await this.$store.dispatch('fetchReleaseById', this.$route.params.releaseId); | 		this.release = await this.$store.dispatch('fetchReleaseById', this.$route.params.releaseId); | ||||||
| 	} | 	} | ||||||
|  | @ -232,11 +246,37 @@ async function fetchRelease() { | ||||||
| 		this.release = await this.$store.dispatch('fetchMovieById', this.$route.params.releaseId); | 		this.release = await this.$store.dispatch('fetchMovieById', this.$route.params.releaseId); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (this.$refs.content) { | 	if (scroll && this.$refs.content) { | ||||||
| 		this.$refs.content.scrollTop = 0; | 		this.$refs.content.scrollTop = 0; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | async function stashScene() { | ||||||
|  | 	this.$store.dispatch('stashScene', { | ||||||
|  | 		sceneId: this.release.id, | ||||||
|  | 		stashId: this.$store.getters.favorites.id, | ||||||
|  | 	}); | ||||||
|  | 
 | ||||||
|  | 	this.fetchRelease(false); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | async function unstashScene() { | ||||||
|  | 	this.$store.dispatch('unstashScene', { | ||||||
|  | 		sceneId: this.release.id, | ||||||
|  | 		stashId: this.$store.getters.favorites.id, | ||||||
|  | 	}); | ||||||
|  | 
 | ||||||
|  | 	this.fetchRelease(false); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function me() { | ||||||
|  | 	return this.$store.state.auth.user; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function isStashed() { | ||||||
|  | 	return this.release.stashes?.length > 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| function bannerBackground() { | function bannerBackground() { | ||||||
| 	return (this.release.poster && this.getBgPath(this.release.poster, 'thumbnail')) | 	return (this.release.poster && this.getBgPath(this.release.poster, 'thumbnail')) | ||||||
| 		|| (this.release.covers.length > 0 && this.getBgPath(this.release.covers[0], 'thumbnail')); | 		|| (this.release.covers.length > 0 && this.getBgPath(this.release.covers[0], 'thumbnail')); | ||||||
|  | @ -271,6 +311,8 @@ export default { | ||||||
| 	computed: { | 	computed: { | ||||||
| 		pageTitle, | 		pageTitle, | ||||||
| 		bannerBackground, | 		bannerBackground, | ||||||
|  | 		isStashed, | ||||||
|  | 		me, | ||||||
| 		showAlbum, | 		showAlbum, | ||||||
| 	}, | 	}, | ||||||
| 	watch: { | 	watch: { | ||||||
|  | @ -279,6 +321,8 @@ export default { | ||||||
| 	mounted: fetchRelease, | 	mounted: fetchRelease, | ||||||
| 	methods: { | 	methods: { | ||||||
| 		fetchRelease, | 		fetchRelease, | ||||||
|  | 		stashScene, | ||||||
|  | 		unstashScene, | ||||||
| 	}, | 	}, | ||||||
| }; | }; | ||||||
| </script> | </script> | ||||||
|  | @ -353,6 +397,22 @@ export default { | ||||||
| 	color: var(--shadow); | 	color: var(--shadow); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .stash.icon { | ||||||
|  | 	width: 1.5rem; | ||||||
|  | 	height: 1.5rem; | ||||||
|  | 	padding: 0 1rem; | ||||||
|  | 	fill: var(--darken); | ||||||
|  | 
 | ||||||
|  | 	&.stashed { | ||||||
|  | 		fill: var(--primary); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	&:hover { | ||||||
|  | 		fill: var(--primary); | ||||||
|  | 		cursor: pointer; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .album-toggle { | .album-toggle { | ||||||
| 	height: fit-content; | 	height: fit-content; | ||||||
| 	display: inline-flex; | 	display: inline-flex; | ||||||
|  |  | ||||||
|  | @ -346,6 +346,21 @@ const releaseFragment = ` | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	stashes: stashesScenesBySceneId( | ||||||
|  | 		filter: { | ||||||
|  | 			stash: { | ||||||
|  | 				userId: { | ||||||
|  | 					equalTo: $userId | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	) @include(if: $hasAuth) { | ||||||
|  | 		stash { | ||||||
|  | 			id | ||||||
|  | 			name | ||||||
|  | 			slug | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|   } |   } | ||||||
| `;
 | `;
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -37,11 +37,17 @@ function initReleasesActions(store, router) { | ||||||
| 		// const release = await get(`/releases/${releaseId}`);
 | 		// const release = await get(`/releases/${releaseId}`);
 | ||||||
| 
 | 
 | ||||||
| 		const { release } = await graphql(` | 		const { release } = await graphql(` | ||||||
|             query Release($releaseId:Int!) { |             query Release( | ||||||
|  | 				$releaseId: Int! | ||||||
|  | 				$hasAuth: Boolean! | ||||||
|  | 				$userId: Int | ||||||
|  | 			) { | ||||||
|                 ${releaseFragment} |                 ${releaseFragment} | ||||||
|             } |             } | ||||||
|         `, {
 |         `, {
 | ||||||
| 			releaseId: Number(releaseId), | 			releaseId: Number(releaseId), | ||||||
|  | 			hasAuth: !!store.state.auth.user, | ||||||
|  | 			userId: store.state.auth.user?.id, | ||||||
| 		}); | 		}); | ||||||
| 
 | 
 | ||||||
| 		if (!release) { | 		if (!release) { | ||||||
|  |  | ||||||
|  | @ -9,9 +9,19 @@ function initStashesActions(_store, _router) { | ||||||
| 		await del(`/stashes/${stashId}/actors/${actorId}`); | 		await del(`/stashes/${stashId}/actors/${actorId}`); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	async function stashScene(context, { sceneId, stashId }) { | ||||||
|  | 		await post(`/stashes/${stashId}/scenes`, { sceneId }); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	async function unstashScene(context, { sceneId, stashId }) { | ||||||
|  | 		await del(`/stashes/${stashId}/scenes/${sceneId}`); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return { | 	return { | ||||||
| 		stashActor, | 		stashActor, | ||||||
|  | 		stashScene, | ||||||
| 		unstashActor, | 		unstashActor, | ||||||
|  | 		unstashScene, | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,4 +1,6 @@ | ||||||
| import { graphql } from '../api'; | import { graphql } from '../api'; | ||||||
|  | import { releaseFields } from '../fragments'; | ||||||
|  | import { curateUser } from '../curate'; | ||||||
| 
 | 
 | ||||||
| function initUsersActions(_store, _router) { | function initUsersActions(_store, _router) { | ||||||
| 	async function fetchUser(context, username) { | 	async function fetchUser(context, username) { | ||||||
|  | @ -43,45 +45,7 @@ function initUsersActions(_store, _router) { | ||||||
| 						scenes: stashesScenes { | 						scenes: stashesScenes { | ||||||
| 							comment | 							comment | ||||||
| 							scene { | 							scene { | ||||||
| 								id | 								${releaseFields} | ||||||
| 								title |  | ||||||
| 								slug |  | ||||||
| 								url |  | ||||||
| 								date |  | ||||||
| 								actors: releasesActors { |  | ||||||
| 									actor { |  | ||||||
| 										id |  | ||||||
| 										name |  | ||||||
| 										slug |  | ||||||
| 									} |  | ||||||
| 								} |  | ||||||
| 								tags: releasesTags { |  | ||||||
| 									tag { |  | ||||||
| 										id |  | ||||||
| 										name |  | ||||||
| 										slug |  | ||||||
| 									} |  | ||||||
| 								} |  | ||||||
| 								entity { |  | ||||||
| 									id |  | ||||||
| 									name |  | ||||||
| 									slug |  | ||||||
| 									independent |  | ||||||
| 									parent { |  | ||||||
| 										id |  | ||||||
| 										name |  | ||||||
| 										slug |  | ||||||
| 										independent |  | ||||||
| 									} |  | ||||||
| 								} |  | ||||||
| 								poster: releasesPosterByReleaseId { |  | ||||||
| 									media { |  | ||||||
| 										path |  | ||||||
| 										thumbnail |  | ||||||
| 										lazy |  | ||||||
| 										isS3 |  | ||||||
| 									} |  | ||||||
| 								} |  | ||||||
| 							} | 							} | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
|  | @ -91,7 +55,7 @@ function initUsersActions(_store, _router) { | ||||||
| 			username, | 			username, | ||||||
| 		}); | 		}); | ||||||
| 
 | 
 | ||||||
| 		return user; | 		return curateUser(user); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return { | 	return { | ||||||
|  |  | ||||||
|  | @ -1328,7 +1328,6 @@ exports.up = knex => Promise.resolve() | ||||||
| 				)); | 				)); | ||||||
| 		`, {
 | 		`, {
 | ||||||
| 			visitor: knex.raw(config.database.query.user), | 			visitor: knex.raw(config.database.query.user), | ||||||
| 			password: knex.raw(config.database.query.password), |  | ||||||
| 		}); | 		}); | ||||||
| 	}) | 	}) | ||||||
| 	// VIEWS AND COMMENTS
 | 	// VIEWS AND COMMENTS
 | ||||||
|  |  | ||||||
|  | @ -21,7 +21,7 @@ function logActive() { | ||||||
| 	setTimeout(() => { | 	setTimeout(() => { | ||||||
| 		log(); | 		log(); | ||||||
| 		logActive(); | 		logActive(); | ||||||
| 	}, 600000); | 	}, argv.logActive || 60000); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function init() { | async function init() { | ||||||
|  |  | ||||||
|  | @ -48,19 +48,31 @@ async function stashScene(sceneId, stashId, sessionUser) { | ||||||
| 	await knex('stashes_scenes') | 	await knex('stashes_scenes') | ||||||
| 		.insert({ | 		.insert({ | ||||||
| 			stash_id: stash.id, | 			stash_id: stash.id, | ||||||
| 			actor_id: sceneId, | 			scene_id: sceneId, | ||||||
| 		}); | 		}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function unstashActor(actorId, stashId, sessionUser) { | async function unstashActor(actorId, stashId, sessionUser) { | ||||||
| 	await knex | 	await knex | ||||||
| 		.from('stashes_actors') | 		.from('stashes_actors AS deletable') | ||||||
| 		.whereIn('stashes_actors.id', knex('stashes_actors') | 		.where('deletable.actor_id', actorId) | ||||||
| 			.select('stashes_actors.id') | 		.where('deletable.stash_id', stashId) | ||||||
|  | 		.whereExists(knex('stashes_actors') // verify user owns this stash
 | ||||||
| 			.leftJoin('stashes', 'stashes.id', 'stashes_actors.stash_id') | 			.leftJoin('stashes', 'stashes.id', 'stashes_actors.stash_id') | ||||||
| 			.where('stashes.user_id', sessionUser.id) // verify user owns this stash
 | 			.where('stashes_actors.stash_id', knex.raw('deletable.stash_id')) | ||||||
| 			.where('stashes_actors.actor_id', actorId) | 			.where('stashes.user_id', sessionUser.id)) | ||||||
| 			.where('stashes_actors.stash_id', stashId)) | 		.delete(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | async function unstashScene(sceneId, stashId, sessionUser) { | ||||||
|  | 	await knex | ||||||
|  | 		.from('stashes_scenes AS deletable') | ||||||
|  | 		.where('deletable.scene_id', sceneId) | ||||||
|  | 		.where('deletable.stash_id', stashId) | ||||||
|  | 		.whereExists(knex('stashes_scenes') // verify user owns this stash
 | ||||||
|  | 			.leftJoin('stashes', 'stashes.id', 'stashes_scenes.stash_id') | ||||||
|  | 			.where('stashes_scenes.stash_id', knex.raw('deletable.stash_id')) | ||||||
|  | 			.where('stashes.user_id', sessionUser.id)) | ||||||
| 		.delete(); | 		.delete(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -68,6 +80,6 @@ module.exports = { | ||||||
| 	curateStash, | 	curateStash, | ||||||
| 	stashActor, | 	stashActor, | ||||||
| 	stashScene, | 	stashScene, | ||||||
| 	// unstashScene,
 | 	unstashScene, | ||||||
| 	unstashActor, | 	unstashActor, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -80,20 +80,9 @@ function getLimiter(options = {}, url) { | ||||||
| 	return limiters[interval][concurrency]; | 	return limiters[interval][concurrency]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function request(method = 'get', url, body, requestOptions = {}, limiter, timeout) { | async function request(method = 'get', url, body, requestOptions = {}, limiter) { | ||||||
| 	const http = requestOptions.session || bhttp; | 	const http = requestOptions.session || bhttp; | ||||||
| 
 | 	const options = requestOptions; | ||||||
| 	const options = { |  | ||||||
| 		...defaultOptions, |  | ||||||
| 		...requestOptions, |  | ||||||
| 		headers: { |  | ||||||
| 			...defaultOptions.headers, |  | ||||||
| 			...requestOptions.headers, |  | ||||||
| 		}, |  | ||||||
| 		responseTimeout: requestOptions.responseTimeout || requestOptions.timeout || defaultOptions.timeout, |  | ||||||
| 		stream: !!requestOptions.destination, |  | ||||||
| 		session: null, |  | ||||||
| 	}; |  | ||||||
| 
 | 
 | ||||||
| 	const withProxy = useProxy(url); | 	const withProxy = useProxy(url); | ||||||
| 
 | 
 | ||||||
|  | @ -107,8 +96,10 @@ async function request(method = 'get', url, body, requestOptions = {}, limiter, | ||||||
| 		? http[method](url, body, options) | 		? http[method](url, body, options) | ||||||
| 		: http[method](url, options)); | 		: http[method](url, options)); | ||||||
| 
 | 
 | ||||||
| 	timeout.cancel(); | 	return res; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|  | async function finalizeResult(res, options) { | ||||||
| 	if (options.destination) { | 	if (options.destination) { | ||||||
| 		// res.on('progress', (bytes, totalBytes) => logger.silly(`Downloaded ${Math.round((bytes / totalBytes) * 100)}% of ${url}`));
 | 		// res.on('progress', (bytes, totalBytes) => logger.silly(`Downloaded ${Math.round((bytes / totalBytes) * 100)}% of ${url}`));
 | ||||||
| 
 | 
 | ||||||
|  | @ -140,21 +131,39 @@ async function request(method = 'get', url, body, requestOptions = {}, limiter, | ||||||
| 
 | 
 | ||||||
| function getTimeout(options, url) { | function getTimeout(options, url) { | ||||||
| 	return new Promise((resolve, reject, onCancel) => { | 	return new Promise((resolve, reject, onCancel) => { | ||||||
| 		const timeoutId = setTimeout(() => { | 		const timeout = setTimeout(() => { | ||||||
| 			reject(new Error(`URL ${url} timed out`)); | 			reject(new Error(`URL ${url} timed out`)); | ||||||
| 		}, (options?.timeout || defaultOptions.timeout) + 10000); | 		}, (options?.timeout || defaultOptions.timeout) + 10000); | ||||||
| 
 | 
 | ||||||
| 		onCancel(() => clearTimeout(timeoutId)); | 		onCancel(() => { | ||||||
|  | 			clearTimeout(timeout); | ||||||
|  | 		}); | ||||||
| 	}); | 	}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function scheduleRequest(method = 'get', url, body, options) { | async function scheduleRequest(method = 'get', url, body, requestOptions = {}) { | ||||||
|  | 	const options = { | ||||||
|  | 		...defaultOptions, | ||||||
|  | 		...requestOptions, | ||||||
|  | 		headers: { | ||||||
|  | 			...defaultOptions.headers, | ||||||
|  | 			...requestOptions.headers, | ||||||
|  | 		}, | ||||||
|  | 		responseTimeout: requestOptions.responseTimeout || requestOptions.timeout || defaultOptions.timeout, | ||||||
|  | 		stream: !!requestOptions.destination, | ||||||
|  | 		session: null, | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
| 	const limiter = getLimiter(options, url); | 	const limiter = getLimiter(options, url); | ||||||
| 	const timeout = getTimeout(options, url); | 	const timeout = getTimeout(options, url); | ||||||
| 
 | 
 | ||||||
| 	const result = await limiter.schedule(() => Promise.race([request(method, url, body, options, limiter, timeout), timeout])); | 	const result = await limiter.schedule(async () => Promise.race([request(method, url, body, options, limiter), timeout])); | ||||||
| 
 | 
 | ||||||
| 	return result; | 	timeout.cancel(); | ||||||
|  | 
 | ||||||
|  | 	const curatedResult = await finalizeResult(result, options); | ||||||
|  | 
 | ||||||
|  | 	return curatedResult; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function get(url, options) { | async function get(url, options) { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue