/
service.go
132 lines (116 loc) · 3.81 KB
/
service.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package do
import (
"context"
"time"
"github.com/samber/do/v2/stacktrace"
typetostring "github.com/samber/go-type-to-string"
)
type ServiceType string
const (
ServiceTypeLazy ServiceType = "lazy"
ServiceTypeEager ServiceType = "eager"
ServiceTypeTransient ServiceType = "transient"
ServiceTypeAlias ServiceType = "alias"
)
var serviceTypeToIcon = map[ServiceType]string{
ServiceTypeLazy: "😴",
ServiceTypeEager: "🔁",
ServiceTypeTransient: "🏭",
ServiceTypeAlias: "🔗",
}
type Service[T any] interface {
getName() string
getType() ServiceType
getEmptyInstance() any
getInstanceAny(Injector) (any, error)
getInstance(Injector) (T, error)
isHealthchecker() bool
healthcheck(context.Context) error
isShutdowner() bool
shutdown(context.Context) error
clone() any
source() (stacktrace.Frame, []stacktrace.Frame)
}
// Like Service[T] but without the generic type.
type ServiceAny interface {
getName() string
getType() ServiceType
getEmptyInstance() any
getInstanceAny(Injector) (any, error)
// getInstance(Injector) (T, error)
isHealthchecker() bool
healthcheck(context.Context) error
isShutdowner() bool
shutdown(context.Context) error
clone() any
source() (stacktrace.Frame, []stacktrace.Frame)
}
type serviceGetName interface{ getName() string }
type serviceGetType interface{ getType() ServiceType }
type serviceGetEmptyInstance interface{ getEmptyInstance() any }
type serviceGetInstanceAny interface{ getInstanceAny(Injector) (any, error) }
type serviceGetInstance[T any] interface{ getInstance(Injector) (T, error) } //nolint:unused
type serviceIsHealthchecker interface{ isHealthchecker() bool }
type serviceHealthcheck interface{ healthcheck(context.Context) error }
type serviceIsShutdowner interface{ isShutdowner() bool }
type serviceShutdown interface{ shutdown(context.Context) error }
type serviceClone interface{ clone() any }
type serviceSource interface {
source() (stacktrace.Frame, []stacktrace.Frame)
}
type serviceBuildTime interface {
getBuildTime() (time.Duration, bool)
}
var _ serviceGetName = (Service[int])(nil)
var _ serviceGetType = (Service[int])(nil)
var _ serviceGetEmptyInstance = (Service[int])(nil)
var _ serviceGetInstanceAny = (Service[int])(nil)
var _ serviceIsHealthchecker = (Service[int])(nil)
var _ serviceHealthcheck = (Service[int])(nil)
var _ serviceIsShutdowner = (Service[int])(nil)
var _ serviceShutdown = (Service[int])(nil)
var _ serviceClone = (Service[int])(nil)
var _ serviceSource = (Service[int])(nil)
func inferServiceName[T any]() string {
return typetostring.GetType[T]()
}
func inferServiceProviderStacktrace(service ServiceAny) (stacktrace.Frame, bool) {
if service.getType() == ServiceTypeTransient {
return stacktrace.Frame{}, false
} else {
providerFrame, _ := service.source()
return providerFrame, true
}
}
type serviceInfo struct {
name string
serviceType ServiceType
serviceBuildTime time.Duration
healthchecker bool
shutdowner bool
}
func inferServiceInfo(injector Injector, name string) (serviceInfo, bool) {
if serviceAny, ok := injector.serviceGet(name); ok {
var buildTime time.Duration
if lazy, ok := serviceAny.(serviceBuildTime); ok {
buildTime, _ = lazy.getBuildTime()
}
return serviceInfo{
name: name,
serviceType: serviceAny.(serviceGetType).getType(),
serviceBuildTime: buildTime,
healthchecker: serviceAny.(serviceIsHealthchecker).isHealthchecker(),
shutdowner: serviceAny.(serviceIsShutdowner).isShutdowner(),
}, true
}
return serviceInfo{}, false
}
func serviceIsAssignable[T any](service any) bool {
if svc, ok := service.(serviceGetEmptyInstance); ok {
// we need an empty instance here, because we don't want to instantiate the service when not needed
if _, ok = svc.getEmptyInstance().(T); ok {
return true
}
}
return false
}