feat: 完成基本设计

This commit is contained in:
大鹏 2022-10-16 23:02:09 +08:00
parent 287d5abd89
commit 0d643686d8
16 changed files with 581 additions and 1 deletions

8
.idea/.gitignore generated vendored Normal file
View 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
View 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
View 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
View 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>

View File

@ -1 +1,6 @@
# gone
# gone
## 概念
> 这是一个上天堂的故事
> 逝者被埋葬后,在天堂永生

146
cemetery.go Normal file
View 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
View 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
View File

@ -0,0 +1,6 @@
package gone
type DeadFlag struct {
}
func (*DeadFlag) gone() {}

31
error.go Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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)
}