Spaces:
Sleeping
Sleeping
File size: 4,346 Bytes
b2806e8 8626b2e b2806e8 8626b2e b2806e8 8626b2e b2806e8 8626b2e b2806e8 8626b2e b2806e8 8626b2e b2806e8 8626b2e b2806e8 8626b2e b2806e8 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
import {
Controller,
Get,
Post,
Param,
Query,
Body,
Res,
Inject,
Optional,
NotFoundException,
} from '@nestjs/common';
import { Response } from 'express';
import { MarketsService } from './markets.service';
import { MarketCacheService } from './market-cache.service';
@Controller('markets')
export class MarketsController {
private readonly marketQueue: any;
constructor(
private readonly marketsService: MarketsService,
private readonly cacheService: MarketCacheService,
@Optional() @Inject('BullQueue_market-processing') marketQueue?: any,
) {
this.marketQueue = marketQueue || null;
}
@Get()
getMarkets(@Query('q') query?: string) {
if (query && query.trim().length > 0) {
return this.marketsService.searchMarkets(query);
}
const markets = this.marketsService.getMarkets();
// Enrich with processing status
return markets.map((m) => {
const cached = this.cacheService.get(m.slug);
return {
...m,
processingStatus: cached?.status || 'unknown',
};
});
}
@Post('search')
searchMarket(@Body('query') query: string) {
if (!query || query.trim().length < 2) {
return { error: 'Query must be at least 2 characters' };
}
const detail = this.marketsService.searchOrCreateMarket(query.trim());
return detail;
}
@Get('jobs/status')
getJobsStatus() {
const all = this.cacheService.getAll();
return {
markets: all.map((c) => ({
slug: c.slug,
status: c.status,
updatedAt: c.updatedAt,
error: c.error,
})),
summary: {
total: all.length,
ready: all.filter((c) => c.status === 'ready').length,
processing: all.filter((c) => c.status === 'processing').length,
pending: all.filter((c) => c.status === 'pending').length,
error: all.filter((c) => c.status === 'error').length,
},
};
}
@Post(':slug/refresh')
async refreshMarket(@Param('slug') slug: string) {
const market = this.marketsService.getMarkets().find((m) => m.slug === slug);
if (!market) {
throw new NotFoundException('Market not found');
}
if (this.marketQueue) {
this.cacheService.setStatus(slug, 'pending');
await this.marketQueue.add(
'process-market',
{ slug },
{ removeOnComplete: 100, removeOnFail: 50 },
);
return { message: 'Market refresh queued', slug, status: 'pending' };
}
return { message: 'Market data refreshed (no queue)', slug, status: 'ready' };
}
@Get(':slug')
getMarketDetail(@Param('slug') slug: string) {
// Return cached data if available (processed by BullMQ worker)
const cached = this.cacheService.get(slug);
if (cached?.status === 'ready' && cached.data) {
return {
...cached.data,
fromCache: true,
processingStatus: 'ready',
};
}
// Try to get the market detail (works for both hardcoded + dynamic)
const market = this.marketsService.getMarketDetail(slug);
if (!market) {
throw new NotFoundException('Market not found');
}
return {
...market,
fromCache: false,
processingStatus: cached?.status || 'not-queued',
};
}
@Get(':slug/export/odds-csv')
exportOddsCsv(@Param('slug') slug: string, @Res() res: Response) {
const csv = this.marketsService.getOddsHistoryCsv(slug);
if (!csv) {
throw new NotFoundException('Market not found');
}
res.setHeader('Content-Type', 'text/csv');
res.setHeader(
'Content-Disposition',
`attachment; filename=odds_history_${slug}.csv`,
);
res.send(csv);
}
@Get(':slug/export/integrity-csv')
exportIntegrityCsv(@Param('slug') slug: string, @Res() res: Response) {
const csv = this.marketsService.getIntegrityCsv(slug);
if (!csv) {
throw new NotFoundException('Market not found');
}
res.setHeader('Content-Type', 'text/csv');
res.setHeader(
'Content-Disposition',
`attachment; filename=integrity_${slug}.csv`,
);
res.send(csv);
}
@Get(':slug/export/dossier-json')
exportDossierJson(@Param('slug') slug: string) {
const dossier = this.marketsService.getDossierJson(slug);
if (!dossier) {
throw new NotFoundException('Market not found');
}
return dossier;
}
}
|