Skip to content

Commit 8c0ff46

Browse files
Merge pull request #1466 from multiversx/feat/media-redirect
Media redirect
2 parents 8f8da65 + ab0cc03 commit 8c0ff46

17 files changed

+473
-81
lines changed

config/config.devnet.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ features:
5252
assetsFetch:
5353
enabled: true
5454
assetesUrl: 'https://tools.multiversx.com/assets-cdn'
55+
mediaRedirect:
56+
enabled: false
57+
storageUrls:
58+
- 'https://s3.amazonaws.com/devnet-media.elrond.com'
5559
auth:
5660
enabled: false
5761
maxExpirySeconds: 86400

config/config.mainnet.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ features:
109109
assetsFetch:
110110
enabled: true
111111
assetesUrl: 'https://tools.multiversx.com/assets-cdn'
112+
mediaRedirect:
113+
enabled: false
114+
storageUrls:
115+
- 'https://s3.amazonaws.com/media.elrond.com'
112116
image:
113117
width: 600
114118
height: 600

config/config.testnet.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ features:
108108
assetsFetch:
109109
enabled: true
110110
assetesUrl: 'https://tools.multiversx.com/assets-cdn'
111+
mediaRedirect:
112+
enabled: false
113+
storageUrls:
114+
- 'https://s3.amazonaws.com/testnet-media.elrond.com'
111115
image:
112116
width: 600
113117
height: 600

package-lock.json

+67-63
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+8-8
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,14 @@
9090
"@golevelup/nestjs-rabbitmq": "^4.0.0",
9191
"@multiversx/sdk-core": "^13.2.2",
9292
"@multiversx/sdk-data-api-client": "^0.7.0",
93-
"@multiversx/sdk-nestjs-auth": "4.0.1",
94-
"@multiversx/sdk-nestjs-cache": "4.0.1",
95-
"@multiversx/sdk-nestjs-common": "4.0.1",
96-
"@multiversx/sdk-nestjs-elastic": "^4.0.1",
97-
"@multiversx/sdk-nestjs-http": "4.0.1",
98-
"@multiversx/sdk-nestjs-monitoring": "4.0.1",
99-
"@multiversx/sdk-nestjs-rabbitmq": "4.0.1",
100-
"@multiversx/sdk-nestjs-redis": "4.0.1",
93+
"@multiversx/sdk-nestjs-auth": "4.2.0",
94+
"@multiversx/sdk-nestjs-cache": "4.2.0",
95+
"@multiversx/sdk-nestjs-common": "4.2.0",
96+
"@multiversx/sdk-nestjs-elastic": "^4.2.0",
97+
"@multiversx/sdk-nestjs-http": "4.2.0",
98+
"@multiversx/sdk-nestjs-monitoring": "4.2.0",
99+
"@multiversx/sdk-nestjs-rabbitmq": "4.2.0",
100+
"@multiversx/sdk-nestjs-redis": "4.2.0",
101101
"@multiversx/sdk-wallet": "^4.0.0",
102102
"@nestjs/apollo": "12.0.11",
103103
"@nestjs/common": "10.2.0",

src/common/api-config/api.config.service.ts

+8
Original file line numberDiff line numberDiff line change
@@ -912,4 +912,12 @@ export class ApiConfigService {
912912
getCacheDuration(): number {
913913
return this.configService.get<number>('caching.cacheDuration') ?? 3;
914914
}
915+
916+
isMediaRedirectFeatureEnabled(): boolean {
917+
return this.configService.get<boolean>('features.mediaRedirect.enabled') ?? false;
918+
}
919+
920+
getMediaRedirectFileStorageUrls(): string[] {
921+
return this.configService.get<string[]>('features.mediaRedirect.storageUrls') ?? [];
922+
}
915923
}

src/endpoints/endpoints.controllers.module.ts

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import { PoolController } from "./pool/pool.controller";
3939
import { TpsController } from "./tps/tps.controller";
4040
import { ApplicationController } from "./applications/application.controller";
4141
import { EventsController } from "./events/events.controller";
42+
import { MediaController } from "./media/media.controller";
4243

