mirror of
https://github.com/gone-io/gone.git
synced 2025-01-23 01:00:23 +08:00
feat: 完成基本设计
This commit is contained in:
parent
287d5abd89
commit
0d643686d8
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
9
.idea/gone.iml
generated
Normal file
9
.idea/gone.iml
generated
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/gone.iml" filepath="$PROJECT_DIR$/.idea/gone.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
146
cemetery.go
Normal file
146
cemetery.go
Normal file
@ -0,0 +1,146 @@
|
||||
package gone
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func NewCemetery() Cemetery {
|
||||
return &cemetery{
|
||||
Logger: &defaultLogger{},
|
||||
tombMap: make(map[GonerId]Tomb),
|
||||
}
|
||||
}
|
||||
|
||||
type cemetery struct {
|
||||
Logger `inject:"-"`
|
||||
|
||||
tombMap map[GonerId]Tomb
|
||||
tombs []Tomb
|
||||
}
|
||||
|
||||
func (c *cemetery) Bury(goner Goner, id GonerId) Tomb {
|
||||
t := NewTomb(goner)
|
||||
if id != "" {
|
||||
_, ok := c.tombMap[id]
|
||||
if ok {
|
||||
panic(GonerIdIsExistedError)
|
||||
}
|
||||
|
||||
c.tombMap[id] = t.SetId(id)
|
||||
}
|
||||
c.tombs = append(c.tombs, t)
|
||||
return t
|
||||
}
|
||||
|
||||
func (c *cemetery) ReplaceBury(Goner, GonerId) Tomb {
|
||||
//todo
|
||||
return nil
|
||||
}
|
||||
|
||||
const goneTag = "gone"
|
||||
const matchAll = "*"
|
||||
|
||||
func parseGoneTagId(tag string) (id GonerId, extend string) {
|
||||
//todo
|
||||
return
|
||||
}
|
||||
|
||||
func (c *cemetery) reviveOne(tomb Tomb) (err error) {
|
||||
goner := tomb.GetGoner()
|
||||
|
||||
gonerType := reflect.TypeOf(goner).Elem()
|
||||
gonerValue := reflect.ValueOf(goner).Elem()
|
||||
|
||||
for i := 0; i < gonerValue.NumField(); i++ {
|
||||
field := gonerType.Field(i)
|
||||
tag := field.Tag.Get(goneTag)
|
||||
if tag == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
id, extConfig := parseGoneTagId(tag)
|
||||
t := field.Type
|
||||
v := gonerValue.Field(i)
|
||||
|
||||
if !field.IsExported() {
|
||||
//黑魔法:让非导出字段可以访问
|
||||
v = reflect.NewAt(t, unsafe.Pointer(v.UnsafeAddr())).Elem()
|
||||
}
|
||||
|
||||
//gone标记的是slice
|
||||
if t.Kind() == reflect.Slice {
|
||||
if id == matchAll {
|
||||
tombs := c.GetTomByType(t)
|
||||
print(tombs)
|
||||
//todo:设置数组
|
||||
} else {
|
||||
tomb := c.GetTomById(id)
|
||||
if tomb == nil {
|
||||
err = newCannotFoundGonerById(id)
|
||||
return
|
||||
}
|
||||
|
||||
goner := tomb.GetGoner()
|
||||
builder, ok := goner.(Builder)
|
||||
if ok {
|
||||
err = builder.Build(extConfig, v)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else if IsCompatible(goner, t) {
|
||||
//todo: 设置数组
|
||||
v.Set(reflect.ValueOf(goner))
|
||||
} else {
|
||||
err = newNotCompatibleGonerError(id)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//todo 结构体指针 或者 接口
|
||||
|
||||
c.Infof("field field:%v, type:%v", field, v)
|
||||
}
|
||||
|
||||
after, ok := goner.(ReviveAfter)
|
||||
if ok {
|
||||
err = after.After(c, tomb)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *cemetery) revive() error {
|
||||
for _, tomb := range c.tombs {
|
||||
err := c.reviveOne(tomb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *cemetery) GetTomById(id GonerId) Tomb {
|
||||
return c.tombMap[id]
|
||||
}
|
||||
|
||||
func (c *cemetery) GetTomByType(t reflect.Type) (tombs []Tomb) {
|
||||
for _, tomb := range c.tombs {
|
||||
if IsCompatible(tomb.GetGoner(), t) {
|
||||
tombs = append(tombs, tomb)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func IsCompatible(goner Goner, t reflect.Type) bool {
|
||||
gonerType := reflect.TypeOf(goner)
|
||||
if isInterface(gonerType) {
|
||||
return gonerType.Implements(t)
|
||||
}
|
||||
return gonerType == t
|
||||
}
|
||||
|
||||
func isInterface(t reflect.Type) bool {
|
||||
return t.Kind() == reflect.Interface
|
||||
}
|
40
cemetery_test.go
Normal file
40
cemetery_test.go
Normal file
@ -0,0 +1,40 @@
|
||||
package gone
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_cemetery_reviveOne(t *testing.T) {
|
||||
type A struct {
|
||||
DeadFlag
|
||||
a int
|
||||
b int
|
||||
}
|
||||
|
||||
type B struct {
|
||||
DeadFlag
|
||||
a A `gone:"*"`
|
||||
A A `gone:"*"`
|
||||
}
|
||||
|
||||
cemetery := NewCemetery()
|
||||
|
||||
cemetery.Bury(&A{}, "")
|
||||
cemetery.Bury(&B{}, "")
|
||||
|
||||
err := cemetery.revive()
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
type A struct {
|
||||
DeadFlag
|
||||
a int `gone:"xxxx,zzz,xxx,yyy"`
|
||||
b int
|
||||
}
|
||||
|
||||
type B struct {
|
||||
DeadFlag
|
||||
a A `gone:"*"`
|
||||
A A `gone:"*"`
|
||||
}
|
6
dead.go
Normal file
6
dead.go
Normal file
@ -0,0 +1,6 @@
|
||||
package gone
|
||||
|
||||
type DeadFlag struct {
|
||||
}
|
||||
|
||||
func (*DeadFlag) gone() {}
|
31
error.go
Normal file
31
error.go
Normal file
@ -0,0 +1,31 @@
|
||||
package gone
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var GonerIdIsExistedError = errors.New("goner id is existed")
|
||||
|
||||
type CannotFoundGonerByIdError struct {
|
||||
Id GonerId
|
||||
}
|
||||
|
||||
func (e *CannotFoundGonerByIdError) Error() string {
|
||||
return fmt.Sprintf("cannot found the Goner by Id(%s)", e.Id)
|
||||
}
|
||||
func newCannotFoundGonerById(id GonerId) *CannotFoundGonerByIdError {
|
||||
return &CannotFoundGonerByIdError{Id: id}
|
||||
}
|
||||
|
||||
type NotCompatibleGonerError struct {
|
||||
Id GonerId
|
||||
}
|
||||
|
||||
func (e *NotCompatibleGonerError) Error() string {
|
||||
return fmt.Sprintf("Id(%s) goner is not compatible", e.Id)
|
||||
}
|
||||
|
||||
func newNotCompatibleGonerError(id GonerId) *NotCompatibleGonerError {
|
||||
return &NotCompatibleGonerError{Id: id}
|
||||
}
|
11
go.mod
Normal file
11
go.mod
Normal file
@ -0,0 +1,11 @@
|
||||
module github.com/gone-io/gone
|
||||
|
||||
go 1.18
|
||||
|
||||
require github.com/stretchr/testify v1.8.0
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
15
go.sum
Normal file
15
go.sum
Normal file
@ -0,0 +1,15 @@
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
134
heaven.go
Normal file
134
heaven.go
Normal file
@ -0,0 +1,134 @@
|
||||
package gone
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"reflect"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Run
|
||||
// ```go
|
||||
//
|
||||
// // 加载服务
|
||||
// func LoadServer(c Cemetery) error {
|
||||
// c.Bury(goneXorm.New())
|
||||
// c.Bury(goneGin.New())
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
// // 加载组件
|
||||
// func LoadComponent(c Cemetery) error {
|
||||
// c.Bury(componentA.New())
|
||||
// c.Bury(componentB.New())
|
||||
// }
|
||||
//
|
||||
// gone.Run(LoadServer, LoadComponent)
|
||||
//
|
||||
// ```
|
||||
func Run(digGraves ...Digger) {
|
||||
New(digGraves...).Start()
|
||||
}
|
||||
|
||||
// New 新建Heaven
|
||||
func New(digGraves ...Digger) Heaven {
|
||||
return &heaven{
|
||||
cemetery: NewCemetery(),
|
||||
digGraves: digGraves,
|
||||
signal: make(chan os.Signal),
|
||||
}
|
||||
}
|
||||
|
||||
type heaven struct {
|
||||
cemetery Cemetery
|
||||
|
||||
digGraves []Digger
|
||||
|
||||
beforeStartHandlers []Process
|
||||
afterStartHandlers []Process
|
||||
beforeStopHandlers []Process
|
||||
afterStopHandlers []Process
|
||||
|
||||
signal chan os.Signal
|
||||
}
|
||||
|
||||
func getAngelType() reflect.Type {
|
||||
var angelPtr *Angel = nil
|
||||
return reflect.TypeOf(angelPtr).Elem()
|
||||
}
|
||||
|
||||
func (h *heaven) Start() {
|
||||
for _, digGrave := range h.digGraves {
|
||||
err := digGrave(h.cemetery)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
err := h.cemetery.revive()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
angleTombs := h.cemetery.GetTomByType(getAngelType())
|
||||
for _, tomb := range angleTombs {
|
||||
angel := tomb.GetGoner().(Angel)
|
||||
h.BeforeStart(angel.Start)
|
||||
h.BeforeStop(angel.Stop)
|
||||
}
|
||||
|
||||
// start Handlers 顺序调用:先注册的先调用
|
||||
for _, before := range h.beforeStartHandlers {
|
||||
err := before(h.cemetery)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, after := range h.afterStartHandlers {
|
||||
err := after(h.cemetery)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
signal.Notify(h.signal, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-h.signal
|
||||
|
||||
// stop Handlers 逆序调用:先注册的后调用
|
||||
for i := len(h.beforeStopHandlers) - 1; i >= 0; i-- {
|
||||
before := h.beforeStopHandlers[i]
|
||||
err := before(h.cemetery)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
for i := len(h.afterStopHandlers) - 1; i >= 0; i-- {
|
||||
before := h.afterStopHandlers[i]
|
||||
err := before(h.cemetery)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *heaven) Stop() {}
|
||||
|
||||
func (h *heaven) BeforeStart(p Process) Heaven {
|
||||
h.beforeStartHandlers = append(h.beforeStopHandlers, p)
|
||||
return h
|
||||
}
|
||||
func (h *heaven) AfterStart(p Process) Heaven {
|
||||
h.afterStopHandlers = append(h.afterStartHandlers, p)
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *heaven) BeforeStop(p Process) Heaven {
|
||||
h.beforeStopHandlers = append(h.beforeStopHandlers, p)
|
||||
return h
|
||||
}
|
||||
func (h *heaven) AfterStop(p Process) Heaven {
|
||||
h.afterStopHandlers = append(h.afterStopHandlers, p)
|
||||
return h
|
||||
}
|
71
interface.go
Normal file
71
interface.go
Normal file
@ -0,0 +1,71 @@
|
||||
package gone
|
||||
|
||||
import "reflect"
|
||||
|
||||
// Goner 逝者
|
||||
type Goner interface {
|
||||
gone()
|
||||
}
|
||||
|
||||
// GonerId 逝者ID
|
||||
type GonerId string
|
||||
|
||||
// Tomb 坟墓,逝者的容器
|
||||
type Tomb interface {
|
||||
SetId(GonerId) Tomb
|
||||
GetId() GonerId
|
||||
GetGoner() Goner
|
||||
}
|
||||
|
||||
// Cemetery 墓园
|
||||
type Cemetery interface {
|
||||
Bury(Goner, GonerId) Tomb // 埋葬,将逝者埋葬到墓园
|
||||
ReplaceBury(Goner, GonerId) Tomb // 替换
|
||||
|
||||
revive() error // 复活,对逝者进行复活,让他们升入天堂
|
||||
|
||||
GetTomById(GonerId) Tomb
|
||||
GetTomByType(reflect.Type) []Tomb
|
||||
}
|
||||
|
||||
type BuildError error
|
||||
type Builder interface {
|
||||
Build(conf string, pointer interface{}) BuildError
|
||||
}
|
||||
|
||||
type ReviveAfterError error
|
||||
type ReviveAfter interface {
|
||||
After(Cemetery, Tomb) ReviveAfterError
|
||||
}
|
||||
|
||||
// Goner Example
|
||||
// type jim struct {
|
||||
// DeadFlag
|
||||
//
|
||||
// XMan XMan `revive:"x-man"`
|
||||
// }
|
||||
//
|
||||
// type XMan struct {
|
||||
// DeadFlag
|
||||
// }
|
||||
|
||||
// Digger 掘墓
|
||||
type Digger func(Cemetery Cemetery) error
|
||||
|
||||
type Process func(Cemetery) error
|
||||
type Heaven interface {
|
||||
Start()
|
||||
Stop()
|
||||
|
||||
BeforeStart(Process) Heaven
|
||||
AfterStart(Process) Heaven
|
||||
|
||||
BeforeStop(Process) Heaven
|
||||
AfterStop(Process) Heaven
|
||||
}
|
||||
|
||||
type Angel interface {
|
||||
Goner
|
||||
Start(Cemetery) error
|
||||
Stop(Cemetery) error
|
||||
}
|
22
logger.go
Normal file
22
logger.go
Normal file
@ -0,0 +1,22 @@
|
||||
package gone
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Logger interface {
|
||||
Tracef(format string, args ...interface{})
|
||||
Warnf(format string, args ...interface{})
|
||||
Infof(format string, args ...interface{})
|
||||
}
|
||||
|
||||
type defaultLogger struct {
|
||||
}
|
||||
|
||||
func (*defaultLogger) Tracef(format string, args ...interface{}) {
|
||||
fmt.Printf(format, args...)
|
||||
}
|
||||
func (*defaultLogger) Warnf(format string, args ...interface{}) {
|
||||
fmt.Printf(format, args...)
|
||||
}
|
||||
func (*defaultLogger) Infof(format string, args ...interface{}) {
|
||||
fmt.Printf(format, args...)
|
||||
}
|
23
tomb.go
Normal file
23
tomb.go
Normal file
@ -0,0 +1,23 @@
|
||||
package gone
|
||||
|
||||
func NewTomb(goner Goner) Tomb {
|
||||
return &tomb{goner: goner}
|
||||
}
|
||||
|
||||
type tomb struct {
|
||||
id GonerId
|
||||
goner Goner
|
||||
}
|
||||
|
||||
func (t *tomb) SetId(id GonerId) Tomb {
|
||||
t.id = id
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *tomb) GetId() GonerId {
|
||||
return t.id
|
||||
}
|
||||
|
||||
func (t *tomb) GetGoner() Goner {
|
||||
return t.goner
|
||||
}
|
45
x_test.go
Normal file
45
x_test.go
Normal file
@ -0,0 +1,45 @@
|
||||
package gone_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gone-io/gone"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"reflect"
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func getStructPtrUnExportedField(source interface{}, fieldName string) reflect.Value {
|
||||
// 获取非导出字段反射对象
|
||||
v := reflect.ValueOf(source).Elem().FieldByName(fieldName)
|
||||
t, b := reflect.TypeOf(source).Elem().FieldByName(fieldName)
|
||||
if b {
|
||||
tag := t.Tag
|
||||
print(tag)
|
||||
}
|
||||
|
||||
// 构建指向该字段的可寻址(addressable)反射对象
|
||||
return reflect.NewAt(v.Type(), unsafe.Pointer(v.UnsafeAddr())).Elem()
|
||||
}
|
||||
|
||||
func setStructPtrUnExportedStrField(source interface{}, fieldName string, fieldVal interface{}) (err error) {
|
||||
v := getStructPtrUnExportedField(source, fieldName)
|
||||
rv := reflect.ValueOf(fieldVal)
|
||||
if v.Kind() != rv.Kind() {
|
||||
return fmt.Errorf("invalid kind: expected kind %v, got kind: %v", v.Kind(), rv.Kind())
|
||||
}
|
||||
// 修改非导出字段值
|
||||
v.Set(rv)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Test_SetPrivateProperty(t *testing.T) {
|
||||
var a = new(gone.A)
|
||||
var b = new(gone.B)
|
||||
|
||||
err := setStructPtrUnExportedStrField(a, "a", int(4))
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = setStructPtrUnExportedStrField(b, "a", *a)
|
||||
assert.Nil(t, err)
|
||||
}
|
Loading…
Reference in New Issue
Block a user