Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
S
srvpro2
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
srvpro2
Commits
b7dfc180
Commit
b7dfc180
authored
Feb 14, 2026
by
nanahira
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update config format
parent
7dcde5ac
Pipeline
#43217
passed with stages
in 1 minute and 44 seconds
Changes
6
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
135 additions
and
42 deletions
+135
-42
AGENTS.md
AGENTS.md
+1
-0
config.example.yaml
config.example.yaml
+39
-35
src/config.ts
src/config.ts
+16
-6
src/scripts/gen-config-example.ts
src/scripts/gen-config-example.ts
+22
-1
src/utility/normalize-config-by-default-keys.ts
src/utility/normalize-config-by-default-keys.ts
+26
-0
src/utility/normalize-config-value.ts
src/utility/normalize-config-value.ts
+31
-0
No files found.
AGENTS.md
View file @
b7dfc180
...
@@ -15,6 +15,7 @@
...
@@ -15,6 +15,7 @@
-
目录内引用:同级文件使用
`'./xxx'`
,子目录文件使用
`'../xxx'`
-
目录内引用:同级文件使用
`'./xxx'`
,子目录文件使用
`'../xxx'`
-
目录外引用:必须通过 index.ts 引用,如
`'../room'`
`'../client'`
(指向 index.ts)
-
目录外引用:必须通过 index.ts 引用,如
`'../room'`
`'../client'`
(指向 index.ts)
-
禁止直接引用具体文件:不要使用
`'../room/room'`
`'../client/client'`
这样的路径
-
禁止直接引用具体文件:不要使用
`'../room/room'`
`'../client/client'`
这样的路径
-
如果正在写的算法代码与 this 和业务无关,那么不要放在类方法里面,而是在 utility 目录新开一个 ts 文件放进去
## 模块结构
## 模块结构
...
...
config.example.yaml
View file @
b7dfc180
HOST
:
"
::"
host
:
"
::"
PORT
:
"
7911"
port
:
7911
REDIS_URL
:
"
"
redisUrl
:
"
"
LOG_LEVEL
:
info
logLevel
:
info
WS_PORT
:
"
0"
wsPort
:
0
SSL_PATH
:
"
"
sslPath
:
"
"
SSL_CERT
:
"
"
sslCert
:
"
"
SSL_KEY
:
"
"
sslKey
:
"
"
TRUSTED_PROXIES
:
127.0.0.0/8,::1/128
trustedProxies
:
NO_CONNECT_COUNT_LIMIT
:
"
"
-
127.0.0.0/8
YGOPRO_VERSION
:
"
"
-
::1/128
ALT_VERSIONS
:
"
"
noConnectCountLimit
:
"
"
USE_PROXY
:
"
"
ygoproVersion
:
"
0x1362"
YGOPRO_PATH
:
./ygopro
altVersions
:
EXTRA_SCRIPT_PATH
:
"
"
-
2330
DECK_MAIN_MIN
:
"
40"
-
2331
DECK_MAIN_MAX
:
"
60"
useProxy
:
"
"
DECK_EXTRA_MAX
:
"
15"
ygoproPath
:
./ygopro
DECK_SIDE_MAX
:
"
15"
extraScriptPath
:
"
"
DECK_MAX_COPIES
:
"
3"
deckMainMin
:
40
OCGCORE_DEBUG_LOG
:
"
"
deckMainMax
:
60
OCGCORE_WASM_PATH
:
"
"
deckExtraMax
:
15
WELCOME
:
"
"
deckSideMax
:
15
ENABLE_RECONNECT
:
"
1"
deckMaxCopies
:
3
RECONNECT_TIMEOUT
:
"
180000"
ocgcoreDebugLog
:
0
HOSTINFO_LFLIST
:
"
0"
ocgcoreWasmPath
:
"
"
HOSTINFO_RULE
:
"
0"
welcome
:
"
"
HOSTINFO_MODE
:
"
0"
enableReconnect
:
1
HOSTINFO_DUEL_RULE
:
"
5"
reconnectTimeout
:
180000
HOSTINFO_NO_CHECK_DECK
:
"
0"
hostinfoLflist
:
0
HOSTINFO_NO_SHUFFLE_DECK
:
"
0"
hostinfoRule
:
0
HOSTINFO_START_LP
:
"
8000"
hostinfoMode
:
0
HOSTINFO_START_HAND
:
"
5"
hostinfoDuelRule
:
5
HOSTINFO_DRAW_COUNT
:
"
1"
hostinfoNoCheckDeck
:
0
HOSTINFO_TIME_LIMIT
:
"
240"
hostinfoNoShuffleDeck
:
0
hostinfoStartLp
:
8000
hostinfoStartHand
:
5
hostinfoDrawCount
:
1
hostinfoTimeLimit
:
240
src/config.ts
View file @
b7dfc180
...
@@ -2,6 +2,7 @@ import yaml from 'yaml';
...
@@ -2,6 +2,7 @@ import yaml from 'yaml';
import
*
as
fs
from
'
node:fs
'
;
import
*
as
fs
from
'
node:fs
'
;
import
{
DefaultHostinfo
}
from
'
./room/default-hostinfo
'
;
import
{
DefaultHostinfo
}
from
'
./room/default-hostinfo
'
;
import
{
Prettify
}
from
'
nfkit
'
;
import
{
Prettify
}
from
'
nfkit
'
;
import
{
normalizeConfigByDefaultKeys
}
from
'
./utility/normalize-config-by-default-keys
'
;
export
type
HostinfoOptions
=
{
export
type
HostinfoOptions
=
{
[
K
in
keyof
typeof
DefaultHostinfo
as
`HOSTINFO_
${
Uppercase
<
K
>
}
`
]:
string
;
[
K
in
keyof
typeof
DefaultHostinfo
as
`HOSTINFO_
${
Uppercase
<
K
>
}
`
]:
string
;
...
@@ -30,9 +31,9 @@ export const defaultConfig = {
...
@@ -30,9 +31,9 @@ export const defaultConfig = {
// Boolean parse rule (default false): ''/'0'/'false'/'null' => false, otherwise true.
// Boolean parse rule (default false): ''/'0'/'false'/'null' => false, otherwise true.
NO_CONNECT_COUNT_LIMIT
:
''
,
NO_CONNECT_COUNT_LIMIT
:
''
,
// Restrict accepted YGOPro version. Format: version string; empty means no restriction.
// Restrict accepted YGOPro version. Format: version string; empty means no restriction.
YGOPRO_VERSION
:
''
,
YGOPRO_VERSION
:
'
0x1362
'
,
// Additional accepted versions. Format: comma-separated version strings.
// Additional accepted versions. Format: comma-separated version strings.
ALT_VERSIONS
:
''
,
ALT_VERSIONS
:
'
2330,2331
'
,
// Proxy URL for outbound HTTP(S) requests.
// Proxy URL for outbound HTTP(S) requests.
// Format: proxy URL string (e.g. http://127.0.0.1:7890). Empty means no proxy.
// Format: proxy URL string (e.g. http://127.0.0.1:7890). Empty means no proxy.
USE_PROXY
:
''
,
USE_PROXY
:
''
,
...
@@ -52,7 +53,7 @@ export const defaultConfig = {
...
@@ -52,7 +53,7 @@ export const defaultConfig = {
DECK_MAX_COPIES
:
'
3
'
,
DECK_MAX_COPIES
:
'
3
'
,
// Enable ocgcore debug logs.
// Enable ocgcore debug logs.
// Boolean parse rule (default false): ''/'0'/'false'/'null' => false, otherwise true.
// Boolean parse rule (default false): ''/'0'/'false'/'null' => false, otherwise true.
OCGCORE_DEBUG_LOG
:
''
,
OCGCORE_DEBUG_LOG
:
'
0
'
,
// OCGCore wasm file path. Format: filesystem path string. Empty means use default wasm loading.
// OCGCore wasm file path. Format: filesystem path string. Empty means use default wasm loading.
OCGCORE_WASM_PATH
:
''
,
OCGCORE_WASM_PATH
:
''
,
// Welcome message sent when players join. Format: plain string.
// Welcome message sent when players join. Format: plain string.
...
@@ -77,16 +78,25 @@ export const defaultConfig = {
...
@@ -77,16 +78,25 @@ export const defaultConfig = {
export
type
Config
=
Prettify
<
typeof
defaultConfig
&
HostinfoOptions
>
;
export
type
Config
=
Prettify
<
typeof
defaultConfig
&
HostinfoOptions
>
;
export
function
loadConfig
():
Config
{
export
function
loadConfig
():
Config
{
let
readConfig
:
Partial
<
Config
>
=
{};
let
readConfig
:
Record
<
string
,
unknown
>
=
{};
try
{
try
{
const
configText
=
fs
.
readFileSync
(
'
./config.yaml
'
,
'
utf-8
'
);
const
configText
=
fs
.
readFileSync
(
'
./config.yaml
'
,
'
utf-8
'
);
readConfig
=
yaml
.
parse
(
configText
);
const
parsed
=
yaml
.
parse
(
configText
);
if
(
parsed
&&
typeof
parsed
===
'
object
'
)
{
readConfig
=
parsed
;
}
}
catch
(
e
)
{
}
catch
(
e
)
{
console
.
error
(
`Failed to read config:
${
e
.
toString
()}
`
);
console
.
error
(
`Failed to read config:
${
e
.
toString
()}
`
);
}
}
const
normalizedConfig
=
normalizeConfigByDefaultKeys
(
readConfig
,
defaultConfig
,
);
return
{
return
{
...
defaultConfig
,
...
defaultConfig
,
...
rea
dConfig
,
...
normalize
dConfig
,
...
process
.
env
,
...
process
.
env
,
};
};
}
}
src/scripts/gen-config-example.ts
View file @
b7dfc180
...
@@ -2,8 +2,29 @@ import * as fs from 'fs';
...
@@ -2,8 +2,29 @@ import * as fs from 'fs';
import
yaml
from
'
yaml
'
;
import
yaml
from
'
yaml
'
;
import
{
defaultConfig
}
from
'
../config
'
;
import
{
defaultConfig
}
from
'
../config
'
;
function
toCamelCaseKey
(
key
:
string
):
string
{
const
lower
=
key
.
toLowerCase
();
return
lower
.
replace
(
/_
([
a-z0-9
])
/g
,
(
_
,
ch
:
string
)
=>
ch
.
toUpperCase
());
}
function
toTypedValue
(
value
:
string
):
string
|
number
{
if
(
/^
\d
+$/
.
test
(
value
))
{
return
Number
.
parseInt
(
value
,
10
);
}
return
value
;
}
async
function
main
():
Promise
<
void
>
{
async
function
main
():
Promise
<
void
>
{
const
output
=
yaml
.
stringify
(
defaultConfig
);
const
exampleConfig
=
Object
.
fromEntries
(
Object
.
entries
(
defaultConfig
).
map
(([
key
,
value
])
=>
{
if
(
value
.
includes
(
'
,
'
))
{
const
items
=
value
.
split
(
'
,
'
).
map
((
item
)
=>
toTypedValue
(
item
));
return
[
toCamelCaseKey
(
key
),
items
];
}
return
[
toCamelCaseKey
(
key
),
toTypedValue
(
value
)];
}),
);
const
output
=
yaml
.
stringify
(
exampleConfig
);
await
fs
.
promises
.
writeFile
(
'
./config.example.yaml
'
,
output
,
'
utf-8
'
);
await
fs
.
promises
.
writeFile
(
'
./config.example.yaml
'
,
output
,
'
utf-8
'
);
console
.
log
(
'
Generated config.example.yaml
'
);
console
.
log
(
'
Generated config.example.yaml
'
);
}
}
...
...
src/utility/normalize-config-by-default-keys.ts
0 → 100644
View file @
b7dfc180
import
{
normalizeConfigValue
}
from
'
./normalize-config-value
'
;
function
toCamelCaseKey
(
key
:
string
):
string
{
const
lower
=
key
.
toLowerCase
();
return
lower
.
replace
(
/_
([
a-z0-9
])
/g
,
(
_
,
ch
:
string
)
=>
ch
.
toUpperCase
());
}
export
function
normalizeConfigByDefaultKeys
<
T
extends
Record
<
string
,
string
>>
(
readConfig
:
Record
<
string
,
unknown
>
,
defaultConfig
:
T
,
):
Partial
<
T
>
{
const
normalizedConfig
:
Partial
<
T
>
=
{};
for
(
const
key
of
Object
.
keys
(
defaultConfig
)
as
Array
<
keyof
T
>
)
{
const
rawKey
=
key
as
string
;
const
camelKey
=
toCamelCaseKey
(
rawKey
);
const
value
=
readConfig
[
camelKey
]
!==
undefined
?
readConfig
[
camelKey
]
:
readConfig
[
rawKey
];
const
normalized
=
normalizeConfigValue
(
value
);
if
(
normalized
!==
undefined
)
{
normalizedConfig
[
key
]
=
normalized
as
T
[
typeof
key
];
}
}
return
normalizedConfig
;
}
src/utility/normalize-config-value.ts
0 → 100644
View file @
b7dfc180
function
normalizeArrayItem
(
value
:
unknown
):
string
{
if
(
typeof
value
===
'
string
'
)
{
return
value
;
}
if
(
typeof
value
===
'
number
'
)
{
return
value
.
toString
();
}
if
(
typeof
value
===
'
boolean
'
)
{
return
value
?
'
1
'
:
'
0
'
;
}
return
String
(
value
);
}
export
function
normalizeConfigValue
(
value
:
unknown
):
string
|
undefined
{
if
(
value
===
undefined
)
{
return
undefined
;
}
if
(
typeof
value
===
'
string
'
)
{
return
value
;
}
if
(
typeof
value
===
'
number
'
)
{
return
value
.
toString
();
}
if
(
typeof
value
===
'
boolean
'
)
{
return
value
?
'
1
'
:
'
0
'
;
}
if
(
Array
.
isArray
(
value
))
{
return
value
.
map
((
item
)
=>
normalizeArrayItem
(
item
)).
join
(
'
,
'
);
}
return
String
(
value
);
}
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