`choise/index.js` 的代码简单调整一下。

pull/311/head
王良 2024-04-30 15:53:17 +08:00
parent 166ccd13a1
commit 17bf7c4e36
4 changed files with 58 additions and 51 deletions

View File

@ -25,40 +25,44 @@ class ChoiceCache {
class DynamicChoice {
constructor (key) {
this.key = key
this.count = {}
this.countMap = {} /* ip -> count { value, total, error, keepErrorCount, successRate } */
this.value = null // 当前使用的host
this.backupList = [] // 备选host列表
this.createTime = new Date()
}
doRank () {
// 将count里面根据权重排序
const list = []
for (const key in this.count) {
list.push(this.count[key])
// 将count里面根据成功率排序
const countList = []
for (const key in this.countMap) {
countList.push(this.countMap[key])
}
list.sort((a, b) => {
// 将countList根据成功率排序
countList.sort((a, b) => {
return b.successRate - a.successRate
})
log.info('do rank', JSON.stringify(list))
const backup = list.map(item => item.value)
this.setBackupList(backup)
log.info('Do rank:', JSON.stringify(countList))
const newBackupList = countList.map(item => item.value)
this.setBackupList(newBackupList)
}
/**
* 设置新的backup列表
* @param backupList
* @param newBackupList 新的backupList
*/
setBackupList (backupList) {
this.backup = backupList
let defaultTotal = backupList.length
for (const item of backupList) {
if (this.count[item]) {
continue
setBackupList (newBackupList) {
this.backupList = newBackupList
let defaultTotal = newBackupList.length
for (const ip of newBackupList) {
if (!this.countMap[ip]) {
this.countMap[ip] = { value: ip, total: defaultTotal, error: 0, keepErrorCount: 0, successRate: 0.5 }
defaultTotal--
}
this.count[item] = { value: item, total: defaultTotal, error: 0, keepErrorCount: 0, successRate: 0.5 }
defaultTotal--
}
this.value = backupList.shift()
this.value = newBackupList.shift()
this.doCount(this.value, false)
}
@ -67,45 +71,52 @@ class DynamicChoice {
}
/**
* 换下一个
* @param count
*/
* 换下一个
* @param count 计数器
*/
changeNext (count) {
log.info('切换backup', count, this.backup)
log.info('切换backup', count, this.backupList)
count.keepErrorCount = 0 // 清空连续失败
count.total = 0
count.error = 0
if (this.backup.length > 0) {
this.value = this.backup.shift()
const valueBackup = this.value
if (this.backupList.length > 0) {
this.value = this.backupList.shift()
log.info(`切换backup完成: ${this.key}, ip: ${valueBackup}${this.value}, this:`, this)
} else {
this.value = null
log.info(`切换backup完成: ${this.key}, backupList为空了设置this.value: from '${valueBackup}' to null. this:`, this)
}
log.info('切换backup完成', this.value, this.backup)
}
/**
* 记录使用次数或错误次数
* @param value
* @param isError
*/
doCount (value, isError) {
let count = this.count[value]
* 记录使用次数或错误次数
* @param ip
* @param isError
*/
doCount (ip, isError) {
let count = this.countMap[ip]
if (count == null) {
count = this.count[value] = { value: value, total: 5, error: 0, keepErrorCount: 0, successRate: 1 }
count = this.countMap[ip] = { value: ip, total: 5, error: 0, keepErrorCount: 0, successRate: 1 }
}
if (isError) {
// 失败次数+1累计连续失败次数+1
count.error++
count.keepErrorCount++
} else {
count.total += 1
// 总次数+1
count.total++
}
// 计算成功率
count.successRate = 1.0 - (count.error / count.total)
if (isError && this.value === value) {
if (isError && this.value === ip) {
// 连续错误3次切换下一个
if (count.keepErrorCount >= 3) {
this.changeNext(count)
}
// 成功率小于50%,切换下一个
// 成功率小于40%,切换下一个
if (count.successRate < 0.4) {
this.changeNext(count)
}

View File

@ -50,7 +50,7 @@ module.exports = function createConnectHandler (sslConnectInterceptor, middlewar
function connect (req, cltSocket, head, hostname, port, dnsConfig/* , sniRegexpMap */) {
// tunneling https
// log.info('connect:', hostname, port)
const start = new Date().getTime()
const start = new Date()
let isDnsIntercept = null
const hostport = `${hostname}:${port}`
// const replaceSni = matchUtil.matchHostname(sniRegexpMap, hostname, 'sni')
@ -102,13 +102,13 @@ function connect (req, cltSocket, head, hostname, port, dnsConfig/* , sniRegexpM
log.error(`cltSocket error: ${hostport}, errorMsg: ${e.message}`)
})
proxySocket.on('timeout', () => {
const end = new Date().getTime()
log.info('代理socket timeout', hostname, port, (end - start) + 'ms')
const cost = new Date() - start
log.info('代理socket timeout', hostname, port, cost + 'ms')
})
proxySocket.on('error', (e) => {
// 连接失败可能被GFW拦截或者服务端拥挤
const end = new Date().getTime()
log.error('代理连接失败:', e.message, hostname, port, (end - start) + 'ms')
const cost = new Date() - start
log.error('代理连接失败:', e.message, hostname, port, cost + 'ms')
cltSocket.destroy()
if (isDnsIntercept) {
const { dns, ip, hostname } = isDnsIntercept

View File

@ -109,7 +109,7 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
function onFree () {
const url = `${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${rOptions.path}`
const start = new Date().getTime()
const start = new Date()
log.info('代理请求:', url, rOptions.method, rOptions.servername ? ', sni: ' + rOptions.servername : '')
let isDnsIntercept
if (dnsConfig) {
@ -147,8 +147,7 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
// log.debug('agent:', rOptions.agent)
// log.debug('agent.options:', rOptions.agent.options)
proxyReq = (rOptions.protocol === 'https:' ? https : http).request(rOptions, (proxyRes) => {
const end = new Date().getTime()
const cost = end - start
const cost = new Date() - start
if (rOptions.protocol === 'https:') {
log.info('代理请求返回:', url, cost + 'ms')
}
@ -161,8 +160,7 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
// 代理请求的事件监听
proxyReq.on('timeout', () => {
const end = new Date().getTime()
const cost = end - start
const cost = new Date() - start
log.error('代理请求超时', rOptions.protocol, rOptions.hostname, rOptions.path, cost + 'ms')
countSlow(isDnsIntercept, 'to slow ' + cost + 'ms')
proxyReq.end()
@ -172,15 +170,13 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
reject(error)
})
proxyReq.on('error', (e) => {
const end = new Date().getTime()
const cost = end - start
const cost = new Date() - start
log.error('代理请求错误', e.code, e.message, rOptions.hostname, rOptions.path, cost + 'ms')
countSlow(isDnsIntercept, 'error:' + e.message)
reject(e)
})
proxyReq.on('aborted', () => {
const end = new Date().getTime()
const cost = end - start
const cost = new Date() - start
log.error('代理请求被取消', rOptions.hostname, rOptions.path, cost + 'ms')
if (cost > MAX_SLOW_TIME) {

View File

@ -24,7 +24,7 @@ utils.createCA = function (CN) {
const cert = pki.createCertificate()
cert.publicKey = keys.publicKey
cert.serialNumber = (new Date()).getTime() + ''
cert.validity.notBefore = new Date(new Date().getTime() - (60 * 60 * 1000))
cert.validity.notBefore = new Date(new Date() - (60 * 60 * 1000))
cert.validity.notAfter = new Date()
cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 20)
const attrs = [{