From 5dcc1aff28290fe3b7e2ed5cbe99d3034c0b6f34 Mon Sep 17 00:00:00 2001 From: Ricardo Cino Date: Wed, 22 Jun 2022 22:10:39 +0200 Subject: chore: recipes/request stores js => ts --- src/stores/RecipesStore.ts | 169 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 src/stores/RecipesStore.ts (limited to 'src/stores/RecipesStore.ts') diff --git a/src/stores/RecipesStore.ts b/src/stores/RecipesStore.ts new file mode 100644 index 000000000..af2aa7fb0 --- /dev/null +++ b/src/stores/RecipesStore.ts @@ -0,0 +1,169 @@ +import { action, computed, observable } from 'mobx'; +import { readJSONSync } from 'fs-extra'; +import semver from 'semver'; + +import { Stores } from 'src/stores.types'; +import { ApiInterface } from 'src/api'; +import { Actions } from 'src/actions/lib/actions'; +import Recipe from 'src/models/Recipe'; +import CachedRequest from './lib/CachedRequest'; +import Request from './lib/Request'; +import { matchRoute } from '../helpers/routing-helpers'; +import { asarRecipesPath } from '../helpers/asar-helpers'; +import TypedStore from './lib/TypedStore'; + +const debug = require('../preload-safe-debug')('Ferdium:RecipeStore'); + +export default class RecipesStore extends TypedStore { + @observable allRecipesRequest = new CachedRequest(this.api.recipes, 'all'); + + @observable installRecipeRequest = new Request(this.api.recipes, 'install'); + + @observable getRecipeUpdatesRequest = new Request(this.api.recipes, 'update'); + + constructor(stores: Stores, api: ApiInterface, actions: Actions) { + super(stores, api, actions); + + // Register action handlers + this.actions.recipe.install.listen(this._install.bind(this)); + this.actions.recipe.update.listen(this._update.bind(this)); + + // Reactions + this.registerReactions([this._checkIfRecipeIsInstalled.bind(this)]); + } + + async setup(): Promise { + // Initially load all recipes + this.all; + } + + @computed get all(): Recipe[] { + return this.allRecipesRequest.execute().result || []; + } + + @computed get active() { + const match = matchRoute( + '/settings/services/add/:id', + this.stores.router.location.pathname, + ); + if (match) { + const activeRecipe = this.one(match.id); + if (activeRecipe) { + return activeRecipe; + } + + debug(`Recipe ${match.id} not installed`); + } + + return null; + } + + @computed get recipeIdForServices(): string[] { + return this.stores.services.all.map(s => s.recipe.id); + } + + one(id: string): Recipe | undefined { + return this.all.find(recipe => recipe.id === id); + } + + isInstalled(id: string): boolean { + return !!this.one(id); + } + + // Actions + async _install({ recipeId }): Promise { + const recipe = await this.installRecipeRequest.execute(recipeId)._promise; + await this.allRecipesRequest.invalidate({ immediately: true })._promise; + + return recipe; + } + + @action async _update() { + const recipeIds = this.recipeIdForServices; + const recipes = {}; + + // Hackfix, reference this.all to fetch services + debug(`Check Recipe updates for ${this.all.map(recipe => recipe.id)}`); + + for (const r of recipeIds) { + const recipe = this.one(r); + if (recipe) { + recipes[r] = recipe.version; + } + } + + if (Object.keys(recipes).length === 0) return; + + const remoteUpdates = await this.getRecipeUpdatesRequest.execute(recipes) + ._promise; + + // Check for local updates + const allJsonFile = asarRecipesPath('all.json'); + const allJson = readJSONSync(allJsonFile); + const localUpdates: string[] = []; + + for (const recipe of Object.keys(recipes)) { + const version = recipes[recipe]; + + // Find recipe in local recipe repository + const localRecipe = allJson.find(r => r.id === recipe); + + if (localRecipe && semver.lt(version, localRecipe.version)) { + localUpdates.push(recipe); + } + } + + const updates = [...remoteUpdates, ...localUpdates]; + debug( + 'Got update information (local, remote):', + localUpdates, + remoteUpdates, + ); + + const length = updates.length - 1; + const syncUpdate = async i => { + const update = updates[i]; + + this.actions.recipe.install({ recipeId: update }); + await this.installRecipeRequest._promise; + + this.installRecipeRequest.reset(); + + if (i === length) { + this.stores.ui.showServicesUpdatedInfoBar = true; + } else if (i < length) { + syncUpdate(i + 1); + } + }; + + if (length >= 0) { + syncUpdate(0); + } + } + + async _checkIfRecipeIsInstalled(): Promise { + const { router } = this.stores; + + const match = + router.location && + matchRoute('/settings/services/add/:id', router.location.pathname); + if (match) { + const recipeId = match.id; + + if (!this.stores.recipes.isInstalled(recipeId)) { + router.push('/settings/recipes'); + debug(`Recipe ${recipeId} is not installed, trying to install it`); + + const recipe = await this.installRecipeRequest.execute(recipeId) + ._promise; + if (recipe) { + await this.allRecipesRequest.invalidate({ immediately: true }) + ._promise; + router.push(`/settings/services/add/${recipeId}`); + } else { + router.push('/settings/recipes'); + } + } + } + } +} -- cgit v1.2.3-70-g09d2