node.js - Multiple cameras websocket view - stream with raspivid, nodejs, and angular - Stack Overflow

SO, I have this code on multiple raspi cameras:const express = require('express');const Web

SO, I have this code on multiple raspi cameras:

const express = require('express');
const WebSocket = require('ws');
const raspividStream = require('raspivid-stream');
const fs = require('fs');
const readline = require('readline');
const app = express();
const wss = require('express-ws')(app);
const { exec } = require('child_process');
const path = require('path');

var vstreamCounter = 0;
var videoStream = null;
var recording = false;
var websoc = null;

var currentDir = __dirname;
var camfn = 'camera.conf';
var p = path.join(currentDir, camfn);


if (fs.existsSync(p)) {

    const fileStream = fs.createReadStream(p);

    fileStream.on('error', (error) => {
      console.error(`Error reading file: ${error.message}`);
    });

    const rl = readline.createInterface({
      input: fileStream,
      crlfDelay: Infinity
    });

    rl.on('line', (line) => {
      console.log(`Got ip from file: ${line}`);

      var serverUrl = 'ws://'+line+':1337';
      console.log(serverUrl);
      websoc = new WebSocket(serverUrl);

      websoc.on('open', function open() {
        console.log('Connected to the server');
      });
    });

    rl.on('close', () => {
      console.log('File reading finished');
    });

} else {
    console.log("missing configuration file camera.conf");
    process.exit();
}

app.get('/camera-status', (req, res) => {

    exec('vcgencmd get_camera', (error, stdout, stderr) => {
        if (error) {
          console.error(`Error: ${error.message}`);
          return;
        }
        if (stderr) {
          console.error(`stderr: ${stderr}`);
          return;
        }
        console.log(`stdout: ${stdout}`);

        var position = stdout.indexOf(",");

        if (position != -1) {
            var sbstr = stdout.substring(0, position);
            var rgxp = new RegExp("1", 'g');
            var occurences = sbstr.match(rgxp);

            if (occurences.length == 2){
                res.send(200);
            } else {
                res.send(500);
            }
        }

      });
  });

app.ws('/vstream', async (ws, req) => {
    console.log('Client connected');

    vstreamCounter = vstreamCounter + 1;

    ws.send(JSON.stringify({
        action: "init",
         width: 640,
         height: 480
    }));

    videoStream = await raspividStream();

    videoStream.on('data', (data) => {
        if (ws.readyState === WebSocket.OPEN) {
            ws.send(data, { binary: true }, (error) => { if (error) {console.error(error)/* process.exit()*/;}  });


        }
    });

    ws.on("message", async (msg) => {
        await messageHandling(msg, null);
    });

    if (ws.readyState === WebSocket.OPEN) {
        ws.on('close', async () => {
            await closing(videoStream);
        });
     }
});

app.ws('/vstream-90', async (ws, req) => {
    console.log('Client connected');

    vstreamCounter = vstreamCounter + 1;

    ws.send(JSON.stringify({
        action: "init",
         width: 640,
         height: 480,
         rotation: 90
    }));

    videoStream = await raspividStream({ rotation: 90 });

    videoStream.on('data', (data) => {
        if (ws.readyState === WebSocket.OPEN) {
            ws.send(data, { binary: true }, (error) => { if (error) {console.error(error)/* process.exit()*/;}  });
        }
    });

    ws.on("message", async (msg) => {
        await messageHandling(msg, 90);
    });

    if (ws.readyState === WebSocket.OPEN) {
        ws.on('close', async () => {
            await closing(videoStream);
        });
     }
});

app.ws('/vstream-180', async (ws, req) => {

    console.log('Client connected');

    vstreamCounter = vstreamCounter + 1;

    ws.send(JSON.stringify({
        action: "init",
         width: 640,
         height: 480,
         rotation: 180
    }));

    videoStream = await raspividStream({ rotation: 180 });

    videoStream.on('data', async (data) => {

        if (ws.readyState === WebSocket.OPEN) {
            ws.send(data, { binary: true }, (error) => { if (error) {console.error(error)/* process.exit()*/;}  });
        }
    });

    ws.on("message", async (msg) => {
        await messageHandling(msg, 180);
    });

    if (ws.readyState === WebSocket.OPEN) {
        ws.on('close', async () => {
        await closing(videoStream);
    });}
});


