Nodejs 同步与备份服务器仓库

发布于 1周前 作者 eggper 来自 nodejs/Nestjs

Nodejs 同步与备份服务器仓库

听说 Github 上有个仓库叫 famanoder/gitsync,里面用 Nodejs 实现了一个接口,用来远程执行 git 命令,来同步更新和备份服务器资源;由于服务器资源的特殊重要性,该接口做了个简单的签名认证,防止链接被盗取后的恶意操作;当然这只是个简单的认证,要更全面的防范,扩展一下也是很容易的;

实现背景:

最近项目的一个需求是客户端需要可以多个版本切换,比如当前最新版本为 3.5.0,那么对应前端的资源引用路径应该是 //cdn.host/3.5.0/js/*.js,如此一来,前端的静态资源就需要按需求版本划分为多个包了,OK,复制粘贴就完事了嘛!大不了用 Nodejs 写个复制粘贴也不麻烦的;这里最容易首先想到的一个巨坑就是,一旦需要修复旧版本的 bug,需要同步修复的文件到很多版本包,如果涉及的模块错综复杂的话,就得像 git 里需要手动解决冲突了,呵呵了吧!但转念一想,其实这个问题不会存在的,因为如果客户那里出问题了的话,如果没升级到最新版,我们首先是提醒用户升级,如果是新版的问题,那么改问题,当前版本不可提交的话,改上个版本提交,同步到当前版本就是,这样的话,说到底多版本控制其实就是最多两个版本控制了;如果有版本涉及到会员收费呢,有的用户就是不愿意付费咋办,那时候最多就不止两个版本了,好吧,反正有用户愿意付费,我们麻烦点也没啥~接下来的问题就是前端开发环境的配置多版本问题了;目前是 webpack,开发环境 npm run dev,package.json 的 scripts 为:

"dev":"webpack --config ./webpack.config.dev.js --progress --colors"

如果以后每个版本都有个独立的包的话,那么势必 webpack 的配置也会有多个,而多个 webpack 配置唯一不一样的地方就是版本号!设想下可能是这样:

"dev3.5.0":"webpack --config ./webpack.config.dev3.5.0.js --progress --colors"
"dev4.0.0":"webpack --config ./webpack.config.dev4.0.0.js --progress --colors"
"dev5.0.0":"webpack --config ./webpack.config.dev5.0.0.js --progress --colors"
。。。

貌似可以哈!原谅我的强迫症,每次复制粘贴相关模块就算了,连开发环境的配置也得重新弄一份,以后要加或改个 loader、plugin 什么的,不是得每个配置文件走一遍。。。

这时候 Nodejs 该做点什么了:比如,命令行输入 node startWebpack 3.5.0,那么首先尝试启动 3.5.0 版本,如果没有该版本,则创建 3.5.0 版本并启动它;到这的话,package.json 的 scripts 的相关 webpack 启动都是多余的了,接下来要做的就是在 startWebpack.js 里根据输入的版本号启动对应版本,打包对应版本的前端资源;同时开多个版本的话也互不影响,各自独立工作;目前实现了三种命令,注意不是三个命令:

1、node startWebpack init newVersion [from oldVersion]

初始化一个版本,可以指定从哪个版本的基础上生成新版本

2、node startWebpack version

启动一个版本

3、除了上面两个,其它参数统一返回已存在的所有版本号

详细代码就不出了,可能这种需求不具有普遍性,坑啊!

原来的 webpack.config.js 里需要提前注入一个 version 参数;

var agrs=process.argv.slice(2).join(' ');
var matAegsInit=agrs.match(/init\s+([^\s]+)(?:\sfrom\s(.+))?/);
var matAegsStart=agrs.match(/\s+/);

function startWebpack(version,webpackConfig){ process.title = process.cwd()+’ Webpack ’ +version; webpack(webpackConfig,(err,stats)=>{ if(err) throw err; process.stdout… }); } module.exports=function bootstrapWebpackVersionCtrl(WebpackVersionConfig){ if(matAegsInit&&matAegsInit.length&&matAegsInit[1]){ initAndStartWebpack();
}else if(!matAegsStart){ startWebpack(); }else{ getVersionList(); } }

