多宽带叠加的分布式云盘:文件秒传、断点续传、大文件下载

多宽带叠加的分布式云盘:文件秒传、断点续传、大文件下载

*
1. 前言
2. 各种私有云盘对比
3.本云盘实现的功能
4. 界面
4. 安装

+ 4.1 负载均衡服务器
+ 4.1 储存节点
5. 代码说明

1. 前言

家中有三条宽带,想通过搭建私有云盘,叠加上传和下载的速度。对比了多种私有云的系统,没找到满足的要求的,所以便萌生出搭建一个可宽带叠加的分布式私有云存储。

2. 各种私有云盘对比

可道云、Nextcloud、易有云:没有多节点。
Cloidreve:有从服务器,但只是用来离线下载的
Seafile:支持ceph分布式储存,只能单节点。
IPFS:去中心化,p2p,未来之星。网关被污染了,有点费硬盘。
Minio: 分布式储存,但传输时只有一个节点传输,别的节点负责加油。
Resilio Sync、微力备份(接近要求,但属于备份软件,比较占储存空间)
jigdo(实现不了,没找到部署教程)(大佬可是试试这个)

3.本云盘实现的功能

多宽带叠加的分布式云盘:文件秒传、断点续传、大文件下载

√ 多节点
√ 部署简单
√ 文件秒传
√ 断点续传
√ MD5值校验
√ minio存储(防止文件上传漏洞)
√ 大文件下载(数据流的方式,内存占用小)
√ 下载和上传的速度基本取决于宽带上传的下载的速度。

; 4. 界面

上传界面

多宽带叠加的分布式云盘:文件秒传、断点续传、大文件下载

文件浏览

多宽带叠加的分布式云盘:文件秒传、断点续传、大文件下载

4. 安装

4.1 负载均衡服务器

负责提供浏览界面,接收客户端的请求,返回文件的md5。

多宽带叠加的分布式云盘:文件秒传、断点续传、大文件下载
只需修改config.php

$nodes = ['http://ip1:80',"http://ip2:80"];
$dbh = new PDO('mysql:host=localhost;dbname=dbname', "dbuser", "password");
?>

4.1 储存节点

修改


minioClient = Minio('ip:9000',
                  access_key='minio_key',
                  secret_key='minio_secret',
                  secure=False)

buckets = "mydisk"

运行

//运行minio
/home/minio/app/minio server /home/minio/data --config-dir /home/minio/config --console-address :42606 --address :9000

//运行node.py
python3 node.py

5. 代码说明

计算文件的MD5 ,获取切片


function md5(file, chunkSize = 1024*1024*1) {
    return new Promise((resolve, reject) => {
        let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
        let chunks = Math.ceil(file.size / chunkSize);
        let currentChunk = 0;
        let spark = new SparkMD5.ArrayBuffer();
        let fileReader = new FileReader();
        var slices = [];
        fileReader.onload = function(e) {
            spark.append(e.target.result);
            currentChunk++;

            num = 100*currentChunk/chunks;
            num = num.toFixed(2);
            jindutiao(num,"计算哈希","#7A0BE2")

            if (currentChunk < chunks) {
                loadNext();
            } else {
                slices.push(spark.end());
                resolve(slices);
            }
        };

        function loadNext() {
            let start = currentChunk * chunkSize;
            let end = start + chunkSize;
            if (end > file.size){
                end = file.size;
            }
            slice = blobSlice.call(file, start, end);
            slices.push(slice);
            fileReader.readAsArrayBuffer(slice);
        }
        loadNext();
    });
}

上传片段


function sendChunk(id, chunks,offset,name){

  var  task=offset.length;
  var  alllen = chunks.length ;

  chunks.forEach(function(chunk, index){

        if (offset.length > 0) {text = "断点续传";}
        if (offset.length === 0){text = "文件上传";}

       if (offset.indexOf(index.toString()) >= 0) {
         return;
       }

        var formData = new FormData();
        formData.append('fileId', id);
        formData.append('myFileChunk', chunk);
        formData.append('chunkIndex', index);
        url = nodes[index%nodes.length]+"/success";

        console.log(url);
        $.ajax({
          type: "POST",
          url: url,
          data: formData,
          contentType: false,
          processData: false,
          async: true,
          success: function(done){
              console.log("a00" + done + "a00");
            if(done == 200){
                task =task + 1;
                num = 100*task/alllen ;
                num = num.toFixed(2);
                console.log(index + "已完成" + num.toString() + "%");
                jindutiao(num,text)
            }
          }
        })
    })
}

进度条


function jindutiao(ini,text,color="pink") {
    let texth = document.getElementById("text");
    let cont = document.getElementById("cont");
    let container = document.getElementById("container");

    cont.style.backgroundColor = color;
    container.style.display = 'block';
    cont.style.width = ini + "%";
    if(ini>=100){
        text = text + "成功";
        ini = 100.00;
    }
    texth.innerText = text + ": " + ini + "%";
}

下载文件,二进制的方式。


function getBinaryContent(url , i) {

    return new Promise((resolve, reject) => {
        try {
            let xhr = new XMLHttpRequest();
            xhr.open("GET", url, true);
            xhr.responseType = "arraybuffer";
            xhr.onload = function () {
                resolve({
                    index: i,
                    buffer: xhr.response,
                });
            };
            xhr.onprogress=function(event){
                if(event.lengthComputable) {
                    var percentComplete = event.loaded / event.total*100;
                        percentComplete = percentComplete.toFixed(2);

                }
            }
            xhr.send();
        } catch (err) {
            reject(new Error(err));
        }
    });

}

多进程


async function download( urls, poolLimit = 2 ) {

    const fileStream= streamSaver.createWriteStream(filename);
    const writer = fileStream.getWriter();
    const all_part_num = Object.keys(urls).length;
    const pools = oneArrToTwoArr([...new Array(all_part_num).keys()],poolLimit*2);
    const MD5 = new SparkMD5();

    for (let pool of pools) {
        var results = await asyncPool(
            poolLimit,
            pool,
            (i) => {

                ini = (i+1)/all_part_num*100;
                ini = ini.toFixed(2)
                jindutiao(ini,"文件下载")

                return getBinaryContent(urls[i], i);
            }
        );

        var sortedBuffers = results.map((item) => new Uint8Array(item.buffer));

        for (let array of sortedBuffers) {
            writer.write(array)
        }
    }
    writer.close();
}

async function asyncPool(poolLimit, array, iteratorFn) {
    const ret = [];
    const executing = [];
    for (const item of array) {

        const p = Promise.resolve().then(() => iteratorFn(item, array));
        ret.push(p);

        if (poolLimit  array.length) {

            const e = p.then(() => executing.splice(executing.indexOf(e), 1));
            executing.push(e);
            if (executing.length >= poolLimit) {
                await Promise.race(executing);
            }
        }
    }
    return Promise.all(ret);
}

下载文件,二进制的方式。


function getBinaryContent(url , i) {

    return new Promise((resolve, reject) => {
        try {
            let xhr = new XMLHttpRequest();
            xhr.open("GET", url, true);
            xhr.responseType = "arraybuffer";
            xhr.onload = function () {
                resolve({
                    index: i,
                    buffer: xhr.response,
                });
            };
            xhr.onprogress=function(event){
                if(event.lengthComputable) {
                    var percentComplete = event.loaded / event.total*100;
                        percentComplete = percentComplete.toFixed(2);

                }
            }
            xhr.send();
        } catch (err) {
            reject(new Error(err));
        }
    });

}

Original: https://blog.csdn.net/liuyuncc/article/details/126142290
Author: 流云cc
Title: 多宽带叠加的分布式云盘:文件秒传、断点续传、大文件下载

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/748556/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球