feat: enhance DNS resolution handling in API service and add react-zoom-pan-pinch dependency

This commit is contained in:
Julien Froidefond
2025-10-16 13:39:40 +02:00
parent 4139d8a059
commit fd22e2ee83
5 changed files with 74 additions and 12 deletions

View File

@@ -7,6 +7,8 @@ const nextConfig = {
}; };
return config; return config;
}, },
// Configuration pour améliorer la résolution DNS
serverExternalPackages: ['dns'],
}; };
module.exports = nextConfig; module.exports = nextConfig;

View File

@@ -33,6 +33,7 @@
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-i18next": "^15.4.1", "react-i18next": "^15.4.1",
"react-zoom-pan-pinch": "^3.7.0",
"sharp": "0.33.2", "sharp": "0.33.2",
"tailwind-merge": "^3.0.2", "tailwind-merge": "^3.0.2",
"tailwindcss-animate": "1.0.7", "tailwindcss-animate": "1.0.7",

15
pnpm-lock.yaml generated
View File

@@ -74,6 +74,9 @@ importers:
react-i18next: react-i18next:
specifier: ^15.4.1 specifier: ^15.4.1
version: 15.7.4(i18next@24.2.3(typescript@5.3.3))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.3.3) version: 15.7.4(i18next@24.2.3(typescript@5.3.3))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.3.3)
react-zoom-pan-pinch:
specifier: ^3.7.0
version: 3.7.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
sharp: sharp:
specifier: 0.33.2 specifier: 0.33.2
version: 0.33.2 version: 0.33.2
@@ -2729,6 +2732,13 @@ packages:
'@types/react': '@types/react':
optional: true optional: true
react-zoom-pan-pinch@3.7.0:
resolution: {integrity: sha512-UmReVZ0TxlKzxSbYiAj+LeGRW8s8LraAFTXRAxzMYnNRgGPsxCudwZKVkjvGmjtx7SW/hZamt69NUmGf4xrkXA==}
engines: {node: '>=8', npm: '>=5'}
peerDependencies:
react: '*'
react-dom: '*'
react@18.2.0: react@18.2.0:
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@@ -5859,6 +5869,11 @@ snapshots:
optionalDependencies: optionalDependencies:
'@types/react': 18.2.64 '@types/react': 18.2.64
react-zoom-pan-pinch@3.7.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
react@18.2.0: react@18.2.0:
dependencies: dependencies:
loose-envify: 1.4.0 loose-envify: 1.4.0

View File

@@ -13,7 +13,9 @@ export const ErrorMessage = ({ errorCode, error, variant = "default" }: ErrorMes
const { t } = useTranslate(); const { t } = useTranslate();
const message = t(`errors.${errorCode}`); const message = t(`errors.${errorCode}`);
if (error) {
console.error(error); console.error(error);
}
if (variant === "form") { if (variant === "form") {
return ( return (

View File

@@ -83,6 +83,26 @@ export abstract class BaseApiService {
return url.toString(); return url.toString();
} }
protected static async resolveWithFallback(url: string): Promise<string> {
try {
// Essayer de résoudre le DNS d'abord
const urlObj = new URL(url);
const hostname = urlObj.hostname;
// Si c'est un nom de domaine, essayer de le résoudre
if (!/^\d+\.\d+\.\d+\.\d+$/.test(hostname)) {
// Vérifier si le domaine peut être résolu
const { lookup } = await import('dns').then(dns => dns.promises);
await lookup(hostname);
}
return url;
} catch (dnsError) {
console.warn(`DNS resolution failed for ${url}, using original URL:`, dnsError);
return url;
}
}
protected static async fetchFromApi<T>( protected static async fetchFromApi<T>(
urlBuilder: KomgaUrlBuilder, urlBuilder: KomgaUrlBuilder,
headersOptions = {}, headersOptions = {},
@@ -90,7 +110,7 @@ export abstract class BaseApiService {
): Promise<T> { ): Promise<T> {
const config: AuthConfig = await this.getKomgaConfig(); const config: AuthConfig = await this.getKomgaConfig();
const { path, params } = urlBuilder; const { path, params } = urlBuilder;
const url = this.buildUrl(config, path, params); const url = await this.resolveWithFallback(this.buildUrl(config, path, params));
const headers: Headers = this.getAuthHeaders(config); const headers: Headers = this.getAuthHeaders(config);
if (headersOptions) { if (headersOptions) {
@@ -109,6 +129,7 @@ export abstract class BaseApiService {
try { try {
// Enqueue la requête pour limiter la concurrence // Enqueue la requête pour limiter la concurrence
const response = await RequestQueueService.enqueue(async () => { const response = await RequestQueueService.enqueue(async () => {
try {
return await fetch(url, { return await fetch(url, {
headers, headers,
...options, ...options,
@@ -119,6 +140,27 @@ export abstract class BaseApiService {
bodyTimeout: timeoutMs, bodyTimeout: timeoutMs,
headersTimeout: timeoutMs, headersTimeout: timeoutMs,
}); });
} catch (fetchError: any) {
// Gestion spécifique des erreurs DNS
if (fetchError?.cause?.code === 'EAI_AGAIN' || fetchError?.code === 'EAI_AGAIN') {
console.error(`DNS resolution failed for ${url}. Retrying with different DNS settings...`);
// Retry avec des paramètres DNS différents
return await fetch(url, {
headers,
...options,
signal: controller.signal,
// @ts-ignore - undici-specific options
connectTimeout: timeoutMs,
bodyTimeout: timeoutMs,
headersTimeout: timeoutMs,
// Force IPv4 si IPv6 pose problème
// @ts-ignore
family: 4,
});
}
throw fetchError;
}
}); });
clearTimeout(timeoutId); clearTimeout(timeoutId);
const endTime = performance.now(); const endTime = performance.now();