优化结构
This commit is contained in:
parent
7d89e2ea4d
commit
40632c5756
|
|
@ -10,7 +10,7 @@ configs/ 运行配置
|
||||||
internal/biz/ 领域对象、用例和仓储接口(按 system/payment/integration/task 拆分)
|
internal/biz/ 领域对象、用例和仓储接口(按 system/payment/integration/task 拆分)
|
||||||
internal/data/ 数据库、缓存、对象存储及仓储实现
|
internal/data/ 数据库、缓存、对象存储及仓储实现
|
||||||
internal/server/ Gin 服务、路由、中间件和 Handler
|
internal/server/ Gin 服务、路由、中间件和 Handler
|
||||||
internal/service/ HTTP 输入输出与领域对象转换
|
internal/service/ 按业务模块组织的 HTTP 输入输出与领域对象转换
|
||||||
internal/worker/ 定时任务调度与后台工作进程
|
internal/worker/ 定时任务调度与后台工作进程
|
||||||
web/ Vue 管理端
|
web/ Vue 管理端
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,10 @@ import (
|
||||||
"kra/internal/server"
|
"kra/internal/server"
|
||||||
"kra/internal/server/handler"
|
"kra/internal/server/handler"
|
||||||
"kra/internal/server/router"
|
"kra/internal/server/router"
|
||||||
"kra/internal/service"
|
integration4 "kra/internal/service/integration"
|
||||||
|
payment3 "kra/internal/service/payment"
|
||||||
|
system3 "kra/internal/service/system"
|
||||||
|
task3 "kra/internal/service/task"
|
||||||
"kra/internal/worker"
|
"kra/internal/worker"
|
||||||
"kra/pkg/logging"
|
"kra/pkg/logging"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
|
@ -56,7 +59,7 @@ func wireApp(confServer *conf.Server, runtime *conf.Runtime, logger *slog.Logger
|
||||||
authorityAccessRepo := system.NewAuthorityAccessRepo(dataData)
|
authorityAccessRepo := system.NewAuthorityAccessRepo(dataData)
|
||||||
apiRepo := system.NewAPIRepo(dataData)
|
apiRepo := system.NewAPIRepo(dataData)
|
||||||
accessControlUsecase := system2.NewAccessControlUsecase(authorityAccessRepo, apiRepo)
|
accessControlUsecase := system2.NewAccessControlUsecase(authorityAccessRepo, apiRepo)
|
||||||
accessControlService := service.NewAccessControlService(accessControlUsecase)
|
v := system3.NewAccessControlService(accessControlUsecase)
|
||||||
userRepo := system.NewUserRepo(dataData)
|
userRepo := system.NewUserRepo(dataData)
|
||||||
userUsecase := system2.NewUserUsecase(userRepo)
|
userUsecase := system2.NewUserUsecase(userRepo)
|
||||||
securityRepo := system.NewSecurityRepo(dataData)
|
securityRepo := system.NewSecurityRepo(dataData)
|
||||||
|
|
@ -68,45 +71,45 @@ func wireApp(confServer *conf.Server, runtime *conf.Runtime, logger *slog.Logger
|
||||||
tokenIssuer := system.NewTokenIssuer(runtimeSettings)
|
tokenIssuer := system.NewTokenIssuer(runtimeSettings)
|
||||||
auditRecordRepo := system.NewAuditRecorderRepo(dataData)
|
auditRecordRepo := system.NewAuditRecorderRepo(dataData)
|
||||||
authenticationUsecase := system2.NewAuthenticationUsecase(userUsecase, securityUsecase, tokenIssuer, auditRecordRepo)
|
authenticationUsecase := system2.NewAuthenticationUsecase(userUsecase, securityUsecase, tokenIssuer, auditRecordRepo)
|
||||||
authService := service.NewAuthService(authenticationUsecase)
|
authService := system3.NewAuthService(authenticationUsecase)
|
||||||
securityService := service.NewSecurityService(securityUsecase)
|
v2 := system3.NewSecurityService(securityUsecase)
|
||||||
auditRecorderUsecase := system2.NewAuditRecorderUsecase(auditRecordRepo)
|
auditRecorderUsecase := system2.NewAuditRecorderUsecase(auditRecordRepo)
|
||||||
auditRecorder := service.NewAuditRecorder(auditRecorderUsecase)
|
v3 := system3.NewAuditRecorder(auditRecorderUsecase)
|
||||||
authorityUsecase := system2.NewAuthorityUsecase(authorityAccessRepo)
|
authorityUsecase := system2.NewAuthorityUsecase(authorityAccessRepo)
|
||||||
authorityService := service.NewAuthorityService(authorityUsecase)
|
v4 := system3.NewAuthorityService(authorityUsecase)
|
||||||
authority := handler.NewAuthority(authorityService)
|
authority := handler.NewAuthority(v4)
|
||||||
menuRepo := system.NewMenuRepo(dataData)
|
menuRepo := system.NewMenuRepo(dataData)
|
||||||
menuUsecase := system2.NewMenuUsecase(menuRepo)
|
menuUsecase := system2.NewMenuUsecase(menuRepo)
|
||||||
menuService := service.NewMenuService(menuUsecase)
|
v5 := system3.NewMenuService(menuUsecase)
|
||||||
menu := handler.NewMenu(menuService)
|
menu := handler.NewMenu(v5)
|
||||||
apiUsecase := system2.NewAPIUsecase(apiRepo)
|
apiUsecase := system2.NewAPIUsecase(apiRepo)
|
||||||
apiService := service.NewAPIService(apiUsecase, runtimeSettings)
|
v6 := system3.NewAPIService(apiUsecase, runtimeSettings)
|
||||||
api := handler.NewAPI(apiService)
|
api := handler.NewAPI(v6)
|
||||||
permissionRepo := system.NewPermissionRepo(dataData)
|
permissionRepo := system.NewPermissionRepo(dataData)
|
||||||
permissionUsecase := system2.NewPermissionUsecase(permissionRepo)
|
permissionUsecase := system2.NewPermissionUsecase(permissionRepo)
|
||||||
permissionService := service.NewPermissionService(permissionUsecase)
|
v7 := system3.NewPermissionService(permissionUsecase)
|
||||||
permission := handler.NewPermission(permissionService)
|
permission := handler.NewPermission(v7)
|
||||||
departmentRepo := system.NewDepartmentRepo(dataData)
|
departmentRepo := system.NewDepartmentRepo(dataData)
|
||||||
departmentUsecase := system2.NewDepartmentUsecase(departmentRepo)
|
departmentUsecase := system2.NewDepartmentUsecase(departmentRepo)
|
||||||
departmentService := service.NewDepartmentService(departmentUsecase)
|
v8 := system3.NewDepartmentService(departmentUsecase)
|
||||||
positionRepo := system.NewPositionRepo(dataData)
|
positionRepo := system.NewPositionRepo(dataData)
|
||||||
positionUsecase := system2.NewPositionUsecase(positionRepo)
|
positionUsecase := system2.NewPositionUsecase(positionRepo)
|
||||||
positionService := service.NewPositionService(positionUsecase)
|
v9 := system3.NewPositionService(positionUsecase)
|
||||||
organization := handler.NewOrganization(departmentService, positionService)
|
organization := handler.NewOrganization(v8, v9)
|
||||||
announcementRepo := system.NewAnnouncementRepo(dataData)
|
announcementRepo := system.NewAnnouncementRepo(dataData)
|
||||||
announcementUsecase := system2.NewAnnouncementUsecase(announcementRepo)
|
announcementUsecase := system2.NewAnnouncementUsecase(announcementRepo)
|
||||||
announcementService := service.NewAnnouncementService(announcementUsecase)
|
v10 := system3.NewAnnouncementService(announcementUsecase)
|
||||||
announcement := handler.NewAnnouncement(announcementService)
|
announcement := handler.NewAnnouncement(v10)
|
||||||
emailRepo := email.NewEmailRepo(runtime)
|
emailRepo := email.NewEmailRepo(runtime)
|
||||||
emailUsecase := system2.NewEmailUsecase(emailRepo)
|
emailUsecase := system2.NewEmailUsecase(emailRepo)
|
||||||
emailService := service.NewEmailService(emailUsecase)
|
v11 := system3.NewEmailService(emailUsecase)
|
||||||
handlerEmail := handler.NewEmail(emailService)
|
handlerEmail := handler.NewEmail(v11)
|
||||||
paymentConfigReader := integration.NewPaymentConfigReader(dataData)
|
paymentConfigReader := integration.NewPaymentConfigReader(dataData)
|
||||||
paymentRepo := payment.NewPaymentRepo(dataData, paymentConfigReader)
|
paymentRepo := payment.NewPaymentRepo(dataData, paymentConfigReader)
|
||||||
paymentOrderRepo := payment.NewPaymentOrderRepo(dataData)
|
paymentOrderRepo := payment.NewPaymentOrderRepo(dataData)
|
||||||
paymentUsecase := payment2.NewPaymentUsecase(paymentRepo, paymentOrderRepo, logger)
|
paymentUsecase := payment2.NewPaymentUsecase(paymentRepo, paymentOrderRepo, logger)
|
||||||
paymentService := service.NewPaymentService(paymentUsecase)
|
v12 := payment3.NewPaymentService(paymentUsecase)
|
||||||
handlerPayment := handler.NewPayment(paymentService)
|
handlerPayment := handler.NewPayment(v12)
|
||||||
taskRepo := task.NewTaskRepo(dataData)
|
taskRepo := task.NewTaskRepo(dataData)
|
||||||
registry := app.TaskRegistry(catalog)
|
registry := app.TaskRegistry(catalog)
|
||||||
taskUsecase := task2.NewTaskUsecaseWithRegistry(taskRepo, registry)
|
taskUsecase := task2.NewTaskUsecaseWithRegistry(taskRepo, registry)
|
||||||
|
|
@ -116,53 +119,53 @@ func wireApp(confServer *conf.Server, runtime *conf.Runtime, logger *slog.Logger
|
||||||
taskScheduler := worker.NewTaskScheduler(taskUsecase, authorityUsecase, taskExecutor, logger)
|
taskScheduler := worker.NewTaskScheduler(taskUsecase, authorityUsecase, taskExecutor, logger)
|
||||||
taskRuntime := worker.NewTaskRuntime(taskScheduler)
|
taskRuntime := worker.NewTaskRuntime(taskScheduler)
|
||||||
taskApplicationUsecase := task2.NewTaskApplicationUsecase(taskUsecase, taskRuntime)
|
taskApplicationUsecase := task2.NewTaskApplicationUsecase(taskUsecase, taskRuntime)
|
||||||
taskService := service.NewTaskService(taskApplicationUsecase)
|
v13 := task3.NewTaskService(taskApplicationUsecase)
|
||||||
handlerTask := handler.NewTask(taskService)
|
handlerTask := handler.NewTask(v13)
|
||||||
mediaService := service.NewMediaService(mediaUsecase, runtimeSettings)
|
v14 := system3.NewMediaService(mediaUsecase, runtimeSettings)
|
||||||
media := handler.NewMedia(mediaService)
|
media := handler.NewMedia(v14)
|
||||||
auditQueryRepo := system.NewAuditRepo(dataData)
|
auditQueryRepo := system.NewAuditRepo(dataData)
|
||||||
auditUsecase := system2.NewAuditUsecase(auditQueryRepo)
|
auditUsecase := system2.NewAuditUsecase(auditQueryRepo)
|
||||||
auditService := service.NewAuditService(auditUsecase)
|
v15 := system3.NewAuditService(auditUsecase)
|
||||||
logFileRepo := system.NewLogFileRepo(dataData)
|
logFileRepo := system.NewLogFileRepo(dataData)
|
||||||
logViewerUsecase := system2.NewLogViewerUsecase(logFileRepo)
|
logViewerUsecase := system2.NewLogViewerUsecase(logFileRepo)
|
||||||
logViewerService := service.NewLogViewerService(logViewerUsecase)
|
v16 := system3.NewLogViewerService(logViewerUsecase)
|
||||||
audit := handler.NewAudit(auditService, auditRecorder, logViewerService, logger)
|
audit := handler.NewAudit(v15, v3, v16, logger)
|
||||||
exportRepo := system.NewExportRepo(dataData)
|
exportRepo := system.NewExportRepo(dataData)
|
||||||
exportUsecase := system2.NewExportUsecase(exportRepo)
|
exportUsecase := system2.NewExportUsecase(exportRepo)
|
||||||
exportService := service.NewExportService(exportUsecase, systemCache)
|
v17 := system3.NewExportService(exportUsecase, systemCache)
|
||||||
export := handler.NewExport(exportService)
|
export := handler.NewExport(v17)
|
||||||
versionRepo := system.NewVersionRepo(dataData)
|
versionRepo := system.NewVersionRepo(dataData)
|
||||||
versionUsecase := system2.NewVersionUsecase(versionRepo)
|
versionUsecase := system2.NewVersionUsecase(versionRepo)
|
||||||
versionService := service.NewVersionService(versionUsecase)
|
v18 := system3.NewVersionService(versionUsecase)
|
||||||
version := handler.NewVersion(versionService)
|
version := handler.NewVersion(v18)
|
||||||
dictionaryRepo := system.NewDictionaryRepo(dataData)
|
dictionaryRepo := system.NewDictionaryRepo(dataData)
|
||||||
dictionaryUsecase := system2.NewDictionaryUsecase(dictionaryRepo)
|
dictionaryUsecase := system2.NewDictionaryUsecase(dictionaryRepo)
|
||||||
dictionaryService := service.NewDictionaryService(dictionaryUsecase)
|
v19 := system3.NewDictionaryService(dictionaryUsecase)
|
||||||
dictionary := handler.NewDictionary(dictionaryService)
|
dictionary := handler.NewDictionary(v19)
|
||||||
parameterRepo := system.NewParameterRepo(dataData)
|
parameterRepo := system.NewParameterRepo(dataData)
|
||||||
parameterUsecase := system2.NewParameterUsecase(parameterRepo)
|
parameterUsecase := system2.NewParameterUsecase(parameterRepo)
|
||||||
parameterService := service.NewParameterService(parameterUsecase)
|
v20 := system3.NewParameterService(parameterUsecase)
|
||||||
parameter := handler.NewParameter(parameterService)
|
parameter := handler.NewParameter(v20)
|
||||||
tokenService := service.NewTokenService(tokenUsecase, tokenIssuer)
|
v21 := system3.NewTokenService(tokenUsecase, tokenIssuer)
|
||||||
apiToken := handler.NewAPIToken(tokenService)
|
apiToken := handler.NewAPIToken(v21)
|
||||||
initializationRepo := initialize.NewRepo(dataData, catalog)
|
initializationRepo := initialize.NewRepo(dataData, catalog)
|
||||||
taskReloader := worker.NewTaskReloader(taskScheduler)
|
taskReloader := worker.NewTaskReloader(taskScheduler)
|
||||||
systemConfigUsecase := system2.NewSystemConfigUsecase(initializationRepo, taskReloader)
|
systemConfigUsecase := system2.NewSystemConfigUsecase(initializationRepo, taskReloader)
|
||||||
systemConfigService := service.NewSystemConfigService(systemConfigUsecase, runtimeSettings)
|
v22 := system3.NewSystemConfigService(systemConfigUsecase, runtimeSettings)
|
||||||
systemConfig := handler.NewSystemConfig(systemConfigService, securityService)
|
systemConfig := handler.NewSystemConfig(v22, v2)
|
||||||
public := handler.NewPublic(authService, systemConfigService, securityService)
|
public := handler.NewPublic(authService, v22, v2)
|
||||||
userService := service.NewUserService(userUsecase, securityService)
|
v23 := system3.NewUserService(userUsecase, v2)
|
||||||
user := handler.NewUser(userService, authService)
|
user := handler.NewUser(v23, authService)
|
||||||
navigation := handler.NewNavigation(userService)
|
navigation := handler.NewNavigation(v23)
|
||||||
session := handler.NewSession(tokenService)
|
session := handler.NewSession(v21)
|
||||||
integrationConfigRepo := integration.NewIntegrationConfigRepo(dataData)
|
integrationConfigRepo := integration.NewIntegrationConfigRepo(dataData)
|
||||||
store := data.NewIntegrationRuntime(dataData)
|
store := data.NewIntegrationRuntime(dataData)
|
||||||
connectivityTester := integration2.NewConnectivityTester(store)
|
connectivityTester := integration2.NewConnectivityTester(store)
|
||||||
integrationConfigUsecase := integration3.NewIntegrationConfigUsecase(integrationConfigRepo, connectivityTester)
|
integrationConfigUsecase := integration3.NewIntegrationConfigUsecase(integrationConfigRepo, connectivityTester)
|
||||||
integrationConfigService := service.NewIntegrationConfigService(integrationConfigUsecase)
|
v24 := integration4.NewIntegrationConfigService(integrationConfigUsecase)
|
||||||
integrationConfig := handler.NewIntegrationConfig(integrationConfigService)
|
integrationConfig := handler.NewIntegrationConfig(v24)
|
||||||
v := handler.NewSet(authority, menu, api, permission, organization, announcement, handlerEmail, handlerPayment, handlerTask, media, audit, export, version, dictionary, parameter, apiToken, systemConfig, public, user, navigation, session, integrationConfig)
|
v25 := handler.NewSet(authority, menu, api, permission, organization, announcement, handlerEmail, handlerPayment, handlerTask, media, audit, export, version, dictionary, parameter, apiToken, systemConfig, public, user, navigation, session, integrationConfig)
|
||||||
routes := router.NewRoutes(v)
|
routes := router.NewRoutes(v25)
|
||||||
maintenanceRepo := system.NewMaintenanceRepo(dataData)
|
maintenanceRepo := system.NewMaintenanceRepo(dataData)
|
||||||
maintenanceUsecase := system2.NewMaintenanceUsecase(maintenanceRepo)
|
maintenanceUsecase := system2.NewMaintenanceUsecase(maintenanceRepo)
|
||||||
taskMethods := worker.NewTaskMethods(taskUsecase, maintenanceUsecase, mediaUsecase, runtime)
|
taskMethods := worker.NewTaskMethods(taskUsecase, maintenanceUsecase, mediaUsecase, runtime)
|
||||||
|
|
@ -173,7 +176,7 @@ func wireApp(confServer *conf.Server, runtime *conf.Runtime, logger *slog.Logger
|
||||||
cleanup()
|
cleanup()
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
engine := server.NewGinEngineWithRuntime(runtime, accessControlService, authService, securityService, auditRecorder, logger, string2, moduleRuntime, websocketServer)
|
engine := server.NewGinEngineWithRuntime(runtime, v, authService, v2, v3, logger, string2, moduleRuntime, websocketServer)
|
||||||
httpServer := server.NewGinServer(confServer, engine)
|
httpServer := server.NewGinServer(confServer, engine)
|
||||||
mqReloadable, cleanup3, err := mq.New(store, logger)
|
mqReloadable, cleanup3, err := mq.New(store, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -181,7 +184,7 @@ func wireApp(confServer *conf.Server, runtime *conf.Runtime, logger *slog.Logger
|
||||||
cleanup()
|
cleanup()
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
kratosApp := newApp(logger, httpServer, taskScheduler, auditRecorder, reloadableLogger, mqReloadable)
|
kratosApp := newApp(logger, httpServer, taskScheduler, v3, reloadableLogger, mqReloadable)
|
||||||
return kratosApp, func() {
|
return kratosApp, func() {
|
||||||
cleanup3()
|
cleanup3()
|
||||||
cleanup2()
|
cleanup2()
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,10 @@
|
||||||
- `routecatalog`:统一声明 HTTP 路由的公开性、操作审计、请求体策略和 API 元数据
|
- `routecatalog`:统一声明 HTTP 路由的公开性、操作审计、请求体策略和 API 元数据
|
||||||
- `security`:后台 JWT 等安全实现
|
- `security`:后台 JWT 等安全实现
|
||||||
- `server`:Gin server 组合与生命周期;横切 HTTP 代码按子包维护:
|
- `server`:Gin server 组合与生命周期;横切 HTTP 代码按子包维护:
|
||||||
`server/handler`、`server/middleware`、`server/router`、`server/httpx`
|
`server/handler`、`server/middleware`、`server/router`、`server/staticfiles`;
|
||||||
- `service`:应用服务、DTO 与领域对象转换;DTO 集中在
|
通用响应和 Cookie 工具位于 `pkg/httpx`
|
||||||
`service/dto`,根包中的 `dto_aliases.go` 只负责兼容旧调用方
|
- `service`:按 `system`、`payment`、`integration`、`task` 分模块的应用服务、
|
||||||
|
DTO 与领域对象转换;DTO 集中在 `service/dto`,根包是兼容旧调用方的类型/构造器门面
|
||||||
- `worker`:定时任务执行与调度
|
- `worker`:定时任务执行与调度
|
||||||
|
|
||||||
目录代表边界,模块文件按资源命名。DTO、handler、中间件、路由和 HTTP
|
目录代表边界,模块文件按资源命名。DTO、handler、中间件、路由和 HTTP
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"kra/internal/biz/system"
|
"kra/internal/biz/system"
|
||||||
|
|
||||||
"kra/internal/conf"
|
"kra/internal/conf"
|
||||||
"kra/internal/service"
|
"kra/internal/utils/routepath"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
@ -30,7 +30,7 @@ func AccessControl(runtime *conf.Runtime, access accessController) gin.HandlerFu
|
||||||
path := c.Request.URL.Path
|
path := c.Request.URL.Path
|
||||||
policyPath := path
|
policyPath := path
|
||||||
if config := runtime.Admin(); config != nil {
|
if config := runtime.Admin(); config != nil {
|
||||||
policyPath = service.NormalizeRoutePath(policyPath, config.RouterPrefix)
|
policyPath = routepath.Normalize(policyPath, config.RouterPrefix)
|
||||||
}
|
}
|
||||||
allowed, err := access.Authorize(c.Request.Context(), claims.AuthorityID, policyPath, c.Request.Method)
|
allowed, err := access.Authorize(c.Request.Context(), claims.AuthorityID, policyPath, c.Request.Method)
|
||||||
if err != nil || !allowed {
|
if err != nil || !allowed {
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,28 @@
|
||||||
|
|
||||||
`service` adapts HTTP-facing DTOs to business usecases and owns application
|
`service` adapts HTTP-facing DTOs to business usecases and owns application
|
||||||
orchestration. Request/response/filter contracts live in `dto/`; the root
|
orchestration. Request/response/filter contracts live in `dto/`; the root
|
||||||
package contains resource services, conversions, and security
|
package is a compatibility facade and module provider aggregator.
|
||||||
coordination.
|
|
||||||
|
|
||||||
`dto_alias.go` is a compatibility bridge for existing service callers. New
|
Implementations are grouped by the same business modules as `biz` and `data`:
|
||||||
transport code should import `service/dto` directly when it needs a contract.
|
|
||||||
|
| Directory | Responsibility |
|
||||||
|
| --- | --- |
|
||||||
|
| `system/` | authentication, users, authorization, menus, organization, dictionaries, settings, audit, media, announcements, email, versions, exports |
|
||||||
|
| `payment/` | payment orchestration and callback handling |
|
||||||
|
| `integration/` | integration configuration orchestration |
|
||||||
|
| `task/` | scheduled task orchestration |
|
||||||
|
| `dto/` | HTTP request/response contracts |
|
||||||
|
|
||||||
|
The stateless router-prefix helper lives in `internal/utils/routepath` because
|
||||||
|
both service modules and HTTP middleware use it; it does not depend on a
|
||||||
|
business usecase or DTO.
|
||||||
|
|
||||||
|
Each module owns its Wire `ProviderSet`. The root `service` package re-exports
|
||||||
|
the existing service types and constructors through aliases and thin wrappers, so handlers, middleware
|
||||||
|
and generated Wire code can migrate independently without a flag day.
|
||||||
|
|
||||||
|
Within `system/`, larger cross-cutting resources stay in the same package while
|
||||||
|
being split by concern (`audit.go` and its error/log companions, `media.go` and
|
||||||
|
upload companion, and `export.go`/`export_excel.go`). New transport code should
|
||||||
|
import the module package directly when it does not need the compatibility
|
||||||
|
facade.
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import "github.com/google/wire"
|
||||||
|
|
||||||
|
// ProviderSet wires integration transport services.
|
||||||
|
var ProviderSet = wire.NewSet(NewIntegrationConfigService)
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package payment
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package payment
|
||||||
|
|
||||||
|
import "github.com/google/wire"
|
||||||
|
|
||||||
|
// ProviderSet wires payment transport services.
|
||||||
|
var ProviderSet = wire.NewSet(NewPaymentService)
|
||||||
|
|
@ -1,6 +1,148 @@
|
||||||
package service
|
package service
|
||||||
|
|
||||||
import "github.com/google/wire"
|
// This package is a compatibility facade for the transport layer. Concrete
|
||||||
|
// implementations live under service/system, service/payment,
|
||||||
|
// service/integration, and service/task; aliases here preserve the original
|
||||||
|
// service.* API used by handlers and the composition root.
|
||||||
|
|
||||||
// ProviderSet is service providers.
|
import (
|
||||||
var ProviderSet = wire.NewSet(NewAuthService, NewUserService, NewSystemConfigService, NewAuthorityService, NewPermissionService, NewAccessControlService, NewAPIService, NewMenuService, NewDepartmentService, NewPositionService, NewDictionaryService, NewParameterService, NewTokenService, NewSecurityService, NewVersionService, NewExportService, NewAuditService, NewAuditRecorder, NewLogViewerService, NewTaskService, NewMediaService, NewAnnouncementService, NewEmailService, NewPaymentService, NewIntegrationConfigService)
|
"kra/internal/biz/integration"
|
||||||
|
paymentbiz "kra/internal/biz/payment"
|
||||||
|
"kra/internal/biz/system"
|
||||||
|
taskbiz "kra/internal/biz/task"
|
||||||
|
"kra/internal/service/dto"
|
||||||
|
integrationservice "kra/internal/service/integration"
|
||||||
|
paymentservice "kra/internal/service/payment"
|
||||||
|
systemservice "kra/internal/service/system"
|
||||||
|
taskservice "kra/internal/service/task"
|
||||||
|
"kra/internal/utils/routepath"
|
||||||
|
|
||||||
|
"github.com/google/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AccessControlService = systemservice.AccessControlService
|
||||||
|
type AnnouncementInput = systemservice.AnnouncementInput
|
||||||
|
type AnnouncementService = systemservice.AnnouncementService
|
||||||
|
type APIService = systemservice.APIService
|
||||||
|
type AuditService = systemservice.AuditService
|
||||||
|
type AuditRecorder = systemservice.AuditRecorder
|
||||||
|
type AuthService = systemservice.AuthService
|
||||||
|
type AuthorityService = systemservice.AuthorityService
|
||||||
|
type DepartmentService = systemservice.DepartmentService
|
||||||
|
type DictionaryService = systemservice.DictionaryService
|
||||||
|
type EmailService = systemservice.EmailService
|
||||||
|
type ExportService = systemservice.ExportService
|
||||||
|
type ExportToken = systemservice.ExportToken
|
||||||
|
type LogViewerService = systemservice.LogViewerService
|
||||||
|
type MediaService = systemservice.MediaService
|
||||||
|
type MenuService = systemservice.MenuService
|
||||||
|
type ParameterService = systemservice.ParameterService
|
||||||
|
type PermissionService = systemservice.PermissionService
|
||||||
|
type PositionService = systemservice.PositionService
|
||||||
|
type SecurityService = systemservice.SecurityService
|
||||||
|
type PasswordPolicyError = systemservice.PasswordPolicyError
|
||||||
|
type SystemConfigService = systemservice.SystemConfigService
|
||||||
|
type TokenService = systemservice.TokenService
|
||||||
|
type VersionService = systemservice.VersionService
|
||||||
|
type PaymentService = paymentservice.PaymentService
|
||||||
|
type IntegrationConfigService = integrationservice.IntegrationConfigService
|
||||||
|
type TaskService = taskservice.TaskService
|
||||||
|
type UserService = systemservice.UserService
|
||||||
|
|
||||||
|
func NewAccessControlService(uc *system.AccessControlUsecase) *AccessControlService {
|
||||||
|
return systemservice.NewAccessControlService(uc)
|
||||||
|
}
|
||||||
|
func NewAnnouncementService(uc *system.AnnouncementUsecase) *AnnouncementService {
|
||||||
|
return systemservice.NewAnnouncementService(uc)
|
||||||
|
}
|
||||||
|
func NewAPIService(uc *system.APIUsecase, settings system.RuntimeSettings) *APIService {
|
||||||
|
return systemservice.NewAPIService(uc, settings)
|
||||||
|
}
|
||||||
|
func NewAuditService(uc *system.AuditUsecase) *AuditService {
|
||||||
|
return systemservice.NewAuditService(uc)
|
||||||
|
}
|
||||||
|
func NewAuditRecorder(uc *system.AuditRecorderUsecase) *AuditRecorder {
|
||||||
|
return systemservice.NewAuditRecorder(uc)
|
||||||
|
}
|
||||||
|
func NewAuthService(uc *system.AuthenticationUsecase) *AuthService {
|
||||||
|
return systemservice.NewAuthService(uc)
|
||||||
|
}
|
||||||
|
func NewAuthorityService(uc *system.AuthorityUsecase) *AuthorityService {
|
||||||
|
return systemservice.NewAuthorityService(uc)
|
||||||
|
}
|
||||||
|
func NewDepartmentService(uc *system.DepartmentUsecase) *DepartmentService {
|
||||||
|
return systemservice.NewDepartmentService(uc)
|
||||||
|
}
|
||||||
|
func NewDictionaryService(uc *system.DictionaryUsecase) *DictionaryService {
|
||||||
|
return systemservice.NewDictionaryService(uc)
|
||||||
|
}
|
||||||
|
func NewEmailService(uc *system.EmailUsecase) *EmailService {
|
||||||
|
return systemservice.NewEmailService(uc)
|
||||||
|
}
|
||||||
|
func NewExportService(uc *system.ExportUsecase, cache system.Cache) *ExportService {
|
||||||
|
return systemservice.NewExportService(uc, cache)
|
||||||
|
}
|
||||||
|
func NewIntegrationConfigService(uc *integration.IntegrationConfigUsecase) *IntegrationConfigService {
|
||||||
|
return integrationservice.NewIntegrationConfigService(uc)
|
||||||
|
}
|
||||||
|
func NewLogViewerService(uc *system.LogViewerUsecase) *LogViewerService {
|
||||||
|
return systemservice.NewLogViewerService(uc)
|
||||||
|
}
|
||||||
|
func NewMediaService(uc *system.MediaUsecase, settings system.RuntimeSettings) *MediaService {
|
||||||
|
return systemservice.NewMediaService(uc, settings)
|
||||||
|
}
|
||||||
|
func NewMenuService(uc *system.MenuUsecase) *MenuService {
|
||||||
|
return systemservice.NewMenuService(uc)
|
||||||
|
}
|
||||||
|
func NewParameterService(uc *system.ParameterUsecase) *ParameterService {
|
||||||
|
return systemservice.NewParameterService(uc)
|
||||||
|
}
|
||||||
|
func NewPaymentService(uc *paymentbiz.PaymentUsecase) *PaymentService {
|
||||||
|
return paymentservice.NewPaymentService(uc)
|
||||||
|
}
|
||||||
|
func NewPermissionService(uc *system.PermissionUsecase) *PermissionService {
|
||||||
|
return systemservice.NewPermissionService(uc)
|
||||||
|
}
|
||||||
|
func NewPositionService(uc *system.PositionUsecase) *PositionService {
|
||||||
|
return systemservice.NewPositionService(uc)
|
||||||
|
}
|
||||||
|
func NewSecurityService(uc *system.SecurityUsecase) *SecurityService {
|
||||||
|
return systemservice.NewSecurityService(uc)
|
||||||
|
}
|
||||||
|
func NewSystemConfigService(uc *system.SystemConfigUsecase, settings system.RuntimeSettings) *SystemConfigService {
|
||||||
|
return systemservice.NewSystemConfigService(uc, settings)
|
||||||
|
}
|
||||||
|
func NewTaskService(uc *taskbiz.TaskApplicationUsecase) *TaskService {
|
||||||
|
return taskservice.NewTaskService(uc)
|
||||||
|
}
|
||||||
|
func NewTokenService(uc *system.TokenUsecase, issuer system.TokenIssuer) *TokenService {
|
||||||
|
return systemservice.NewTokenService(uc, issuer)
|
||||||
|
}
|
||||||
|
func NewUserService(uc *system.UserUsecase, settings *SecurityService) *UserService {
|
||||||
|
return systemservice.NewUserService(uc, settings)
|
||||||
|
}
|
||||||
|
func NewVersionService(uc *system.VersionUsecase) *VersionService {
|
||||||
|
return systemservice.NewVersionService(uc)
|
||||||
|
}
|
||||||
|
|
||||||
|
var ErrExportTokenInvalid = systemservice.ErrExportTokenInvalid
|
||||||
|
var ErrExportTokenMalformed = systemservice.ErrExportTokenMalformed
|
||||||
|
var ErrExportTokenType = systemservice.ErrExportTokenType
|
||||||
|
|
||||||
|
func NormalizeRoutePath(path, routerPrefix string) string {
|
||||||
|
return routepath.Normalize(path, routerPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsPasswordPolicyError(err error) bool { return systemservice.IsPasswordPolicyError(err) }
|
||||||
|
|
||||||
|
func DefaultPaymentCallbackAck(provider string, success bool) dto.PaymentCallbackAck {
|
||||||
|
return paymentservice.DefaultPaymentCallbackAck(provider, success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProviderSet aggregates all service modules for Wire.
|
||||||
|
var ProviderSet = wire.NewSet(
|
||||||
|
systemservice.ProviderSet,
|
||||||
|
paymentservice.ProviderSet,
|
||||||
|
integrationservice.ProviderSet,
|
||||||
|
taskservice.ProviderSet,
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"kra/internal/biz/system"
|
"kra/internal/biz/system"
|
||||||
|
"kra/internal/utils/routepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"kra/internal/service/dto"
|
"kra/internal/service/dto"
|
||||||
|
|
@ -21,7 +22,7 @@ func (s *APIService) NormalizeRoutePath(path string) string {
|
||||||
if s.settings == nil {
|
if s.settings == nil {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
return NormalizeRoutePath(path, s.settings.RouterPrefix())
|
return routepath.Normalize(path, s.settings.RouterPrefix())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *APIService) apiDomain(value *dto.APIRequest) *system.API {
|
func (s *APIService) apiDomain(value *dto.APIRequest) *system.API {
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"kra/internal/biz/system"
|
"kra/internal/biz/system"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package system
|
||||||
|
|
||||||
|
import "github.com/google/wire"
|
||||||
|
|
||||||
|
// ProviderSet wires HTTP-facing services backed by the system business
|
||||||
|
// module.
|
||||||
|
var ProviderSet = wire.NewSet(
|
||||||
|
NewAuthService,
|
||||||
|
NewUserService,
|
||||||
|
NewSystemConfigService,
|
||||||
|
NewAuthorityService,
|
||||||
|
NewPermissionService,
|
||||||
|
NewAccessControlService,
|
||||||
|
NewAPIService,
|
||||||
|
NewMenuService,
|
||||||
|
NewDepartmentService,
|
||||||
|
NewPositionService,
|
||||||
|
NewDictionaryService,
|
||||||
|
NewParameterService,
|
||||||
|
NewTokenService,
|
||||||
|
NewSecurityService,
|
||||||
|
NewVersionService,
|
||||||
|
NewExportService,
|
||||||
|
NewAuditService,
|
||||||
|
NewAuditRecorder,
|
||||||
|
NewLogViewerService,
|
||||||
|
NewMediaService,
|
||||||
|
NewAnnouncementService,
|
||||||
|
NewEmailService,
|
||||||
|
)
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"kra/internal/biz/system"
|
"kra/internal/biz/system"
|
||||||
"kra/internal/routecatalog"
|
"kra/internal/routecatalog"
|
||||||
"kra/internal/service/dto"
|
"kra/internal/service/dto"
|
||||||
|
"kra/internal/utils/routepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *SystemConfigService) Initialize(ctx context.Context, input *dto.DatabaseInitRequest, apis []*system.API) error {
|
func (s *SystemConfigService) Initialize(ctx context.Context, input *dto.DatabaseInitRequest, apis []*system.API) error {
|
||||||
|
|
@ -28,7 +29,7 @@ func (s *SystemConfigService) Initialize(ctx context.Context, input *dto.Databas
|
||||||
func (s *SystemConfigService) InitializeRoutes(ctx context.Context, input *dto.DatabaseInitRequest, routes []dto.Route) error {
|
func (s *SystemConfigService) InitializeRoutes(ctx context.Context, input *dto.DatabaseInitRequest, routes []dto.Route) error {
|
||||||
apis := make([]*system.API, 0, len(routes))
|
apis := make([]*system.API, 0, len(routes))
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
path := NormalizeRoutePath(route.Path, s.settings.RouterPrefix())
|
path := routepath.Normalize(route.Path, s.settings.RouterPrefix())
|
||||||
descriptor := routecatalog.Describe(route.Method, path)
|
descriptor := routecatalog.Describe(route.Method, path)
|
||||||
group, description := descriptor.Group, descriptor.Description
|
group, description := descriptor.Group, descriptor.Description
|
||||||
apis = append(apis, &system.API{Path: path, Method: route.Method, APIGroup: group, Description: description})
|
apis = append(apis, &system.API{Path: path, Method: route.Method, APIGroup: group, Description: description})
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"kra/internal/biz/system"
|
"kra/internal/biz/system"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package task
|
||||||
|
|
||||||
|
import "github.com/google/wire"
|
||||||
|
|
||||||
|
// ProviderSet wires task transport services.
|
||||||
|
var ProviderSet = wire.NewSet(NewTaskService)
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package service
|
package task
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
package service
|
package routepath
|
||||||
|
|
||||||
import "strings"
|
import "strings"
|
||||||
|
|
||||||
// NormalizeRoutePath removes only a complete configured router prefix. Paths
|
// Normalize removes only a complete configured router prefix. Paths
|
||||||
// such as /administrator must not be shortened when the prefix is /admin.
|
// such as /administrator must not be shortened when the prefix is /admin.
|
||||||
func NormalizeRoutePath(path, routerPrefix string) string {
|
func Normalize(path, routerPrefix string) string {
|
||||||
prefix := strings.TrimSuffix(strings.TrimSpace(routerPrefix), "/")
|
prefix := strings.TrimSuffix(strings.TrimSpace(routerPrefix), "/")
|
||||||
if prefix == "" || prefix == "/" {
|
if prefix == "" || prefix == "/" {
|
||||||
return path
|
return path
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package service
|
package routepath
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func TestNormalizeRoutePath(t *testing.T) {
|
func TestNormalize(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
path string
|
path string
|
||||||
|
|
@ -18,8 +18,8 @@ func TestNormalizeRoutePath(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if got := NormalizeRoutePath(tt.path, tt.prefix); got != tt.want {
|
if got := Normalize(tt.path, tt.prefix); got != tt.want {
|
||||||
t.Fatalf("NormalizeRoutePath(%q, %q) = %q, want %q", tt.path, tt.prefix, got, tt.want)
|
t.Fatalf("Normalize(%q, %q) = %q, want %q", tt.path, tt.prefix, got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -272,3 +272,39 @@ func TestStopCancelsAndWaitsForActiveRuns(t *testing.T) {
|
||||||
t.Fatal("scheduler accepted a new run after Stop()")
|
t.Fatal("scheduler accepted a new run after Stop()")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStartReturnsAfterStop(t *testing.T) {
|
||||||
|
scheduler := newTestTaskScheduler(&workerTaskRepo{})
|
||||||
|
started := make(chan error, 1)
|
||||||
|
go func() {
|
||||||
|
started <- scheduler.Start(context.Background())
|
||||||
|
}()
|
||||||
|
|
||||||
|
deadline := time.Now().Add(time.Second)
|
||||||
|
for {
|
||||||
|
scheduler.ctxMu.RLock()
|
||||||
|
ready := scheduler.cancel != nil
|
||||||
|
scheduler.ctxMu.RUnlock()
|
||||||
|
if ready {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if time.Now().After(deadline) {
|
||||||
|
t.Fatal("scheduler did not start")
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
stopCtx, stopCancel := context.WithTimeout(context.Background(), time.Second)
|
||||||
|
defer stopCancel()
|
||||||
|
if err := scheduler.Stop(stopCtx); err != nil {
|
||||||
|
t.Fatalf("Stop() error = %v", err)
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case err := <-started:
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Start() error = %v", err)
|
||||||
|
}
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Fatal("Start() did not return after Stop()")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,9 @@ type scheduledEntry struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTaskScheduler(tasks *taskbiz.TaskUsecase, authorities *system.AuthorityUsecase, executor *TaskExecutor, logger *slog.Logger) *TaskScheduler {
|
func NewTaskScheduler(tasks *taskbiz.TaskUsecase, authorities *system.AuthorityUsecase, executor *TaskExecutor, logger *slog.Logger) *TaskScheduler {
|
||||||
|
if logger == nil {
|
||||||
|
logger = slog.Default()
|
||||||
|
}
|
||||||
idle := make(chan struct{})
|
idle := make(chan struct{})
|
||||||
close(idle)
|
close(idle)
|
||||||
return &TaskScheduler{tasks: tasks, authorities: authorities, executor: executor, logger: logger.With("mod", "timedTask"), standard: cron.New(), seconds: cron.New(cron.WithSeconds()), entries: map[uint]scheduledEntry{}, running: map[uint]struct{}{}, idle: idle, subscribers: map[uint]map[chan []byte]struct{}{}}
|
return &TaskScheduler{tasks: tasks, authorities: authorities, executor: executor, logger: logger.With("mod", "timedTask"), standard: cron.New(), seconds: cron.New(cron.WithSeconds()), entries: map[uint]scheduledEntry{}, running: map[uint]struct{}{}, idle: idle, subscribers: map[uint]map[chan []byte]struct{}{}}
|
||||||
|
|
@ -50,24 +53,42 @@ func NewTaskRuntime(scheduler *TaskScheduler) taskbiz.TaskRuntime { return sched
|
||||||
func NewTaskReloader(scheduler *TaskScheduler) system.TaskReloader { return scheduler }
|
func NewTaskReloader(scheduler *TaskScheduler) system.TaskReloader { return scheduler }
|
||||||
|
|
||||||
func (s *TaskScheduler) Start(ctx context.Context) error {
|
func (s *TaskScheduler) Start(ctx context.Context) error {
|
||||||
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
runContext, cancel := context.WithCancel(ctx)
|
runContext, cancel := context.WithCancel(ctx)
|
||||||
s.ctxMu.Lock()
|
s.ctxMu.Lock()
|
||||||
s.runContext, s.cancel = runContext, cancel
|
s.runContext, s.cancel = runContext, cancel
|
||||||
s.ctxMu.Unlock()
|
s.ctxMu.Unlock()
|
||||||
s.runMu.Lock()
|
s.runMu.Lock()
|
||||||
|
if s.stopping {
|
||||||
|
s.runMu.Unlock()
|
||||||
|
cancel()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
s.stopping = false
|
s.stopping = false
|
||||||
s.runMu.Unlock()
|
|
||||||
s.standard.Start()
|
s.standard.Start()
|
||||||
s.seconds.Start()
|
s.seconds.Start()
|
||||||
if err := s.Reload(ctx); err != nil {
|
if err := s.Reload(runContext); err != nil {
|
||||||
s.logger.WarnContext(ctx, "timed task table is not ready", "error", err)
|
s.logger.WarnContext(runContext, "timed task table is not ready", "error", err)
|
||||||
|
}
|
||||||
|
s.runMu.Unlock()
|
||||||
|
// Stop cancels runContext. Waiting on the child context is important: the
|
||||||
|
// application lifecycle passes a long-lived parent context to Start and
|
||||||
|
// invokes Stop separately during graceful shutdown.
|
||||||
|
<-runContext.Done()
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
cleanupCtx, cleanupCancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
|
defer cleanupCancel()
|
||||||
|
_ = s.Stop(cleanupCtx)
|
||||||
}
|
}
|
||||||
<-ctx.Done()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TaskScheduler) Stop(ctx context.Context) error {
|
func (s *TaskScheduler) Stop(ctx context.Context) error {
|
||||||
s.closeSubscribers()
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
s.runMu.Lock()
|
s.runMu.Lock()
|
||||||
s.stopping = true
|
s.stopping = true
|
||||||
idle := s.idle
|
idle := s.idle
|
||||||
|
|
@ -75,6 +96,16 @@ func (s *TaskScheduler) Stop(ctx context.Context) error {
|
||||||
idle = make(chan struct{})
|
idle = make(chan struct{})
|
||||||
close(idle)
|
close(idle)
|
||||||
}
|
}
|
||||||
|
// Keep the lifecycle lock while closing subscriber channels so a new SSE
|
||||||
|
// subscription cannot arrive between the shutdown flag and the close.
|
||||||
|
s.subMu.Lock()
|
||||||
|
for userID, subscribers := range s.subscribers {
|
||||||
|
for ch := range subscribers {
|
||||||
|
close(ch)
|
||||||
|
}
|
||||||
|
delete(s.subscribers, userID)
|
||||||
|
}
|
||||||
|
s.subMu.Unlock()
|
||||||
s.runMu.Unlock()
|
s.runMu.Unlock()
|
||||||
s.ctxMu.Lock()
|
s.ctxMu.Lock()
|
||||||
cancel := s.cancel
|
cancel := s.cancel
|
||||||
|
|
@ -329,6 +360,15 @@ func (s *TaskScheduler) Trigger(task *taskbiz.TimedTask) bool {
|
||||||
|
|
||||||
func (s *TaskScheduler) Subscribe(userID uint) chan []byte {
|
func (s *TaskScheduler) Subscribe(userID uint) chan []byte {
|
||||||
ch := make(chan []byte, 16)
|
ch := make(chan []byte, 16)
|
||||||
|
s.runMu.Lock()
|
||||||
|
if s.stopping {
|
||||||
|
close(ch)
|
||||||
|
s.runMu.Unlock()
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
if s.subscribers == nil {
|
||||||
|
s.subscribers = make(map[uint]map[chan []byte]struct{})
|
||||||
|
}
|
||||||
s.subMu.Lock()
|
s.subMu.Lock()
|
||||||
if s.subscribers[userID] == nil {
|
if s.subscribers[userID] == nil {
|
||||||
s.subscribers[userID] = map[chan []byte]struct{}{}
|
s.subscribers[userID] = map[chan []byte]struct{}{}
|
||||||
|
|
@ -342,6 +382,7 @@ func (s *TaskScheduler) Subscribe(userID uint) chan []byte {
|
||||||
}
|
}
|
||||||
s.subscribers[userID][ch] = struct{}{}
|
s.subscribers[userID][ch] = struct{}{}
|
||||||
s.subMu.Unlock()
|
s.subMu.Unlock()
|
||||||
|
s.runMu.Unlock()
|
||||||
return ch
|
return ch
|
||||||
}
|
}
|
||||||
func (s *TaskScheduler) Unsubscribe(userID uint, ch chan []byte) {
|
func (s *TaskScheduler) Unsubscribe(userID uint, ch chan []byte) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue