Skip to content

Commit 63484eb

Browse files
committed
Refactor controllers and services for improved structure and clarity
- Removed the old Controller class and replaced it with specific controllers for handling graphs, languages, and stats. - Introduced GraphController, LanguageController, and StatsController to manage respective functionalities. - Updated import paths to reflect the new controller structure. - Refactored base service and cache service to enhance dependency injection and service management. - Implemented GitHubGraphQLOptimizer for optimized GraphQL queries with batching capabilities. - Adjusted Redis and memory cache services for better performance and error handling. - Enhanced error logging and response handling across controllers.
1 parent 5801e77 commit 63484eb

15 files changed

Lines changed: 1368 additions & 1389 deletions

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "github-stats",
3-
"version": "2.0.2",
3+
"version": "2.0.3",
44
"description": "Generate dynamic GitHub stats cards for your README",
55
"main": "dist/index.js",
66
"type": "module",
Lines changed: 560 additions & 560 deletions
Large diffs are not rendered by default.

src/controllers/controller.ts

Lines changed: 0 additions & 21 deletions
This file was deleted.
Lines changed: 234 additions & 234 deletions
Large diffs are not rendered by default.

src/controllers/health.controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import { Request, Response } from 'express';
7-
import { ICacheService } from '../services/base.js';
7+
import { ICacheService } from '../services/base.service.js';
88
import { db } from '../db/index.js';
99
import { createLogger } from '../common/logger.js';
1010
import { getConfig } from '../config/index.js';
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,68 @@
1-
import { Request, Response } from 'express';
2-
import { GitHubClient } from '../utils/github-client.js';
3-
import { LanguageCardRenderer } from '../components/language-card.js';
4-
import { LanguagePieChartRenderer } from '../components/language-pie-chart.js';
5-
export class LanguageController {
6-
private static githubClient: GitHubClient;
7-
private static cache: Map<string, { data: string; timestamp: number }>;
8-
private static CACHE_DURATION: number;
9-
static routeDocs = {
10-
requiredParams: ['username'],
11-
optionalParams: [
12-
'type',
13-
'theme',
14-
'show_info',
15-
'info_outline'
16-
],
17-
payload: null as null,
18-
example: '/languages?username=pphatdev&type=card&theme=default'
19-
};
20-
21-
static initialize(githubClient: GitHubClient, cache: Map<string, { data: string; timestamp: number }>, cacheDuration: number) {
22-
this.githubClient = githubClient;
23-
this.cache = cache;
24-
this.CACHE_DURATION = cacheDuration;
25-
}
26-
27-
static async getSvg(req: Request, res: Response) {
28-
try {
29-
const { username, type = 'card', theme = 'default', show_info, info_outline = 'solid' } = req.query;
30-
31-
if (!username || typeof username !== 'string') {
32-
return res.status(400).send('Username is required');
33-
}
34-
35-
const cacheKey = `languages-${username}-${type}-${theme}-${show_info}-${info_outline}`;
36-
const cached = LanguageController.cache.get(cacheKey);
37-
if (cached && Date.now() - cached.timestamp < LanguageController.CACHE_DURATION) {
38-
res.setHeader('Content-Type', 'image/svg+xml');
39-
res.setHeader('Cache-Control', 'public, max-age=600');
40-
return res.send(cached.data);
41-
}
42-
43-
const languages = await LanguageController.githubClient.fetchUserLanguages(username);
44-
45-
let svg: string;
46-
if (type === 'pie') {
47-
svg = LanguagePieChartRenderer.generatePieChart(languages, {
48-
theme: theme as string,
49-
});
50-
} else {
51-
svg = LanguageCardRenderer.generateLanguagesCard(languages, {
52-
theme: theme as string,
53-
showInfo: show_info !== 'false',
54-
dataBorderStyle: info_outline === 'frame' ? 'frame' : 'solid',
55-
});
56-
}
57-
58-
LanguageController.cache.set(cacheKey, { data: svg, timestamp: Date.now() });
59-
60-
res.setHeader('Content-Type', 'image/svg+xml');
61-
res.setHeader('Cache-Control', 'public, max-age=600');
62-
res.send(svg);
63-
} catch (error) {
64-
console.error('Error generating languages background:', error);
65-
res.status(500).send(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
66-
}
67-
}
68-
}
1+
import { Request, Response } from 'express';
2+
import { GitHubClient } from '../utils/github-client.js';
3+
import { LanguageCardRenderer } from '../components/language-card.js';
4+
import { LanguagePieChartRenderer } from '../components/language-pie-chart.js';
5+
export class LanguageController {
6+
private static githubClient: GitHubClient;
7+
private static cache: Map<string, { data: string; timestamp: number }>;
8+
private static CACHE_DURATION: number;
9+
static routeDocs = {
10+
requiredParams: ['username'],
11+
optionalParams: [
12+
'type',
13+
'theme',
14+
'show_info',
15+
'info_outline'
16+
],
17+
payload: null as null,
18+
example: '/languages?username=pphatdev&type=card&theme=default'
19+
};
20+
21+
static initialize(githubClient: GitHubClient, cache: Map<string, { data: string; timestamp: number }>, cacheDuration: number) {
22+
this.githubClient = githubClient;
23+
this.cache = cache;
24+
this.CACHE_DURATION = cacheDuration;
25+
}
26+
27+
static async getSvg(req: Request, res: Response) {
28+
try {
29+
const { username, type = 'card', theme = 'default', show_info, info_outline = 'solid' } = req.query;
30+
31+
if (!username || typeof username !== 'string') {
32+
return res.status(400).send('Username is required');
33+
}
34+
35+
const cacheKey = `languages-${username}-${type}-${theme}-${show_info}-${info_outline}`;
36+
const cached = LanguageController.cache.get(cacheKey);
37+
if (cached && Date.now() - cached.timestamp < LanguageController.CACHE_DURATION) {
38+
res.setHeader('Content-Type', 'image/svg+xml');
39+
res.setHeader('Cache-Control', 'public, max-age=600');
40+
return res.send(cached.data);
41+
}
42+
43+
const languages = await LanguageController.githubClient.fetchUserLanguages(username);
44+
45+
let svg: string;
46+
if (type === 'pie') {
47+
svg = LanguagePieChartRenderer.generatePieChart(languages, {
48+
theme: theme as string,
49+
});
50+
} else {
51+
svg = LanguageCardRenderer.generateLanguagesCard(languages, {
52+
theme: theme as string,
53+
showInfo: show_info !== 'false',
54+
dataBorderStyle: info_outline === 'frame' ? 'frame' : 'solid',
55+
});
56+
}
57+
58+
LanguageController.cache.set(cacheKey, { data: svg, timestamp: Date.now() });
59+
60+
res.setHeader('Content-Type', 'image/svg+xml');
61+
res.setHeader('Cache-Control', 'public, max-age=600');
62+
res.send(svg);
63+
} catch (error) {
64+
console.error('Error generating languages background:', error);
65+
res.status(500).send(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
66+
}
67+
}
68+
}

src/index.refactored.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ import { createLogger } from './common/logger.js';
2323
// Services
2424
import { GitHubService } from './services/github.service.js';
2525
import { MemoryCacheService, HybridCacheService } from './services/cache.service.js';
26-
import { getServiceContainer } from './services/base.js';
26+
import { getServiceContainer } from './services/base.service.js';
2727

2828
// Middleware
2929
import { errorHandler, notFoundHandler, requestLogger, asyncHandler } from './middleware/error.middleware.js';
3030

3131
// Controllers
32-
import { StatsController } from './controllers/stats.js';
33-
import { LanguageController } from './controllers/languages.js';
34-
import { GraphController } from './controllers/graph.js';
32+
import { StatsController } from './controllers/stats.controller.js';
33+
import { LanguageController } from './controllers/languages.controller.js';
34+
import { GraphController } from './controllers/graph.controller.js';
3535
import { UserBadgeController } from './controllers/user-badge.controller.js';
3636
import { ProjectBadgeController } from './controllers/project-badge.controller.js';
3737
import {

src/routes/docs.routes.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { GraphController } from "../controllers/graph.js";
2-
import { LanguageController } from "../controllers/languages.js";
3-
import { StatsController } from "../controllers/stats.js";
1+
import { GraphController } from "../controllers/graph.controller.js";
2+
import { LanguageController } from "../controllers/languages.controller.js";
3+
import { StatsController } from "../controllers/stats.controller.js";
44
import { getProjectBadgeRouteDocs } from "./project-badge.routes.js";
55
import { getUserBadgeRouteDocs } from "./user-badge.routes.js";
66
import { getIconsRouteDocs } from "./icons.routes.js";

src/routes/redis-cached.routes.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
* Routes for stats, languages, and graph with caching middleware
44
*/
55
import type { Application, Request } from 'express';
6-
import { StatsController } from '../controllers/stats.js';
7-
import { LanguageController } from '../controllers/languages.js';
8-
import { GraphController } from '../controllers/graph.js';
6+
import { StatsController } from '../controllers/stats.controller.js';
7+
import { LanguageController } from '../controllers/languages.controller.js';
8+
import { GraphController } from '../controllers/graph.controller.js';
99
import { cacheMiddleware } from '../utils/cache-middleware.js';
1010
import { CACHE_KEYS, DEFAULT_TTL } from '../utils/redis-client.js';
1111

0 commit comments

Comments
 (0)