缓存管理
This commit is contained in:
parent
43521cf93f
commit
4ac4026187
26
README.md
26
README.md
@ -3,6 +3,17 @@
|
|||||||
P2P CDN
|
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%
|
||||||
|
在线人数越多则减耗比率越大
|
||||||
|
|
||||||
|
@ -2,3 +2,4 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>PCDN</title>
|
<title>PCDN</title>
|
||||||
<script src="./main.js"></script>
|
<script src="./main.js"></script>
|
||||||
|
<img src="test.jpg" />
|
||||||
|
52
main.js
52
main.js
@ -1,33 +1,33 @@
|
|||||||
//export class Node {
|
// 连接信令服务器
|
||||||
// id: ''
|
const protocol = window.location.protocol.replace('http', 'ws')
|
||||||
// name: ''
|
const ws = new WebSocket(`${protocol}//${window.location.host}/api`)
|
||||||
// assets: new Map()
|
ws.onopen = () => {
|
||||||
// get(name) {}
|
console.log('WebSocket connection opened')
|
||||||
// set(name) {}
|
ws.send(JSON.stringify({ type: 'init', data: 'Hello Server' }))
|
||||||
// del(name) {}
|
}
|
||||||
//}
|
ws.onmessage = (event) => {
|
||||||
//
|
console.log('Message from server:', event.data)
|
||||||
//export const nodes = new Map() // 在线的节点
|
}
|
||||||
//export const assets = new Map() // 在线的资源
|
ws.onerror = (error) => {
|
||||||
//
|
console.error('WebSocket error:', error)
|
||||||
//// 示例: 查询持有某个资源的节点列表
|
}
|
||||||
//const list = query('xxx.jpg').map(item => 'node id')
|
ws.onclose = () => {
|
||||||
//const 测速排序 = () => {}
|
console.log('WebSocket connection closed')
|
||||||
//
|
}
|
||||||
//// 查询某个
|
|
||||||
//
|
|
||||||
//// 示例: 通过PCDN节点网络获取某个资源
|
|
||||||
//const pcdn = new PCDN({ server: '/pcdn' })
|
|
||||||
//pcdn.get('xxx.jpg').then(file => {})
|
|
||||||
|
|
||||||
|
// Service Worker
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
navigator.serviceWorker.addEventListener('message', event => {
|
navigator.serviceWorker.addEventListener('message', event => {
|
||||||
console.log('收到消息 Service Worker: ', event.data) // 接收消息
|
console.log('收到消息 Service Worker: ', event.data) // 接收消息
|
||||||
event.source.postMessage('Hello from main thread') // 回应 Service Worker
|
event.source.postMessage('Hello from main thread') // 回应 Service Worker
|
||||||
})
|
})
|
||||||
navigator.serviceWorker.register('/sw.js').then((registration) => {
|
navigator.serviceWorker.register('/sw.js')
|
||||||
console.log('Service Worker 注册成功: ')
|
//.then((registration) => {
|
||||||
}).catch((error) => {
|
// console.log('Service Worker 注册成功')
|
||||||
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)
|
||||||
|
//})
|
||||||
|
10
package.json
10
package.json
@ -2,13 +2,19 @@
|
|||||||
"name": "pcdn",
|
"name": "pcdn",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "P2P CDN",
|
"description": "P2P CDN",
|
||||||
"main": "index.js",
|
"type": "module",
|
||||||
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --open"
|
"dev": "concurrently 'vite --open' 'node server.js'",
|
||||||
|
"start": "node server.js"
|
||||||
},
|
},
|
||||||
"author": "satori.love",
|
"author": "satori.love",
|
||||||
"license": "GPL-3.0-only",
|
"license": "GPL-3.0-only",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"concurrently": "^8.2.2",
|
||||||
"vite": "^5.2.12"
|
"vite": "^5.2.12"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ws": "^8.18.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
public/test.jpg
Normal file
BIN
public/test.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 73 KiB |
29
server.js
Normal file
29
server.js
Normal 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
81
sw.js
@ -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) => {
|
self.addEventListener('install', (event) => {
|
||||||
console.log('Service Worker 安装')
|
console.log('Service Worker 安装')
|
||||||
})
|
})
|
||||||
|
|
||||||
self.addEventListener('activate', (event) => {
|
self.addEventListener('activate', (event) => {
|
||||||
console.log('Service Worker 激活')
|
console.log('Service Worker 激活, 立即接管页面')
|
||||||
|
event.waitUntil(clients.claim())
|
||||||
})
|
})
|
||||||
|
|
||||||
self.addEventListener('fetch', (event) => {
|
self.addEventListener('fetch', (event) => {
|
||||||
console.log('Fetch intercepted for:', event.request.url)
|
//console.log('Service Worker 获取资源:', event.request.url)
|
||||||
self.clients.matchAll().then(clients => {
|
|
||||||
clients.forEach(client => {
|
if (!event.request.url.match(/\.(jpeg|jpg|gif|png|webp|svg)$/i)) {
|
||||||
client.postMessage('Hello from Service Worker')
|
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 => {
|
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');
|
||||||
|
//}
|
Loading…
Reference in New Issue
Block a user