Showing posts with label NestJS. Show all posts
Showing posts with label NestJS. Show all posts

Tuesday, February 10, 2026

how to response markdown file using next.js , nest.js

 on nest.js

import {
    Body,
    Controller,
    Get,
    HttpStatus,
    Post,
    Render,
    Req,
    Res,
} from '@nestjs/common';
import { Request, Response } from 'express';
import { Throttle } from '@nestjs/throttler';
import * as fs from 'fs';
import * as path from 'path';

import { AppSessionService } from '../core/app.session.service';
import { AppConstants } from '../core/app.constants';
import { DataMemoryCacher } from '../libs/memory-cacher/data.memory-cacher';

@Controller()
export class AppController {
    constructor(
        private readonly dataCacher: DataMemoryCacher,
        private readonly appSessionService: AppSessionService,
    ) {}

    @Get('/')
    @Render('home')
    app_home(@Req() req: Request, @Res() res: Response): any {
        var hosts = [req.headers.host];
        var username = this.appSessionService.getUserName();
        let last_one = this.dataCacher.get('puu_last_one_from');

        return {
            title: 'PUU - PAAS',
            hosts: hosts,
            username: username,
            last_one: last_one ? last_one.doc_num : '-0-',
        };
    }

    @Get('/about')
    async app_about(@Req() req: Request, @Res() res: Response): Promise<any> {
        let apiDoc = '';

        // // load from cache
        // const keyCache = 'site-home-md';
        // // const dataCache = this.dataCacher.get(keyCache);
        // const dataCache = null;

        // if (dataCache) {
        //     apiDoc = dataCache;
        // } else {
        //     const mdPath = path.join(process.cwd(), 'views', 'about-api.md');
        //     apiDoc = fs.readFileSync(mdPath, 'utf8');
        //     this.dataCacher.set(keyCache, apiDoc);
        // }

        res.render('about', {
            title: 'PUU - About API',
            apiDoc,
        });
    }

    @Get('apiDocs.md')
    getApiDoc(@Res() res: Response) {
        const mdPath = path.join(process.cwd(), 'views', 'about-api.md');
        const md = fs.readFileSync(mdPath, 'utf8');
        res.type('text/markdown').send(md);
    }

    // for API

    @Throttle(AppConstants.throttler_limits.website_send)
    @Post('/language')
    app_language_sel(@Body() body: any, @Res() res: Response) {
        if (body.code && AppConstants.supported_languages.includes(body.code)) {
            this.appSessionService.setLanguage(body.code);

            return res
                .status(HttpStatus.OK)
                .json({ success: true, result: body.code });
        }
        return res.status(HttpStatus.BAD_REQUEST).json({ success: false });
    }

    @Throttle(AppConstants.throttler_limits.brute_force)
    @Get('/ip')
    ip(@Req() req: Request, @Res() res: Response) {
        return res.status(HttpStatus.OK).json({
            ip: req.ip,
            forwarded: req.headers['x-forwarded-for'],
        });
    }
}


on next.js


import fs from 'fs';
import path from 'path';
import { NextResponse } from 'next/server';

export async function GET() {
    const mdPath = path.join(process.cwd(), 'docs', 'about-api.md');
    const md = fs.readFileSync(mdPath, 'utf8');

    return new NextResponse(md, {
        headers: {
            'Content-Type': 'text/markdown; charset=utf-8',
        },
    });
}




Tuesday, June 27, 2023

How to lock an object when websocketgateway has many requests mutex

 test.ts

class Mutex {   
    queue: any[];
    queue_args: any[];
    locked: boolean;

    constructor() {
        this.locked = false;
        this.queue = [];
        this.queue_args = [];
    }

    lock(data: any) {
        return new Promise<void>(resolve => {
            if (this.locked) {
                this.queue.push(resolve);
                this.queue_args.push(data);
                console.log('lock', this.queue_args);
            } else {
                this.locked = true;
                resolve();
            }
        });
    }

    unlock() {
        if (this.queue.length > 0) {
            const nextResolver = this.queue.shift();
            const nextArgs = this.queue_args.shift();
            console.log('unlock', nextArgs, this.queue_args);
            nextResolver();
        } else {
            this.locked = false;
        }
    }
}

class WebSocketGateway {
    data: {};
    mutex: Mutex;

    constructor() {
        this.data = {};
        this.mutex = new Mutex();
    }

    async handleRequest(request) {
        await this.mutex.lock(request.data);
        try {
            await new Promise(resolve => setTimeout(resolve, 1000));
        } finally {
            this.mutex.unlock();
        }
    }
}

const gateway = new WebSocketGateway();
for (var i = 0; i < 4; i++)
    gateway.handleRequest({ data: 'request-' + i });