缓存管理

This commit is contained in:
Last 2025-03-25 01:23:03 +08:00
parent 43521cf93f
commit 4ac4026187
7 changed files with 163 additions and 36 deletions

View File

@ -3,6 +3,17 @@
P2P CDN
/data/path/filename.xx
缓存指定资源后, 假设资源按 16kb 分片
a1 要求返回第 1 片,
a2 要求返回第 2 片, 如果 a2 提前完成, 继续返回第 3 片
全部分片接收完毕后合并进行 size 和 hash 验证
资源表汇报给
持有资源变动时, 通知节点列表
获取一个资源时, 先查找拥有此资源的节点列表
@ -34,3 +45,18 @@ O1双向查询
建立连接后交换资源列表及过期时间
### 最短响应时间
1. 请求某个资源时, 先向节点列表伺服器请求拥有此资源的节点列表, 再通过节点列表取一个建立连接信道, 随后获取此资源
2. 由于节点是持久在线, 资源伺服器对节点空间位置进行节点网络分布预测, 返回给距离请求节点最近的几个节点列表(减少地域距离耗时)
3. 同时向多个节点建立连接, 获取某个资源时从不同节点请求不同分片, 这需要预先了解资源大小分片数量(通过并发减少串行下载时间, 且能从更快的节点下载更多的分片, 慢的节点减少分片下载)
4. 建立连接需要多次三方通信握手, 且保持连接也需要续握手, 如何减少握手时间?
5. 每个资源都从服务器请求节点列表效率极差, 如何复用,
6. 建立连接耗时较大, 如何复用连接?
在线与资源分布计算,
假设 10-100 同时在线, 每节点储量为1000资源(1GB)
100 设备储存 100G资源, 去除重复 75% 则 25G 资源被减耗
高峰访问不均, 利用率上升 50% 则实 %50 流量被减耗
由于峰值浮动, 在低谷期减耗效率仅为 10%
在线人数越多则减耗比率越大

View File

@ -2,3 +2,4 @@
<meta charset="UTF-8">
<title>PCDN</title>
<script src="./main.js"></script>
<img src="test.jpg" />

52
main.js
View File

@ -1,33 +1,33 @@
//export class Node {
// id: ''
// name: ''
// assets: new Map()
// get(name) {}
// set(name) {}
// del(name) {}
//}
//
//export const nodes = new Map() // 在线的节点
//export const assets = new Map() // 在线的资源
//
//// 示例: 查询持有某个资源的节点列表
//const list = query('xxx.jpg').map(item => 'node id')
//const 测速排序 = () => {}
//
//// 查询某个
//
//// 示例: 通过PCDN节点网络获取某个资源
//const pcdn = new PCDN({ server: '/pcdn' })
//pcdn.get('xxx.jpg').then(file => {})
// 连接信令服务器
const protocol = window.location.protocol.replace('http', 'ws')
const ws = new WebSocket(`${protocol}//${window.location.host}/api`)
ws.onopen = () => {
console.log('WebSocket connection opened')
ws.send(JSON.stringify({ type: 'init', data: 'Hello Server' }))
}
ws.onmessage = (event) => {
console.log('Message from server:', event.data)
}
ws.onerror = (error) => {
console.error('WebSocket error:', error)
}
ws.onclose = () => {
console.log('WebSocket connection closed')
}
// Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.addEventListener('message', event => {
console.log('收到消息 Service Worker: ', event.data) // 接收消息
event.source.postMessage('Hello from main thread') // 回应 Service Worker
})
navigator.serviceWorker.register('/sw.js').then((registration) => {
console.log('Service Worker 注册成功: ')
}).catch((error) => {
console.log('Service Worker 注册失败: ')
})
navigator.serviceWorker.register('/sw.js')
//.then((registration) => {
// console.log('Service Worker 注册成功')
// registration.showNotification('Hello World')
//})
}
//navigator.storage.estimate().then((estimate) => {
// console.log('Storage usage: ', estimate.usage / 1000 / 1000 / 1000, estimate.quota / 1000 / 1000 / 1000)
//})

View File

