| @@ -16,20 +16,20 @@ func Test_JobSet(t *testing.T) { | |||
| id, err := cli.JobSetSumbit(JobSetSumbitReq{ | |||
| JobSetInfo: models.JobSetInfo{ | |||
| Jobs: []models.JobInfo{ | |||
| models.ResourceJobInfo{ | |||
| &models.ResourceJobInfo{ | |||
| Type: models.JobTypeResource, | |||
| }, | |||
| models.NormalJobInfo{ | |||
| &models.NormalJobInfo{ | |||
| Type: models.JobTypeNormal, | |||
| Files: models.JobFilesInfo{ | |||
| Dataset: models.PackageJobFileInfo{ | |||
| Dataset: &models.PackageJobFileInfo{ | |||
| Type: models.FileInfoTypePackage, | |||
| }, | |||
| Code: models.LocalJobFileInfo{ | |||
| Code: &models.LocalJobFileInfo{ | |||
| Type: models.FileInfoTypeLocalFile, | |||
| LocalPath: "code", | |||
| }, | |||
| Image: models.ImageJobFileInfo{ | |||
| Image: &models.ImageJobFileInfo{ | |||
| Type: models.FileInfoTypeImage, | |||
| }, | |||
| }, | |||
| @@ -20,7 +20,9 @@ type JobSetInfo struct { | |||
| Jobs []JobInfo `json:"jobs"` | |||
| } | |||
| type JobInfo interface{} | |||
| type JobInfo interface { | |||
| GetLocalJobID() string | |||
| } | |||
| var JobInfoTypeUnion = types.NewTypeUnion[JobInfo]( | |||
| myreflect.TypeOf[NormalJobInfo](), | |||
| @@ -28,16 +30,24 @@ var JobInfoTypeUnion = types.NewTypeUnion[JobInfo]( | |||
| ) | |||
| var JobInfoTaggedTypeUnion = serder.NewTaggedTypeUnion(JobInfoTypeUnion, "Type", "type") | |||
| type JobInfoBase struct { | |||
| LocalJobID string `json:"localJobID"` | |||
| } | |||
| func (i *JobInfoBase) GetLocalJobID() string { | |||
| return i.LocalJobID | |||
| } | |||
| type NormalJobInfo struct { | |||
| LocalJobID string `json:"localJobID"` | |||
| Type string `json:"type" union:"Normal"` | |||
| Files JobFilesInfo `json:"files"` | |||
| Runtime JobRuntimeInfo `json:"runtime"` | |||
| Resources JobResourcesInfo `json:"resources"` | |||
| JobInfoBase | |||
| Type string `json:"type" union:"Normal"` | |||
| Files JobFilesInfo `json:"files"` | |||
| Runtime JobRuntimeInfo `json:"runtime"` | |||
| Resources JobResourcesInfo `json:"resources"` | |||
| } | |||
| type ResourceJobInfo struct { | |||
| LocalJobID string `json:"localJobID"` | |||
| JobInfoBase | |||
| Type string `json:"type" union:"Resource"` | |||
| TargetLocalJobID string `json:"targetLocalJobID"` | |||
| } | |||
| @@ -48,7 +58,9 @@ type JobFilesInfo struct { | |||
| Image JobFileInfo `json:"image"` | |||
| } | |||
| type JobFileInfo interface{} | |||
| type JobFileInfo interface { | |||
| Noop() | |||
| } | |||
| var FileInfoTypeUnion = types.NewTypeUnion[JobFileInfo]( | |||
| myreflect.TypeOf[PackageJobFileInfo](), | |||
| @@ -58,22 +70,30 @@ var FileInfoTypeUnion = types.NewTypeUnion[JobFileInfo]( | |||
| ) | |||
| var FileInfoTaggedTypeUnion = serder.NewTaggedTypeUnion(FileInfoTypeUnion, "Type", "type") | |||
| type JobFileInfoBase struct{} | |||
| func (i *JobFileInfoBase) Noop() {} | |||
| type PackageJobFileInfo struct { | |||
| JobFileInfoBase | |||
| Type string `json:"type" union:"Package"` | |||
| PackageID int64 `json:"packageID"` | |||
| } | |||
| type LocalJobFileInfo struct { | |||
| JobFileInfoBase | |||
| Type string `json:"type" union:"LocalFile"` | |||
| LocalPath string `json:"localPath"` | |||
| } | |||
| type ResourceJobFileInfo struct { | |||
| JobFileInfoBase | |||
| Type string `json:"type" union:"Resource"` | |||
| ResourceLocalJobID string `json:"resourceLocalJobID"` | |||
| } | |||
| type ImageJobFileInfo struct { | |||
| JobFileInfoBase | |||
| Type string `json:"type" union:"Image"` | |||
| ImageID string `json:"imageID"` | |||
| } | |||
| @@ -16,16 +16,15 @@ const ( | |||
| ) | |||
| type SlwNode struct { | |||
| ID int64 `json:"ID"` | |||
| Name string `json:"name"` | |||
| SlwRegionID int64 `json:"slwRegionID"` | |||
| StgNodeID int64 `json:"stgNodeID"` | |||
| StorageID int64 `json:"StorageID"` | |||
| ID int64 `json:"ID"` | |||
| Name string `json:"name"` | |||
| SlwRegionID int64 `json:"slwRegionID"` | |||
| StgNodeID int64 `json:"stgNodeID"` | |||
| StorageID int64 `json:"StorageID"` | |||
| } | |||
| type ResourceData interface{} | |||
| type ResourceDataConst interface { | |||
| ResourceData | CPUResourceData | NPUResourceData | GPUResourceData | MLUResourceData | StorageResourceData | MemoryResourceData | |||
| type ResourceData interface { | |||
| Noop() | |||
| } | |||
| var ResourceDataTypeUnion = types.NewTypeUnion[ResourceData]( | |||
| @@ -38,19 +37,24 @@ var ResourceDataTypeUnion = types.NewTypeUnion[ResourceData]( | |||
| ) | |||
| var ResourceDataTaggedTypeUnion = serder.NewTaggedTypeUnion(ResourceDataTypeUnion, "Name", "name") | |||
| type ResourceDataBase struct{} | |||
| func (d *ResourceDataBase) Noop() {} | |||
| type DetailType[T any] struct { | |||
| Unit string `json:"unit"` | |||
| Value T `json:"value"` | |||
| } | |||
| type CPUResourceData struct { | |||
| ResourceDataBase | |||
| Name string `json:"name" union:"CPU"` | |||
| Total DetailType[int64] `json:"total"` | |||
| Available DetailType[int64] `json:"available"` | |||
| } | |||
| func NewCPUResourceData(name string, total DetailType[int64], available DetailType[int64]) CPUResourceData { | |||
| return CPUResourceData{ | |||
| func NewCPUResourceData(name string, total DetailType[int64], available DetailType[int64]) *CPUResourceData { | |||
| return &CPUResourceData{ | |||
| Name: name, | |||
| Total: total, | |||
| Available: available, | |||
| @@ -58,13 +62,14 @@ func NewCPUResourceData(name string, total DetailType[int64], available DetailTy | |||
| } | |||
| type NPUResourceData struct { | |||
| ResourceDataBase | |||
| Name string `json:"name" union:"NPU"` | |||
| Total DetailType[int64] `json:"total"` | |||
| Available DetailType[int64] `json:"available"` | |||
| } | |||
| func NewNPUResourceData(name string, total DetailType[int64], available DetailType[int64]) NPUResourceData { | |||
| return NPUResourceData{ | |||
| func NewNPUResourceData(name string, total DetailType[int64], available DetailType[int64]) *NPUResourceData { | |||
| return &NPUResourceData{ | |||
| Name: name, | |||
| Total: total, | |||
| Available: available, | |||
| @@ -72,13 +77,14 @@ func NewNPUResourceData(name string, total DetailType[int64], available DetailTy | |||
| } | |||
| type GPUResourceData struct { | |||
| ResourceDataBase | |||
| Name string `json:"name" union:"GPU"` | |||
| Total DetailType[int64] `json:"total"` | |||
| Available DetailType[int64] `json:"available"` | |||
| } | |||
| func NewGPUResourceData(name string, total DetailType[int64], available DetailType[int64]) GPUResourceData { | |||
| return GPUResourceData{ | |||
| func NewGPUResourceData(name string, total DetailType[int64], available DetailType[int64]) *GPUResourceData { | |||
| return &GPUResourceData{ | |||
| Name: name, | |||
| Total: total, | |||
| Available: available, | |||
| @@ -86,13 +92,14 @@ func NewGPUResourceData(name string, total DetailType[int64], available DetailTy | |||
| } | |||
| type MLUResourceData struct { | |||
| ResourceDataBase | |||
| Name string `json:"name" union:"MLU"` | |||
| Total DetailType[int64] `json:"total"` | |||
| Available DetailType[int64] `json:"available"` | |||
| } | |||
| func NewMLUResourceData(name string, total DetailType[int64], available DetailType[int64]) MLUResourceData { | |||
| return MLUResourceData{ | |||
| func NewMLUResourceData(name string, total DetailType[int64], available DetailType[int64]) *MLUResourceData { | |||
| return &MLUResourceData{ | |||
| Name: name, | |||
| Total: total, | |||
| Available: available, | |||
| @@ -100,13 +107,14 @@ func NewMLUResourceData(name string, total DetailType[int64], available DetailTy | |||
| } | |||
| type StorageResourceData struct { | |||
| ResourceDataBase | |||
| Name string `json:"name" union:"STORAGE"` | |||
| Total DetailType[float64] `json:"total"` | |||
| Available DetailType[float64] `json:"available"` | |||
| } | |||
| func NewStorageResourceData(name string, total DetailType[float64], available DetailType[float64]) StorageResourceData { | |||
| return StorageResourceData{ | |||
| func NewStorageResourceData(name string, total DetailType[float64], available DetailType[float64]) *StorageResourceData { | |||
| return &StorageResourceData{ | |||
| Name: name, | |||
| Total: total, | |||
| Available: available, | |||
| @@ -114,13 +122,14 @@ func NewStorageResourceData(name string, total DetailType[float64], available De | |||
| } | |||
| type MemoryResourceData struct { | |||
| ResourceDataBase | |||
| Name string `json:"name" union:"MEMORY"` | |||
| Total DetailType[float64] `json:"total"` | |||
| Available DetailType[float64] `json:"available"` | |||
| } | |||
| func NewMemoryResourceData(name string, total DetailType[float64], available DetailType[float64]) MemoryResourceData { | |||
| return MemoryResourceData{ | |||
| func NewMemoryResourceData(name string, total DetailType[float64], available DetailType[float64]) *MemoryResourceData { | |||
| return &MemoryResourceData{ | |||
| Name: name, | |||
| Total: total, | |||
| Available: available, | |||
| @@ -20,16 +20,16 @@ const ( | |||
| type MessageBody interface { | |||
| // 此方法无任何作用,仅用于避免MessageBody是一个空interface,从而导致任何类型的值都可以赋值给它 | |||
| // 与下方的MessageBodyBase配合使用: | |||
| // IsMessageBody只让实现了此接口的类型能赋值给它,内嵌MessageBodyBase让类型必须是个指针类型, | |||
| // Noop只让实现了此接口的类型能赋值给它,内嵌MessageBodyBase让类型必须是个指针类型, | |||
| // 这就确保了Message.Body必是某个类型的指针类型,避免序列化、反序列化过程出错 | |||
| IsMessageBody() | |||
| Noop() | |||
| } | |||
| // 这个结构体无任何字段,但实现了IsMessageBody,每种MessageBody都要内嵌这个结构体 | |||
| // 这个结构体无任何字段,但实现了Noop,每种MessageBody都要内嵌这个结构体 | |||
| type MessageBodyBase struct{} | |||
| // 此处的receiver是指针 | |||
| func (b *MessageBodyBase) IsMessageBody() {} | |||
| func (b *MessageBodyBase) Noop() {} | |||
| type Message struct { | |||
| Type string `json:"type"` | |||
| @@ -4,8 +4,11 @@ import ( | |||
| myreflect "gitlink.org.cn/cloudream/common/utils/reflect" | |||
| ) | |||
| // 描述一个类型集合 | |||
| type TypeUnion struct { | |||
| UnionType myreflect.Type | |||
| // 这个集合的类型 | |||
| UnionType myreflect.Type | |||
| // 集合中包含的类型,即遇到UnionType类型的值时,它内部的实际类型的范围 | |||
| ElementTypes []myreflect.Type | |||
| } | |||
| @@ -108,7 +108,8 @@ func MapToObject(m map[string]any, obj any, opt ...MapToObjectOption) error { | |||
| convs := []Converter{ | |||
| func(from reflect.Value, to reflect.Value) (interface{}, error) { | |||
| info, ok := unionTypeMapping[to.Type()] | |||
| toType := to.Type() | |||
| info, ok := unionTypeMapping[toType] | |||
| if !ok { | |||
| return from.Interface(), nil | |||
| } | |||
| @@ -116,20 +117,20 @@ func MapToObject(m map[string]any, obj any, opt ...MapToObjectOption) error { | |||
| mp := from.Interface().(map[string]any) | |||
| tag, ok := mp[info.JSONTagField] | |||
| if !ok { | |||
| return nil, fmt.Errorf("converting to %v: no tag field %s in map", to.Type(), info.JSONTagField) | |||
| return nil, fmt.Errorf("converting to %v: no tag field %s in map", toType, info.JSONTagField) | |||
| } | |||
| tagStr, ok := tag.(string) | |||
| if !ok { | |||
| return nil, fmt.Errorf("converting to %v: tag field %s value is %v, which is not a string", to.Type(), info.JSONTagField, tag) | |||
| return nil, fmt.Errorf("converting to %v: tag field %s value is %v, which is not a string", toType, info.JSONTagField, tag) | |||
| } | |||
| eleType, ok := info.TagToType[tagStr] | |||
| if !ok { | |||
| return nil, fmt.Errorf("converting to %v: unknow type tag %s", to.Type(), tagStr) | |||
| return nil, fmt.Errorf("converting to %v: unknow type tag %s", toType, tagStr) | |||
| } | |||
| to.Set(reflect.Indirect(reflect.New(eleType))) | |||
| to.Set(reflect.New(eleType)) | |||
| return from.Interface(), nil | |||
| }, | |||
| @@ -404,8 +404,8 @@ func Test_MapToObject(t *testing.T) { | |||
| So(err, ShouldBeNil) | |||
| So(ret.Us, ShouldResemble, []UnionType{ | |||
| EleType1{Type: "1", Value1: "1"}, | |||
| EleType2{Type: "2", Value2: 2}, | |||
| &EleType1{Type: "1", Value1: "1"}, | |||
| &EleType2{Type: "2", Value2: 2}, | |||
| }) | |||
| }) | |||
| @@ -442,6 +442,6 @@ func Test_MapToObject(t *testing.T) { | |||
| So(err, ShouldBeNil) | |||
| So(ret, ShouldResemble, EleType1{Type: "1", Value1: "1"}) | |||
| So(ret, ShouldResemble, &EleType1{Type: "1", Value1: "1"}) | |||
| }) | |||
| } | |||