0

I'm trying to make a server that are used like a "CDN proxy".

We have

  • S1: main server that has all media
  • S2 CDN proxy
  • client

The aim is:

  1. obtain a stream from server1 (S1) (I'm using this follow link as placeholder, the effective link could be a temp link)
axios.get(link, { responseType: "stream", adapter: httpAdapter })
    .then((axiosResponse: any) => { ... }) 
  1. since I have a stream, I don't need to proxy the entire media to the client, but just a chunk (specified from the client)

I don't know how to retrieve a specific chunk without download all chunks up to the desired chunk.

This is a scratch:

import express, { Request, Response } from 'express';
import expressAsyncHandler from 'express-async-handler';
import * as http from 'http';
const axios = require("axios");
const httpAdapter = require("axios/lib/adapters/http");



const app = express();
const HTTP_PORT = 3000;
var server = http.createServer(app);


const link = 'https://images.all-free-download.com/footage_preview/mp4/city_panorama_6891675.mp4';

app.get('/video.mp4', expressAsyncHandler(async (req: Request, res: Response) => {
  axios.get(link, { responseType: "stream", adapter: httpAdapter })
    .then((axiosResponse: any) => {
      let stream = axiosResponse?.data;

      const fileSize = axiosResponse["headers"]["content-length"];
      const range = req.headers.range
      if (range) {
        const parts = range.replace(/bytes=/, "").split("-")
        const start = parseInt(parts[0], 10)
        const end = parts[1]
          ? parseInt(parts[1], 10)
          : fileSize - 1
        const chunksize = (end - start) + 1

        /*******************************/
        const streamChunk = /* GET CHUNCK FROM STREAM WITHOUT OVERHEAD */ null;
        /*******************************/

        const head = {
          'Content-Range': `bytes ${start}-${end}/${fileSize}`,
          'Accept-Ranges': 'bytes',
          'Content-Length': chunksize,
          'Content-Type': 'video/mp4',
        }
        res.writeHead(206, head);
        streamChunk.pipe(res);
      } else {
        const head = {
          'Content-Length': fileSize,
          'Content-Type': 'video/mp4',
        }
        res.writeHead(200, head)
        stream.pipe(res)
      }
    })
}));

server.listen(HTTP_PORT, () => {
  console.log("Running on port: " + HTTP_PORT);
});

I hope someone can help me.

Thanks in advice :)

UPDATE Follow code works on VLC

import express, { Request, Response } from 'express';
import expressAsyncHandler from 'express-async-handler';
import * as http from 'http';
import * as https from 'https';
const axios = require("axios");
const httpAdapter = require("axios/lib/adapters/http");

const app = express();
const HTTP_PORT = 3000;
var server = http.createServer(app);

/************************************************/
// PREVENT EXCEPTION CLOSURE
process.on('uncaughtException', function (err) {
  console.error(err);
  console.log("Node NOT Exiting...");
});
/************************************************/

const link = 'https://samplelib.com/lib/preview/mp4/sample-30s.mp4';


app.get('/video.mp4', expressAsyncHandler(async (req: Request, res: Response) => {
  if (req.socket.destroyed) {
    return;
  }

  delete req.headers.referer;

  let head;
  let status;
  const range = req.headers.range
  const axiosResponseHead = await axios.head(link)
  const fileSize = axiosResponseHead["headers"]["content-length"];

  const agent = new https.Agent({
    rejectUnauthorized: false
  });


  console.log(range)

  if (range) {
    req.headers.host = new URL(link).hostname;

    const parts = range?.replace(/bytes=/, "")?.split("-")
    const start = parseInt(parts[0], 10)
    const end = parts[1]
      ? parseInt(parts[1], 10)
      : fileSize - 1
    const chunksize = (end - start) + 1
    head = {
      'Content-Range': `bytes ${start}-${end}/${fileSize}`,
      'range': `bytes=${start}-${end}`,
      'Accept-Ranges': 'bytes',
      'Content-Length': chunksize,
      'Content-Type': 'video/mp4',
    }
    status = 206;
    req.headers.range = head.range
  } else {
    head = {
      'Content-Length': fileSize,
      'Content-Type': 'video/mp4',
    }
    status = 200;
  }


  console.log(req.headers)
  console.log(head)
  console.log("==================================")


  let axiosResponse: any
  let stream: any;

  res.on('close', function () {
    stream?.destroy();
  });

  let instance = axios.create();
  axiosResponse = await instance.get(link, {
    responseType: "stream", adapter: httpAdapter, headers: req.headers, httpsAgent: agent
  })
  stream = axiosResponse?.data;
  res.writeHead(status, head)
  stream.pipe(res, { end: true });
}));


server.listen(HTTP_PORT, () => {
  console.log("Running on port: " + HTTP_PORT);
});

function sleep(ms: number) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
0Franky
  • 1
  • 2

0 Answers0