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
945fdbcd
Commit
945fdbcd
authored
Feb 14, 2026
by
nanahira
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
migrate config to configurer
parent
b7dfc180
Pipeline
#43222
passed with stages
in 1 minute
Changes
25
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
62 additions
and
210 deletions
+62
-210
config.example.yaml
config.example.yaml
+2
-1
package-lock.json
package-lock.json
+4
-4
package.json
package.json
+1
-1
src/app.ts
src/app.ts
+1
-1
src/client/ip-resolver.ts
src/client/ip-resolver.ts
+3
-7
src/client/ssl-finder.ts
src/client/ssl-finder.ts
+8
-3
src/client/transport/tcp/server.ts
src/client/transport/tcp/server.ts
+3
-4
src/client/transport/ws/server.ts
src/client/transport/ws/server.ts
+3
-4
src/config.ts
src/config.ts
+11
-15
src/feats/client-version-check.ts
src/feats/client-version-check.ts
+2
-7
src/feats/reconnect.ts
src/feats/reconnect.ts
+2
-6
src/feats/welcome.ts
src/feats/welcome.ts
+1
-1
src/room/default-hostinfo-provder.ts
src/room/default-hostinfo-provder.ts
+1
-1
src/room/room.ts
src/room/room.ts
+7
-8
src/room/ygopro-resource-loader.ts
src/room/ygopro-resource-loader.ts
+7
-6
src/scripts/gen-config-example.ts
src/scripts/gen-config-example.ts
+2
-22
src/services/aragami.ts
src/services/aragami.ts
+1
-1
src/services/config.ts
src/services/config.ts
+1
-8
src/services/http-client.ts
src/services/http-client.ts
+1
-1
src/services/logger.ts
src/services/logger.ts
+1
-1
src/utility/convert-string-array.ts
src/utility/convert-string-array.ts
+0
-11
src/utility/load-path.ts
src/utility/load-path.ts
+0
-5
src/utility/normalize-config-by-default-keys.ts
src/utility/normalize-config-by-default-keys.ts
+0
-26
src/utility/normalize-config-value.ts
src/utility/normalize-config-value.ts
+0
-31
src/utility/parse-config-boolean.ts
src/utility/parse-config-boolean.ts
+0
-35
No files found.
config.example.yaml
View file @
945fdbcd
...
...
@@ -3,7 +3,8 @@ port: 7911
redisUrl
:
"
"
logLevel
:
info
wsPort
:
0
sslPath
:
"
"
enableSsl
:
0
sslPath
:
./ssl
sslCert
:
"
"
sslKey
:
"
"
trustedProxies
:
...
...
package-lock.json
View file @
945fdbcd
...
...
@@ -16,7 +16,7 @@
"https-proxy-agent"
:
"^7.0.6"
,
"ipaddr.js"
:
"^2.3.0"
,
"koishipro-core.js"
:
"^1.3.3"
,
"nfkit"
:
"^1.0.2
7
"
,
"nfkit"
:
"^1.0.2
9
"
,
"p-queue"
:
"6.6.2"
,
"pino"
:
"^10.3.1"
,
"pino-pretty"
:
"^13.1.3"
,
...
...
@@ -5291,9 +5291,9 @@
"license"
:
"MIT"
},
"node_modules/nfkit"
:
{
"version"
:
"1.0.2
7
"
,
"resolved"
:
"https://registry.npmjs.org/nfkit/-/nfkit-1.0.2
7
.tgz"
,
"integrity"
:
"sha512-
xgsVsp1aHgrkvxWeTb6Zv55kji9Hq3KcFTZqaIDtQmBBgDwcRtmC2o2/BTQ4ZYjzhaopX+uJCFacfRn39xfL2w
=="
,
"version"
:
"1.0.2
9
"
,
"resolved"
:
"https://registry.npmjs.org/nfkit/-/nfkit-1.0.2
9
.tgz"
,
"integrity"
:
"sha512-
dt3fhhlvAt594N6OxNkFx4VQwrbd86iFR//NuMvAGPevxGTozekF4oT3J76a45K+f06TLS0icxzxXH5Ux2KbqA
=="
,
"license"
:
"MIT"
},
"node_modules/node-int64"
:
{
...
...
package.json
View file @
945fdbcd
...
...
@@ -69,7 +69,7 @@
"
https-proxy-agent
"
:
"
^7.0.6
"
,
"
ipaddr.js
"
:
"
^2.3.0
"
,
"
koishipro-core.js
"
:
"
^1.3.3
"
,
"
nfkit
"
:
"
^1.0.2
7
"
,
"
nfkit
"
:
"
^1.0.2
9
"
,
"
p-queue
"
:
"
6.6.2
"
,
"
pino
"
:
"
^10.3.1
"
,
"
pino-pretty
"
:
"
^13.1.3
"
,
...
...
src/app.ts
View file @
945fdbcd
...
...
@@ -12,7 +12,7 @@ import { FeatsModule } from './feats/feats-module';
const
core
=
createAppContext
()
.
provide
(
ConfigService
,
{
merge
:
[
'
getC
onfig
'
],
merge
:
[
'
c
onfig
'
],
})
.
provide
(
Logger
,
{
merge
:
[
'
createLogger
'
]
})
.
provide
(
Emitter
,
{
merge
:
[
'
dispatch
'
,
'
middleware
'
,
'
removeMiddleware
'
]
})
...
...
src/client/ip-resolver.ts
View file @
945fdbcd
import
{
Context
}
from
'
../app
'
;
import
{
Client
}
from
'
./client
'
;
import
*
as
ipaddr
from
'
ipaddr.js
'
;
import
{
convertStringArray
}
from
'
../utility/convert-string-array
'
;
import
{
parseConfigBoolean
}
from
'
../utility/parse-config-boolean
'
;
export
class
IpResolver
{
private
logger
=
this
.
ctx
.
createLogger
(
'
IpResolver
'
);
...
...
@@ -11,9 +9,7 @@ export class IpResolver {
private
trustedProxies
:
Array
<
[
ipaddr
.
IPv4
|
ipaddr
.
IPv6
,
number
]
>
=
[];
constructor
(
private
ctx
:
Context
)
{
const
proxies
=
convertStringArray
(
this
.
ctx
.
getConfig
(
'
TRUSTED_PROXIES
'
,
'
127.0.0.0/8,::1/128
'
),
);
const
proxies
=
this
.
ctx
.
config
.
getStringArray
(
'
TRUSTED_PROXIES
'
);
for
(
const
trusted
of
proxies
)
{
try
{
...
...
@@ -111,8 +107,8 @@ export class IpResolver {
client
.
isLocal
=
isLocal
;
// Increment count for new IP
const
noConnectCountLimit
=
parseConfig
Boolean
(
this
.
ctx
.
getConfig
(
'
NO_CONNECT_COUNT_LIMIT
'
,
''
)
,
const
noConnectCountLimit
=
this
.
ctx
.
config
.
get
Boolean
(
'
NO_CONNECT_COUNT_LIMIT
'
,
);
let
connectCount
=
this
.
connectedIpCount
.
get
(
newIp
)
||
0
;
...
...
src/client/ssl-finder.ts
View file @
945fdbcd
...
...
@@ -20,9 +20,10 @@ type LoadedCandidate = {
export
class
SSLFinder
{
constructor
(
private
ctx
:
Context
)
{}
private
sslPath
=
this
.
ctx
.
getConfig
(
'
SSL_PATH
'
,
'
./ssl
'
);
private
sslKey
=
this
.
ctx
.
getConfig
(
'
SSL_KEY
'
,
''
);
private
sslCert
=
this
.
ctx
.
getConfig
(
'
SSL_CERT
'
,
''
);
private
enableSSL
=
this
.
ctx
.
config
.
getBoolean
(
'
ENABLE_SSL
'
);
private
sslPath
=
this
.
ctx
.
config
.
getString
(
'
SSL_PATH
'
);
private
sslKey
=
this
.
ctx
.
config
.
getString
(
'
SSL_KEY
'
);
private
sslCert
=
this
.
ctx
.
config
.
getString
(
'
SSL_CERT
'
);
private
logger
=
this
.
ctx
.
createLogger
(
'
SSLFinder
'
);
...
...
@@ -36,6 +37,10 @@ export class SSLFinder {
}
findSSL
():
TlsOptions
|
undefined
{
if
(
!
this
.
enableSSL
)
{
return
undefined
;
}
// 1) 优先 SSL_CERT + SSL_KEY
const
explicit
=
this
.
tryExplicit
(
this
.
sslCert
,
this
.
sslKey
);
if
(
explicit
)
return
{
cert
:
explicit
.
certBuf
,
key
:
explicit
.
keyBuf
};
...
...
src/client/transport/tcp/server.ts
View file @
945fdbcd
...
...
@@ -10,14 +10,13 @@ export class TcpServer {
constructor
(
private
ctx
:
Context
)
{}
async
init
():
Promise
<
void
>
{
const
port
=
this
.
ctx
.
getConfig
(
'
PORT
'
,
'
0
'
);
if
(
!
port
||
port
===
'
0
'
)
{
const
port
Num
=
this
.
ctx
.
config
.
getInt
(
'
PORT
'
);
if
(
!
port
Num
)
{
this
.
logger
.
info
(
'
PORT not configured, TCP server will not start
'
);
return
;
}
const
host
=
this
.
ctx
.
getConfig
(
'
HOST
'
,
'
::
'
);
const
portNum
=
parseInt
(
port
,
10
);
const
host
=
this
.
ctx
.
config
.
getString
(
'
HOST
'
);
this
.
server
=
createServer
((
socket
)
=>
{
this
.
handleConnection
(
socket
);
...
...
src/client/transport/ws/server.ts
View file @
945fdbcd
...
...
@@ -18,16 +18,15 @@ export class WsServer {
constructor
(
private
ctx
:
Context
)
{}
async
init
():
Promise
<
void
>
{
const
wsPort
=
this
.
ctx
.
getConfig
(
'
WS_PORT
'
,
'
0
'
);
if
(
!
wsPort
||
wsPort
===
'
0
'
)
{
const
portNum
=
this
.
ctx
.
config
.
getInt
(
'
WS_PORT
'
);
if
(
!
portNum
)
{
this
.
logger
.
info
(
'
WS_PORT not configured, WebSocket server will not start
'
,
);
return
;
}
const
host
=
this
.
ctx
.
getConfig
(
'
HOST
'
,
'
::
'
);
const
portNum
=
parseInt
(
wsPort
,
10
);
const
host
=
this
.
ctx
.
config
.
getString
(
'
HOST
'
);
// Try to get SSL configuration
const
sslFinder
=
this
.
ctx
.
get
(()
=>
SSLFinder
);
...
...
src/config.ts
View file @
945fdbcd
import
yaml
from
'
yaml
'
;
import
*
as
fs
from
'
node:fs
'
;
import
{
DefaultHostinfo
}
from
'
./room/default-hostinfo
'
;
import
{
Prettify
}
from
'
nfkit
'
;
import
{
normalizeConfigByDefaultKeys
}
from
'
./utility/normalize-config-by-default-keys
'
;
import
{
Configurer
}
from
'
nfkit
'
;
export
type
HostinfoOptions
=
{
[
K
in
keyof
typeof
DefaultHostinfo
as
`HOSTINFO_
${
Uppercase
<
K
>
}
`
]:
string
;
...
...
@@ -19,8 +18,11 @@ export const defaultConfig = {
LOG_LEVEL
:
'
info
'
,
// WebSocket port. Format: integer string. '0' means do not open a separate WS port.
WS_PORT
:
'
0
'
,
// Enable SSL for WebSocket server.
// Boolean parse rule (default false): ''/'0'/'false'/'null' => false, otherwise true.
ENABLE_SSL
:
'
0
'
,
// SSL certificate directory path. Format: filesystem path string.
SSL_PATH
:
''
,
SSL_PATH
:
'
./ssl
'
,
// SSL certificate file name. Format: file name string.
SSL_CERT
:
''
,
// SSL private key file name. Format: file name string.
...
...
@@ -75,9 +77,9 @@ export const defaultConfig = {
)
as
HostinfoOptions
),
};
export
type
Config
=
Prettify
<
typeof
defaultConfig
&
HostinfoOptions
>
;
export
const
configurer
=
new
Configurer
(
defaultConfig
)
;
export
function
loadConfig
()
:
Config
{
export
function
loadConfig
()
{
let
readConfig
:
Record
<
string
,
unknown
>
=
{};
try
{
const
configText
=
fs
.
readFileSync
(
'
./config.yaml
'
,
'
utf-8
'
);
...
...
@@ -89,14 +91,8 @@ export function loadConfig(): Config {
console
.
error
(
`Failed to read config:
${
e
.
toString
()}
`
);
}
const
normalizedConfig
=
normalizeConfigByDefaultKeys
(
readConfig
,
defaultConfig
,
);
return
{
...
defaultConfig
,
...
normalizedConfig
,
...
process
.
env
,
};
return
configurer
.
loadConfig
({
obj
:
readConfig
,
env
:
process
.
env
,
});
}
src/feats/client-version-check.ts
View file @
945fdbcd
...
...
@@ -4,16 +4,11 @@ import {
YGOProStocErrorMsg
,
}
from
'
ygopro-msg-encode
'
;
import
{
Context
}
from
'
../app
'
;
import
{
convertNumberArray
}
from
'
../utility/convert-string-array
'
;
const
YGOPRO_VERSION
=
0x1362
;
export
class
ClientVersionCheck
{
private
altVersions
=
convertNumberArray
(
this
.
ctx
.
getConfig
(
'
ALT_VERSIONS
'
)
);
private
altVersions
=
this
.
ctx
.
config
.
getIntArray
(
'
ALT_VERSIONS
'
);
version
=
parseInt
(
this
.
ctx
.
getConfig
(
'
YGOPRO_VERSION
'
,
YGOPRO_VERSION
.
toString
()),
);
version
=
this
.
ctx
.
config
.
getInt
(
'
YGOPRO_VERSION
'
);
constructor
(
private
ctx
:
Context
)
{
this
.
ctx
.
middleware
(
...
...
src/feats/reconnect.ts
View file @
945fdbcd
...
...
@@ -30,7 +30,6 @@ import { RoomManager } from '../room/room-manager';
import
{
getSpecificFields
}
from
'
../utility/metadata
'
;
import
{
YGOProCtosDisconnect
}
from
'
../utility/ygopro-ctos-disconnect
'
;
import
{
isUpdateDeckPayloadEqual
}
from
'
../utility/deck-compare
'
;
import
{
parseConfigBoolean
}
from
'
../utility/parse-config-boolean
'
;
interface
DisconnectInfo
{
roomName
:
string
;
...
...
@@ -54,14 +53,11 @@ declare module '../client' {
export
class
Reconnect
{
private
disconnectList
=
new
Map
<
string
,
DisconnectInfo
>
();
private
isLooseReconnectRule
=
false
;
// 宽松匹配模式,日后可能配置支持
private
reconnectTimeout
=
parseInt
(
this
.
ctx
.
getConfig
(
'
RECONNECT_TIMEOUT
'
,
''
)
||
'
180000
'
,
10
,
);
// 超时时间,单位:毫秒(默认 180000ms = 3分钟)
private
reconnectTimeout
=
this
.
ctx
.
config
.
getInt
(
'
RECONNECT_TIMEOUT
'
);
// 超时时间,单位:毫秒(默认 180000ms = 3分钟)
constructor
(
private
ctx
:
Context
)
{
// 检查是否启用断线重连(默认启用)
if
(
!
parseConfigBoolean
(
this
.
ctx
.
getConfig
(
'
ENABLE_RECONNECT
'
,
''
),
true
))
{
if
(
!
this
.
ctx
.
config
.
getBoolean
(
'
ENABLE_RECONNECT
'
))
{
return
;
}
...
...
src/feats/welcome.ts
View file @
945fdbcd
...
...
@@ -10,7 +10,7 @@ declare module '../room' {
}
export
class
Welcome
{
private
welcomeMessage
=
this
.
ctx
.
getConfi
g
(
'
WELCOME
'
);
private
welcomeMessage
=
this
.
ctx
.
config
.
getStrin
g
(
'
WELCOME
'
);
constructor
(
private
ctx
:
Context
)
{
this
.
ctx
.
middleware
(
OnRoomJoin
,
async
(
event
,
client
,
next
)
=>
{
...
...
src/room/default-hostinfo-provder.ts
View file @
945fdbcd
...
...
@@ -9,7 +9,7 @@ export class DefaultHostInfoProvider {
const
hostinfo
=
{
...
DefaultHostinfo
};
for
(
const
key
of
Object
.
keys
(
hostinfo
))
{
const
configKey
=
`HOSTINFO_
${
key
.
toUpperCase
()}
`
;
const
value
=
this
.
ctx
.
getConfig
(
configKey
as
any
)
as
string
;
const
value
=
this
.
ctx
.
config
.
getString
(
configKey
as
any
)
;
if
(
value
)
{
const
num
=
Number
(
value
);
if
(
!
isNaN
(
num
))
{
...
...
src/room/room.ts
View file @
945fdbcd
...
...
@@ -89,7 +89,6 @@ import { shuffleDecksBySeed } from '../utility/shuffle-decks-by-seed';
import
{
isUpdateMessage
}
from
'
../utility/is-update-message
'
;
import
{
getMessageIdentifier
}
from
'
../utility/get-message-identifier
'
;
import
{
canIncreaseTime
}
from
'
../utility/can-increase-time
'
;
import
{
parseConfigBoolean
}
from
'
../utility/parse-config-boolean
'
;
import
{
TimerState
}
from
'
./timer-state
'
;
import
{
makeArray
}
from
'
aragami/dist/src/utility/utility
'
;
import
path
from
'
path
'
;
...
...
@@ -738,11 +737,11 @@ export class Room {
const
deckError
=
checkDeck
(
deck
,
cardReader
,
{
ot
:
this
.
hostinfo
.
rule
,
lflist
:
this
.
lflist
,
minMain
:
parseInt
(
this
.
ctx
.
getConfig
(
'
DECK_MAIN_MIN
'
,
'
40
'
)
),
maxMain
:
parseInt
(
this
.
ctx
.
getConfig
(
'
DECK_MAIN_MAX
'
,
'
60
'
)
),
maxExtra
:
parseInt
(
this
.
ctx
.
getConfig
(
'
DECK_EXTRA_MAX
'
,
'
15
'
)
),
maxSide
:
parseInt
(
this
.
ctx
.
getConfig
(
'
DECK_SIDE_MAX
'
,
'
15
'
)
),
maxCopies
:
parseInt
(
this
.
ctx
.
getConfig
(
'
DECK_MAX_COPIES
'
,
'
3
'
)
),
minMain
:
this
.
ctx
.
config
.
getInt
(
'
DECK_MAIN_MIN
'
),
maxMain
:
this
.
ctx
.
config
.
getInt
(
'
DECK_MAIN_MAX
'
),
maxExtra
:
this
.
ctx
.
config
.
getInt
(
'
DECK_EXTRA_MAX
'
),
maxSide
:
this
.
ctx
.
config
.
getInt
(
'
DECK_SIDE_MAX
'
),
maxCopies
:
this
.
ctx
.
config
.
getInt
(
'
DECK_MAX_COPIES
'
),
});
this
.
logger
.
debug
(
...
...
@@ -1211,7 +1210,7 @@ export class Room {
'
Initializing OCGCoreWorker
'
,
);
const
ocgcoreWasmPathConfig
=
this
.
ctx
.
getConfig
(
'
OCGCORE_WASM_PATH
'
,
'
'
);
const
ocgcoreWasmPathConfig
=
this
.
ctx
.
config
.
getString
(
'
OCGCORE_WASM_PATH
'
);
const
ocgcoreWasmPath
=
ocgcoreWasmPathConfig
?
path
.
resolve
(
process
.
cwd
(),
ocgcoreWasmPathConfig
)
:
undefined
;
...
...
@@ -1283,7 +1282,7 @@ export class Room {
this
.
ocgcore
.
message$
.
subscribe
((
msg
)
=>
{
if
(
msg
.
type
===
OcgcoreMessageType
.
DebugMessage
&&
!
parseConfigBoolean
(
this
.
ctx
.
getConfig
(
'
OCGCORE_DEBUG_LOG
'
,
''
)
)
!
this
.
ctx
.
config
.
getBoolean
(
'
OCGCORE_DEBUG_LOG
'
)
)
{
return
;
}
...
...
src/room/ygopro-resource-loader.ts
View file @
945fdbcd
import
{
Context
}
from
'
../app
'
;
import
{
loadPaths
}
from
'
../utility/load-path
'
;
import
{
DirCardReader
,
searchYGOProResource
}
from
'
koishipro-core.js
'
;
import
{
YGOProLFList
}
from
'
ygopro-lflist-encode
'
;
import
path
from
'
node:path
'
;
...
...
@@ -7,11 +6,13 @@ import path from 'node:path';
export
class
YGOProResourceLoader
{
constructor
(
private
ctx
:
Context
)
{}
ygoproPaths
=
loadPaths
(
this
.
ctx
.
getConfig
(
'
YGOPRO_PATH
'
)).
flatMap
((
p
)
=>
[
path
.
join
(
p
,
'
expansions
'
),
p
,
]);
extraScriptPaths
=
loadPaths
(
this
.
ctx
.
getConfig
(
'
EXTRA_SCRIPT_PATH
'
));
ygoproPaths
=
this
.
ctx
.
config
.
getStringArray
(
'
YGOPRO_PATH
'
)
.
map
((
p
)
=>
path
.
resolve
(
process
.
cwd
(),
p
))
.
flatMap
((
p
)
=>
[
path
.
join
(
p
,
'
expansions
'
),
p
]);
extraScriptPaths
=
this
.
ctx
.
config
.
getStringArray
(
'
EXTRA_SCRIPT_PATH
'
)
.
map
((
p
)
=>
path
.
resolve
(
process
.
cwd
(),
p
));
private
logger
=
this
.
ctx
.
createLogger
(
this
.
constructor
.
name
);
...
...
src/scripts/gen-config-example.ts
View file @
945fdbcd
import
*
as
fs
from
'
fs
'
;
import
yaml
from
'
yaml
'
;
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
;
}
import
{
configurer
}
from
'
../config
'
;
async
function
main
():
Promise
<
void
>
{
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
exampleConfig
=
configurer
.
generateExampleObject
();
const
output
=
yaml
.
stringify
(
exampleConfig
);
await
fs
.
promises
.
writeFile
(
'
./config.example.yaml
'
,
output
,
'
utf-8
'
);
console
.
log
(
'
Generated config.example.yaml
'
);
...
...
src/services/aragami.ts
View file @
945fdbcd
...
...
@@ -5,7 +5,7 @@ import { ConfigService } from './config';
export
class
AragamiService
{
constructor
(
private
ctx
:
AppContext
)
{}
private
redisUrl
=
this
.
ctx
.
get
(
ConfigService
).
getConfi
g
(
'
REDIS_URL
'
);
private
redisUrl
=
this
.
ctx
.
get
(
ConfigService
).
config
.
getStrin
g
(
'
REDIS_URL
'
);
aragami
=
new
Aragami
({
redis
:
this
.
redisUrl
?
{
uri
:
this
.
redisUrl
}
:
undefined
,
...
...
src/services/config.ts
View file @
945fdbcd
import
{
AppContext
}
from
'
nfkit
'
;
import
{
Config
,
loadConfig
}
from
'
../config
'
;
import
{
loadConfig
}
from
'
../config
'
;
export
class
ConfigService
{
constructor
(
private
app
:
AppContext
)
{}
config
=
loadConfig
();
getConfig
<
K
extends
keyof
Config
,
D
extends
Config
[
K
]
>
(
key
:
K
,
defaultValue
?:
D
,
):
D
extends
string
?
Config
[
K
]
|
D
:
Config
[
K
]
|
undefined
{
return
(
this
.
config
[
key
]
||
(
defaultValue
??
undefined
))
as
any
;
}
}
src/services/http-client.ts
View file @
945fdbcd
...
...
@@ -6,6 +6,6 @@ import { ConfigService } from './config';
export
class
HttpClient
{
constructor
(
private
ctx
:
AppContext
)
{}
http
=
axios
.
create
({
...
useProxy
(
this
.
ctx
.
get
(()
=>
ConfigService
).
getConfig
(
'
USE_PROXY
'
,
'
'
)),
...
useProxy
(
this
.
ctx
.
get
(()
=>
ConfigService
).
config
.
getString
(
'
USE_PROXY
'
)),
});
}
src/services/logger.ts
View file @
945fdbcd
...
...
@@ -5,7 +5,7 @@ import { ConfigService } from './config';
export
class
Logger
{
constructor
(
private
ctx
:
AppContext
)
{}
private
readonly
logger
=
pino
({
level
:
this
.
ctx
.
get
(()
=>
ConfigService
).
getConfig
(
'
LOG_LEVEL
'
)
||
'
info
'
,
level
:
this
.
ctx
.
get
(()
=>
ConfigService
).
config
.
getString
(
'
LOG_LEVEL
'
)
,
transport
:
{
target
:
'
pino-pretty
'
,
options
:
{
...
...
src/utility/convert-string-array.ts
deleted
100644 → 0
View file @
b7dfc180
export
const
convertStringArray
=
(
str
:
string
)
=>
str
?.
split
(
'
,
'
)
.
map
((
s
)
=>
s
.
trim
())
.
filter
((
s
)
=>
s
)
||
[];
export
const
convertNumberArray
=
(
str
:
string
)
=>
str
?.
split
(
'
,
'
)
.
map
((
s
)
=>
parseInt
(
s
.
trim
()))
.
filter
((
n
)
=>
!
isNaN
(
n
))
||
[];
src/utility/load-path.ts
deleted
100644 → 0
View file @
b7dfc180
import
path
from
'
path
'
;
import
{
convertStringArray
}
from
'
./convert-string-array
'
;
export
const
loadPaths
=
(
pathStr
:
string
)
=>
convertStringArray
(
pathStr
).
map
((
p
)
=>
path
.
resolve
(
process
.
cwd
(),
p
))
||
[];
src/utility/normalize-config-by-default-keys.ts
deleted
100644 → 0
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
deleted
100644 → 0
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
);
}
src/utility/parse-config-boolean.ts
deleted
100644 → 0
View file @
b7dfc180
export
function
parseConfigBoolean
(
value
:
unknown
,
defaultValue
=
false
,
):
boolean
{
if
(
typeof
value
===
'
boolean
'
)
{
return
value
;
}
if
(
typeof
value
===
'
number
'
)
{
return
value
!==
0
;
}
if
(
typeof
value
===
'
string
'
)
{
const
normalized
=
value
.
trim
().
toLowerCase
();
if
(
defaultValue
)
{
return
!
(
normalized
===
'
0
'
||
normalized
===
'
false
'
||
normalized
===
'
null
'
);
}
return
!
(
normalized
===
''
||
normalized
===
'
0
'
||
normalized
===
'
false
'
||
normalized
===
'
null
'
);
}
if
(
value
==
null
)
{
return
defaultValue
;
}
return
Boolean
(
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