Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
S
srvpro
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
srvpro
Commits
04888860
Commit
04888860
authored
Nov 15, 2020
by
nanahira
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
rework server init
parent
de15fb02
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1387 additions
and
1426 deletions
+1387
-1426
ygopro-auth.coffee
ygopro-auth.coffee
+2
-2
ygopro-auth.js
ygopro-auth.js
+2
-2
ygopro-server.coffee
ygopro-server.coffee
+502
-513
ygopro-server.js
ygopro-server.js
+881
-909
No files found.
ygopro-auth.coffee
View file @
04888860
...
@@ -59,7 +59,7 @@ add_log = (message) ->
...
@@ -59,7 +59,7 @@ add_log = (message) ->
text
=
mt
.
format
(
'YYYY-MM-DD HH:mm:ss'
)
+
" --> "
+
message
+
"
\n
"
text
=
mt
.
format
(
'YYYY-MM-DD HH:mm:ss'
)
+
" --> "
+
message
+
"
\n
"
res
=
false
res
=
false
try
try
await
util
.
promisify
(
fs
.
appendFile
)
(
"./logs/"
+
mt
.
format
(
'YYYY-MM-DD'
)
+
".log"
,
text
)
await
fs
.
promises
.
appendFile
(
"./logs/"
+
mt
.
format
(
'YYYY-MM-DD'
)
+
".log"
,
text
)
res
=
true
res
=
true
catch
catch
res
=
false
res
=
false
...
@@ -69,7 +69,7 @@ add_log = (message) ->
...
@@ -69,7 +69,7 @@ add_log = (message) ->
default_data
=
loadJSON
(
'./data/default_data.json'
)
default_data
=
loadJSON
(
'./data/default_data.json'
)
setting_save
=
(
settings
)
->
setting_save
=
(
settings
)
->
try
try
await
util
.
promisify
(
fs
.
writeFile
)
(
settings
.
file
,
JSON
.
stringify
(
settings
,
null
,
2
))
await
fs
.
promises
.
writeFile
(
settings
.
file
,
JSON
.
stringify
(
settings
,
null
,
2
))
catch
e
catch
e
add_log
(
"save fail"
);
add_log
(
"save fail"
);
return
return
...
...
ygopro-auth.js
View file @
04888860
...
@@ -73,7 +73,7 @@
...
@@ -73,7 +73,7 @@
text
=
mt
.
format
(
'
YYYY-MM-DD HH:mm:ss
'
)
+
"
-->
"
+
message
+
"
\n
"
;
text
=
mt
.
format
(
'
YYYY-MM-DD HH:mm:ss
'
)
+
"
-->
"
+
message
+
"
\n
"
;
res
=
false
;
res
=
false
;
try
{
try
{
await
util
.
promisify
(
fs
.
appendFile
)
(
"
./logs/
"
+
mt
.
format
(
'
YYYY-MM-DD
'
)
+
"
.log
"
,
text
);
await
fs
.
promises
.
appendFile
(
"
./logs/
"
+
mt
.
format
(
'
YYYY-MM-DD
'
)
+
"
.log
"
,
text
);
res
=
true
;
res
=
true
;
}
catch
(
error
)
{
}
catch
(
error
)
{
res
=
false
;
res
=
false
;
...
@@ -86,7 +86,7 @@
...
@@ -86,7 +86,7 @@
setting_save
=
async
function
(
settings
)
{
setting_save
=
async
function
(
settings
)
{
var
e
;
var
e
;
try
{
try
{
await
util
.
promisify
(
fs
.
writeFile
)
(
settings
.
file
,
JSON
.
stringify
(
settings
,
null
,
2
));
await
fs
.
promises
.
writeFile
(
settings
.
file
,
JSON
.
stringify
(
settings
,
null
,
2
));
}
catch
(
error
)
{
}
catch
(
error
)
{
e
=
error
;
e
=
error
;
add_log
(
"
save fail
"
);
add_log
(
"
save fail
"
);
...
...
ygopro-server.coffee
View file @
04888860
...
@@ -21,6 +21,7 @@ request = require 'request'
...
@@ -21,6 +21,7 @@ request = require 'request'
axios
=
require
'axios'
axios
=
require
'axios'
qs
=
require
"querystring"
qs
=
require
"querystring"
zlib
=
require
'zlib'
zlib
=
require
'zlib'
axios
=
require
'axios'
bunyan
=
require
'bunyan'
bunyan
=
require
'bunyan'
log
=
global
.
log
=
bunyan
.
createLogger
name
:
"mycard"
log
=
global
.
log
=
bunyan
.
createLogger
name
:
"mycard"
...
@@ -83,54 +84,24 @@ merge = require 'deepmerge'
...
@@ -83,54 +84,24 @@ merge = require 'deepmerge'
loadJSON
=
require
(
'load-json-file'
).
sync
loadJSON
=
require
(
'load-json-file'
).
sync
loadJSONAsync
=
require
(
'load-json-file'
)
util
=
require
(
"util"
)
util
=
require
(
"util"
)
Q
=
require
(
"q"
)
Q
=
require
(
"q"
)
#heapdump = require 'heapdump'
#heapdump = require 'heapdump'
# 配置
checkFileExists
=
(
path
)
=>
# 导入旧配置
try
if
not
fs
.
existsSync
(
'./config'
)
await
fs
.
promises
.
access
(
path
)
fs
.
mkdirSync
(
'./config'
)
return
true
try
catch
e
oldconfig
=
loadJSON
(
'./config.user.json'
)
return
false
if
oldconfig
.
tips
oldtips
=
{}
createDirectoryIfNotExists
=
(
path
)
=>
oldtips
.
file
=
'./config/tips.json'
if
!
await
checkFileExists
(
path
)
oldtips
.
tips
=
oldconfig
.
tips
await
fs
.
promises
.
mkdir
(
path
,
{
recursive
:
true
})
fs
.
writeFileSync
(
oldtips
.
file
,
JSON
.
stringify
(
oldtips
,
null
,
2
))
delete
oldconfig
.
tips
if
oldconfig
.
dialogues
olddialogues
=
{}
olddialogues
.
file
=
'./config/dialogues.json'
olddialogues
.
dialogues
=
oldconfig
.
dialogues
fs
.
writeFileSync
(
olddialogues
.
file
,
JSON
.
stringify
(
olddialogues
,
null
,
2
))
delete
oldconfig
.
dialogues
oldbadwords
=
{}
if
oldconfig
.
ban
if
oldconfig
.
ban
.
badword_level0
oldbadwords
.
level0
=
oldconfig
.
ban
.
badword_level0
if
oldconfig
.
ban
.
badword_level1
oldbadwords
.
level1
=
oldconfig
.
ban
.
badword_level1
if
oldconfig
.
ban
.
badword_level2
oldbadwords
.
level2
=
oldconfig
.
ban
.
badword_level2
if
oldconfig
.
ban
.
badword_level3
oldbadwords
.
level3
=
oldconfig
.
ban
.
badword_level3
if
not
_
.
isEmpty
(
oldbadwords
)
oldbadwords
.
file
=
'./config/badwords.json'
fs
.
writeFileSync
(
oldbadwords
.
file
,
JSON
.
stringify
(
oldbadwords
,
null
,
2
))
delete
oldconfig
.
ban
.
badword_level0
delete
oldconfig
.
ban
.
badword_level1
delete
oldconfig
.
ban
.
badword_level2
delete
oldconfig
.
ban
.
badword_level3
if
not
_
.
isEmpty
(
oldconfig
)
# log.info oldconfig
fs
.
writeFileSync
(
'./config/config.json'
,
JSON
.
stringify
(
oldconfig
,
null
,
2
))
log
.
info
'imported old config from config.user.json'
fs
.
renameSync
(
'./config.user.json'
,
'./config.user.bak'
)
catch
e
log
.
info
e
unless
e
.
code
==
'ENOENT'
setting_save
=
global
.
setting_save
=
(
settings
)
->
setting_save
=
global
.
setting_save
=
(
settings
)
->
try
try
...
@@ -155,218 +126,82 @@ setting_change = global.setting_change = (settings, path, val) ->
...
@@ -155,218 +126,82 @@ setting_change = global.setting_change = (settings, path, val) ->
await
setting_save
(
settings
)
await
setting_save
(
settings
)
return
return
# 读取配置
importOldConfig
=
()
->
default_config
=
loadJSON
(
'./data/default_config.json'
)
if
fs
.
existsSync
(
'./config/config.json'
)
try
try
config
=
loadJSON
(
'./config/config.json'
)
oldconfig
=
await
loadJSONAsync
(
'./config.user.json'
)
if
oldconfig
.
tips
oldtips
=
{}
oldtips
.
file
=
'./config/tips.json'
oldtips
.
tips
=
oldconfig
.
tips
await
fs
.
promises
.
writeFile
(
oldtips
.
file
,
JSON
.
stringify
(
oldtips
,
null
,
2
))
delete
oldconfig
.
tips
if
oldconfig
.
dialogues
olddialogues
=
{}
olddialogues
.
file
=
'./config/dialogues.json'
olddialogues
.
dialogues
=
oldconfig
.
dialogues
await
fs
.
promises
.
writeFile
(
olddialogues
.
file
,
JSON
.
stringify
(
olddialogues
,
null
,
2
))
delete
oldconfig
.
dialogues
oldbadwords
=
{}
if
oldconfig
.
ban
if
oldconfig
.
ban
.
badword_level0
oldbadwords
.
level0
=
oldconfig
.
ban
.
badword_level0
if
oldconfig
.
ban
.
badword_level1
oldbadwords
.
level1
=
oldconfig
.
ban
.
badword_level1
if
oldconfig
.
ban
.
badword_level2
oldbadwords
.
level2
=
oldconfig
.
ban
.
badword_level2
if
oldconfig
.
ban
.
badword_level3
oldbadwords
.
level3
=
oldconfig
.
ban
.
badword_level3
if
not
_
.
isEmpty
(
oldbadwords
)
oldbadwords
.
file
=
'./config/badwords.json'
await
fs
.
promises
.
writeFile
(
oldbadwords
.
file
,
JSON
.
stringify
(
oldbadwords
,
null
,
2
))
delete
oldconfig
.
ban
.
badword_level0
delete
oldconfig
.
ban
.
badword_level1
delete
oldconfig
.
ban
.
badword_level2
delete
oldconfig
.
ban
.
badword_level3
if
not
_
.
isEmpty
(
oldconfig
)
# log.info oldconfig
await
fs
.
promises
.
writeFile
(
'./config/config.json'
,
JSON
.
stringify
(
oldconfig
,
null
,
2
))
log
.
info
'imported old config from config.user.json'
await
fs
.
promises
.
rename
(
'./config.user.json'
,
'./config.user.bak'
)
catch
e
catch
e
console
.
error
(
"Failed reading config: "
,
e
.
toString
())
log
.
info
e
unless
e
.
code
==
'ENOENT'
process
.
exit
(
1
)
else
config
=
{}
settings
=
global
.
settings
=
merge
(
default_config
,
config
,
{
arrayMerge
:
(
destination
,
source
)
->
source
})
auth
=
global
.
auth
=
require
'./ygopro-auth.js'
auth
=
global
.
auth
=
require
'./ygopro-auth.js'
#import old configs
imported
=
false
#reset http.quick_death_rule from true to 1
if
settings
.
modules
.
http
.
quick_death_rule
==
true
settings
.
modules
.
http
.
quick_death_rule
=
1
imported
=
true
#import the old passwords to new admin user system
if
settings
.
modules
.
http
.
password
auth
.
add_user
(
"olduser"
,
settings
.
modules
.
http
.
password
,
true
,
{
"get_rooms"
:
true
,
"shout"
:
true
,
"stop"
:
true
,
"change_settings"
:
true
,
"ban_user"
:
true
,
"kick_user"
:
true
,
"start_death"
:
true
})
delete
settings
.
modules
.
http
.
password
imported
=
true
if
settings
.
modules
.
tournament_mode
.
password
auth
.
add_user
(
"tournament"
,
settings
.
modules
.
tournament_mode
.
password
,
true
,
{
"duel_log"
:
true
,
"download_replay"
:
true
,
"clear_duel_log"
:
true
,
"deck_dashboard_read"
:
true
,
"deck_dashboard_write"
:
true
,
})
delete
settings
.
modules
.
tournament_mode
.
password
imported
=
true
if
settings
.
modules
.
pre_util
.
password
auth
.
add_user
(
"pre"
,
settings
.
modules
.
pre_util
.
password
,
true
,
{
"pre_dashboard"
:
true
})
delete
settings
.
modules
.
pre_util
.
password
imported
=
true
if
settings
.
modules
.
update_util
.
password
auth
.
add_user
(
"update"
,
settings
.
modules
.
update_util
.
password
,
true
,
{
"update_dashboard"
:
true
})
delete
settings
.
modules
.
update_util
.
password
imported
=
true
#import the old enable_priority hostinfo
if
settings
.
hostinfo
.
enable_priority
or
settings
.
hostinfo
.
enable_priority
==
false
if
settings
.
hostinfo
.
enable_priority
settings
.
hostinfo
.
duel_rule
=
3
else
settings
.
hostinfo
.
duel_rule
=
5
delete
settings
.
hostinfo
.
enable_priority
imported
=
true
#import the old Challonge api key option
if
settings
.
modules
.
challonge
.
api_key
settings
.
modules
.
challonge
.
options
.
apiKey
=
settings
.
modules
.
challonge
.
api_key
delete
settings
.
modules
.
challonge
.
api_key
imported
=
true
#import the old random_duel.blank_pass_match option
if
settings
.
modules
.
random_duel
.
blank_pass_match
==
true
settings
.
modules
.
random_duel
.
blank_pass_modes
=
{
"S"
:
true
,
"M"
:
true
,
"T"
:
false
}
delete
settings
.
modules
.
random_duel
.
blank_pass_match
imported
=
true
if
settings
.
modules
.
random_duel
.
blank_pass_match
==
false
settings
.
modules
.
random_duel
.
blank_pass_modes
=
{
"S"
:
true
,
"M"
:
false
,
"T"
:
false
}
delete
settings
.
modules
.
random_duel
.
blank_pass_match
imported
=
true
#finish
if
imported
setting_save
(
settings
)
# 读取数据
default_data
=
loadJSON
(
'./data/default_data.json'
)
try
tips
=
global
.
tips
=
loadJSON
(
'./config/tips.json'
)
catch
tips
=
global
.
tips
=
default_data
.
tips
setting_save
(
tips
)
try
dialogues
=
global
.
dialogues
=
loadJSON
(
'./config/dialogues.json'
)
catch
dialogues
=
global
.
dialogues
=
default_data
.
dialogues
setting_save
(
dialogues
)
try
badwords
=
global
.
badwords
=
loadJSON
(
'./config/badwords.json'
)
catch
badwords
=
global
.
badwords
=
default_data
.
badwords
setting_save
(
badwords
)
try
chat_color
=
global
.
chat_color
=
loadJSON
(
'./config/chat_color.json'
)
catch
chat_color
=
global
.
chat_color
=
default_data
.
chat_color
setting_save
(
chat_color
)
try
cppversion
=
parseInt
(
fs
.
readFileSync
(
'ygopro/gframe/game.cpp'
,
'utf8'
).
match
(
/PRO_VERSION = ([x\dABCDEF]+)/
)[
1
],
'16'
)
setting_change
(
settings
,
"version"
,
cppversion
)
log
.
info
"ygopro version 0x"
+
settings
.
version
.
toString
(
16
),
"(from source code)"
catch
#settings.version = settings.version_default
log
.
info
"ygopro version 0x"
+
settings
.
version
.
toString
(
16
),
"(from config)"
# load the lflist of current date
lflists
=
global
.
lflists
=
[]
# expansions/lflist
try
for
list
in
fs
.
readFileSync
(
'ygopro/expansions/lflist.conf'
,
'utf8'
).
match
(
/!.*/g
)
date
=
list
.
match
(
/!([\d\.]+)/
)
continue
unless
date
lflists
.
push
({
date
:
moment
(
list
.
match
(
/!([\d\.]+)/
)[
1
],
'YYYY.MM.DD'
).
utcOffset
(
"-08:00"
),
tcg
:
list
.
indexOf
(
'TCG'
)
!=
-
1
})
catch
# lflist
try
for
list
in
fs
.
readFileSync
(
'ygopro/lflist.conf'
,
'utf8'
).
match
(
/!.*/g
)
date
=
list
.
match
(
/!([\d\.]+)/
)
continue
unless
date
lflists
.
push
({
date
:
moment
(
list
.
match
(
/!([\d\.]+)/
)[
1
],
'YYYY.MM.DD'
).
utcOffset
(
"-08:00"
),
tcg
:
list
.
indexOf
(
'TCG'
)
!=
-
1
})
catch
if
settings
.
modules
.
windbot
.
enabled
windbots
=
global
.
windbots
=
loadJSON
(
settings
.
modules
.
windbot
.
botlist
).
windbots
real_windbot_server_ip
=
global
.
real_windbot_server_ip
=
settings
.
modules
.
windbot
.
server_ip
if
!
settings
.
modules
.
windbot
.
server_ip
.
includes
(
"127.0.0.1"
)
dns
=
require
(
'dns'
)
dns
.
lookup
(
settings
.
modules
.
windbot
.
server_ip
,(
err
,
addr
)
->
if
(
!
err
)
real_windbot_server_ip
=
global
.
real_windbot_server_ip
=
addr
)
if
settings
.
modules
.
heartbeat_detection
.
enabled
long_resolve_cards
=
global
.
long_resolve_cards
=
loadJSON
(
'./data/long_resolve_cards.json'
)
if
settings
.
modules
.
tournament_mode
.
enable_recover
ReplayParser
=
global
.
ReplayParser
=
require
"./Replay.js"
if
settings
.
modules
.
athletic_check
.
enabled
AthleticChecker
=
require
(
"./athletic-check.js"
).
AthleticChecker
athleticChecker
=
global
.
athleticChecker
=
new
AthleticChecker
(
settings
.
modules
.
athletic_check
)
# 组件
ygopro
=
global
.
ygopro
=
require
'./ygopro.js'
ygopro
=
global
.
ygopro
=
require
'./ygopro.js'
roomlist
=
global
.
roomlist
=
require
'./roomlist.js'
if
settings
.
modules
.
http
.
websocket_roomlist
roomlist
=
null
if
settings
.
modules
.
i18n
.
auto_pick
geoip
=
require
(
'geoip-country-lite'
)
# cache users of mycard login
settings
=
{}
tips
=
null
dialogues
=
null
badwords
=
null
lflists
=
global
.
lflists
=
[]
real_windbot_server_ip
=
null
long_resolve_cards
=
[]
ReplayParser
=
null
athleticChecker
=
null
users_cache
=
{}
users_cache
=
{}
geoip
=
null
if
settings
.
modules
.
mysql
.
enabled
dataManager
=
null
DataManager
=
require
(
'./data-manager/DataManager.js'
).
DataManager
disconnect_list
=
{}
# {old_client, old_server, room_id, timeout, deckbuf}
dataManager
=
global
.
dataManager
=
new
DataManager
(
settings
.
modules
.
mysql
.
db
,
log
)
dataManager
.
init
().
then
(()
->
log
.
info
(
"Database ready."
))
challonge
=
null
else
challonge_cache
=
{
log
.
warn
(
"Some functions may be limited without MySQL ."
)
participants
:
null
if
settings
.
modules
.
cloud_replay
.
enabled
matches
:
null
settings
.
modules
.
cloud_replay
.
enabled
=
false
}
setting_save
(
settings
)
challonge_queue_callbacks
=
{
log
.
warn
(
"Cloud replay cannot be enabled because no MySQL."
)
participants
:
[]
if
settings
.
modules
.
enable_recover
.
enabled
matches
:
[]
settings
.
modules
.
enable_recover
.
enabled
=
false
}
setting_save
(
settings
)
is_challonge_requesting
=
{
log
.
warn
(
"Recover mode cannot be enabled because no MySQL."
)
participants
:
null
if
settings
.
modules
.
chat_color
.
enabled
matches
:
null
settings
.
modules
.
chat_color
.
enabled
=
false
}
setting_save
(
settings
)
get_callback
=
()
->
log
.
warn
(
"Chat color cannot be enabled because no MySQL."
)
replaced_index
=
()
->
if
settings
.
modules
.
mycard
.
enabled
pgClient
=
require
(
'pg'
).
Client
refresh_challonge_cache
=
()
->
pg_client
=
global
.
pg_client
=
new
pgClient
(
settings
.
modules
.
mycard
.
auth_database
)
pg_client
.
on
'error'
,
(
err
)
->
log
.
warn
"PostgreSQL ERROR: "
,
err
return
pg_query
=
pg_client
.
query
(
'SELECT username, id from users'
)
pg_query
.
on
'error'
,
(
err
)
->
log
.
warn
"PostgreSQL Query ERROR: "
,
err
return
pg_query
.
on
'row'
,
(
row
)
->
#log.info "load user", row.username, row.id
users_cache
[
row
.
username
]
=
row
.
id
return
pg_query
.
on
'end'
,
(
result
)
->
log
.
info
"users loaded"
,
result
.
rowCount
return
pg_client
.
on
'drain'
,
pg_client
.
end
.
bind
(
pg_client
)
log
.
info
"loading mycard user..."
pg_client
.
connect
()
if
settings
.
modules
.
arena_mode
.
enabled
and
settings
.
modules
.
arena_mode
.
init_post
.
enabled
request
.
post
{
url
:
settings
.
modules
.
arena_mode
.
init_post
.
url
,
qs
:
{
ak
:
settings
.
modules
.
arena_mode
.
init_post
.
accesskey
,
arena
:
settings
.
modules
.
arena_mode
.
mode
}},
(
error
,
response
,
body
)
=>
if
error
log
.
warn
'ARENA INIT POST ERROR'
,
error
else
if
response
.
statusCode
>=
400
log
.
warn
'ARENA INIT POST FAIL'
,
response
.
statusCode
,
response
.
statusMessage
,
body
#else
# log.info 'ARENA INIT POST OK', response.statusCode, response.statusMessage
return
class
ResolveData
class
ResolveData
constructor
:
(
@
func
)
->
constructor
:
(
@
func
)
->
...
@@ -378,99 +213,401 @@ class ResolveData
...
@@ -378,99 +213,401 @@ class ResolveData
@
func
(
err
,
data
)
@
func
(
err
,
data
)
return
true
return
true
if
settings
.
modules
.
challonge
.
enabled
challonge_module_name
=
'challonge'
loadLFList
=
(
path
)
->
if
settings
.
modules
.
challonge
.
use_custom_module
try
challonge_module_name
=
settings
.
modules
.
challonge
.
use_custom_module
for
list
in
fs
.
promises
.
readFile
(
path
,
'utf8'
).
match
(
/!.*/g
)
challonge
=
global
.
challonge
=
require
(
challonge_module_name
).
createClient
(
settings
.
modules
.
challonge
.
options
)
date
=
list
.
match
(
/!([\d\.]+)/
)
if
settings
.
modules
.
challonge
.
cache_ttl
continue
unless
date
lflists
.
push
({
date
:
moment
(
list
.
match
(
/!([\d\.]+)/
)[
1
],
'YYYY.MM.DD'
).
utcOffset
(
"-08:00"
),
tcg
:
list
.
indexOf
(
'TCG'
)
!=
-
1
})
catch
init
=
()
->
await
createDirectoryIfNotExists
(
"./config"
)
await
importOldConfig
()
defaultConfig
=
await
loadJSONAsync
(
'./data/default_config.json'
)
if
await
checkFileExists
(
"./config/config.json"
)
try
config
=
await
loadJSONAsync
(
'./config/config.json'
)
catch
e
console
.
error
(
"Failed reading config: "
,
e
.
toString
())
process
.
exit
(
1
)
else
config
=
{}
settings
=
global
.
settings
=
merge
(
defaultConfig
,
config
,
{
arrayMerge
:
(
destination
,
source
)
->
source
})
#import old configs
imported
=
false
#reset http.quick_death_rule from true to 1
if
settings
.
modules
.
http
.
quick_death_rule
==
true
settings
.
modules
.
http
.
quick_death_rule
=
1
imported
=
true
#import the old passwords to new admin user system
if
settings
.
modules
.
http
.
password
await
auth
.
add_user
(
"olduser"
,
settings
.
modules
.
http
.
password
,
true
,
{
"get_rooms"
:
true
,
"shout"
:
true
,
"stop"
:
true
,
"change_settings"
:
true
,
"ban_user"
:
true
,
"kick_user"
:
true
,
"start_death"
:
true
})
delete
settings
.
modules
.
http
.
password
imported
=
true
if
settings
.
modules
.
tournament_mode
.
password
await
auth
.
add_user
(
"tournament"
,
settings
.
modules
.
tournament_mode
.
password
,
true
,
{
"duel_log"
:
true
,
"download_replay"
:
true
,
"clear_duel_log"
:
true
,
"deck_dashboard_read"
:
true
,
"deck_dashboard_write"
:
true
,
})
delete
settings
.
modules
.
tournament_mode
.
password
imported
=
true
if
settings
.
modules
.
pre_util
.
password
await
auth
.
add_user
(
"pre"
,
settings
.
modules
.
pre_util
.
password
,
true
,
{
"pre_dashboard"
:
true
})
delete
settings
.
modules
.
pre_util
.
password
imported
=
true
if
settings
.
modules
.
update_util
.
password
await
auth
.
add_user
(
"update"
,
settings
.
modules
.
update_util
.
password
,
true
,
{
"update_dashboard"
:
true
})
delete
settings
.
modules
.
update_util
.
password
imported
=
true
#import the old enable_priority hostinfo
if
settings
.
hostinfo
.
enable_priority
or
settings
.
hostinfo
.
enable_priority
==
false
if
settings
.
hostinfo
.
enable_priority
settings
.
hostinfo
.
duel_rule
=
3
else
settings
.
hostinfo
.
duel_rule
=
5
delete
settings
.
hostinfo
.
enable_priority
imported
=
true
#import the old Challonge api key option
if
settings
.
modules
.
challonge
.
api_key
settings
.
modules
.
challonge
.
options
.
apiKey
=
settings
.
modules
.
challonge
.
api_key
delete
settings
.
modules
.
challonge
.
api_key
imported
=
true
#import the old random_duel.blank_pass_match option
if
settings
.
modules
.
random_duel
.
blank_pass_match
==
true
settings
.
modules
.
random_duel
.
blank_pass_modes
=
{
"S"
:
true
,
"M"
:
true
,
"T"
:
false
}
delete
settings
.
modules
.
random_duel
.
blank_pass_match
imported
=
true
if
settings
.
modules
.
random_duel
.
blank_pass_match
==
false
settings
.
modules
.
random_duel
.
blank_pass_modes
=
{
"S"
:
true
,
"M"
:
false
,
"T"
:
false
}
delete
settings
.
modules
.
random_duel
.
blank_pass_match
imported
=
true
#finish
if
imported
await
setting_save
(
settings
)
# 读取数据
default_data
=
await
loadJSONAsync
(
'./data/default_data.json'
)
try
tips
=
global
.
tips
=
await
loadJSONAsync
(
'./config/tips.json'
)
catch
tips
=
global
.
tips
=
default_data
.
tips
await
setting_save
(
tips
)
try
dialogues
=
global
.
dialogues
=
await
loadJSONAsync
(
'./config/dialogues.json'
)
catch
dialogues
=
global
.
dialogues
=
default_data
.
dialogues
await
setting_save
(
dialogues
)
try
badwords
=
global
.
badwords
=
await
loadJSONAsync
(
'./config/badwords.json'
)
catch
badwords
=
global
.
badwords
=
default_data
.
badwords
await
setting_save
(
badwords
)
if
settings
.
modules
.
chat_color
.
enabled
try
chat_color
=
global
.
chat_color
=
await
loadJSONAsync
(
'./config/chat_color.json'
)
catch
chat_color
=
global
.
chat_color
=
default_data
.
chat_color
await
setting_save
(
chat_color
)
try
cppversion
=
parseInt
(
await
fs
.
promises
.
readFile
(
'ygopro/gframe/game.cpp'
,
'utf8'
).
match
(
/PRO_VERSION = ([x\dABCDEF]+)/
)[
1
],
'16'
)
await
setting_change
(
settings
,
"version"
,
cppversion
)
log
.
info
"ygopro version 0x"
+
settings
.
version
.
toString
(
16
),
"(from source code)"
catch
#settings.version = settings.version_default
log
.
info
"ygopro version 0x"
+
settings
.
version
.
toString
(
16
),
"(from config)"
# load the lflist of current date
await
loadLFList
(
'ygopro/expansions/lflist.conf'
)
await
loadLFList
(
'ygopro/lflist.conf'
)
if
settings
.
modules
.
windbot
.
enabled
windbots
=
global
.
windbots
=
await
loadJSONAsync
(
settings
.
modules
.
windbot
.
botlist
).
windbots
real_windbot_server_ip
=
global
.
real_windbot_server_ip
=
settings
.
modules
.
windbot
.
server_ip
if
!
settings
.
modules
.
windbot
.
server_ip
.
includes
(
"127.0.0.1"
)
dns
=
require
(
'dns'
)
real_windbot_server_ip
=
global
.
real_windbot_server_ip
=
await
util
.
promisify
(
dns
.
lookup
)(
settings
.
modules
.
windbot
.
server_ip
)
if
settings
.
modules
.
heartbeat_detection
.
enabled
long_resolve_cards
=
global
.
long_resolve_cards
=
await
loadJSONAsync
(
'./data/long_resolve_cards.json'
)
if
settings
.
modules
.
tournament_mode
.
enable_recover
ReplayParser
=
global
.
ReplayParser
=
require
"./Replay.js"
if
settings
.
modules
.
athletic_check
.
enabled
AthleticChecker
=
require
(
"./athletic-check.js"
).
AthleticChecker
athleticChecker
=
global
.
athleticChecker
=
new
AthleticChecker
(
settings
.
modules
.
athletic_check
)
if
settings
.
modules
.
http
.
websocket_roomlist
roomlist
=
global
.
roomlist
=
require
'./roomlist.js'
if
settings
.
modules
.
i18n
.
auto_pick
geoip
=
require
(
'geoip-country-lite'
)
if
settings
.
modules
.
mysql
.
enabled
DataManager
=
require
(
'./data-manager/DataManager.js'
).
DataManager
dataManager
=
global
.
dataManager
=
new
DataManager
(
settings
.
modules
.
mysql
.
db
,
log
)
await
dataManager
.
init
()
else
log
.
warn
(
"Some functions may be limited without MySQL ."
)
if
settings
.
modules
.
cloud_replay
.
enabled
settings
.
modules
.
cloud_replay
.
enabled
=
false
await
setting_save
(
settings
)
log
.
warn
(
"Cloud replay cannot be enabled because no MySQL."
)
if
settings
.
modules
.
enable_recover
.
enabled
settings
.
modules
.
enable_recover
.
enabled
=
false
await
setting_save
(
settings
)
log
.
warn
(
"Recover mode cannot be enabled because no MySQL."
)
if
settings
.
modules
.
chat_color
.
enabled
settings
.
modules
.
chat_color
.
enabled
=
false
await
setting_save
(
settings
)
log
.
warn
(
"Chat color cannot be enabled because no MySQL."
)
if
settings
.
modules
.
mycard
.
enabled
pgClient
=
require
(
'pg'
).
Client
pg_client
=
global
.
pg_client
=
new
pgClient
(
settings
.
modules
.
mycard
.
auth_database
)
pg_client
.
on
'error'
,
(
err
)
->
log
.
warn
"PostgreSQL ERROR: "
,
err
return
pg_query
=
pg_client
.
query
(
'SELECT username, id from users'
)
pg_query
.
on
'error'
,
(
err
)
->
log
.
warn
"PostgreSQL Query ERROR: "
,
err
return
pg_query
.
on
'row'
,
(
row
)
->
#log.info "load user", row.username, row.id
users_cache
[
row
.
username
]
=
row
.
id
return
pg_query
.
on
'end'
,
(
result
)
->
log
.
info
"users loaded"
,
result
.
rowCount
return
pg_client
.
on
'drain'
,
pg_client
.
end
.
bind
(
pg_client
)
log
.
info
"loading mycard user..."
pg_client
.
connect
()
if
settings
.
modules
.
arena_mode
.
enabled
and
settings
.
modules
.
arena_mode
.
init_post
.
enabled
postData
=
qs
.
stringify
({
ak
:
settings
.
modules
.
arena_mode
.
init_post
.
accesskey
,
arena
:
settings
.
modules
.
arena_mode
.
mode
})
try
await
axios
.
post
(
settings
.
modules
.
arena_mode
.
init_post
.
url
+
"?"
+
postData
,
{
responseType
:
"json"
})
catch
e
log
.
warn
'ARENA INIT POST ERROR'
,
e
if
settings
.
modules
.
challonge
.
enabled
challonge_module_name
=
'challonge'
if
settings
.
modules
.
challonge
.
use_custom_module
challonge_module_name
=
settings
.
modules
.
challonge
.
use_custom_module
challonge
=
global
.
challonge
=
require
(
challonge_module_name
).
createClient
(
settings
.
modules
.
challonge
.
options
)
challonge_cache
=
{
challonge_cache
=
{
participants
:
null
participants
:
null
matches
:
null
matches
:
null
}
}
challonge_queue_callbacks
=
{
challonge_queue_callbacks
=
{
participants
:
[]
participants
:
[]
matches
:
[]
matches
:
[]
}
}
is_challonge_requesting
=
{
is_challonge_requesting
=
{
participants
:
null
participants
:
null
matches
:
null
matches
:
null
}
}
get_callback
=
(
challonge_type
,
resolve_data
)
->
get_callback
=
(
challonge_type
,
resolve_data
)
->
return
((
err
,
data
)
->
return
((
err
,
data
)
->
if
settings
.
modules
.
challonge
.
cache_ttl
and
!
err
and
data
if
settings
.
modules
.
challonge
.
cache_ttl
and
!
err
and
data
challonge_cache
[
challonge_type
]
=
data
challonge_cache
[
challonge_type
]
=
data
is_challonge_requesting
[
challonge_type
]
=
null
is_challonge_requesting
[
challonge_type
]
=
null
resolve_data
.
resolve
(
err
,
data
)
resolve_data
.
resolve
(
err
,
data
)
while
challonge_queue_callbacks
[
challonge_type
].
length
while
challonge_queue_callbacks
[
challonge_type
].
length
cur_resolve_data
=
challonge_queue_callbacks
[
challonge_type
].
splice
(
0
,
1
)[
0
]
cur_resolve_data
=
challonge_queue_callbacks
[
challonge_type
].
splice
(
0
,
1
)[
0
]
cur_resolve_data
.
resolve
(
err
,
data
)
cur_resolve_data
.
resolve
(
err
,
data
)
return
)
replaced_index
=
(
challonge_type
)
->
return
(
_data
)
->
resolve_data
=
new
ResolveData
(
_data
.
callback
)
if
settings
.
modules
.
challonge
.
cache_ttl
and
!
_data
.
no_cache
and
challonge_cache
[
challonge_type
]
resolve_data
.
resolve
(
null
,
challonge_cache
[
challonge_type
])
else
if
is_challonge_requesting
[
challonge_type
]
and
moment
()
-
is_challonge_requesting
[
challonge_type
]
<=
5000
challonge_queue_callbacks
[
challonge_type
].
push
(
resolve_data
)
else
_data
.
callback
=
get_callback
(
challonge_type
,
resolve_data
)
is_challonge_requesting
[
challonge_type
]
=
moment
()
try
challonge
[
challonge_type
].
index
(
_data
)
catch
err
_data
.
callback
(
err
,
null
)
return
for
challonge_type
in
[
"participants"
,
"matches"
]
challonge
[
challonge_type
].
_index
=
replaced_index
(
challonge_type
)
challonge
.
matches
.
_update
=
(
_data
)
->
try
challonge
.
matches
.
update
(
_data
)
catch
err
log
.
warn
(
"Errored pushing scores to Challonge."
,
err
)
return
return
)
refresh_challonge_cache
=
global
.
refresh_challonge_cache
=
()
->
replaced_index
=
(
challonge_type
)
->
if
settings
.
modules
.
challonge
.
cache_ttl
return
(
_data
)
->
challonge_cache
.
participants
=
null
resolve_data
=
new
ResolveData
(
_data
.
callback
)
challonge_cache
.
matches
=
null
if
settings
.
modules
.
challonge
.
cache_ttl
and
!
_data
.
no_cache
and
challonge_cache
[
challonge_type
]
resolve_data
.
resolve
(
null
,
challonge_cache
[
challonge_type
])
else
if
is_challonge_requesting
[
challonge_type
]
and
moment
()
-
is_challonge_requesting
[
challonge_type
]
<=
5000
challonge_queue_callbacks
[
challonge_type
].
push
(
resolve_data
)
else
_data
.
callback
=
get_callback
(
challonge_type
,
resolve_data
)
is_challonge_requesting
[
challonge_type
]
=
moment
()
try
challonge
[
challonge_type
].
index
(
_data
)
catch
err
_data
.
callback
(
err
,
null
)
return
return
for
challonge_type
in
[
"participants"
,
"matches"
]
refresh_challonge_cache
()
challonge
[
challonge_type
].
_index
=
replaced_index
(
challonge_type
)
challonge
.
matches
.
_update
=
(
_data
)
->
try
challonge
.
matches
.
update
(
_data
)
catch
err
log
.
warn
(
"Errored pushing scores to Challonge."
,
err
)
return
refresh_challonge_cache
=
global
.
refresh_challonge_cache
=
()
->
if
settings
.
modules
.
challonge
.
cache_ttl
if
settings
.
modules
.
challonge
.
cache_ttl
challonge_cache
.
participants
=
null
setInterval
(
refresh_challonge_cache
,
settings
.
modules
.
challonge
.
cache_ttl
)
challonge_cache
.
matches
=
null
if
settings
.
modules
.
tips
.
get
load_tips
()
setInterval
()
->
for
room
in
ROOM_all
when
room
and
room
.
established
ygopro
.
stoc_send_random_tip_to_room
(
room
)
if
room
.
duel_stage
==
ygopro
.
constants
.
DUEL_STAGE
.
SIDING
or
room
.
duel_stage
==
ygopro
.
constants
.
DUEL_STAGE
.
BEGIN
return
,
30000
if
settings
.
modules
.
dialogues
.
get
load_dialogues
()
if
settings
.
modules
.
random_duel
.
post_match_scores
setInterval
(()
->
scores_pair
=
_
.
pairs
ROOM_players_scores
scores_by_lose
=
_
.
sortBy
(
scores_pair
,
(
score
)
->
return
score
[
1
].
lose
).
reverse
()
# 败场由高到低
scores_by_win
=
_
.
sortBy
(
scores_by_lose
,
(
score
)
->
return
score
[
1
].
win
).
reverse
()
# 然后胜场由低到高,再逆转,就是先排胜场再排败场
scores
=
_
.
first
(
scores_by_win
,
10
)
#log.info scores
request
.
post
{
url
:
settings
.
modules
.
random_duel
.
post_match_scores
,
form
:
{
accesskey
:
settings
.
modules
.
random_duel
.
post_match_accesskey
,
rank
:
JSON
.
stringify
(
scores
)
}},
(
error
,
response
,
body
)
=>
if
error
log
.
warn
'RANDOM SCORE POST ERROR'
,
error
else
if
response
.
statusCode
!=
204
and
response
.
statusCode
!=
200
log
.
warn
'RANDOM SCORE POST FAIL'
,
response
.
statusCode
,
response
.
statusMessage
,
body
#else
# log.info 'RANDOM SCORE POST OK', response.statusCode, response.statusMessage
return
return
,
60000
)
if
settings
.
modules
.
random_duel
.
enabled
setInterval
()
->
for
room
in
ROOM_all
when
room
and
room
.
duel_stage
!=
ygopro
.
constants
.
DUEL_STAGE
.
BEGIN
and
room
.
random_type
and
room
.
last_active_time
and
room
.
waiting_for_player
and
room
.
get_disconnected_count
()
==
0
and
(
!
settings
.
modules
.
side_timeout
or
room
.
duel_stage
!=
ygopro
.
constants
.
DUEL_STAGE
.
SIDING
)
and
!
room
.
recovered
time_passed
=
Math
.
floor
((
moment
()
-
room
.
last_active_time
)
/
1000
)
#log.info time_passed
if
time_passed
>=
settings
.
modules
.
random_duel
.
hang_timeout
room
.
last_active_time
=
moment
()
await
ROOM_ban_player
(
room
.
waiting_for_player
.
name
,
room
.
waiting_for_player
.
ip
,
"${random_ban_reason_AFK}"
)
room
.
scores
[
room
.
waiting_for_player
.
name_vpass
]
=
-
9
#log.info room.waiting_for_player.name, room.scores[room.waiting_for_player.name_vpass]
ygopro
.
stoc_send_chat_to_room
(
room
,
"
#{
room
.
waiting_for_player
.
name
}
${kicked_by_system}"
,
ygopro
.
constants
.
COLORS
.
RED
)
CLIENT_send_replays
(
room
.
waiting_for_player
,
room
)
CLIENT_kick
(
room
.
waiting_for_player
)
else
if
time_passed
>=
(
settings
.
modules
.
random_duel
.
hang_timeout
-
20
)
and
not
(
time_passed
%
10
)
ygopro
.
stoc_send_chat_to_room
(
room
,
"
#{
room
.
waiting_for_player
.
name
}
${afk_warn_part1}
#{
settings
.
modules
.
random_duel
.
hang_timeout
-
time_passed
}
${afk_warn_part2}"
,
ygopro
.
constants
.
COLORS
.
RED
)
ROOM_unwelcome
(
room
,
room
.
waiting_for_player
,
"${random_ban_reason_AFK}"
)
return
,
1000
if
settings
.
modules
.
mycard
.
enabled
setInterval
()
->
for
room
in
ROOM_all
when
room
and
room
.
duel_stage
!=
ygopro
.
constants
.
DUEL_STAGE
.
BEGIN
and
room
.
arena
and
room
.
last_active_time
and
room
.
waiting_for_player
and
room
.
get_disconnected_count
()
==
0
and
(
!
settings
.
modules
.
side_timeout
or
room
.
duel_stage
!=
ygopro
.
constants
.
DUEL_STAGE
.
SIDING
)
and
!
room
.
recovered
time_passed
=
Math
.
floor
((
moment
()
-
room
.
last_active_time
)
/
1000
)
#log.info time_passed
if
time_passed
>=
settings
.
modules
.
random_duel
.
hang_timeout
room
.
last_active_time
=
moment
()
ygopro
.
stoc_send_chat_to_room
(
room
,
"
#{
room
.
waiting_for_player
.
name
}
${kicked_by_system}"
,
ygopro
.
constants
.
COLORS
.
RED
)
room
.
scores
[
room
.
waiting_for_player
.
name_vpass
]
=
-
9
#log.info room.waiting_for_player.name, room.scores[room.waiting_for_player.name_vpass]
CLIENT_send_replays
(
room
.
waiting_for_player
,
room
)
CLIENT_kick
(
room
.
waiting_for_player
)
else
if
time_passed
>=
(
settings
.
modules
.
random_duel
.
hang_timeout
-
20
)
and
not
(
time_passed
%
10
)
ygopro
.
stoc_send_chat_to_room
(
room
,
"
#{
room
.
waiting_for_player
.
name
}
${afk_warn_part1}
#{
settings
.
modules
.
random_duel
.
hang_timeout
-
time_passed
}
${afk_warn_part2}"
,
ygopro
.
constants
.
COLORS
.
RED
)
return
if
true
# settings.modules.arena_mode.punish_quit_before_match
for
room
in
ROOM_all
when
room
and
room
.
arena
and
room
.
duel_stage
==
ygopro
.
constants
.
DUEL_STAGE
.
BEGIN
and
room
.
get_playing_player
().
length
<
2
player
=
room
.
get_playing_player
()[
0
]
if
player
and
player
.
join_time
and
!
player
.
arena_quit_free
waited_time
=
moment
()
-
player
.
join_time
if
waited_time
>=
30000
ygopro
.
stoc_send_chat
(
player
,
"${arena_wait_timeout}"
,
ygopro
.
constants
.
COLORS
.
BABYBLUE
)
player
.
arena_quit_free
=
true
else
if
waited_time
>=
5000
and
waited_time
<
6000
ygopro
.
stoc_send_chat
(
player
,
"${arena_wait_hint}"
,
ygopro
.
constants
.
COLORS
.
BABYBLUE
)
return
,
1000
if
settings
.
modules
.
heartbeat_detection
.
enabled
setInterval
()
->
for
room
in
ROOM_all
when
room
and
room
.
duel_stage
!=
ygopro
.
constants
.
DUEL_STAGE
.
BEGIN
and
(
room
.
hostinfo
.
time_limit
==
0
or
room
.
duel_stage
!=
ygopro
.
constants
.
DUEL_STAGE
.
DUELING
)
and
!
room
.
windbot
for
player
in
room
.
get_playing_player
()
when
player
and
(
room
.
duel_stage
!=
ygopro
.
constants
.
DUEL_STAGE
.
SIDING
or
player
.
selected_preduel
)
CLIENT_heartbeat_register
(
player
,
true
)
return
,
settings
.
modules
.
heartbeat_detection
.
interval
if
settings
.
modules
.
windbot
.
enabled
and
settings
.
modules
.
windbot
.
spawn
spawn_windbot
()
setInterval
()
->
current_time
=
moment
()
for
room
in
ROOM_all
when
room
and
room
.
duel_stage
!=
ygopro
.
constants
.
DUEL_STAGE
.
BEGIN
and
room
.
hostinfo
.
auto_death
and
!
room
.
auto_death_triggered
and
current_time
-
moment
(
room
.
start_time
)
>
60000
*
room
.
hostinfo
.
auto_death
room
.
auto_death_triggered
=
true
room
.
start_death
()
,
1000
net
.
createServer
(
netRequestHandler
).
listen
settings
.
port
,
->
log
.
info
"server started"
,
settings
.
port
return
return
refresh_challonge_cache
()
# challonge.participants._index({
if
settings
.
modules
.
stop
# id: settings.modules.challonge.tournament_id,
log
.
info
"NOTE: server not open due to config, "
,
settings
.
modules
.
stop
# callback: (() ->
# challonge.matches._index({
http_server
=
http
.
createServer
(
httpRequestListener
)
# id: settings.modules.challonge.tournament_id,
http_server
.
listen
settings
.
modules
.
http
.
port
# callback: (() ->
# return
if
settings
.
modules
.
http
.
ssl
.
enabled
# )
https
=
require
'https'
# })
options
=
# return
cert
:
await
fs
.
promises
.
readFile
(
settings
.
modules
.
http
.
ssl
.
cert
)
# )
key
:
await
fs
.
promises
.
readFile
(
settings
.
modules
.
http
.
ssl
.
key
)
# })
https_server
=
https
.
createServer
(
options
,
httpRequestListener
)
if
settings
.
modules
.
challonge
.
cache_ttl
if
settings
.
modules
.
http
.
websocket_roomlist
and
roomlist
setInterval
(
refresh_challonge_cache
,
settings
.
modules
.
challonge
.
cache_ttl
)
roomlist
.
init
https_server
,
ROOM_all
https_server
.
listen
settings
.
modules
.
http
.
ssl
.
port
mkdirList
=
[
"./plugins"
,
settings
.
modules
.
tournament_mode
.
deck_path
,
settings
.
modules
.
tournament_mode
.
replay_path
,
settings
.
modules
.
tournament_mode
.
log_save_path
,
settings
.
modules
.
deck_log
.
local
]
for
path
in
mkdirList
await
createDirectoryIfNotExists
(
path
)
plugin_list
=
await
fs
.
promises
.
readdir
(
"./plugins"
)
for
plugin_filename
in
plugin_list
plugin_path
=
process
.
cwd
()
+
"/plugins/"
+
plugin_filename
require
(
plugin_path
)
log
.
info
(
"Plugin loaded:"
,
plugin_filename
)
# 获取可用内存
# 获取可用内存
memory_usage
=
global
.
memory_usage
=
0
memory_usage
=
global
.
memory_usage
=
0
get_memory_usage
=
get_memory_usage
=
()
->
get_memory_usage
=
global
.
get_memory_usage
=
()
->
prc_free
=
exec
(
"free"
)
percentUsed
=
os
.
freemem
()
*
os
.
totalmem
()
*
100
prc_free
.
stdout
.
on
'data'
,
(
data
)
->
memory_usage
=
global
.
memory_usage
=
percentUsed
lines
=
data
.
toString
().
split
(
/\n/g
)
line
=
lines
[
0
].
split
(
/\s+/
)
new_free
=
if
line
[
6
]
==
'available'
then
true
else
false
line
=
lines
[
1
].
split
(
/\s+/
)
total
=
parseInt
(
line
[
1
],
10
)
free
=
parseInt
(
line
[
3
],
10
)
buffers
=
parseInt
(
line
[
5
],
10
)
if
new_free
actualFree
=
parseInt
(
line
[
6
],
10
)
else
cached
=
parseInt
(
line
[
6
],
10
)
actualFree
=
free
+
buffers
+
cached
percentUsed
=
parseFloat
(((
1
-
(
actualFree
/
total
))
*
100
).
toFixed
(
2
))
memory_usage
=
global
.
memory_usage
=
percentUsed
return
return
return
get_memory_usage
()
get_memory_usage
()
setInterval
(
get_memory_usage
,
3000
)
setInterval
(
get_memory_usage
,
3000
)
...
@@ -555,28 +692,6 @@ ROOM_player_get_score = global.ROOM_player_get_score = (player)->
...
@@ -555,28 +692,6 @@ ROOM_player_get_score = global.ROOM_player_get_score = (player)->
return
"${random_score_part1}
#{
player
.
name
}
${random_score_part2}
#{
Math
.
ceil
(
score
.
win
/
total
*
100
)
}
${random_score_part3}
#{
Math
.
ceil
(
score
.
flee
/
total
*
100
)
}
${random_score_part4}"
return
"${random_score_part1}
#{
player
.
name
}
${random_score_part2}
#{
Math
.
ceil
(
score
.
win
/
total
*
100
)
}
${random_score_part3}
#{
Math
.
ceil
(
score
.
flee
/
total
*
100
)
}
${random_score_part4}"
return
return
if
settings
.
modules
.
random_duel
.
post_match_scores
setInterval
(()
->
scores_pair
=
_
.
pairs
ROOM_players_scores
scores_by_lose
=
_
.
sortBy
(
scores_pair
,
(
score
)
->
return
score
[
1
].
lose
).
reverse
()
# 败场由高到低
scores_by_win
=
_
.
sortBy
(
scores_by_lose
,
(
score
)
->
return
score
[
1
].
win
).
reverse
()
# 然后胜场由低到高,再逆转,就是先排胜场再排败场
scores
=
_
.
first
(
scores_by_win
,
10
)
#log.info scores
request
.
post
{
url
:
settings
.
modules
.
random_duel
.
post_match_scores
,
form
:
{
accesskey
:
settings
.
modules
.
random_duel
.
post_match_accesskey
,
rank
:
JSON
.
stringify
(
scores
)
}},
(
error
,
response
,
body
)
=>
if
error
log
.
warn
'RANDOM SCORE POST ERROR'
,
error
else
if
response
.
statusCode
!=
204
and
response
.
statusCode
!=
200
log
.
warn
'RANDOM SCORE POST FAIL'
,
response
.
statusCode
,
response
.
statusMessage
,
body
#else
# log.info 'RANDOM SCORE POST OK', response.statusCode, response.statusMessage
return
return
,
60000
)
ROOM_find_or_create_by_name
=
global
.
ROOM_find_or_create_by_name
=
(
name
,
player_ip
)
->
ROOM_find_or_create_by_name
=
global
.
ROOM_find_or_create_by_name
=
(
name
,
player_ip
)
->
uname
=
name
.
toUpperCase
()
uname
=
name
.
toUpperCase
()
if
settings
.
modules
.
windbot
.
enabled
and
(
uname
[
0
...
2
]
==
'AI'
or
(
!
settings
.
modules
.
random_duel
.
enabled
and
uname
==
''
))
if
settings
.
modules
.
windbot
.
enabled
and
(
uname
[
0
...
2
]
==
'AI'
or
(
!
settings
.
modules
.
random_duel
.
enabled
and
uname
==
''
))
...
@@ -980,9 +1095,6 @@ CLIENT_kick_reconnect = global.CLIENT_kick_reconnect = (client, deckbuf) ->
...
@@ -980,9 +1095,6 @@ CLIENT_kick_reconnect = global.CLIENT_kick_reconnect = (client, deckbuf) ->
CLIENT_reconnect_unregister
(
client
,
true
)
CLIENT_reconnect_unregister
(
client
,
true
)
return
return
if
settings
.
modules
.
reconnect
.
enabled
disconnect_list
=
{}
# {old_client, old_server, room_id, timeout, deckbuf}
CLIENT_heartbeat_unregister
=
global
.
CLIENT_heartbeat_unregister
=
(
client
)
->
CLIENT_heartbeat_unregister
=
global
.
CLIENT_heartbeat_unregister
=
(
client
)
->
if
!
settings
.
modules
.
heartbeat_detection
.
enabled
or
!
client
.
heartbeat_timeout
if
!
settings
.
modules
.
heartbeat_detection
.
enabled
or
!
client
.
heartbeat_timeout
return
false
return
false
...
@@ -1606,7 +1718,7 @@ class Room
...
@@ -1606,7 +1718,7 @@ class Room
await
return
await
return
# 网络连接
# 网络连接
net
.
createServer
(
client
)
->
net
RequestHandler
=
(
client
)
->
client
.
ip
=
client
.
remoteAddress
client
.
ip
=
client
.
remoteAddress
client
.
is_local
=
client
.
ip
and
(
client
.
ip
.
includes
(
'127.0.0.1'
)
or
client
.
ip
.
includes
(
real_windbot_server_ip
))
client
.
is_local
=
client
.
ip
and
(
client
.
ip
.
includes
(
'127.0.0.1'
)
or
client
.
ip
.
includes
(
real_windbot_server_ip
))
...
@@ -1786,12 +1898,6 @@ net.createServer (client) ->
...
@@ -1786,12 +1898,6 @@ net.createServer (client) ->
return
return
return
return
.
listen
settings
.
port
,
->
log
.
info
"server started"
,
settings
.
port
return
if
settings
.
modules
.
stop
log
.
info
"NOTE: server not open due to config, "
,
settings
.
modules
.
stop
deck_name_match
=
global
.
deck_name_match
=
(
deck_name
,
player_name
)
->
deck_name_match
=
global
.
deck_name_match
=
(
deck_name
,
player_name
)
->
if
deck_name
==
player_name
or
deck_name
==
player_name
+
".ydk"
or
deck_name
==
player_name
+
".ydk.ydk"
if
deck_name
==
player_name
or
deck_name
==
player_name
+
".ydk"
or
deck_name
==
player_name
+
".ydk.ydk"
...
@@ -2396,25 +2502,8 @@ ygopro.stoc_follow 'JOIN_GAME', false, (buffer, info, client, server, datas)->
...
@@ -2396,25 +2502,8 @@ ygopro.stoc_follow 'JOIN_GAME', false, (buffer, info, client, server, datas)->
await
return
await
return
# 登场台词
# 登场台词
load_dialogues
=
global
.
load_dialogues
=
(
callback
)
->
load_dialogues
=
global
.
load_dialogues
=
()
->
request
return
await
loadRemoteData
(
dialogues
,
"dialogues"
,
settings
.
modules
.
dialogues
.
get
)
url
:
settings
.
modules
.
dialogues
.
get
json
:
true
,
(
error
,
response
,
body
)
->
if
_
.
isString
body
log
.
warn
"dialogues bad json"
,
body
else
if
error
or
!
body
log
.
warn
'dialogues error'
,
error
,
response
else
setting_change
(
dialogues
,
"dialogues"
,
body
)
log
.
info
"dialogues loaded"
,
_
.
size
dialogues
.
dialogues
if
callback
callback
(
error
,
body
)
return
await
return
if
settings
.
modules
.
dialogues
.
get
load_dialogues
()
ygopro
.
stoc_follow
'GAME_MSG'
,
true
,
(
buffer
,
info
,
client
,
server
,
datas
)
->
ygopro
.
stoc_follow
'GAME_MSG'
,
true
,
(
buffer
,
info
,
client
,
server
,
datas
)
->
room
=
ROOM_all
[
client
.
rid
]
room
=
ROOM_all
[
client
.
rid
]
...
@@ -2883,30 +2972,26 @@ ygopro.stoc_send_random_tip_to_room = (room)->
...
@@ -2883,30 +2972,26 @@ ygopro.stoc_send_random_tip_to_room = (room)->
ygopro
.
stoc_send_chat_to_room
(
room
,
"Tip: "
+
tips
.
tips
[
Math
.
floor
(
Math
.
random
()
*
tips
.
tips
.
length
)])
ygopro
.
stoc_send_chat_to_room
(
room
,
"Tip: "
+
tips
.
tips
[
Math
.
floor
(
Math
.
random
()
*
tips
.
tips
.
length
)])
await
return
await
return
load
_tips
=
global
.
load_tips
=
(
callback
)
->
load
RemoteData
=
global
.
loadRemoteData
=
(
loadObject
,
name
,
url
)
->
request
try
url
:
settings
.
modules
.
tips
.
get
body
=
(
await
axios
.
get
(
url
,
{
json
:
true
responseType
:
"json"
,
(
error
,
response
,
body
)
->
})).
data
if
_
.
isString
body
if
_
.
isString
body
log
.
warn
"tips bad json"
,
body
log
.
warn
"
#{
name
}
bad json"
,
body
else
if
error
or
!
body
return
false
log
.
warn
'tips error'
,
error
,
response
if
!
body
else
log
.
warn
"
#{
name
}
empty"
,
body
setting_change
(
tips
,
"tips"
,
body
)
return
false
log
.
info
"tips loaded"
,
tips
.
tips
.
length
await
setting_change
(
loadObject
,
name
,
body
)
if
callback
log
.
info
"
#{
name
}
loaded"
callback
(
error
,
body
)
return
true
return
catch
e
await
return
log
.
warn
"
#{
name
}
error"
,
e
return
false
if
settings
.
modules
.
tips
.
get
load_tips
=
global
.
load_tips
=
()
->
load_tips
()
return
await
loadRemoteData
(
tips
,
"tips"
,
settings
.
modules
.
tips
.
get
)
setInterval
()
->
for
room
in
ROOM_all
when
room
and
room
.
established
ygopro
.
stoc_send_random_tip_to_room
(
room
)
if
room
.
duel_stage
==
ygopro
.
constants
.
DUEL_STAGE
.
SIDING
or
room
.
duel_stage
==
ygopro
.
constants
.
DUEL_STAGE
.
BEGIN
return
,
30000
ygopro
.
stoc_follow
'DUEL_START'
,
false
,
(
buffer
,
info
,
client
,
server
,
datas
)
->
ygopro
.
stoc_follow
'DUEL_START'
,
false
,
(
buffer
,
info
,
client
,
server
,
datas
)
->
room
=
ROOM_all
[
client
.
rid
]
room
=
ROOM_all
[
client
.
rid
]
...
@@ -3522,70 +3607,6 @@ ygopro.stoc_follow 'REPLAY', true, (buffer, info, client, server, datas)->
...
@@ -3522,70 +3607,6 @@ ygopro.stoc_follow 'REPLAY', true, (buffer, info, client, server, datas)->
else
else
await
return
settings
.
modules
.
replay_delay
and
room
.
hostinfo
.
mode
==
1
await
return
settings
.
modules
.
replay_delay
and
room
.
hostinfo
.
mode
==
1
if
settings
.
modules
.
random_duel
.
enabled
setInterval
()
->
for
room
in
ROOM_all
when
room
and
room
.
duel_stage
!=
ygopro
.
constants
.
DUEL_STAGE
.
BEGIN
and
room
.
random_type
and
room
.
last_active_time
and
room
.
waiting_for_player
and
room
.
get_disconnected_count
()
==
0
and
(
!
settings
.
modules
.
side_timeout
or
room
.
duel_stage
!=
ygopro
.
constants
.
DUEL_STAGE
.
SIDING
)
and
!
room
.
recovered
time_passed
=
Math
.
floor
((
moment
()
-
room
.
last_active_time
)
/
1000
)
#log.info time_passed
if
time_passed
>=
settings
.
modules
.
random_duel
.
hang_timeout
room
.
last_active_time
=
moment
()
await
ROOM_ban_player
(
room
.
waiting_for_player
.
name
,
room
.
waiting_for_player
.
ip
,
"${random_ban_reason_AFK}"
)
room
.
scores
[
room
.
waiting_for_player
.
name_vpass
]
=
-
9
#log.info room.waiting_for_player.name, room.scores[room.waiting_for_player.name_vpass]
ygopro
.
stoc_send_chat_to_room
(
room
,
"
#{
room
.
waiting_for_player
.
name
}
${kicked_by_system}"
,
ygopro
.
constants
.
COLORS
.
RED
)
CLIENT_send_replays
(
room
.
waiting_for_player
,
room
)
CLIENT_kick
(
room
.
waiting_for_player
)
else
if
time_passed
>=
(
settings
.
modules
.
random_duel
.
hang_timeout
-
20
)
and
not
(
time_passed
%
10
)
ygopro
.
stoc_send_chat_to_room
(
room
,
"
#{
room
.
waiting_for_player
.
name
}
${afk_warn_part1}
#{
settings
.
modules
.
random_duel
.
hang_timeout
-
time_passed
}
${afk_warn_part2}"
,
ygopro
.
constants
.
COLORS
.
RED
)
ROOM_unwelcome
(
room
,
room
.
waiting_for_player
,
"${random_ban_reason_AFK}"
)
return
,
1000
if
settings
.
modules
.
mycard
.
enabled
setInterval
()
->
for
room
in
ROOM_all
when
room
and
room
.
duel_stage
!=
ygopro
.
constants
.
DUEL_STAGE
.
BEGIN
and
room
.
arena
and
room
.
last_active_time
and
room
.
waiting_for_player
and
room
.
get_disconnected_count
()
==
0
and
(
!
settings
.
modules
.
side_timeout
or
room
.
duel_stage
!=
ygopro
.
constants
.
DUEL_STAGE
.
SIDING
)
and
!
room
.
recovered
time_passed
=
Math
.
floor
((
moment
()
-
room
.
last_active_time
)
/
1000
)
#log.info time_passed
if
time_passed
>=
settings
.
modules
.
random_duel
.
hang_timeout
room
.
last_active_time
=
moment
()
ygopro
.
stoc_send_chat_to_room
(
room
,
"
#{
room
.
waiting_for_player
.
name
}
${kicked_by_system}"
,
ygopro
.
constants
.
COLORS
.
RED
)
room
.
scores
[
room
.
waiting_for_player
.
name_vpass
]
=
-
9
#log.info room.waiting_for_player.name, room.scores[room.waiting_for_player.name_vpass]
CLIENT_send_replays
(
room
.
waiting_for_player
,
room
)
CLIENT_kick
(
room
.
waiting_for_player
)
else
if
time_passed
>=
(
settings
.
modules
.
random_duel
.
hang_timeout
-
20
)
and
not
(
time_passed
%
10
)
ygopro
.
stoc_send_chat_to_room
(
room
,
"
#{
room
.
waiting_for_player
.
name
}
${afk_warn_part1}
#{
settings
.
modules
.
random_duel
.
hang_timeout
-
time_passed
}
${afk_warn_part2}"
,
ygopro
.
constants
.
COLORS
.
RED
)
return
if
true
# settings.modules.arena_mode.punish_quit_before_match
for
room
in
ROOM_all
when
room
and
room
.
arena
and
room
.
duel_stage
==
ygopro
.
constants
.
DUEL_STAGE
.
BEGIN
and
room
.
get_playing_player
().
length
<
2
player
=
room
.
get_playing_player
()[
0
]
if
player
and
player
.
join_time
and
!
player
.
arena_quit_free
waited_time
=
moment
()
-
player
.
join_time
if
waited_time
>=
30000
ygopro
.
stoc_send_chat
(
player
,
"${arena_wait_timeout}"
,
ygopro
.
constants
.
COLORS
.
BABYBLUE
)
player
.
arena_quit_free
=
true
else
if
waited_time
>=
5000
and
waited_time
<
6000
ygopro
.
stoc_send_chat
(
player
,
"${arena_wait_hint}"
,
ygopro
.
constants
.
COLORS
.
BABYBLUE
)
return
,
1000
if
settings
.
modules
.
heartbeat_detection
.
enabled
setInterval
()
->
for
room
in
ROOM_all
when
room
and
room
.
duel_stage
!=
ygopro
.
constants
.
DUEL_STAGE
.
BEGIN
and
(
room
.
hostinfo
.
time_limit
==
0
or
room
.
duel_stage
!=
ygopro
.
constants
.
DUEL_STAGE
.
DUELING
)
and
!
room
.
windbot
for
player
in
room
.
get_playing_player
()
when
player
and
(
room
.
duel_stage
!=
ygopro
.
constants
.
DUEL_STAGE
.
SIDING
or
player
.
selected_preduel
)
CLIENT_heartbeat_register
(
player
,
true
)
return
,
settings
.
modules
.
heartbeat_detection
.
interval
setInterval
()
->
current_time
=
moment
()
for
room
in
ROOM_all
when
room
and
room
.
duel_stage
!=
ygopro
.
constants
.
DUEL_STAGE
.
BEGIN
and
room
.
hostinfo
.
auto_death
and
!
room
.
auto_death_triggered
and
current_time
-
moment
(
room
.
start_time
)
>
60000
*
room
.
hostinfo
.
auto_death
room
.
auto_death_triggered
=
true
room
.
start_death
()
,
1000
# spawn windbot
# spawn windbot
windbot_looplimit
=
0
windbot_looplimit
=
0
windbot_process
=
global
.
windbot_process
=
null
windbot_process
=
global
.
windbot_process
=
null
...
@@ -3622,18 +3643,15 @@ spawn_windbot = global.spawn_windbot = () ->
...
@@ -3622,18 +3643,15 @@ spawn_windbot = global.spawn_windbot = () ->
return
return
return
return
if
settings
.
modules
.
windbot
.
enabled
and
settings
.
modules
.
windbot
.
spawn
spawn_windbot
()
global
.
rebooted
=
false
global
.
rebooted
=
false
#http
#http
if
settings
.
modules
.
http
if
true
addCallback
=
(
callback
,
text
)
->
addCallback
=
(
callback
,
text
)
->
if
not
callback
then
return
text
if
not
callback
then
return
text
return
callback
+
"( "
+
text
+
" );"
return
callback
+
"( "
+
text
+
" );"
r
equestListener
=
(
request
,
response
)
->
httpR
equestListener
=
(
request
,
response
)
->
parseQueryString
=
true
parseQueryString
=
true
u
=
url
.
parse
(
request
.
url
,
parseQueryString
)
u
=
url
.
parse
(
request
.
url
,
parseQueryString
)
#pass_validated = u.query.pass == settings.modules.http.password
#pass_validated = u.query.pass == settings.modules.http.password
...
@@ -3823,26 +3841,24 @@ if settings.modules.http
...
@@ -3823,26 +3841,24 @@ if settings.modules.http
response
.
writeHead
(
200
)
response
.
writeHead
(
200
)
response
.
end
(
addCallback
(
u
.
query
.
callback
,
"['密码错误', 0]"
))
response
.
end
(
addCallback
(
u
.
query
.
callback
,
"['密码错误', 0]"
))
return
return
load_tips
((
err
)
->
success
=
await
load_tips
()
response
.
writeHead
(
200
)
response
.
writeHead
(
200
)
if
(
err
)
if
success
response
.
end
(
addCallback
(
u
.
query
.
callback
,
"['tip fail', '"
+
settings
.
modules
.
tips
.
get
+
"']"
))
response
.
end
(
addCallback
(
u
.
query
.
callback
,
"['tip ok', '"
+
settings
.
modules
.
tips
.
get
+
"']"
))
else
else
response
.
end
(
addCallback
(
u
.
query
.
callback
,
"['tip ok', '"
+
settings
.
modules
.
tips
.
get
+
"']"
))
response
.
end
(
addCallback
(
u
.
query
.
callback
,
"['tip fail', '"
+
settings
.
modules
.
tips
.
get
+
"']"
))
)
else
if
u
.
query
.
loaddialogues
else
if
u
.
query
.
loaddialogues
if
!
await
auth
.
auth
(
u
.
query
.
username
,
u
.
query
.
pass
,
"change_settings"
,
"change_dialogues"
)
if
!
await
auth
.
auth
(
u
.
query
.
username
,
u
.
query
.
pass
,
"change_settings"
,
"change_dialogues"
)
response
.
writeHead
(
200
)
response
.
writeHead
(
200
)
response
.
end
(
addCallback
(
u
.
query
.
callback
,
"['密码错误', 0]"
))
response
.
end
(
addCallback
(
u
.
query
.
callback
,
"['密码错误', 0]"
))
return
return
load_dialogues
((
err
)
->
success
=
await
load_tips
()
response
.
writeHead
(
200
)
response
.
writeHead
(
200
)
if
(
err
)
if
success
response
.
end
(
addCallback
(
u
.
query
.
callback
,
"['dialogues fail', '"
+
settings
.
modules
.
dialogues
.
get
+
"']"
))
response
.
end
(
addCallback
(
u
.
query
.
callback
,
"['dialogue ok', '"
+
settings
.
modules
.
tips
.
get
+
"']"
))
else
else
response
.
end
(
addCallback
(
u
.
query
.
callback
,
"['dialogues ok', '"
+
settings
.
modules
.
dialogues
.
get
+
"']"
))
response
.
end
(
addCallback
(
u
.
query
.
callback
,
"['dialogue fail', '"
+
settings
.
modules
.
tips
.
get
+
"']"
))
)
else
if
u
.
query
.
ban
else
if
u
.
query
.
ban
if
!
await
auth
.
auth
(
u
.
query
.
username
,
u
.
query
.
pass
,
"ban_user"
,
"ban_user"
)
if
!
await
auth
.
auth
(
u
.
query
.
username
,
u
.
query
.
pass
,
"ban_user"
,
"ban_user"
)
...
@@ -3942,31 +3958,4 @@ if settings.modules.http
...
@@ -3942,31 +3958,4 @@ if settings.modules.http
response
.
end
()
response
.
end
()
return
return
http_server
=
http
.
createServer
(
requestListener
)
init
()
http_server
.
listen
settings
.
modules
.
http
.
port
if
settings
.
modules
.
http
.
ssl
.
enabled
https
=
require
'https'
options
=
cert
:
fs
.
readFileSync
(
settings
.
modules
.
http
.
ssl
.
cert
)
key
:
fs
.
readFileSync
(
settings
.
modules
.
http
.
ssl
.
key
)
https_server
=
https
.
createServer
(
options
,
requestListener
)
if
settings
.
modules
.
http
.
websocket_roomlist
and
roomlist
roomlist
.
init
https_server
,
ROOM_all
https_server
.
listen
settings
.
modules
.
http
.
ssl
.
port
mkdirList
=
[
"./plugins"
,
settings
.
modules
.
tournament_mode
.
deck_path
,
settings
.
modules
.
tournament_mode
.
replay_path
,
settings
.
modules
.
tournament_mode
.
log_save_path
,
settings
.
modules
.
deck_log
.
local
]
if
not
fs
.
existsSync
(
'./plugins'
)
fs
.
mkdirSync
(
'./plugins'
)
plugin_list
=
fs
.
readdirSync
(
"./plugins"
)
for
plugin_filename
in
plugin_list
plugin_path
=
process
.
cwd
()
+
"/plugins/"
+
plugin_filename
require
(
plugin_path
)
log
.
info
(
"Plugin loaded:"
,
plugin_filename
)
ygopro-server.js
View file @
04888860
This source diff could not be displayed because it is too large. You can
view the blob
instead.
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