@ -2,13 +2,19 @@
"name": "pcdn",
"version": "1.0.0",
"description": "P2P CDN",
"main": "index.js",
"type": "module",
"main": "main.js",
"scripts": {
"dev": "vite --open"
"dev": "concurrently 'vite --open' 'node server.js'",
"start": "node server.js"
},
"author": "satori.love",
"license": "GPL-3.0-only",
"devDependencies": {
"concurrently": "^8.2.2",
"vite": "^5.2.12"
},
"dependencies": {
"ws": "^8.18.1"
}
}

BIN
public/test.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

29
server.js Normal file
View File

@ -0,0 +1,29 @@
import http from 'http'
import { WebSocketServer } from 'ws'
// 创建一个 HTTP 服务器
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' })
res.end('WebSocket server is running')
})
// 创建 WebSocket 服务器,并将其绑定到 HTTP 服务器
const wss = new WebSocketServer({ server })
// 处理 WebSocket 连接
wss.on('connection', ws => {
console.log('A new client connected!')
// 监听客户端发送的消息
ws.on('message', message => {
console.log('收到数据:', message)
})
// 发送欢迎消息给客户端
ws.send('Hello from WebSocket server!')
})
// 启动 HTTP 服务器,监听端口
server.listen(8080, () => {
console.log('Server is listening on http://localhost:8080')
})

81
sw.js
View File

@ -1,20 +1,85 @@
const CACHE_NAME = 'file-cache-v1'
const FILE_TYPES = ['image/png', 'image/jpeg', 'image/gif', 'image/webp', 'image/svg+xml']
self.addEventListener('install', (event) => {
console.log('Service Worker 安装')
})
self.addEventListener('activate', (event) => {
console.log('Service Worker 激活')
console.log('Service Worker 激活, 立即接管页面')
event.waitUntil(clients.claim())
})
self.addEventListener('fetch', (event) => {
console.log('Fetch intercepted for:', event.request.url)
self.clients.matchAll().then(clients => {
clients.forEach(client => {
client.postMessage('Hello from Service Worker')
//console.log('Service Worker 获取资源:', event.request.url)
if (!event.request.url.match(/\.(jpeg|jpg|gif|png|webp|svg)$/i)) {
return event.respondWith(fetch(event.request))
}
event.respondWith(
caches.match(event.request).then(async (cachedResponse) => {
// 如果文件已缓存,则返回缓存的响应
if (cachedResponse) {
console.log('使用了缓存:', event.request.url)
for (const key of await caches.keys()) {
const cache = await caches.open(key)
const requests = await cache.keys()
requests.forEach((request) => {
console.log(request.url)
})
}
return cachedResponse
}
// 如果缓存中没有,则发起网络请求并缓存新图像(检查网络响应是否为文件)
return fetch(event.request).then(async (networkResponse) => {
if (networkResponse && networkResponse.ok && FILE_TYPES.includes(networkResponse.headers.get('Content-Type'))) {
const cache = await caches.open(CACHE_NAME)
await cache.put(event.request, networkResponse.clone())
}
return networkResponse
})
})
})
)
//// 先尝试从 webRTC 获取资源, 如果失败则从网络获取资源
//event.respondWith(async function () {
// const response = await fetch(event.request)
// return response
//}())
//event.respondWith(fetch(event.request))
//self.clients.matchAll().then(clients => {
// clients.forEach(client => {
// client.postMessage('Hello from Service Worker')
// })
//})
})
self.addEventListener('message', event => {
console.log('收到主线程消息: ', event.data)
console.log("%c收到主线程消息: " + event.data, 'color: red;')
})
//// 检查通知权限
//if (Notification.permission === 'granted') {
// // 如果已经授权,则可以显示通知
// registration.showNotification('Hello World')
//} else if (Notification.permission === 'default') {
// // 如果权限尚未授予,则请求权限
// Notification.requestPermission().then(permission => {
// if (permission === 'granted') {
// // 权限授予成功后显示通知
// showNotification();
// } else {
// console.log('Notification permission denied');
// }
// }).catch(err => {
// console.log('Failed to request notification permission', err);
// });
//} else {
// console.log('Notification permission denied');
//}