var recording = true;
var ss = null;
var recordLock = 0;

async function messageHandling(msg, rot){

    if (msg.toString().includes("loc-")){
        websoc.send(msg);
    }

    if (msg.toString().includes("desc-")){
        websoc.send(msg);
    }

    if (msg.toString() === "record"){

        //if (recordLock == 0) {

            recordLock = recordLock + 1;

            if (rot){
                ss = await raspividStream({ rotation: rot });
            } else {
                ss = await raspividStream();
            }

           // if (recording){

                ss.on('data', async (d) => {
                    if (websoc.readyState === WebSocket.OPEN) {
                        websoc.send(d, { binary: true }, (error) => { if (error) {console.error(error)/* process.exit()*/;}  });
                    }
                });
            //}
        //}
    }

    if (msg.toString() === "stoprecord"){
       // if (recording) {
            recording = false;
            websoc.send("stoprecord");
            console.log("stopped recording");
            //process.exit();
      //   }
    }
}

async function closing(){
    console.log('Client left');

    videoStream.removeAllListeners('data');

    vstreamCounter = vstreamCounter - 1;

    //await burnThemInClose(filename, location);

    console.log(vstreamCounter);

    if (vstreamCounter === 0){
        process.exit();
    }
}

app.listen(8080, function(err){
    if (err) console.log("Error in server setup")
    console.log("Server listening on Port");
});

This is server side code that cameras connect to for processing the stream:

const WebSocket = require('ws')
const fs = require('fs');
const ffmpeg = require('fluent-ffmpeg');
const { finished } = require('stream');
const { promisify } = require('util');

const finishedAsync = promisify(finished);
const writeFileAsync1 = promisify((stream, data, callback) => {
  stream.write(data, callback);
});

const server = new WebSocket.Server({ port: 1337 });
let location = null;

server.on('connection', (ws) => {
  console.log('Client connected');

  let writeStream = null;
  let filename = null;

  let view = null;
  let camcnt = 0;

  ws.on('message', async (message) => {

  //  console.log("in message handler");
    const msgStr = message.toString();

    if (msgStr.includes("desc-")) {
      view = msgStr.slice(5);
      console.log(`View set to: ${view}`);
    }

    if (msgStr.includes("loc-")) {
      location = msgStr.slice(4);
      console.log(`Location set to: ${location}`);
    }

    if (msgStr.includes("cam") && camcnt === 0) {
      console.log(`Camera message received: ${msgStr}`);

      if (!location || !view) {
        console.error('Location or view not set. Cannot create filename.');
        return;
      }

      filename = generateFileName(location, view);
      writeStream = fs.createWriteStream(filename);
      console.log(`Write stream created: ${filename}`);
      camcnt++;
    }

    if (writeStream && !msgStr.startsWith("desc-") && !msgStr.startsWith("loc-") && !msgStr.includes("cam1") && !msgStr.includes("cam2")) {
      if (!writeStream.writableEnded) {
        try {
          await writeFileAsync1(writeStream, message);
          console.log('Data written to file');
        } catch (error) {
          console.error('Error writing to stream:', error);
        }
      }
    }

    if (msgStr === "stoprecord") {
      if (writeStream) {
        if (!writeStream.writableEnded) {
          writeStream.end();
          try {
            await finishedAsync(writeStream);
            console.log('Write stream ended');
          } catch (error) {
            console.error('Error ending the stream:', error);
          }
        }
      }
    //  ws.close();
      console.log('WebSocket connection closed');
    }
  });

  ws.on('close', async () => {
    console.log('Client disconnected');
    if (writeStream && !writeStream.writableEnded) {
      writeStream.end();
      try {
        await finishedAsync(writeStream);
        console.log('Write stream ended');
      } catch (error) {
        console.error('Error ending the stream:', error);
      }
    }
  });
});