4344
@Module({})
4445
export class EndpointsControllersModule {
@@ -50,6 +51,7 @@ export class EndpointsControllersModule {
5051
TokenController, TransactionController, UsernameController, VmQueryController, WaitingListController,
5152
HealthCheckController, DappConfigController, WebsocketController, TransferController,
5253
ProcessNftsPublicController, TransactionsBatchController, ApplicationController, EventsController,
54+
MediaController,
5355
];
5456

5557
const isMarketplaceFeatureEnabled = configuration().features?.marketplace?.enabled ?? false;

src/endpoints/endpoints.services.module.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import { PoolModule } from "./pool/pool.module";
3636
import { TpsModule } from "./tps/tps.module";
3737
import { ApplicationModule } from "./applications/application.module";
3838
import { EventsModule } from "./events/events.module";
39+
import { MediaModule } from "./media/media.module";
3940

4041
@Module({
4142
imports: [
@@ -77,13 +78,14 @@ import { EventsModule } from "./events/events.module";
7778
TpsModule,
7879
ApplicationModule,
7980
EventsModule,
81+
MediaModule,
8082
],
8183
exports: [
8284
AccountModule, CollectionModule, BlockModule, DelegationModule, DelegationLegacyModule, IdentitiesModule, KeysModule,
8385
MiniBlockModule, NetworkModule, NftModule, NftMediaModule, TagModule, NodeModule, ProviderModule,
8486
RoundModule, SmartContractResultModule, ShardModule, StakeModule, TokenModule, RoundModule, TransactionModule, UsernameModule, VmQueryModule,
8587
WaitingListModule, EsdtModule, BlsModule, DappConfigModule, TransferModule, PoolModule, TransactionActionModule, WebsocketModule, MexModule,
86-
ProcessNftsModule, NftMarketplaceModule, TransactionsBatchModule, TpsModule, ApplicationModule, EventsModule,
88+
ProcessNftsModule, NftMarketplaceModule, TransactionsBatchModule, TpsModule, ApplicationModule, EventsModule, MediaModule,
8789
],
8890
})
8991
export class EndpointsServicesModule { }
+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { Controller, Get, InternalServerErrorException, NotFoundException, Param, Req, Res } from "@nestjs/common";
2+
import { ApiTags } from "@nestjs/swagger";
3+
import { Request, Response } from "express";
4+
import { MediaService } from "./media.service";
5+
import { ApiService } from "@multiversx/sdk-nestjs-http";
6+
import { OriginLogger } from "@multiversx/sdk-nestjs-common";
7+
import https from 'https';
8+
9+
@Controller()
10+
@ApiTags('media')
11+
export class MediaController {
12+
private readonly logger = new OriginLogger(MediaController.name);
13+
14+
constructor(
15+
private readonly mediaService: MediaService,
16+
private readonly apiService: ApiService,
17+
) { }
18+
19+
@Get("/media/:uri(*)")
20+
async redirectToMediaUri(
21+
@Param('uri') uri: string,
22+
@Req() req: Request,
23+
@Res() res: Response
24+
) {
25+
const redirectUrl = await this.mediaService.getRedirectUrl(uri);
26+
if (!redirectUrl) {
27+
throw new NotFoundException('Not found');
28+
}
29+
30+
try {
31+
const response = await this.apiService.get(redirectUrl, {
32+
// @ts-ignore
33+
responseType: 'stream',
34+
timeout: 60_000, // 60 seconds timeout
35+
httpsAgent: new https.Agent({ rejectUnauthorized: false }),
36+
headers: {
37+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36',
38+
},
39+
});
40+
41+
res.setHeader('content-type', response.headers['content-type']);
42+
res.setHeader('content-length', response.headers['content-length']);
43+
res.setHeader('cache-control', 'max-age=60');
44+
res.setHeader('Access-Control-Allow-Origin', '*');
45+
46+
response.data.pipe(res);
47+
48+
response.data.on('error', (error: any) => {
49+
this.logger?.error(`Error streaming the resource: ${redirectUrl}`);
50+
this.logger?.error(error);
51+
52+
throw new InternalServerErrorException('Failed to fetch URL');
53+
});
54+
55+
req.on('close', () => {
56+
response.data?.destroy();
57+
});
58+
59+
return;
60+
} catch (error) {
61+
this.logger.error(`Failed to fetch URL: ${redirectUrl}`);
62+
63+
throw new InternalServerErrorException('Failed to fetch URL');
64+
}
65+
}
66+
}

0 commit comments

Comments
 (0)