Skip to content

Commit 0211381

Browse files
authored
refactor: migrate global singletons to dependency injection (#20)
* refactor: migrate global singletons to DI Register DAOs, services, the database, and `HttpClient` in the DI container and resolve them with `inject()` instead of shared globals. Pass injected services through routing and controllers, and make image transformation helpers suspend-safe by removing `runBlocking`. * chore: rm useless import
1 parent 93ffcc1 commit 0211381

24 files changed

Lines changed: 280 additions & 190 deletions

app/src/main/kotlin/io/sakurasou/hoshizora/Application.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,9 @@ fun Application.mainModule() {
4040
.toLong()
4141
val clientProxyAddress = environment.config.property("client.proxy.address").getString()
4242

43+
InstanceCenter.init()
4344
InstanceCenter.initClient(clientTimeout, clientProxyAddress)
4445

45-
InstanceCenter.initDao()
46-
InstanceCenter.initService()
4746
configureDatabase()
4847
configureCache(redisHost, redisPort)
4948
configureJwt()

app/src/main/kotlin/io/sakurasou/hoshizora/config/RoutingCenter.kt

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,45 @@ import io.sakurasou.hoshizora.controller.siteInitRoute
1616
import io.sakurasou.hoshizora.controller.strategyRoute
1717
import io.sakurasou.hoshizora.controller.systemRoute
1818
import io.sakurasou.hoshizora.controller.userRoute
19-
import io.sakurasou.hoshizora.di.InstanceCenter.albumService
20-
import io.sakurasou.hoshizora.di.InstanceCenter.authService
21-
import io.sakurasou.hoshizora.di.InstanceCenter.groupService
22-
import io.sakurasou.hoshizora.di.InstanceCenter.imageService
23-
import io.sakurasou.hoshizora.di.InstanceCenter.permissionService
24-
import io.sakurasou.hoshizora.di.InstanceCenter.personalAccessTokenService
25-
import io.sakurasou.hoshizora.di.InstanceCenter.roleService
26-
import io.sakurasou.hoshizora.di.InstanceCenter.settingService
27-
import io.sakurasou.hoshizora.di.InstanceCenter.strategyService
28-
import io.sakurasou.hoshizora.di.InstanceCenter.systemService
29-
import io.sakurasou.hoshizora.di.InstanceCenter.userService
19+
import io.sakurasou.hoshizora.di.inject
3020
import io.sakurasou.hoshizora.plugins.SiteInitCheckPlugin
21+
import io.sakurasou.hoshizora.service.album.AlbumService
22+
import io.sakurasou.hoshizora.service.auth.AuthService
23+
import io.sakurasou.hoshizora.service.common.CommonService
24+
import io.sakurasou.hoshizora.service.group.GroupService
25+
import io.sakurasou.hoshizora.service.image.ImageService
26+
import io.sakurasou.hoshizora.service.permission.PermissionService
27+
import io.sakurasou.hoshizora.service.personalAccessToken.PersonalAccessTokenService
28+
import io.sakurasou.hoshizora.service.role.RoleService
29+
import io.sakurasou.hoshizora.service.setting.SettingService
30+
import io.sakurasou.hoshizora.service.strategy.StrategyService
31+
import io.sakurasou.hoshizora.service.system.SystemService
32+
import io.sakurasou.hoshizora.service.user.UserService
33+
import kotlin.getValue
3134

3235
/**
3336
* @author ShiinaKin
3437
* 2024/10/6 17:22
3538
*/
3639

3740
fun Route.apiRoute() {
41+
val authService: AuthService by inject()
42+
val userService: UserService by inject()
43+
val imageService: ImageService by inject()
44+
val albumService: AlbumService by inject()
45+
val strategyService: StrategyService by inject()
46+
val settingService: SettingService by inject()
47+
val groupService: GroupService by inject()
48+
val roleService: RoleService by inject()
49+
val permissionService: PermissionService by inject()
50+
val personalAccessTokenService: PersonalAccessTokenService by inject()
51+
val commonService by inject<CommonService>()
52+
val systemService: SystemService by inject()
53+
3854
route("api") {
3955
route({ tags("common") }) {
40-
siteInitRoute()
41-
commonSiteSettingRoute()
56+
siteInitRoute(commonService)
57+
commonSiteSettingRoute(commonService)
4258
}
4359
route {
4460
install(SiteInitCheckPlugin)

app/src/main/kotlin/io/sakurasou/hoshizora/controller/AlbumController.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,13 @@ import io.sakurasou.hoshizora.extension.pageRequest
3636
import io.sakurasou.hoshizora.extension.pageRequestSpec
3737
import io.sakurasou.hoshizora.extension.success
3838
import io.sakurasou.hoshizora.plugins.AuthorizationPlugin
39+
import io.sakurasou.hoshizora.service.album.AlbumService
3940

4041
/**
4142
* @author Shiina Kin
4243
* 2024/9/9 08:58
4344
*/
44-
fun Route.albumRoute(albumService: io.sakurasou.hoshizora.service.album.AlbumService) {
45+
fun Route.albumRoute(albumService: AlbumService) {
4546
val controller =
4647
AlbumController(albumService)
4748
route("album", {
@@ -420,7 +421,7 @@ private fun Route.albumManagePage(controller: AlbumController) {
420421
private fun ApplicationCall.albumId() = parameters["albumId"]?.toLongOrNull() ?: throw WrongParameterException()
421422

422423
class AlbumController(
423-
private val albumService: io.sakurasou.hoshizora.service.album.AlbumService,
424+
private val albumService: AlbumService,
424425
) {
425426
suspend fun handleSelfInsert(
426427
userId: Long,

app/src/main/kotlin/io/sakurasou/hoshizora/controller/AuthController.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,17 @@ import io.sakurasou.hoshizora.controller.request.UserInsertRequest
1414
import io.sakurasou.hoshizora.controller.request.UserLoginRequest
1515
import io.sakurasou.hoshizora.controller.vo.CommonResponse
1616
import io.sakurasou.hoshizora.extension.success
17+
import io.sakurasou.hoshizora.service.auth.AuthService
18+
import io.sakurasou.hoshizora.service.user.UserService
1719
import io.swagger.v3.oas.models.media.Schema
1820

1921
/**
2022
* @author Shiina Kin
2123
* 2024/9/12 10:14
2224
*/
2325
fun Route.authRoute(
24-
authService: io.sakurasou.hoshizora.service.auth.AuthService,
25-
userService: io.sakurasou.hoshizora.service.user.UserService,
26+
authService: AuthService,
27+
userService: UserService,
2628
) {
2729
val authController = AuthController(authService, userService)
2830
route("user", {
@@ -120,8 +122,8 @@ private fun Route.signup(authController: AuthController) {
120122
}
121123

122124
class AuthController(
123-
private val authService: io.sakurasou.hoshizora.service.auth.AuthService,
124-
private val userService: io.sakurasou.hoshizora.service.user.UserService,
125+
private val authService: AuthService,
126+
private val userService: UserService,
125127
) {
126128
suspend fun handleLogin(loginRequest: UserLoginRequest): String = authService.login(loginRequest)
127129

app/src/main/kotlin/io/sakurasou/hoshizora/controller/CommonController.kt

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package io.sakurasou.hoshizora.controller
33
import io.github.smiley4.ktorswaggerui.dsl.routing.get
44
import io.github.smiley4.ktorswaggerui.dsl.routing.post
55
import io.github.smiley4.ktorswaggerui.dsl.routing.route
6+
import io.ktor.client.HttpClient
67
import io.ktor.client.request.get
78
import io.ktor.client.statement.bodyAsBytes
89
import io.ktor.http.ContentType
@@ -21,17 +22,17 @@ import io.sakurasou.hoshizora.constant.REGEX_USERNAME
2122
import io.sakurasou.hoshizora.controller.request.SiteInitRequest
2223
import io.sakurasou.hoshizora.controller.vo.CommonResponse
2324
import io.sakurasou.hoshizora.controller.vo.CommonSiteSetting
24-
import io.sakurasou.hoshizora.di.InstanceCenter.client
25-
import io.sakurasou.hoshizora.di.InstanceCenter.commonService
25+
import io.sakurasou.hoshizora.di.inject
2626
import io.sakurasou.hoshizora.exception.controller.param.WrongParameterException
2727
import io.sakurasou.hoshizora.extension.success
2828
import io.sakurasou.hoshizora.plugins.cache
29+
import io.sakurasou.hoshizora.service.common.CommonService
2930

3031
/**
3132
* @author Shiina Kin
3233
* 2024/9/9 09:03
3334
*/
34-
fun Route.commonRoute(commonService: io.sakurasou.hoshizora.service.common.CommonService) {
35+
fun Route.commonRoute(commonService: CommonService) {
3536
val commonController = CommonController(commonService)
3637
route({ tags("common") }) {
3738
cache(cachedNoQueryParamRequest = false) {
@@ -41,7 +42,7 @@ fun Route.commonRoute(commonService: io.sakurasou.hoshizora.service.common.Commo
4142
}
4243
}
4344

44-
fun Route.siteInitRoute() {
45+
fun Route.siteInitRoute(commonService: CommonService) {
4546
val commonController = CommonController(commonService)
4647
route {
4748
install(RequestValidation) {
@@ -80,7 +81,7 @@ fun Route.siteInitRoute() {
8081
}
8182
}
8283

83-
fun Route.commonSiteSettingRoute() {
84+
fun Route.commonSiteSettingRoute(commonService: CommonService) {
8485
val commonController = CommonController(commonService)
8586
get("site/setting", {
8687
description = "fetch common site setting"
@@ -116,6 +117,7 @@ private fun Route.randomFetchImage(commonController: CommonController) {
116117
if (fileDTO.bytes != null) {
117118
call.respondBytes(fileDTO.bytes, ContentType.Image.Any)
118119
} else {
120+
val client by inject<HttpClient>()
119121
call.respondBytes(client.get(fileDTO.url!!).bodyAsBytes(), ContentType.Image.Any)
120122
}
121123
}
@@ -142,13 +144,14 @@ private fun Route.anonymousGetImage(commonController: CommonController) {
142144
if (fileDTO.bytes != null) {
143145
call.respondBytes(fileDTO.bytes, ContentType.Image.Any)
144146
} else {
147+
val client by inject<HttpClient>()
145148
call.respondBytes(client.get(fileDTO.url!!).bodyAsBytes(), ContentType.Image.Any)
146149
}
147150
}
148151
}
149152

150153
class CommonController(
151-
private val commonService: io.sakurasou.hoshizora.service.common.CommonService,
154+
private val commonService: CommonService,
152155
) {
153156
suspend fun handleInit(siteInitRequest: SiteInitRequest) {
154157
commonService.initSite(siteInitRequest)

app/src/main/kotlin/io/sakurasou/hoshizora/controller/GroupController.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,19 @@ import io.sakurasou.hoshizora.controller.vo.GroupAllowedImageType
2424
import io.sakurasou.hoshizora.controller.vo.GroupPageVO
2525
import io.sakurasou.hoshizora.controller.vo.GroupVO
2626
import io.sakurasou.hoshizora.controller.vo.PageResult
27-
import io.sakurasou.hoshizora.extension.*
27+
import io.sakurasou.hoshizora.extension.getPrincipal
28+
import io.sakurasou.hoshizora.extension.id
29+
import io.sakurasou.hoshizora.extension.pageRequest
30+
import io.sakurasou.hoshizora.extension.pageRequestSpec
31+
import io.sakurasou.hoshizora.extension.success
2832
import io.sakurasou.hoshizora.plugins.AuthorizationPlugin
33+
import io.sakurasou.hoshizora.service.group.GroupService
2934

3035
/**
3136
* @author Shiina Kin
3237
* 2024/9/9 08:58
3338
*/
34-
fun Route.groupRoute(groupService: io.sakurasou.hoshizora.service.group.GroupService) {
39+
fun Route.groupRoute(groupService: GroupService) {
3540
val controller = GroupController(groupService)
3641
route("group", {
3742
protected = true
@@ -270,7 +275,7 @@ private fun Route.groupFetchGroupAllowedImageType(controller: GroupController) {
270275
}
271276

272277
class GroupController(
273-
private val groupService: io.sakurasou.hoshizora.service.group.GroupService,
278+
private val groupService: GroupService,
274279
) {
275280
suspend fun handleInsertGroup(insertRequest: GroupInsertRequest) {
276281
groupService.saveGroup(insertRequest)

app/src/main/kotlin/io/sakurasou/hoshizora/controller/ImageController.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import io.github.smiley4.ktorswaggerui.dsl.routing.get
55
import io.github.smiley4.ktorswaggerui.dsl.routing.patch
66
import io.github.smiley4.ktorswaggerui.dsl.routing.post
77
import io.github.smiley4.ktorswaggerui.dsl.routing.route
8+
import io.ktor.client.HttpClient
89
import io.ktor.client.request.get
910
import io.ktor.client.statement.bodyAsBytes
1011
import io.ktor.http.ContentType
@@ -37,7 +38,7 @@ import io.sakurasou.hoshizora.controller.vo.ImageManageVO
3738
import io.sakurasou.hoshizora.controller.vo.ImagePageVO
3839
import io.sakurasou.hoshizora.controller.vo.ImageVO
3940
import io.sakurasou.hoshizora.controller.vo.PageResult
40-
import io.sakurasou.hoshizora.di.InstanceCenter.client
41+
import io.sakurasou.hoshizora.di.inject
4142
import io.sakurasou.hoshizora.exception.controller.param.UnsupportedFileTypeException
4243
import io.sakurasou.hoshizora.exception.controller.param.WrongParameterException
4344
import io.sakurasou.hoshizora.extension.getPrincipal
@@ -48,6 +49,7 @@ import io.sakurasou.hoshizora.plugins.AuthorizationPlugin
4849
import io.sakurasou.hoshizora.plugins.cache
4950
import io.swagger.v3.oas.models.media.Schema
5051
import kotlinx.io.readByteArray
52+
import kotlin.getValue
5153

5254
/**
5355
* @author ShiinaKin
@@ -257,6 +259,7 @@ private fun Route.imageSelfFileFetch(controller: ImageController) {
257259
if (imageFileDTO.bytes != null) {
258260
call.respondBytes(imageFileDTO.bytes, ContentType.Image.Any)
259261
} else {
262+
val client by inject<HttpClient>()
260263
call.respondBytes(client.get(imageFileDTO.url!!).bodyAsBytes(), ContentType.Image.Any)
261264
}
262265
}
@@ -284,6 +287,7 @@ private fun Route.imageSelfThumbnailFileFetch(controller: ImageController) {
284287
if (imageFileDTO.bytes != null) {
285288
call.respondBytes(imageFileDTO.bytes, ContentType.Image.Any)
286289
} else {
290+
val client by inject<HttpClient>()
287291
call.respondBytes(client.get(imageFileDTO.url!!).bodyAsBytes(), ContentType.Image.Any)
288292
}
289293
}
@@ -472,6 +476,7 @@ private fun Route.imageManageFileFetch(controller: ImageController) {
472476
if (imageFileDTO.bytes != null) {
473477
call.respondBytes(imageFileDTO.bytes, ContentType.Image.Any)
474478
} else {
479+
val client by inject<HttpClient>()
475480
call.respondBytes(client.get(imageFileDTO.url!!).bodyAsBytes(), ContentType.Image.Any)
476481
}
477482
}
@@ -498,6 +503,7 @@ private fun Route.imageManageThumbnailFileFetch(controller: ImageController) {
498503
if (imageFileDTO.bytes != null) {
499504
call.respondBytes(imageFileDTO.bytes, ContentType.Image.Any)
500505
} else {
506+
val client by inject<HttpClient>()
501507
call.respondBytes(client.get(imageFileDTO.url!!).bodyAsBytes(), ContentType.Image.Any)
502508
}
503509
}

app/src/main/kotlin/io/sakurasou/hoshizora/controller/PermissionController.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ import io.sakurasou.hoshizora.controller.vo.CommonResponse
99
import io.sakurasou.hoshizora.controller.vo.PermissionVO
1010
import io.sakurasou.hoshizora.extension.success
1111
import io.sakurasou.hoshizora.plugins.AuthorizationPlugin
12+
import io.sakurasou.hoshizora.service.permission.PermissionService
1213

1314
/**
1415
* @author Shiina Kin
1516
* 2024/12/2 17:54
1617
*/
1718

18-
fun Route.permissionRoutes(permissionService: io.sakurasou.hoshizora.service.permission.PermissionService) {
19+
fun Route.permissionRoutes(permissionService: PermissionService) {
1920
val controller = PermissionController(permissionService)
2021
route("permission", {
2122
protected = true
@@ -45,7 +46,7 @@ private fun Route.fetchAllPermissions(controller: PermissionController) {
4546
}
4647

4748
class PermissionController(
48-
private val permissionService: io.sakurasou.hoshizora.service.permission.PermissionService,
49+
private val permissionService: PermissionService,
4950
) {
5051
suspend fun handleFetchAllPermissions(): List<PermissionVO> {
5152
val allPermissions = permissionService.fetchAllPermissions()

app/src/main/kotlin/io/sakurasou/hoshizora/controller/PersonalAccessTokenController.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import io.sakurasou.hoshizora.extension.pageRequest
2525
import io.sakurasou.hoshizora.extension.pageRequestSpec
2626
import io.sakurasou.hoshizora.extension.success
2727
import io.sakurasou.hoshizora.plugins.AuthorizationPlugin
28+
import io.sakurasou.hoshizora.service.personalAccessToken.PersonalAccessTokenService
2829
import kotlinx.datetime.TimeZone
2930
import kotlinx.datetime.toLocalDateTime
3031
import kotlin.time.Clock
@@ -34,9 +35,7 @@ import kotlin.time.Clock
3435
* 2024/11/16 05:38
3536
*/
3637

37-
fun Route.personalAccessTokenRoute(
38-
personalAccessTokenService: io.sakurasou.hoshizora.service.personalAccessToken.PersonalAccessTokenService,
39-
) {
38+
fun Route.personalAccessTokenRoute(personalAccessTokenService: PersonalAccessTokenService) {
4039
val controller = PersonalAccessTokenController(personalAccessTokenService)
4140
route("personal-access-token", {
4241
protected = true
@@ -194,7 +193,7 @@ private fun Route.patPage(controller: PersonalAccessTokenController) {
194193
private fun ApplicationCall.patId() = parameters["patId"]?.toLongOrNull() ?: throw WrongParameterException("Invalid patId")
195194

196195
class PersonalAccessTokenController(
197-
private val personalAccessTokenService: io.sakurasou.hoshizora.service.personalAccessToken.PersonalAccessTokenService,
196+
private val personalAccessTokenService: PersonalAccessTokenService,
198197
) {
199198
suspend fun handleInsert(
200199
userId: Long,

app/src/main/kotlin/io/sakurasou/hoshizora/controller/RoleController.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,14 @@ import io.sakurasou.hoshizora.extension.pageRequest
2626
import io.sakurasou.hoshizora.extension.pageRequestSpec
2727
import io.sakurasou.hoshizora.extension.success
2828
import io.sakurasou.hoshizora.plugins.AuthorizationPlugin
29+
import io.sakurasou.hoshizora.service.role.RoleService
2930

3031
/**
3132
* @author Shiina Kin
3233
* 2024/9/9 08:53
3334
*/
3435

35-
fun Route.roleRoute(roleService: io.sakurasou.hoshizora.service.role.RoleService) {
36+
fun Route.roleRoute(roleService: RoleService) {
3637
val controller = RoleController(roleService)
3738
route("role", {
3839
protected = true
@@ -225,7 +226,7 @@ private fun Route.pageRoles(controller: RoleController) {
225226
}
226227

227228
class RoleController(
228-
private val roleService: io.sakurasou.hoshizora.service.role.RoleService,
229+
private val roleService: RoleService,
229230
) {
230231
suspend fun handleInsertRole(insertRequest: RoleInsertRequest) {
231232
roleService.saveRole(insertRequest)

0 commit comments

Comments
 (0)