Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
C
cdn-node-checker
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nanahira
cdn-node-checker
Commits
f917e7d9
Commit
f917e7d9
authored
Sep 01, 2022
by
nanahira
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
support multiple sources
parent
1d7f0337
Pipeline
#16314
passed with stages
in 3 minutes and 8 seconds
Changes
1
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
180 additions
and
74 deletions
+180
-74
run.ts
run.ts
+180
-74
No files found.
run.ts
View file @
f917e7d9
...
...
@@ -3,20 +3,23 @@ import axios from 'axios';
import
_
from
'
lodash
'
;
import
YAML
from
'
yaml
'
;
import
fs
from
'
fs
'
;
import
{
CronJob
}
from
'
cron
'
;
import
net
from
'
net
'
;
import
{
assert
}
from
'
console
'
;
import
{
ping
}
from
'
icmp
'
;
import
delay
from
'
delay
'
;
interface
RecordRule
{
match
?:
string
;
interface
Source
{
protocol
:
string
;
port
:
number
;
testDomains
?:
string
[];
source
?:
string
;
}
interface
RecordRule
{
match
?:
string
;
sources
:
Source
[];
}
interface
Config
{
aliyun
:
Aliyun
.
Config
;
domain
:
string
;
...
...
@@ -58,8 +61,7 @@ let config: Config;
interface
DomainRecordInfo
{
recordRule
:
RecordRule
;
record
:
DomainRecord
;
protocol
:
string
;
port
:
number
;
sources
:
Source
[];
isCDN
:
boolean
;
good
:
ConnectResult
;
}
...
...
@@ -84,7 +86,7 @@ class Checker {
private
CDNRecords
:
DomainRecordInfo
[];
private
checkMethods
=
new
Map
<
string
,
(
record
:
RecordRul
e
,
address
:
string
)
=>
Promise
<
ConnectResult
>
(
record
:
Sourc
e
,
address
:
string
)
=>
Promise
<
ConnectResult
>
>
();
private
availableRecordRules
:
RecordRule
[];
...
...
@@ -92,53 +94,96 @@ class Checker {
this
.
availableRecordRules
=
[];
await
Promise
.
all
(
this
.
config
.
cdnRecords
.
map
(
async
(
rule
)
=>
{
if
(
rule
.
protocol
===
'
tcp
'
&&
rule
.
source
)
{
this
.
message
(
`Checking source
${
rule
.
source
}
:
${
rule
.
port
}
.`
);
try
{
const
ms
=
await
this
.
checkTcpProcess
(
rule
.
source
,
rule
.
port
);
this
.
availableRecordRules
.
push
(
rule
);
this
.
message
(
`Source
${
rule
.
source
}
:
${
rule
.
port
}
is good:
${
ms
}
ms.`
,
);
}
catch
(
e
)
{
this
.
message
(
`Skipping rule
${
rule
.
match
}
fo source
${
rule
.
source
}
:
${
rule
.
port
}
unhealthy:
${
e
.
toString
()}
`
,
);
}
}
else
if
(
rule
.
source
&&
(
rule
.
protocol
===
'
http
'
||
rule
.
protocol
===
'
https
'
)
)
{
const
availableTestDomains
:
string
[]
=
[];
for
(
const
domain
of
rule
.
testDomains
)
{
this
.
message
(
`Checking source domain
${
domain
}
:
${
rule
.
port
}
.`
);
const
errMessage
=
await
this
.
tryConnectHttp
(
rule
.
protocol
,
domain
,
rule
.
port
,
domain
,
);
if
(
errMessage
)
{
const
{
sources
}
=
rule
;
const
goodSources
:
Source
[]
=
[];
await
Promise
.
all
(
sources
.
map
(
async
(
source
)
=>
{
if
(
source
.
protocol
===
'
tcp
'
&&
source
.
source
)
{
this
.
message
(
`Skipping domain
${
domain
}
of rule
${
rule
.
match
}
for bad source:
${
errMessage
}
`
,
`Checking source
${
this
.
getSourcePattern
(
source
,
source
.
source
,
)}
.`
,
);
try
{
const
ms
=
await
this
.
checkTcpProcess
(
source
.
source
,
source
.
port
,
);
goodSources
.
push
(
source
);
this
.
message
(
`Source
${
this
.
getSourcePattern
(
source
,
source
.
source
,
)}
is good:
${
ms
}
ms.`
,
);
}
catch
(
e
)
{
this
.
message
(
`Skipping rule
${
rule
.
match
}
for source
${
this
.
getSourcePattern
(
source
,
source
.
source
,
)}
unhealthy:
${
e
.
toString
()}
`
,
);
}
}
else
if
(
source
.
protocol
===
'
http
'
||
source
.
protocol
===
'
https
'
)
{
const
availableTestDomains
:
string
[]
=
[];
await
Promise
.
all
(
source
.
testDomains
.
map
(
async
(
domain
)
=>
{
this
.
message
(
`Checking source domain
${
this
.
getSourcePattern
(
source
,
domain
,
)}
.`
,
);
const
errMessage
=
await
this
.
tryConnectHttp
(
source
.
protocol
,
domain
,
source
.
port
,
domain
,
);
if
(
errMessage
)
{
this
.
message
(
`Skipping domain
${
this
.
getSourcePattern
(
source
,
domain
,
)}
of rule
${
rule
.
match
}
for bad source:
${
errMessage
}
`
,
);
}
else
{
this
.
message
(
`Source domain
${
this
.
getSourcePattern
(
source
,
domain
,
)}
is good.`
,
);
availableTestDomains
.
push
(
domain
);
}
}),
);
if
(
availableTestDomains
.
length
)
{
source
.
testDomains
=
availableTestDomains
;
goodSources
.
push
(
source
);
}
else
{
this
.
message
(
`Skipping source
${
rule
.
match
}
${
source
.
testDomains
.
join
(
'
,
'
,
)}
for no available source domains.`
,
);
}
}
else
{
this
.
message
(
`Source domain
${
domain
}
is good.`
);
availableTestDomains
.
push
(
domain
);
goodSources
.
push
(
source
);
}
}
if
(
availableTestDomains
.
length
)
{
rule
.
testDomains
=
availableTestDomains
;
this
.
availableRecordRules
.
push
(
rule
);
}
else
{
this
.
message
(
`Skipping rule
${
rule
.
match
}
for no available sources.`
,
);
}
}
else
{
}),
);
if
(
goodSources
.
length
)
{
rule
.
sources
=
goodSources
;
this
.
availableRecordRules
.
push
(
rule
);
}
else
{
this
.
message
(
`Skipping rule
${
rule
.
match
}
for no available sources.`
);
}
}),
);
...
...
@@ -167,7 +212,7 @@ class Checker {
// const urlKey = `${url}-${hostHeader}`;
return
this
.
connectHttpProcess
(
url
,
hostHeader
);
}
async
checkHttpOrHttps
(
record
:
RecordRul
e
,
address
:
string
)
{
async
checkHttpOrHttps
(
record
:
Sourc
e
,
address
:
string
)
{
let
good
=
false
;
if
(
!
record
.
testDomains
.
length
)
{
return
ConnectResult
.
SourceBad
;
...
...
@@ -194,7 +239,10 @@ class Checker {
);
if
(
nodeErrorMessage
!=
null
)
{
this
.
message
(
`Node
${
address
}
:
${
record
.
port
}
is broken:
${
nodeErrorMessage
}
`
,
`Connection
${
this
.
getSourcePattern
(
record
,
address
,
)}
is broken:
${
nodeErrorMessage
}
`
,
);
return
ConnectResult
.
CDNBad
;
}
else
{
...
...
@@ -202,10 +250,17 @@ class Checker {
}
}
if
(
!
good
)
{
this
.
message
(
`Node
${
address
}
:
${
record
.
port
}
skipped for no sources.`
);
this
.
message
(
`Connection
${
this
.
getSourcePattern
(
record
,
address
,
)}
skipped for no sources.`
,
);
return
ConnectResult
.
SourceBad
;
}
this
.
message
(
`Node
${
address
}
:
${
record
.
port
}
is good.`
);
this
.
message
(
`Connection
${
this
.
getSourcePattern
(
record
,
address
)}
is good.`
,
);
return
ConnectResult
.
Good
;
}
async
checkTcpProcess
(
address
:
string
,
port
:
number
)
{
...
...
@@ -238,7 +293,7 @@ class Checker {
}
});
}
async
checkTcp
(
record
:
RecordRul
e
,
address
:
string
)
{
async
checkTcp
(
record
:
Sourc
e
,
address
:
string
)
{
/*if (record.source) {
try {
await this.checkTcpProcess(record.source, record.port);
...
...
@@ -251,20 +306,37 @@ class Checker {
}*/
try
{
const
ms
=
await
this
.
checkTcpProcess
(
address
,
record
.
port
);
this
.
message
(
`Node
${
address
}
:
${
record
.
port
}
is good:
${
ms
}
ms.`
);
this
.
message
(
`Connection
${
this
.
getSourcePattern
(
record
,
address
,
)}
is good:
${
ms
}
ms.`
,
);
return
ConnectResult
.
Good
;
}
catch
(
e
)
{
this
.
message
(
`Node
${
address
}
:
${
record
.
port
}
failed:
${
e
.
toString
()}
`
);
this
.
message
(
`Connection
${
this
.
getSourcePattern
(
record
,
address
,
)}
failed:
${
e
.
toString
()}
`
,
);
return
ConnectResult
.
CDNBad
;
}
}
async
checkIcmp
(
address
:
string
)
{
async
checkIcmp
(
record
:
Source
,
address
:
string
)
{
try
{
await
ping
(
address
,
this
.
config
.
timeout
);
this
.
message
(
`Node
${
address
}
:ICMP is good.`
);
this
.
message
(
`Connection
${
this
.
getSourcePattern
(
record
,
address
)}
is good.`
,
);
return
ConnectResult
.
Good
;
}
catch
(
e
)
{
this
.
message
(
`Node
${
address
}
:ICMP failed:
${
e
.
toString
()}
`
);
this
.
message
(
`Connection
${
this
.
getSourcePattern
(
record
,
address
,
)}
failed:
${
e
.
toString
()}
`
,
);
return
ConnectResult
.
CDNBad
;
}
}
...
...
@@ -272,17 +344,17 @@ class Checker {
this
.
client
=
new
Aliyun
(
config
.
aliyun
);
this
.
cdnRecordsRegex
=
config
.
cdnRecords
.
map
((
m
)
=>
new
RegExp
(
m
.
match
));
this
.
id
=
++
Checker
.
order
;
this
.
checkMethods
.
set
(
'
http
'
,
(
record
:
RecordRul
e
,
address
:
string
)
=>
{
this
.
checkMethods
.
set
(
'
http
'
,
(
record
:
Sourc
e
,
address
:
string
)
=>
{
return
this
.
checkHttpOrHttps
(
record
,
address
);
});
this
.
checkMethods
.
set
(
'
https
'
,
(
record
:
RecordRul
e
,
address
:
string
)
=>
{
this
.
checkMethods
.
set
(
'
https
'
,
(
record
:
Sourc
e
,
address
:
string
)
=>
{
return
this
.
checkHttpOrHttps
(
record
,
address
);
});
this
.
checkMethods
.
set
(
'
tcp
'
,
(
record
:
RecordRul
e
,
address
:
string
)
=>
{
this
.
checkMethods
.
set
(
'
tcp
'
,
(
record
:
Sourc
e
,
address
:
string
)
=>
{
return
this
.
checkTcp
(
record
,
address
);
});
this
.
checkMethods
.
set
(
'
icmp
'
,
(
record
:
RecordRul
e
,
address
:
string
)
=>
{
return
this
.
checkIcmp
(
address
);
this
.
checkMethods
.
set
(
'
icmp
'
,
(
record
:
Sourc
e
,
address
:
string
)
=>
{
return
this
.
checkIcmp
(
record
,
address
);
});
}
private
message
(
msg
:
string
)
{
...
...
@@ -300,9 +372,14 @@ class Checker {
valuePrefix
&&
this
.
cdnRecordsRegex
.
some
((
r
)
=>
!!
valuePrefix
.
match
(
r
))
);
}
getSourcePattern
(
source
:
Source
,
address
:
string
)
{
return
`
${
source
.
protocol
}
://
${
address
}
:
${
source
.
port
}
`
;
}
getRecordPattern
(
recordInfo
:
DomainRecordInfo
)
{
const
record
=
recordInfo
.
record
;
return
`
${
record
.
RR
}
.
${
this
.
config
.
domain
}
=>
${
record
.
Value
}
:
${
recordInfo
.
port
}
`
;
return
`
${
record
.
RR
}
.
${
this
.
config
.
domain
}
=>
${
recordInfo
.
sources
.
map
((
s
)
=>
this
.
getSourcePattern
(
s
,
record
.
Value
))
.
join
(
'
,
'
)}
`
;
}
async
getRecords
():
Promise
<
DomainRecordInfo
[]
>
{
this
.
message
(
`Fetching domain records of
${
this
.
config
.
domain
}
.`
);
...
...
@@ -338,13 +415,11 @@ class Checker {
);
continue
;
}
const
{
port
,
protocol
}
=
matchCDNRecord
;
const
isCDN
=
this
.
isCDNRecord
(
record
);
const
recordInfo
:
DomainRecordInfo
=
{
recordRule
:
matchCDNRecord
,
record
,
protocol
,
port
,
sources
:
matchCDNRecord
.
sources
,
isCDN
,
good
:
null
,
};
...
...
@@ -354,27 +429,58 @@ class Checker {
}
return
res
;
}
async
checkNode
(
record
:
RecordRule
,
address
:
string
):
Promise
<
ConnectResult
>
{
const
checkMethodFunction
=
this
.
checkMethods
.
get
(
record
.
protocol
);
async
checkSource
(
source
:
Source
,
address
:
string
):
Promise
<
ConnectResult
>
{
const
checkMethodFunction
=
this
.
checkMethods
.
get
(
source
.
protocol
);
assert
(
checkMethodFunction
,
`Check method
${
record
.
protocol
}
not supported.`
,
`Check method
${
source
.
protocol
}
not supported.`
,
);
let
lastResult
:
ConnectResult
;
for
(
let
i
=
1
;
i
<=
this
.
config
.
retryCount
;
++
i
)
{
const
result
=
await
checkMethodFunction
(
record
,
address
);
const
result
=
await
checkMethodFunction
(
source
,
address
);
if
(
result
==
ConnectResult
.
Good
)
{
return
result
;
}
lastResult
=
result
;
}
if
(
lastResult
===
ConnectResult
.
CDNBad
)
{
this
.
message
(
`Node
${
address
}
:
${
record
.
port
}
is bad.`
);
this
.
message
(
`Connection
${
this
.
getSourcePattern
(
source
,
address
)}
is bad.`
,
);
}
else
{
this
.
message
(
`Node
${
address
}
:
${
record
.
port
}
skipped for source broken.`
);
this
.
message
(
`Connection
${
this
.
getSourcePattern
(
source
,
address
,
)}
skipped for source broken.`
,
);
}
return
lastResult
;
}
async
checkNode
(
recordInfo
:
DomainRecordInfo
):
Promise
<
ConnectResult
>
{
const
record
=
recordInfo
.
recordRule
;
const
address
=
recordInfo
.
record
.
Value
;
const
checks
=
await
Promise
.
all
(
record
.
sources
.
map
(
async
(
source
)
=>
this
.
checkSource
(
source
,
address
)),
);
if
(
checks
.
some
((
r
)
=>
r
===
ConnectResult
.
CDNBad
))
{
this
.
message
(
`Node
${
this
.
getRecordPattern
(
recordInfo
)}
is bad.`
);
return
ConnectResult
.
CDNBad
;
}
if
(
checks
.
every
((
r
)
=>
r
===
ConnectResult
.
SourceBad
))
{
this
.
message
(
`Node
${
this
.
getRecordPattern
(
recordInfo
,
)}
skipped for no good sources.`
,
);
return
ConnectResult
.
SourceBad
;
}
this
.
message
(
`Node
${
this
.
getRecordPattern
(
recordInfo
)}
is good.`
);
return
ConnectResult
.
Good
;
}
async
checkRecord
(
recordInfo
:
DomainRecordInfo
)
{
const
record
=
recordInfo
.
record
;
this
.
message
(
...
...
@@ -382,7 +488,7 @@ class Checker {
recordInfo
,
)}
with old status of
${
record
.
Status
}
.`
,
);
const
good
=
await
this
.
checkNode
(
recordInfo
.
recordRule
,
record
.
Value
);
const
good
=
await
this
.
checkNode
(
recordInfo
);
await
this
.
handleRecordResult
(
recordInfo
,
good
);
}
isRecordGood
(
recordInfo
:
DomainRecordInfo
):
boolean
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment