market types from mammon

This commit is contained in:
Sirttas
2026-06-13 16:30:31 +02:00
parent 3a35d2181d
commit 16078cc62b
5 changed files with 184 additions and 55 deletions
+71
View File
@@ -449,6 +449,37 @@ paths:
$ref: "#/components/schemas/MarketHistoryResponse"
"400":
description: The days parameter is not greater than 0
/market/types:
get:
tags:
- market
summary: Return the static market type details for each requested type id
operationId: findTypes
parameters:
- name: ids
in: query
description: "Market type ids to look up, e.g. ids=34,35"
required: true
schema:
type: array
items:
type: integer
format: int64
responses:
"200":
description: The market types found for the requested ids; unknown ids are
omitted
content:
'*/*':
schema:
type: array
items:
$ref: "#/components/schemas/MarketTypeResponse"
"400":
description: |-
Returned when:
- the ids parameter is missing
- an ids value is not a numeric id
/market/scan:
get:
tags:
@@ -916,6 +947,46 @@ components:
- marketTypeId
- orderCount
- volume
MarketTypeResponse:
type: object
properties:
id:
type: integer
format: int64
name:
type: string
groupId:
type: integer
format: int64
marketGroupId:
type: integer
format: int64
description:
type: string
published:
type: boolean
basePrice:
type: number
volume:
type: number
format: double
portionSize:
type: integer
format: int32
iconId:
type: integer
format: int64
required:
- basePrice
- description
- groupId
- iconId
- id
- marketGroupId
- name
- portionSize
- published
- volume
MarketPriceResponse:
type: object
properties:
+83
View File
@@ -124,6 +124,18 @@ export interface MarketScanResponse {
'profit': number;
'score': number;
}
export interface MarketTypeResponse {
'id': number;
'name': string;
'groupId': number;
'marketGroupId': number;
'description': string;
'published': boolean;
'basePrice': number;
'volume': number;
'portionSize': number;
'iconId': number;
}
export interface RuleBookResponse {
'ruleBookId': string;
'name': string;
@@ -1352,6 +1364,43 @@ export const MarketApiAxiosParamCreator = function (configuration?: Configuratio
options: localVarRequestOptions,
};
},
/**
*
* @summary Return the static market type details for each requested type id
* @param {Array<number>} ids Market type ids to look up, e.g. ids&#x3D;34,35
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
findTypes: async (ids: Array<number>, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'ids' is not null or undefined
assertParamExists('findTypes', 'ids', ids)
const localVarPath = `/market/types`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
if (ids) {
localVarQueryParameter['ids'] = ids;
}
localVarHeaderParameter['Accept'] = '*/*';
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @summary Scan every tracked market type, returning volume-weighted price quartiles for each
@@ -1482,6 +1531,19 @@ export const MarketApiFp = function(configuration?: Configuration) {
const localVarOperationServerBasePath = operationServerMap['MarketApi.findHistory']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
*
* @summary Return the static market type details for each requested type id
* @param {Array<number>} ids Market type ids to look up, e.g. ids&#x3D;34,35
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async findTypes(ids: Array<number>, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<MarketTypeResponse>>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.findTypes(ids, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['MarketApi.findTypes']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
*
* @summary Scan every tracked market type, returning volume-weighted price quartiles for each
@@ -1543,6 +1605,16 @@ export const MarketApiFactory = function (configuration?: Configuration, basePat
findHistory(marketTypeId: number, days?: number, options?: RawAxiosRequestConfig): AxiosPromise<Array<MarketHistoryResponse>> {
return localVarFp.findHistory(marketTypeId, days, options).then((request) => request(axios, basePath));
},
/**
*
* @summary Return the static market type details for each requested type id
* @param {Array<number>} ids Market type ids to look up, e.g. ids&#x3D;34,35
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
findTypes(ids: Array<number>, options?: RawAxiosRequestConfig): AxiosPromise<Array<MarketTypeResponse>> {
return localVarFp.findTypes(ids, options).then((request) => request(axios, basePath));
},
/**
*
* @summary Scan every tracked market type, returning volume-weighted price quartiles for each
@@ -1598,6 +1670,17 @@ export class MarketApi extends BaseAPI {
return MarketApiFp(this.configuration).findHistory(marketTypeId, days, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary Return the static market type details for each requested type id
* @param {Array<number>} ids Market type ids to look up, e.g. ids&#x3D;34,35
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
public findTypes(ids: Array<number>, options?: RawAxiosRequestConfig) {
return MarketApiFp(this.configuration).findTypes(ids, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary Scan every tracked market type, returning volume-weighted price quartiles for each
+11 -11
View File
@@ -1,15 +1,15 @@
import { defineStore } from 'pinia';
import { RegionalMarketCache } from '../RegionalMarketCache';
import { jitaId } from '../market';
import { MarketType } from "../type";
import { MarketTypePrice } from './MarketTypePrice';
import { getMammonPrices } from './mammon';
import {defineStore} from 'pinia';
import {RegionalMarketCache} from '../RegionalMarketCache';
import {jitaId} from '../market';
import {MarketType} from "../type";
import {MarketTypePrice} from './MarketTypePrice';
import {getMammonPrices} from './mammon';
const cacheDuration = 1000 * 60 * 5; // 5 minutes
const batchSize = 100;
const CACHE_DURATION = 1000 * 60 * 5; // 5 minutes
const BATCH_SIZE = 100;
export const useApraisalStore = defineStore('appraisal', () => {
const cache: RegionalMarketCache<MarketTypePrice> = new RegionalMarketCache(cacheDuration);
const cache: RegionalMarketCache<MarketTypePrice> = new RegionalMarketCache(CACHE_DURATION);
const getPricesUncached = getMammonPrices;
@@ -32,8 +32,8 @@ export const useApraisalStore = defineStore('appraisal', () => {
if (uncached.length > 0) {
const batches: Promise<MarketTypePrice[]>[] = [];
for (let i = 0; i < uncached.length; i += batchSize) {
batches.push(getPricesUncached(uncached.slice(i, i + batchSize)));
for (let i = 0; i < uncached.length; i += BATCH_SIZE) {
batches.push(getPricesUncached(uncached.slice(i, i + BATCH_SIZE)));
}
const prices = (await Promise.all(batches)).flat();
+18 -43
View File
@@ -1,30 +1,23 @@
import {esiAxiosInstance} from '@/service';
import {marketApi} from '@/mammon/mammonService';
import type {MarketTypeResponse} from '@/generated/mammon';
export type MarketType = {
id: number;
group_id: number;
market_group_id: number;
name: string;
published: boolean;
description: string;
base_price: number;
icon_id: number;
volume: number;
portion_size: number;
}
export type MarketType = MarketTypeResponse;
const cache = new Map<number, MarketType>(); // TODO move to pinia store
const fetchType = (id: number): Promise<MarketType> => {
if (cache.has(id)) {
return Promise.resolve(cache.get(id)!);
const BATCH_SIZE = 100;
const fetchTypes = async (ids: number[]): Promise<void> => {
const missing = ids.filter(id => !cache.has(id));
if (missing.length === 0) {
return;
}
return esiAxiosInstance.get<Omit<MarketType, 'id'> & { type_id: number }>(`/universe/types/${id}/`).then(r => {
const { type_id, ...rest } = r.data;
const marketType: MarketType = { id: type_id, ...rest };
cache.set(id, marketType);
return marketType;
});
const batches: Promise<MarketType[]>[] = [];
for (let i = 0; i < missing.length; i += BATCH_SIZE) {
batches.push(marketApi.findTypes(missing.slice(i, i + BATCH_SIZE)).then(r => r.data));
}
const results = await Promise.all(batches);
results.flat().forEach(t => cache.set(t.id, t));
};
export const getMarketType = async (type: string | number): Promise<MarketType> => (await getMarketTypes([type]))[0];
@@ -33,28 +26,10 @@ export const getMarketTypes = async (types: (string | number)[]): Promise<Market
return [];
}
const ids = types.filter((t): t is number => typeof t === 'number');
return Promise.all(ids.map(fetchType));
await fetchTypes(ids);
return ids.map(id => cache.get(id)).filter((t): t is MarketType => t !== undefined);
}
const blueprintMarketGroups = [ // TODO add all groups
2,
2157,
2159,
2339,
2160,
211,
1016,
339,
2290,
357,
1530,
359,
1531,
1532,
1533,
358
]
export const searchMarketTypes = async (search: string): Promise<MarketType[]> => {
export const searchMarketTypes = async (_search: string): Promise<MarketType[]> => {
return []
}
+1 -1
View File
@@ -89,7 +89,7 @@ watchEffect(async () => {
<template>
<div @click="() => isOpen = true" v-on-click-outside="() => isOpen = false">
<div class="fake-input">
<img v-if="modelValue?.type_id" :src="`https://images.evetech.net/types/${modelValue.type_id}/icon?size=32`" alt="" />
<img v-if="modelValue?.id" :src="`https://images.evetech.net/types/${modelValue.id}/icon?size=32`" alt="" />
<input type="text" v-model="name" @keyup.enter="submit" @keyup.down="moveDown" @keyup.up="moveUp" />
</div>
<div v-if="suggestions.length > 1" class="z-20 absolute w-96">