function generateFileName(location, view) {
    var d = new Date();
    var filename = location +"_"+view+"_"+
    d.getFullYear() + "-" +
    ("00" + (d.getMonth() + 1)).slice(-2) + "-" +
    ("00" + d.getDate()).slice(-2) + "_" +
    ("00" + d.getHours()).slice(-2) + ":" +
    ("00" + d.getMinutes()).slice(-2) + ":" +
    ("00" + d.getSeconds()).slice(-2) + ".h264";

    filename = filename.replace(/["']/g, "");
    filename = filename.replace(/:/g, "_");

    return filename;
}

async function reencodeVideo(inputPath, outputPath) {
    return new Promise((resolve, reject) => {
      ffmpeg(inputPath)
        .videoCodec('libx264')
        .audioCodec('aac')
        .outputOptions('-movflags', 'faststart') // Ensures compatibility with streaming
        .on('end', () => {
          console.log('Video re-encoding complete.');
          resolve();
        })
        .on('error', (err) => {
          console.error('Error:', err);
          reject(err);
        })
        .save(outputPath);
    });
  }

function getVideoMetadata(videofilename) {
    return new Promise((resolve, reject) => {
      ffmpeg.ffprobe(videofilename, (err, metadata) => {
        if (err) {
          reject(err);
        } else {
          resolve(metadata);
        }
      });
    });
  }

  function generateSrtContent(duration, staticText, startTime) {

    // Convert start time to seconds
    const [hours, minutes, seconds] = startTime.split(':').map(Number);
    const startTimeSeconds = hours * 3600 + minutes * 60 + seconds;

    let srtContent = '';

    for (let i = 0; i < duration; i++) {
        const currentTime = startTimeSeconds + i;
        const start = new Date(i * 1000).toISOString().substr(11, 8) + ',000';
        const end = new Date((i + 1) * 1000).toISOString().substr(11, 8) + ',000';
        const timeText = new Date(currentTime * 1000).toISOString().substr(11, 8);

        srtContent += `${i + 1}\n`;
        srtContent += `${start} --> ${end}\n`;
        srtContent += `${staticText} ${timeText}\n\n`;
      }

    return srtContent;
  }

  function writeFileAsync(filePath, content) {
    return new Promise((resolve, reject) => {
      fs.writeFile(filePath, content, (err) => {
        if (err) {
          reject(err);
        } else {
          resolve();
        }
      });
    });
  }

  function encodeVideoWithSubtitles(inputVideo, subtitleFile, outputVideo) {
    return new Promise((resolve, reject) => {
      ffmpeg(inputVideo)
        .outputOptions('-vf', `subtitles=${subtitleFile}`)
        .output(outputVideo)
        .on('end', () => {
          console.log('Video processing complete.');
          resolve();
        })
        .on('error', (err) => {
          console.error('Error:', err);
          reject(err);
        })
        .run();
    });
  }

  var staticcnt = 0;

async function burnThemInClose(filename, location){
    try {
        var d = new Date();
        var hhmmss = ("00" + d.getHours()).slice(-2) + ":" +
        ("00" + d.getMinutes()).slice(-2) + ":" +
        ("00" + d.getSeconds()).slice(-2);

        var staticTime  = d.getFullYear() + "-" +
        ("00" + (d.getMonth() + 1)).slice(-2) + "-" +
        ("00" + d.getDate()).slice(-2);

        var newMP4 = filename.slice(0, -5)+".mp4"
        await reencodeVideo(filename, "static"+staticcnt+".mp4");

        const metadata = await getVideoMetadata("static"+staticcnt+".mp4");
        staticnt = staticcnt + 1;
        console.log(metadata);
        const duration = Math.floor(metadata.format.duration);
        const outputSrt = "titulky.srt";
        const srtContent = generateSrtContent(duration, location+" "+staticTime, hhmmss);

        if (fs.existsSync(outputSrt)) {
            fs.unlinkSync(outputSrt);
        }

        await writeFileAsync(outputSrt, srtContent);

       // await encodeVideoWithSubtitles("static.mp4", outputSrt, newMP4);

        if (fs.existsSync("static.mp4")) {
            fs.unlinkSync("static.mp4");
        }

        if (fs.existsSync(filename)) {
       //     fs.unlinkSync(filename);
        }

        if (fs.existsSync(outputSrt)) {
            fs.unlinkSync(outputSrt);
        }

        console.log('encoding finished');
      } catch (err) {
        console.error('Error:', err);
      }
}

and this is angluar component for initializing and changing the streams:

  import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
import { RobotComponent } from '@shared/device-interfaces';
import { MatSnackBar } from '@angular/material/snack-bar';
import { WSAvcPlayer } from 'ts-h264-live-player';
import { ServerApiService } from '../../core/services/server-api.service';
import { from } from 'rxjs';
import { Router, ActivatedRoute } from '@angular/router';

const url = require('url');

@Component({
  selector: 'app-h264-camera-streams',
  templateUrl: './h264-camera-streamsponent.html',
  styleUrls: ['./h264-camera-streamsponent.css'],
})
export class H264CameraStreamsComponent implements OnInit, AfterViewInit {
  @Input() cameras: RobotComponent[];
  @ViewChild('canvasOne') canvasOneElementRef: ElementRef;
  @ViewChild('canvasTwo') canvasTwoElementRef: ElementRef;

  playerOne: WSAvcPlayer;
  playerTwo: WSAvcPlayer;
  canvasOneElement: HTMLCanvasElement;
  canvasTwoElement: HTMLCanvasElement;
  useSplitScreen = false;
  selectedCamera: RobotComponent;
  isFormSaved: boolean;
  isRecording: boolean;
  isButtonEnabled: boolean;
  postLocation: string;
  selectedOption: any;

  camerasBackgroud = [
    '../../../assets/images/camera_1.png',
    '../../../assets/images/camera_2.png',
    '../../../assets/images/camera_3.png',
    '../../../assets/images/camera_4.png',
  ];

  city: string;
  street: string;
  data: any;
  isLoading: any;
  intervalId: any;

  constructor(public snackBar: MatSnackBar, private api: ServerApiService, private router: Router, private activatedRoute: ActivatedRoute) {}

  getLocations() {
    let result = this.api.getLocations();


    const observableFromPromise = from(result);

    observableFromPromise.subscribe(
      (response) => {
        this.data = response;


        this.isLoading = false;
      },
      (error) => {
        console.error('Error fetching data', error);
        this.isLoading = false;
      }
    );
  }

  toUrlEncoded(obj) {
    return Object.keys(obj)
      .map(key => encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]))
      .join('&');
  }

  async onOptionSelect(event: Event) {

    const selectElement = event.target as HTMLSelectElement;
    this.selectedOption = selectElement.value;
    let data =  {
      location: this.selectedOption
    };

    let enc  = this.toUrlEncoded(data);
    console.log(this.selectedOption);

    this.playerOne.send("loc-"+this.selectedOption);
    this.playerTwo.send("loc-"+this.selectedOption);

    this.api.postLocations(this.postLocation, enc);

    this.isButtonEnabled = true;

  }

  saveForm(form: any) {

    this.isFormSaved = this.city.trim().length > 0 && this.street.trim().length > 0;

    if (this.isFormSaved){

      let location: any = {"city":this.city,"street":this.street};
      this.api.addLocation(location);
     // window.location.reload();

    } else {
    console.log('Form is invalid');
  }
};




  ngOnInit(): void {

    this.selectedCamera = this.cameras[0];

    const parsedUrl = new URL(this.selectedCamera.camera_stream);
    const hostname = parsedUrl.hostname;
    const port = parsedUrl.port;
    this.postLocation  = "http://" + hostname + ":" + "8080" + "/post-location";


    this.getLocations();


  }


  async ngAfterViewInit() {
    if (this.cameras.length <= 0) return;

    if(this.selectedCamera.split_screen){
      this.useSplitScreen = true;
      this.canvasOneElement = this.canvasOneElementRef.nativeElement;
      this.canvasTwoElement = this.canvasTwoElementRef.nativeElement;

      this.playerOne = new WSAvcPlayer(this.canvasOneElement);
      this.playerTwo = new WSAvcPlayer(this.canvasTwoElement);

      this.playerOne.connectByUrl(this.selectedCamera.camera_stream);
      this.playerTwo.connectByUrl(this.selectedCamera.camera_stream_two);

      //await this.delay(500);

      //this.playerOne.send('REQUESTSTREAM');
      //this.playerTwo.send('REQUESTSTREAM');
    } else {
      this.useSplitScreen = false;
      this.canvasOneElement = this.canvasOneElementRef.nativeElement;
      this.playerOne = new WSAvcPlayer(this.canvasOneElement);
      this.playerOne.connectByUrl(this.selectedCamera.camera_stream);
      await this.delay(500);
      this.playerOne.send('REQUESTSTREAM');
    }
  }

  getColor(camera: RobotComponent) {
    console.log(camera)
    console.log(this.selectedCamera)
    if (camera.id === this.selectedCamera.id) return "primary"
    else return "secondary"
  }

  delay(ms: number) {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  async recordStream() {

   // if (this.useSplitScreen) {

      this.playerOne.send("desc-"+this.selectedCamera.description+"_cam1");

      this.playerOne.send("record");

      await this.delay(500);

      this.playerTwo.send("desc-"+this.selectedCamera.description+"_cam2");

      this.playerTwo.send("record");
    //} else {
      //this.playerOne.send('record');
    //}

    this.isRecording = true;

  }

  async stopRecordStream() {
    if (this.useSplitScreen) {
      this.playerOne.send("stoprecord");
      this.playerTwo.send("stoprecord");


    } else {
      this.playerOne.send('stoprecord');
    }

    this.isRecording = false;
  }



  async changeStream(camera: RobotComponent) {

    this.selectedCamera = camera;

    console.log(this.selectedCamera);


    if (camera.split_screen){

      this.playerOne.send("stoprecord");
      this.playerTwo.send("stoprecord");
      this.clearCanvas();
      this.canvasTwoElement.hidden = false;


      this.playerOne.disconnect();
      this.playerTwo.disconnect();

      this.playerOne.removeAllListeners();
      this.playerTwo.removeAllListeners();


      let ws = new WebSocket(this.selectedCamera.camera_stream);
      let ws2 = new WebSocket(this.selectedCamera.camera_stream_two);

      this.playerOne.connectWithCustomClient(ws);
      this.playerTwo.connectWithCustomClient(ws2);


        await this.delay(500);

      this.playerOne.send("desc-"+camera.description+"_cam1");
        await this.delay(1500);
        this.playerOne.send("record");

        await this.delay(500);

        this.playerTwo.send("desc-"+camera.description+"_cam1");
          await this.delay(1500);
          this.playerTwo.send("record");

      //this.playerOne.connectByUrl(camera.camera_stream);
      //this.playerTwo.connectByUrl(camera.camera_stream_two);

      console.log(this.playerOne);
      console.log(this.playerTwo);


      this.useSplitScreen = true;
    } else {
     // this.stopStream();
      this.clearCanvas()

      this.playerOne.disconnect;
      this.playerOne.removeAllListeners;

      this.playerOne.connectByUrl(camera.camera_stream);
      await this.delay(500);
      //this.playerOne.send('REQUESTSTREAM');

      this.playerOne.send("desc-"+camera.description+"_cam1");
        await this.delay(1500);
        this.playerOne.send("record");
      this.useSplitScreen = false;
    }
  }

  clearCanvas() {
    if (this.useSplitScreen) {
      var contextOne = this.canvasOneElement.getContext('2d');
      var contextTwo = this.canvasTwoElement.getContext('2d');
      contextOne.clearRect(0, 0, this.canvasOneElement.width, this.canvasOneElement.height);
      contextTwo.clearRect(0, 0, this.canvasTwoElement.width, this.canvasTwoElement.height);
      this.canvasTwoElement.hidden = true;
    } else {
      var contextOne = this.canvasOneElement.getContext('2d');
      contextOne.clearRect(0, 0, this.canvasOneElement.width, this.canvasOneElement.height);
    }
  }

  refreshStream() {
    this.stopStream();
    this.delay(150);
    this.startStream();
  }

  startStream() {
    if (this.useSplitScreen) {
      this.playerOne.send('REQUESTSTREAM');
      this.playerTwo.send('REQUESTSTREAM');
    } else {
      this.playerOne.send('REQUESTSTREAM');
    }
  }

  stopStream() {
    if (this.useSplitScreen) {
      this.playerOne.stopStream();
      this.playerTwo.stopStream();
    } else {
      this.playerOne.stopStream();
    }
  }
}

I would like to start new write stream on processing serverside, when the angular changeStream function is called, with new view - with two cameras. Problem is that first loaded view is recorded to two separate files which is correct, but when i call change stream in angular, first two streams are ended which is correct but second view write streams are not created on serverside despite that "record" message is sent to the new newly created websocket stream.

Can any one help out please.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745044861a4608031.html

相关推荐

  • MCP实战

    前言最近热衷于找一些好玩的MCP,集成在cursor中,给大模型外挂许多有趣的功能,例如:什么是MCP?本地如何开发MCP ServerMCP实战 | cursor 如何一句话操作 gitHub 代码库cursor 如何调用 MCP ser

    1小时前
    00
  • 方法分享

    作者,Evil Genius现在的日子,关税在涨,物价在涨,钱是越来越难挣了。什么东西在跌呢?工资在跌,房价也跌,房租反而涨了,生活的压力感觉越来越大了。对于生信分析而言,什么东西是最重要的?尤其是空间转录组的分析?很显然,硬件是服务器,软

    1小时前
    00
  • PDF转换Word深度评测

    ComPDFKit PDF 转换 SDK V3.0有以下几个新功能:使用百万级文档训练数据集对 PPYoloE AI 模型进行微调全场景布局分析算法及下一代表格识别算法重构数据结构、转换流程、PDF解析和输出模块混合布局:将流式布局与固定布

    1小时前
    00
  • Elasticsearch BBQ与OpenSearch FAISS:向量搜索性能对比

    基于二进制量化的向量搜索:Elasticsearch使用BBQ技术比OpenSearch搭配FAISS快5倍。我们收到社区要求,希望能解释Elasticsearch与OpenSearch在语义搜索向量搜索方面的性能差异。因此,我们进行了一

    58分钟前
    00
  • Power BI Vega 条形纵向折线组合图表

    条形图和纵向折线图组合常用来展示绝对值和率值的组合。之前在知识星球分享过SVG的版本(使用内置表格加载),今天换一种实现方式,使用Deneb视觉对象:把需要展示的维度和指标拖拽到Deneb,本例维度为城市,绝对值为[kpi]度量值,率值为[

    56分钟前
    00
  • windows11 x64 操作系统不支持Xilinx ISE 14.4版本,解决方案:创建windows7 x64 虚拟机,再安装Xilinx ISE 14.4。

    点击 下面的xsetup.exe可执行文件&#xff0c;弹出下面的报错框 &#xff1a; 于是我通过网上阅读文章进行了一系列的尝试 。 省流&#xff1a;1-7步骤都可以不用看&#xff0c;这些都是

    51分钟前
    00
  • 8.6K star!完全免费+本地运行+无需GPU,这款AI搜索聚合神器绝了!

    嗨,大家好,我是小华同学,关注我们获得“最新、最全、最优质”开源项目和高效工作学习方法 FreeAskInternet是一款革命性的开源项目,它完美结合了多引擎搜索和智能语言模型,让你在不联网、不花钱、不暴露隐私的情况下,获得媲美ChatG

    51分钟前
    00
  • 瞧瞧别人家的日期处理,那叫一个优雅!

    前言在我们的日常工作中,需要经常处理各种格式,各种类似的的日期或者时间。比如:2025-04-21、20250421、2025年04月21日等等。有些字段是String类型,有些是Date类型,有些是Long类型。如果不同的数据类型,经

    47分钟前
    00
  • 此计算机上的操作系统不符合 sql,windows7系统安装SQL server2012提示操作系统不符合最低要求怎么办...

    SQL server2012是一款数据管理软件&#xff0c;许多windows7系统用户会在电脑中安装使用&#xff0c;但是在安装的过程中&#xff0c;可能会遇到一些错误提示&#xff0c;比如常见的提

    45分钟前
    00
  • 铜缆以太网19

    40G-CR4100G-CR10 (C85)PCS (C82)(二)发送方向发送过程发送过程基于从XLGMIICGMII接收到的TXD<63:0>和TXC<7:0>信号生成块。1个XLGMIICGMII数据发送

    42分钟前
    00
  • 皮尔兹Pnoz c1c2安全继电器配置与接线

    PNOZ compact是皮尔兹的一款经济型的安全继电器系列,价格实惠,空间紧凑,适用于安装急停按钮、安全门或光障光栅 等安全产品。PNOZ C1是适用急停按钮或安全门开关。PNOZ C2用于 4 类光障或带 OSSD 输出的传感器的安全

    40分钟前
    00
  • Fabric8 Kubernetes 日志工具实践

    最近在使用 Fabric8 Kubernetes Client 的过程中发现了新大陆一样,感觉利用这个库可以进行很多有趣的功能尝试,其中一个便是日志的本地化。原因无他,rancher 页面性能实在太差了,经常性的暂停工作,碰到故障排查的时候

    35分钟前
    00
  • Sentinel 的熔断和限流

    在分布式系统里,服务之间牵一发而动全身,一个接口雪崩,可能带崩整个应用链路。要想系统抗住流量洪峰,顶住突发异常,就得在稳定性上下功夫。今天我就来说说稳定性保障里的老将——Sentinel,看看它是怎么凭借限流熔断,在服务治理的江湖里占得一席

    34分钟前
    00
  • PostgreSQL无服务 Neon and Aurora 新技术下的新经济模式 (翻译)

    说完新技术下的新经济模式,下面咱们用Amazon Aurora 的Postgres 无服务的介绍来结束此篇文章。(跟上新形势,不做落后的人)原文地址:引言:文章首先提到,将传统关系型数据库(如 MySQL)分解为独立的存储和计算组件,可

    32分钟前
    00
  • MTVInpaint:多任务视频修复框架,以双分支注意力与两阶段流水线统一完成、插入任务,处理长视频 !

    视频修复涉及在视频中修改局部区域,确保空间和时间上的一致性。现有的大多数方法主要集中在场景完成(即填补缺失区域)上,并缺乏以可控方式在场景中插入新目标的能力。幸运的是,最近在文本到视频(T2V)扩散模型方面的进展为文本指导的视频修复铺平了

    29分钟前
    20
  • R中单细胞RNA

    引言本系列开启 R 中scRNA-seq数据分析教程[1],持续更新,欢迎关注,转发!想要获取更多教程内容或者生信分析服务可以添加文末的学习交流群或客服QQ:941844452。简介RNA 速度分析最早由 La Manno 等人在 2018

    25分钟前
    20
  • 得物增长兑换商城的构架演进

    一、简介在移动互联网蓬勃发展的今天,用户的选择日益多元化,App市场的竞争也愈发白热化。为了在激烈的市场竞争中脱颖而出,提升用户获取效率并增强用户粘性,越来越多的应用开始采用积分兑换、抽奖等互动玩法。这些精心设计的运营策略不仅能够满足用户的

    22分钟前
    20
  • MCE干货分享

    在蛋白功能研究中,亲和力测定是揭示分子互作机制的关键环节。然而,传统方法通常依赖高纯度蛋白,而许多蛋白如膜蛋白、低溶解度蛋白等的研究就受到了限制。微量热泳动技术 (MST) 以其高灵敏度、低样本需求和对粗样品的兼容性,不仅可以检测重组蛋白,

    12分钟前
    00
  • CICD界一颗冉冉升起的新星,主打一个各种可以

    介绍在云计算与容器化技术高速发展的当下,多服务器环境下的软件构建与部署效率已成为开发者亟待突破的瓶颈。Komodo作为开源工具领域的革新者,凭借其高度灵活性、无限扩展潜力及人性化设计,为DevOps团队与独立开发者提供了全链路的解决方案。这

    8分钟前
    00
  • IP 地址和网关是啥关系?看完你能自己配网络了

    IP 地址和网关是啥关系?看完你能自己配网络了前言肝文不易,点个免费的赞和关注,有错误的地方请指出,看个人主页有惊喜。作者:神的孩子都在歌唱你有没有遇到过这样的场景:“我家电脑连不上网,IP地址也有了,咋还是上不了网?”“这什么子网掩码

    33秒前
    00

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信