以上代码只是大概的轮廓,可忽略,重点在于用代码的方式让 webpack 更加灵活可控,其中还要借助 shelljs 模块用代码实现命令行的很多操作;我可不会告诉别人 Github 上的那个 famanoder/gitsync 其实是从这衍生而来的;

gitsync 可以做什么呢?

1、最简单的做法是,放出了一个 url,限定访问的过期时间或次数,配合 query 参数请求服务器执行相应的 git 命令(事实上可以执行绝大多数命令行可执行的命令),比如:先 git commit -m abc 然后 git pull origin master,甚至到指定目录执行其它可执行命令,为了安全考虑限制下吧,命令限制完了,最好还加个简单的签名,服务器上不比你本地的!

2、就我的个人小站而言,乌七八糟的堆了一大堆,散落着七八个仓库,最近越来越感觉这种做法不靠谱,所已现在统一合为一个仓库了,各种操作也容易,同步备份更方便;既然 gitsync 是 Nodejs 写的,那么再加一个定时任务,定时执行 git pull、git push,那么就相当于定时备份整个服务器的资源了,现在就一个仓库,就算服务器不小心挂了,或是被黑的一塌糊涂,也可以安然的从 github 拉取一份,重启就 OK 了;

3、shelljs 可以做的还有更多,比如,我公司内部对外网的访问做了 ip 限制,很多时候我的线上服务挂了,我无法即时登录服务器重启,这时如果 gitsync 放出了一个 path 参数入口的话,shelljs.cd(query.path);shelljs.exec('npm start');即可重启服务了,当然有 pm2 更好了;

4、gitsync 本应非常简单,如果需要过多的维护,说明该换方案了;

function App(req,res){
// ...
const ser={req,res};
SimpleRouter.call(ser,{
    '/gitsync':()=>{
        const query=parseUrl(req.url);
        validateQuery(err,query=>{
           // ...
            validateSignature(err,baseQuery=>{
                // ...
                sj.exec(query.git,{async:true},(code,stdout,err)=>{
                    // ...
                    res.end(out);
                });
            });
        });
    },
    '*':'404.html'
});

}

详细地址: https://github.com/famanoder/gitsync

如果你已在路上,就勇敢的向前吧!

原文来自:花满楼的博客( https://www.famanoder.com


1 回复

在Node.js环境中,实现服务器仓库的同步与备份通常涉及文件系统操作和网络请求。我们可以使用内置的fs模块和第三方库如axios来简化这一过程。以下是一个基本示例,展示如何从源服务器下载文件并在本地备份,同时保持文件同步。

首先,确保安装了axios库:

npm install axios

然后,使用以下代码实现同步与备份:

const fs = require('fs');
const axios = require('axios');
const path = require('path');

async function syncAndBackup(sourceUrl, destinationPath) {
  try {
    const writer = fs.createWriteStream(destinationPath);
    const response = await axios({
      url: sourceUrl,
      method: 'GET',
      responseType: 'stream'
    });

    response.data.pipe(writer);

    return new Promise((resolve, reject) => {
      writer.on('finish', resolve);
      writer.on('error', reject);
    });
  } catch (error) {
    console.error('Error during sync and backup:', error);
  }
}

// 示例使用
const sourceUrl = 'http://example.com/repository.zip';
const destinationPath = path.join(__dirname, 'backup', 'repository.zip');

// 确保备份目录存在
fs.mkdirSync(path.dirname(destinationPath), { recursive: true });

syncAndBackup(sourceUrl, destinationPath).then(() => {
  console.log('Sync and backup completed successfully.');
});

此代码片段从指定的sourceUrl下载文件,并将其保存到本地的destinationPath。通过fs.mkdirSync确保目标目录存在,并使用axios处理HTTP请求。pipe方法将下载的数据流直接写入文件,实现文件的同步与备份。

回到顶部