| @@ -0,0 +1,95 @@ | |||||
| package main | |||||
| import ( | |||||
| "fmt" | |||||
| "io" | |||||
| "os" | |||||
| "strconv" | |||||
| "time" | |||||
| cdssdk "gitlink.org.cn/cloudream/common/sdks/storage" | |||||
| ) | |||||
| func main() { | |||||
| test1("http://121.36.5.116:32010") | |||||
| // test2("http://127.0.0.1:7890") | |||||
| } | |||||
| func test1(url string) { | |||||
| cli := cdssdk.NewClient(&cdssdk.Config{ | |||||
| URL: url, | |||||
| }) | |||||
| openLen, err := strconv.ParseInt(os.Args[1], 10, 64) | |||||
| if err != nil { | |||||
| fmt.Println(err) | |||||
| return | |||||
| } | |||||
| readLen, err := strconv.ParseInt(os.Args[2], 10, 64) | |||||
| if err != nil { | |||||
| fmt.Println(err) | |||||
| return | |||||
| } | |||||
| partLen, err := strconv.ParseInt(os.Args[3], 10, 64) | |||||
| if err != nil { | |||||
| fmt.Println(err) | |||||
| return | |||||
| } | |||||
| startTime := time.Now() | |||||
| obj, err := cli.Object().Download(cdssdk.ObjectDownload{ | |||||
| UserID: 1, | |||||
| ObjectID: 470790, | |||||
| Offset: 0, | |||||
| Length: &openLen, | |||||
| PartSize: partLen, | |||||
| }) | |||||
| if err != nil { | |||||
| fmt.Println(err) | |||||
| return | |||||
| } | |||||
| fmt.Printf("Open time: %v\n", time.Since(startTime)) | |||||
| startTime = time.Now() | |||||
| buf := make([]byte, readLen) | |||||
| _, err = io.ReadFull(obj.File, buf) | |||||
| fmt.Printf("Read time: %v\n", time.Since(startTime)) | |||||
| if err != nil { | |||||
| fmt.Println(err) | |||||
| return | |||||
| } | |||||
| startTime = time.Now() | |||||
| obj.File.Close() | |||||
| fmt.Printf("Close time: %v\n", time.Since(startTime)) | |||||
| } | |||||
| func test2(url string) { | |||||
| cli := cdssdk.NewClient(&cdssdk.Config{ | |||||
| URL: url, | |||||
| }) | |||||
| obj, err := cli.Object().Download(cdssdk.ObjectDownload{ | |||||
| UserID: 1, | |||||
| ObjectID: 27151, | |||||
| Offset: 0, | |||||
| PartSize: 100000000, | |||||
| // Length: &openLen, | |||||
| }) | |||||
| if err != nil { | |||||
| fmt.Println(err) | |||||
| return | |||||
| } | |||||
| f, err := os.Create("test.txt") | |||||
| if err != nil { | |||||
| fmt.Println(err) | |||||
| return | |||||
| } | |||||
| io.Copy(f, obj.File) | |||||
| } | |||||
| @@ -126,7 +126,7 @@ func WaitValue[T any](ctx context.Context, c *CommandChannel, cmd func() (T, err | |||||
| fut.SetComplete(val, err) | fut.SetComplete(val, err) | ||||
| }) | }) | ||||
| return fut.WaitValue(ctx) | |||||
| return fut.Wait(ctx) | |||||
| } | } | ||||
| func WaitValue2[T1 any, T2 any](ctx context.Context, c *CommandChannel, cmd func() (T1, T2, error)) (T1, T2, error) { | func WaitValue2[T1 any, T2 any](ctx context.Context, c *CommandChannel, cmd func() (T1, T2, error)) (T1, T2, error) { | ||||
| @@ -137,5 +137,5 @@ func WaitValue2[T1 any, T2 any](ctx context.Context, c *CommandChannel, cmd func | |||||
| fut.SetComplete(val1, val2, err) | fut.SetComplete(val1, val2, err) | ||||
| }) | }) | ||||
| return fut.WaitValue(ctx) | |||||
| return fut.Wait(ctx) | |||||
| } | } | ||||
| @@ -0,0 +1,89 @@ | |||||
| package async | |||||
| import ( | |||||
| "container/list" | |||||
| "errors" | |||||
| "gitlink.org.cn/cloudream/common/pkgs/future" | |||||
| "sync" | |||||
| ) | |||||
| var ErrChannelClosed = errors.New("channel is closed") | |||||
| type UnboundChannel[T any] struct { | |||||
| values *list.List | |||||
| waiters []*future.SetValueFuture[T] | |||||
| lock sync.Mutex | |||||
| err error | |||||
| } | |||||
| func NewUnboundChannel[T any]() *UnboundChannel[T] { | |||||
| return &UnboundChannel[T]{ | |||||
| values: list.New(), | |||||
| } | |||||
| } | |||||
| func (c *UnboundChannel[T]) Error() error { | |||||
| return c.err | |||||
| } | |||||
| func (c *UnboundChannel[T]) Send(val T) error { | |||||
| c.lock.Lock() | |||||
| defer c.lock.Unlock() | |||||
| if c.err != nil { | |||||
| return c.err | |||||
| } | |||||
| c.values.PushBack(val) | |||||
| for len(c.waiters) > 0 && c.values.Len() > 0 { | |||||
| waiter := c.waiters[0] | |||||
| waiter.SetValue(c.values.Front().Value.(T)) | |||||
| c.values.Remove(c.values.Front()) | |||||
| c.waiters = c.waiters[1:] | |||||
| return nil | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func (c *UnboundChannel[T]) Receive() future.Future1[T] { | |||||
| c.lock.Lock() | |||||
| defer c.lock.Unlock() | |||||
| if c.err != nil { | |||||
| return future.NewReadyError1[T](c.err) | |||||
| } | |||||
| if c.values.Len() > 0 { | |||||
| ret := c.values.Front().Value.(T) | |||||
| c.values.Remove(c.values.Front()) | |||||
| return future.NewReadyValue1[T](ret) | |||||
| } | |||||
| fut := future.NewSetValue[T]() | |||||
| c.waiters = append(c.waiters, fut) | |||||
| return fut | |||||
| } | |||||
| func (c *UnboundChannel[T]) Close() { | |||||
| c.CloseWithError(ErrChannelClosed) | |||||
| } | |||||
| func (c *UnboundChannel[T]) CloseWithError(err error) { | |||||
| c.lock.Lock() | |||||
| defer c.lock.Unlock() | |||||
| if c.err != nil { | |||||
| return | |||||
| } | |||||
| c.err = err | |||||
| for i := 0; i < len(c.waiters); i++ { | |||||
| c.waiters[i].SetError(c.err) | |||||
| } | |||||
| c.waiters = nil | |||||
| c.values = nil | |||||
| } | |||||
| @@ -93,7 +93,7 @@ func (a *AcquireActor) Acquire(ctx context.Context, req LockRequest) (string, er | |||||
| }() | }() | ||||
| // 此处不能直接用ctx去等Callback,原因是Wait超时不代表锁没有获取到,这会导致锁泄露。 | // 此处不能直接用ctx去等Callback,原因是Wait超时不代表锁没有获取到,这会导致锁泄露。 | ||||
| return info.Callback.WaitValue(context.Background()) | |||||
| return info.Callback.Wait(context.Background()) | |||||
| } | } | ||||
| // TryAcquireNow 重试一下内部还没有成功的锁请求。不会阻塞调用者 | // TryAcquireNow 重试一下内部还没有成功的锁请求。不会阻塞调用者 | ||||
| @@ -6,18 +6,31 @@ import ( | |||||
| ) | ) | ||||
| var ErrContextCancelled = fmt.Errorf("context cancelled") | var ErrContextCancelled = fmt.Errorf("context cancelled") | ||||
| var ErrCompleted = fmt.Errorf("context cancelled") | |||||
| type Future interface { | type Future interface { | ||||
| Error() error | |||||
| IsComplete() bool | IsComplete() bool | ||||
| Chan() <-chan error | |||||
| Wait(ctx context.Context) error | Wait(ctx context.Context) error | ||||
| } | } | ||||
| type ValueFuture[T any] interface { | |||||
| Future | |||||
| type ChanValue1[T any] struct { | |||||
| Value T | |||||
| Err error | |||||
| } | |||||
| type ChanValue2[T1 any, T2 any] struct { | |||||
| Value1 T1 | |||||
| Value2 T2 | |||||
| Err error | |||||
| } | |||||
| type Future1[T any] interface { | |||||
| IsComplete() bool | |||||
| Value() T | |||||
| Chan() <-chan ChanValue1[T] | |||||
| WaitValue(ctx context.Context) (T, error) | |||||
| Wait(ctx context.Context) (T, error) | |||||
| } | } | ||||
| @@ -0,0 +1,87 @@ | |||||
| package future | |||||
| import "context" | |||||
| type Ready struct { | |||||
| ch chan error | |||||
| } | |||||
| func NewReady(err error) *Ready { | |||||
| ch := make(chan error, 1) | |||||
| ch <- err | |||||
| close(ch) | |||||
| return &Ready{ | |||||
| ch: ch, | |||||
| } | |||||
| } | |||||
| func (f *Ready) IsComplete() bool { | |||||
| return true | |||||
| } | |||||
| func (f *Ready) Wait(ctx context.Context) error { | |||||
| select { | |||||
| case v, ok := <-f.ch: | |||||
| if !ok { | |||||
| return ErrCompleted | |||||
| } | |||||
| return v | |||||
| case <-ctx.Done(): | |||||
| return ErrContextCancelled | |||||
| } | |||||
| } | |||||
| func (f *Ready) Chan() <-chan error { | |||||
| return f.ch | |||||
| } | |||||
| type Ready1[T any] struct { | |||||
| ch chan ChanValue1[T] | |||||
| } | |||||
| func NewReady1[T any](val T, err error) *Ready1[T] { | |||||
| ch := make(chan ChanValue1[T], 1) | |||||
| ch <- ChanValue1[T]{ | |||||
| Err: err, | |||||
| Value: val, | |||||
| } | |||||
| close(ch) | |||||
| return &Ready1[T]{ | |||||
| ch: ch, | |||||
| } | |||||
| } | |||||
| func NewReadyValue1[T any](val T) *Ready1[T] { | |||||
| return NewReady1[T](val, nil) | |||||
| } | |||||
| func NewReadyError1[T any](err error) *Ready1[T] { | |||||
| var ret T | |||||
| return NewReady1[T](ret, err) | |||||
| } | |||||
| func (f *Ready1[T]) IsComplete() bool { | |||||
| return true | |||||
| } | |||||
| func (f *Ready1[T]) Wait(ctx context.Context) (T, error) { | |||||
| select { | |||||
| case cv, ok := <-f.ch: | |||||
| if !ok { | |||||
| var ret T | |||||
| return ret, cv.Err | |||||
| } | |||||
| return cv.Value, cv.Err | |||||
| case <-ctx.Done(): | |||||
| var ret T | |||||
| return ret, ErrContextCancelled | |||||
| } | |||||
| } | |||||
| func (f *Ready1[T]) Chan() <-chan ChanValue1[T] { | |||||
| return f.ch | |||||
| } | |||||
| @@ -6,72 +6,76 @@ import ( | |||||
| ) | ) | ||||
| type SetValueFuture[T any] struct { | type SetValueFuture[T any] struct { | ||||
| value T | |||||
| err error | |||||
| isCompleted bool | isCompleted bool | ||||
| completeChan chan any | |||||
| ch chan ChanValue1[T] | |||||
| completeOnce sync.Once | completeOnce sync.Once | ||||
| } | } | ||||
| func NewSetValue[T any]() *SetValueFuture[T] { | func NewSetValue[T any]() *SetValueFuture[T] { | ||||
| return &SetValueFuture[T]{ | return &SetValueFuture[T]{ | ||||
| completeChan: make(chan any), | |||||
| ch: make(chan ChanValue1[T], 1), | |||||
| } | } | ||||
| } | } | ||||
| func (f *SetValueFuture[T]) SetComplete(val T, err error) { | func (f *SetValueFuture[T]) SetComplete(val T, err error) { | ||||
| f.completeOnce.Do(func() { | f.completeOnce.Do(func() { | ||||
| f.value = val | |||||
| f.err = err | |||||
| f.ch <- ChanValue1[T]{ | |||||
| Err: err, | |||||
| Value: val, | |||||
| } | |||||
| close(f.ch) | |||||
| f.isCompleted = true | f.isCompleted = true | ||||
| close(f.completeChan) | |||||
| }) | }) | ||||
| } | } | ||||
| func (f *SetValueFuture[T]) SetValue(val T) { | func (f *SetValueFuture[T]) SetValue(val T) { | ||||
| f.completeOnce.Do(func() { | f.completeOnce.Do(func() { | ||||
| f.value = val | |||||
| f.ch <- ChanValue1[T]{ | |||||
| Value: val, | |||||
| } | |||||
| close(f.ch) | |||||
| f.isCompleted = true | f.isCompleted = true | ||||
| close(f.completeChan) | |||||
| }) | }) | ||||
| } | } | ||||
| func (f *SetValueFuture[T]) SetError(err error) { | func (f *SetValueFuture[T]) SetError(err error) { | ||||
| f.completeOnce.Do(func() { | f.completeOnce.Do(func() { | ||||
| f.err = err | |||||
| f.ch <- ChanValue1[T]{ | |||||
| Err: err, | |||||
| } | |||||
| close(f.ch) | |||||
| f.isCompleted = true | f.isCompleted = true | ||||
| close(f.completeChan) | |||||
| }) | }) | ||||
| } | } | ||||
| func (f *SetValueFuture[T]) Error() error { | |||||
| return f.err | |||||
| } | |||||
| func (f *SetValueFuture[T]) Value() T { | |||||
| return f.value | |||||
| } | |||||
| func (f *SetValueFuture[T]) IsComplete() bool { | func (f *SetValueFuture[T]) IsComplete() bool { | ||||
| return f.isCompleted | return f.isCompleted | ||||
| } | } | ||||
| // 等待直到Complete或者ctx被取消。 | |||||
| // 注:返回ErrContextCancelled不代表产生结果的过程没有执行过,甚至不代表Future没有Complete | |||||
| func (f *SetValueFuture[T]) Wait(ctx context.Context) error { | |||||
| select { | |||||
| case <-f.completeChan: | |||||
| return f.err | |||||
| case <-ctx.Done(): | |||||
| return ErrContextCancelled | |||||
| } | |||||
| func (f *SetValueFuture[T]) Chan() <-chan ChanValue1[T] { | |||||
| return f.ch | |||||
| } | } | ||||
| func (f *SetValueFuture[T]) WaitValue(ctx context.Context) (T, error) { | |||||
| // 等待直到Complete或者ctx被取消。 | |||||
| // 注:返回ErrContextCancelled不代表产生结果的过程没有执行过,甚至不代表Future没有Complete | |||||
| //func (f *SetValueFuture[T]) Wait(ctx context.Context) error { | |||||
| // select { | |||||
| // case <-f.ch: | |||||
| // return f.err | |||||
| // | |||||
| // case <-ctx.Done(): | |||||
| // return ErrContextCancelled | |||||
| // } | |||||
| //} | |||||
| func (f *SetValueFuture[T]) Wait(ctx context.Context) (T, error) { | |||||
| select { | select { | ||||
| case <-f.completeChan: | |||||
| return f.value, f.err | |||||
| case cv, ok := <-f.ch: | |||||
| if !ok { | |||||
| var ret T | |||||
| return ret, cv.Err | |||||
| } | |||||
| return cv.Value, cv.Err | |||||
| case <-ctx.Done(): | case <-ctx.Done(): | ||||
| var ret T | var ret T | ||||
| @@ -80,68 +84,61 @@ func (f *SetValueFuture[T]) WaitValue(ctx context.Context) (T, error) { | |||||
| } | } | ||||
| type SetValueFuture2[T1 any, T2 any] struct { | type SetValueFuture2[T1 any, T2 any] struct { | ||||
| value1 T1 | |||||
| value2 T2 | |||||
| err error | |||||
| isCompleted bool | isCompleted bool | ||||
| completeChan chan any | |||||
| ch chan ChanValue2[T1, T2] | |||||
| completeOnce sync.Once | completeOnce sync.Once | ||||
| } | } | ||||
| func NewSetValue2[T1 any, T2 any]() *SetValueFuture2[T1, T2] { | func NewSetValue2[T1 any, T2 any]() *SetValueFuture2[T1, T2] { | ||||
| return &SetValueFuture2[T1, T2]{ | return &SetValueFuture2[T1, T2]{ | ||||
| completeChan: make(chan any), | |||||
| ch: make(chan ChanValue2[T1, T2], 1), | |||||
| } | } | ||||
| } | } | ||||
| func (f *SetValueFuture2[T1, T2]) SetComplete(val1 T1, val2 T2, err error) { | func (f *SetValueFuture2[T1, T2]) SetComplete(val1 T1, val2 T2, err error) { | ||||
| f.completeOnce.Do(func() { | f.completeOnce.Do(func() { | ||||
| f.value1 = val1 | |||||
| f.value2 = val2 | |||||
| f.err = err | |||||
| f.ch <- ChanValue2[T1, T2]{ | |||||
| Value1: val1, | |||||
| Value2: val2, | |||||
| Err: err, | |||||
| } | |||||
| close(f.ch) | |||||
| f.isCompleted = true | f.isCompleted = true | ||||
| close(f.completeChan) | |||||
| }) | }) | ||||
| } | } | ||||
| func (f *SetValueFuture2[T1, T2]) SetValue(val1 T1, val2 T2) { | func (f *SetValueFuture2[T1, T2]) SetValue(val1 T1, val2 T2) { | ||||
| f.completeOnce.Do(func() { | f.completeOnce.Do(func() { | ||||
| f.value1 = val1 | |||||
| f.value2 = val2 | |||||
| f.ch <- ChanValue2[T1, T2]{ | |||||
| Value1: val1, | |||||
| Value2: val2, | |||||
| } | |||||
| close(f.ch) | |||||
| f.isCompleted = true | f.isCompleted = true | ||||
| close(f.completeChan) | |||||
| }) | }) | ||||
| } | } | ||||
| func (f *SetValueFuture2[T1, T2]) SetError(err error) { | func (f *SetValueFuture2[T1, T2]) SetError(err error) { | ||||
| f.completeOnce.Do(func() { | f.completeOnce.Do(func() { | ||||
| f.err = err | |||||
| f.ch <- ChanValue2[T1, T2]{ | |||||
| Err: err, | |||||
| } | |||||
| close(f.ch) | |||||
| f.isCompleted = true | f.isCompleted = true | ||||
| close(f.completeChan) | |||||
| }) | }) | ||||
| } | } | ||||
| func (f *SetValueFuture2[T1, T2]) Error() error { | |||||
| return f.err | |||||
| } | |||||
| func (f *SetValueFuture2[T1, T2]) Value() (T1, T2) { | |||||
| return f.value1, f.value2 | |||||
| } | |||||
| func (f *SetValueFuture2[T1, T2]) IsComplete() bool { | func (f *SetValueFuture2[T1, T2]) IsComplete() bool { | ||||
| return f.isCompleted | return f.isCompleted | ||||
| } | } | ||||
| func (f *SetValueFuture2[T1, T2]) Wait() error { | |||||
| <-f.completeChan | |||||
| return f.err | |||||
| } | |||||
| func (f *SetValueFuture2[T1, T2]) WaitValue(ctx context.Context) (T1, T2, error) { | |||||
| func (f *SetValueFuture2[T1, T2]) Wait(ctx context.Context) (T1, T2, error) { | |||||
| select { | select { | ||||
| case <-f.completeChan: | |||||
| return f.value1, f.value2, f.err | |||||
| case cv, ok := <-f.ch: | |||||
| if !ok { | |||||
| return cv.Value1, cv.Value2, cv.Err | |||||
| } | |||||
| return cv.Value1, cv.Value2, cv.Err | |||||
| case <-ctx.Done(): | case <-ctx.Done(): | ||||
| var ret1 T1 | var ret1 T1 | ||||
| @@ -149,3 +146,7 @@ func (f *SetValueFuture2[T1, T2]) WaitValue(ctx context.Context) (T1, T2, error) | |||||
| return ret1, ret2, ErrContextCancelled | return ret1, ret2, ErrContextCancelled | ||||
| } | } | ||||
| } | } | ||||
| func (f *SetValueFuture2[T1, T2]) Chan() <-chan ChanValue2[T1, T2] { | |||||
| return f.ch | |||||
| } | |||||
| @@ -6,47 +6,50 @@ import ( | |||||
| ) | ) | ||||
| type SetVoidFuture struct { | type SetVoidFuture struct { | ||||
| err error | |||||
| isCompleted bool | isCompleted bool | ||||
| completeChan chan any | |||||
| ch chan error | |||||
| completeOnce sync.Once | completeOnce sync.Once | ||||
| } | } | ||||
| func NewSetVoid() *SetVoidFuture { | func NewSetVoid() *SetVoidFuture { | ||||
| return &SetVoidFuture{ | return &SetVoidFuture{ | ||||
| completeChan: make(chan any), | |||||
| ch: make(chan error, 1), | |||||
| } | } | ||||
| } | } | ||||
| func (f *SetVoidFuture) SetVoid() { | func (f *SetVoidFuture) SetVoid() { | ||||
| f.completeOnce.Do(func() { | f.completeOnce.Do(func() { | ||||
| f.ch <- nil | |||||
| close(f.ch) | |||||
| f.isCompleted = true | f.isCompleted = true | ||||
| close(f.completeChan) | |||||
| }) | }) | ||||
| } | } | ||||
| func (f *SetVoidFuture) SetError(err error) { | func (f *SetVoidFuture) SetError(err error) { | ||||
| f.completeOnce.Do(func() { | f.completeOnce.Do(func() { | ||||
| f.err = err | |||||
| f.ch <- err | |||||
| close(f.ch) | |||||
| f.isCompleted = true | f.isCompleted = true | ||||
| close(f.completeChan) | |||||
| }) | }) | ||||
| } | } | ||||
| func (f *SetVoidFuture) Error() error { | |||||
| return f.err | |||||
| } | |||||
| func (f *SetVoidFuture) IsComplete() bool { | func (f *SetVoidFuture) IsComplete() bool { | ||||
| return f.isCompleted | return f.isCompleted | ||||
| } | } | ||||
| func (f *SetVoidFuture) Wait(ctx context.Context) error { | func (f *SetVoidFuture) Wait(ctx context.Context) error { | ||||
| select { | select { | ||||
| case <-f.completeChan: | |||||
| return f.err | |||||
| case v, ok := <-f.ch: | |||||
| if !ok { | |||||
| return ErrCompleted | |||||
| } | |||||
| return v | |||||
| case <-ctx.Done(): | case <-ctx.Done(): | ||||
| return ErrContextCancelled | return ErrContextCancelled | ||||
| } | } | ||||
| } | } | ||||
| func (f *SetVoidFuture) Chan() <-chan error { | |||||
| return f.ch | |||||
| } | |||||
| @@ -2,6 +2,7 @@ package mq | |||||
| import ( | import ( | ||||
| "fmt" | "fmt" | ||||
| "net" | |||||
| "sync" | "sync" | ||||
| "time" | "time" | ||||
| @@ -70,7 +71,14 @@ type RabbitMQTransport struct { | |||||
| } | } | ||||
| func NewRabbitMQTransport(url string, key string, exchange string) (*RabbitMQTransport, error) { | func NewRabbitMQTransport(url string, key string, exchange string) (*RabbitMQTransport, error) { | ||||
| connection, err := amqp.Dial(url) | |||||
| config := amqp.Config{ | |||||
| Dial: func(network, addr string) (net.Conn, error) { | |||||
| return net.DialTimeout(network, addr, 60*time.Second) // 设置连接超时时间为 60 秒 | |||||
| }, | |||||
| } | |||||
| connection, err := amqp.DialConfig(url, config) | |||||
| //connection, err := amqp.Dial(url) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, fmt.Errorf("connecting to %s: %w", url, err) | return nil, fmt.Errorf("connecting to %s: %w", url, err) | ||||
| } | } | ||||
| @@ -2,6 +2,7 @@ package mq | |||||
| import ( | import ( | ||||
| "fmt" | "fmt" | ||||
| "net" | |||||
| "time" | "time" | ||||
| "github.com/streadway/amqp" | "github.com/streadway/amqp" | ||||
| @@ -77,7 +78,14 @@ type RabbitMQServer struct { | |||||
| } | } | ||||
| func NewRabbitMQServer(url string, queueName string, onMessage MessageHandlerFn) (*RabbitMQServer, error) { | func NewRabbitMQServer(url string, queueName string, onMessage MessageHandlerFn) (*RabbitMQServer, error) { | ||||
| connection, err := amqp.Dial(url) | |||||
| config := amqp.Config{ | |||||
| Dial: func(network, addr string) (net.Conn, error) { | |||||
| return net.DialTimeout(network, addr, 60*time.Second) // 设置连接超时时间为 60 秒 | |||||
| }, | |||||
| } | |||||
| connection, err := amqp.DialConfig(url, config) | |||||
| //connection, err := amqp.Dial(url) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, fmt.Errorf("connecting to %s: %w", url, err) | return nil, fmt.Errorf("connecting to %s: %w", url, err) | ||||
| } | } | ||||
| @@ -0,0 +1,197 @@ | |||||
| package schsdk | |||||
| import ( | |||||
| "fmt" | |||||
| "gitlink.org.cn/cloudream/common/consts/errorcode" | |||||
| "gitlink.org.cn/cloudream/common/pkgs/mq" | |||||
| myhttp "gitlink.org.cn/cloudream/common/utils/http" | |||||
| "gitlink.org.cn/cloudream/common/utils/serder" | |||||
| "net/url" | |||||
| "strings" | |||||
| ) | |||||
| // 这个结构体无任何字段,但实现了Noop,每种MessageBody都要内嵌这个结构体 | |||||
| type MessageBodyBase struct{} | |||||
| // 此处的receiver是指针 | |||||
| func (b *MessageBodyBase) Noop() {} | |||||
| type RunningModelResp struct { | |||||
| MessageBodyBase | |||||
| RunningModels map[string]RunningModelInfo `json:"allNode"` | |||||
| } | |||||
| type AllModelResp struct { | |||||
| MessageBodyBase | |||||
| AllModels []Models `json:"allModels"` | |||||
| } | |||||
| type Models struct { | |||||
| ModelID ModelID `json:"modelID"` | |||||
| ModelName ModelName `json:"modelName"` | |||||
| } | |||||
| type NodeInfo struct { | |||||
| MessageBodyBase | |||||
| InstanceID JobID `json:"instanceID"` | |||||
| //NodeID NodeID `json:"nodeID"` | |||||
| Address Address `json:"address"` | |||||
| Status string `json:"status"` | |||||
| } | |||||
| type RunningModelInfo struct { | |||||
| MessageBodyBase | |||||
| JobSetID JobSetID `json:"jobSetID"` | |||||
| ModelID ModelID `json:"modelID"` | |||||
| ModelName ModelName `json:"modelName"` | |||||
| CustomModelName ModelName `json:"customModelName"` | |||||
| Nodes []NodeInfo `json:"nodes"` | |||||
| } | |||||
| type ECSNodeRunningInfoReq struct { | |||||
| mq.MessageBodyBase | |||||
| CustomModelName ModelName `form:"customModelName" json:"customModelName" binding:"required"` | |||||
| ModelID ModelID `form:"modelID" json:"modelID" binding:"required"` | |||||
| } | |||||
| type ECSNodeRunningInfoResp struct { | |||||
| MessageBodyBase | |||||
| NodeUsageRateInfos []NodeUsageRateInfo `json:"nodeUsageRateInfos"` | |||||
| } | |||||
| func NewECSNodeRunningInfoResp(nodeUsageRateInfos []NodeUsageRateInfo) *ECSNodeRunningInfoResp { | |||||
| return &ECSNodeRunningInfoResp{ | |||||
| NodeUsageRateInfos: nodeUsageRateInfos, | |||||
| } | |||||
| } | |||||
| type NodeUsageRateInfo struct { | |||||
| MessageBodyBase | |||||
| InstanceID JobID `json:"instanceID"` | |||||
| Address Address `json:"address"` | |||||
| MemoryUtilization []UsageRate `json:"memoryUtilization"` | |||||
| GPUUtilization []UsageRate `json:"GPUUtilization"` | |||||
| CPUUtilization []UsageRate `json:"CPUUtilization"` | |||||
| } | |||||
| type UsageRate struct { | |||||
| Timestamp string `json:"timestamp"` | |||||
| Number string `json:"number"` | |||||
| } | |||||
| const ( | |||||
| FineTuning = "finetuning" | |||||
| DataPreprocess = "DataPreprocess" | |||||
| CreateECS = "create" | |||||
| RunECS = "run" | |||||
| PauseECS = "pause" | |||||
| DestroyECS = "destroy" | |||||
| OperateServer = "operate" | |||||
| RestartServer = "restartServer" | |||||
| GPUMonitor = "GPUMonitor" | |||||
| RcloneMount = "rclone" | |||||
| Mounted = "mounted" | |||||
| MountDir = "/mnt/oss" | |||||
| Deploying = "Deploying" | |||||
| Waiting = "Waiting" | |||||
| Failed = "Failed" | |||||
| Invalid = "Invalid" | |||||
| ) | |||||
| type QueryRunningModelsReq struct { | |||||
| UserID int64 `form:"userID" json:"userID"` | |||||
| } | |||||
| func (c *Client) QueryRunningModels(req QueryRunningModelsReq) (*RunningModelResp, error) { | |||||
| url, err := url.JoinPath(c.baseURL, "/job/queryRunningModels") | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| resp, err := myhttp.GetJSON(url, myhttp.RequestParam{ | |||||
| Body: req, | |||||
| }) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| contType := resp.Header.Get("Content-Type") | |||||
| if strings.Contains(contType, myhttp.ContentTypeJSON) { | |||||
| var codeResp response[RunningModelResp] | |||||
| if err := serder.JSONToObjectStream(resp.Body, &codeResp); err != nil { | |||||
| return nil, fmt.Errorf("parsing response: %w", err) | |||||
| } | |||||
| if codeResp.Code == errorcode.OK { | |||||
| return &codeResp.Data, nil | |||||
| } | |||||
| return nil, codeResp.ToError() | |||||
| } | |||||
| return nil, fmt.Errorf("unknow response content type: %s", contType) | |||||
| } | |||||
| func (c *Client) QueryAllModels(req QueryRunningModelsReq) (*AllModelResp, error) { | |||||
| url, err := url.JoinPath(c.baseURL, "/job/getAllModels") | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| resp, err := myhttp.GetJSON(url, myhttp.RequestParam{ | |||||
| Body: req, | |||||
| }) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| contType := resp.Header.Get("Content-Type") | |||||
| if strings.Contains(contType, myhttp.ContentTypeJSON) { | |||||
| var codeResp response[AllModelResp] | |||||
| if err := serder.JSONToObjectStream(resp.Body, &codeResp); err != nil { | |||||
| return nil, fmt.Errorf("parsing response: %w", err) | |||||
| } | |||||
| if codeResp.Code == errorcode.OK { | |||||
| return &codeResp.Data, nil | |||||
| } | |||||
| return nil, codeResp.ToError() | |||||
| } | |||||
| return nil, fmt.Errorf("unknow response content type: %s", contType) | |||||
| } | |||||
| func (c *Client) ECSNodeRunningInfo(req ECSNodeRunningInfoReq) (*ECSNodeRunningInfoResp, error) { | |||||
| url, err := url.JoinPath(c.baseURL, "/job/getECSNodeRunningInfo") | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| resp, err := myhttp.GetJSON(url, myhttp.RequestParam{ | |||||
| Body: req, | |||||
| }) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| contType := resp.Header.Get("Content-Type") | |||||
| if strings.Contains(contType, myhttp.ContentTypeJSON) { | |||||
| var codeResp response[ECSNodeRunningInfoResp] | |||||
| if err := serder.JSONToObjectStream(resp.Body, &codeResp); err != nil { | |||||
| return nil, fmt.Errorf("parsing response: %w", err) | |||||
| } | |||||
| if codeResp.Code == errorcode.OK { | |||||
| return &codeResp.Data, nil | |||||
| } | |||||
| return nil, codeResp.ToError() | |||||
| } | |||||
| return nil, fmt.Errorf("unknow response content type: %s", contType) | |||||
| } | |||||
| @@ -7,14 +7,20 @@ import ( | |||||
| ) | ) | ||||
| const ( | const ( | ||||
| JobTypeNormal = "Normal" | |||||
| JobTypeResource = "Resource" | |||||
| JobTypeInstance = "Instance" | |||||
| JobTypeNormal = "Normal" | |||||
| JobTypeResource = "Resource" | |||||
| JobTypeInstance = "Instance" | |||||
| JobTypeFinetuning = "Finetuning" | |||||
| JobTypeDataPreprocess = "DataPreprocess" | |||||
| FileInfoTypePackage = "Package" | FileInfoTypePackage = "Package" | ||||
| FileInfoTypeLocalFile = "LocalFile" | FileInfoTypeLocalFile = "LocalFile" | ||||
| FileInfoTypeResource = "Resource" | FileInfoTypeResource = "Resource" | ||||
| FileInfoTypeImage = "Image" | FileInfoTypeImage = "Image" | ||||
| MemoryUtilization = "MemoryUtilization" | |||||
| GPUUtilization = "GPUUtilization" | |||||
| CPUUtilization = "CPUUtilization" | |||||
| ) | ) | ||||
| type JobID string | type JobID string | ||||
| @@ -26,6 +32,12 @@ type ImageID int64 | |||||
| // 计算中心ID | // 计算中心ID | ||||
| type CCID int64 | type CCID int64 | ||||
| type ModelID string | |||||
| type ModelName string | |||||
| type ECSInstanceID string | |||||
| type NodeID int64 | |||||
| type Address string | |||||
| type JobSetInfo struct { | type JobSetInfo struct { | ||||
| Jobs []JobInfo `json:"jobs"` | Jobs []JobInfo `json:"jobs"` | ||||
| } | } | ||||
| @@ -39,6 +51,9 @@ var JobInfoTypeUnion = types.NewTypeUnion[JobInfo]( | |||||
| (*DataReturnJobInfo)(nil), | (*DataReturnJobInfo)(nil), | ||||
| (*MultiInstanceJobInfo)(nil), | (*MultiInstanceJobInfo)(nil), | ||||
| (*InstanceJobInfo)(nil), | (*InstanceJobInfo)(nil), | ||||
| (*UpdateMultiInstanceJobInfo)(nil), | |||||
| (*FinetuningJobInfo)(nil), | |||||
| (*DataPreprocessJobInfo)(nil), | |||||
| ) | ) | ||||
| var _ = serder.UseTypeUnionInternallyTagged(&JobInfoTypeUnion, "type") | var _ = serder.UseTypeUnionInternallyTagged(&JobInfoTypeUnion, "type") | ||||
| @@ -53,6 +68,30 @@ func (i *JobInfoBase) GetLocalJobID() string { | |||||
| type NormalJobInfo struct { | type NormalJobInfo struct { | ||||
| serder.Metadata `union:"Normal"` | serder.Metadata `union:"Normal"` | ||||
| JobInfoBase | JobInfoBase | ||||
| Type string `json:"type"` | |||||
| Files JobFilesInfo `json:"files"` | |||||
| Runtime JobRuntimeInfo `json:"runtime"` | |||||
| Resources JobResourcesInfo `json:"resources"` | |||||
| Services JobServicesInfo `json:"services"` | |||||
| ModelJobInfo ModelJobInfo `json:"modelJobInfo"` | |||||
| } | |||||
| // FinetuningJobInfo 模型微调 | |||||
| type FinetuningJobInfo struct { | |||||
| serder.Metadata `union:"Finetuning"` | |||||
| JobInfoBase | |||||
| Type string `json:"type"` | |||||
| Files JobFilesInfo `json:"files"` | |||||
| Runtime JobRuntimeInfo `json:"runtime"` | |||||
| Resources JobResourcesInfo `json:"resources"` | |||||
| Services JobServicesInfo `json:"services"` | |||||
| ModelJobInfo ModelJobInfo `json:"modelJobInfo"` | |||||
| } | |||||
| // DataPreprocessJobInfo 数据预处理 | |||||
| type DataPreprocessJobInfo struct { | |||||
| serder.Metadata `union:"DataPreprocess"` | |||||
| JobInfoBase | |||||
| Type string `json:"type"` | Type string `json:"type"` | ||||
| Files JobFilesInfo `json:"files"` | Files JobFilesInfo `json:"files"` | ||||
| Runtime JobRuntimeInfo `json:"runtime"` | Runtime JobRuntimeInfo `json:"runtime"` | ||||
| @@ -68,23 +107,47 @@ type DataReturnJobInfo struct { | |||||
| TargetLocalJobID string `json:"targetLocalJobID"` | TargetLocalJobID string `json:"targetLocalJobID"` | ||||
| } | } | ||||
| // MultiInstanceJobInfo 多实例(推理任务) | |||||
| type MultiInstanceJobInfo struct { | type MultiInstanceJobInfo struct { | ||||
| serder.Metadata `union:"MultiInstance"` | serder.Metadata `union:"MultiInstance"` | ||||
| JobInfoBase | JobInfoBase | ||||
| Type string `json:"type"` | |||||
| Files JobFilesInfo `json:"files"` | |||||
| Runtime JobRuntimeInfo `json:"runtime"` | |||||
| Resources JobResourcesInfo `json:"resources"` | |||||
| Type string `json:"type"` | |||||
| Files JobFilesInfo `json:"files"` | |||||
| Runtime JobRuntimeInfo `json:"runtime"` | |||||
| Resources JobResourcesInfo `json:"resources"` | |||||
| ModelJobInfo ModelJobInfo `json:"modelJobInfo"` | |||||
| } | |||||
| // UpdateMultiInstanceJobInfo 更新模型 | |||||
| type UpdateMultiInstanceJobInfo struct { | |||||
| serder.Metadata `union:"UpdateModel"` | |||||
| JobInfoBase | |||||
| Type string `json:"type"` | |||||
| Files JobFilesInfo `json:"files"` | |||||
| Runtime JobRuntimeInfo `json:"runtime"` | |||||
| MultiInstanceJobSetID JobSetID `json:"multiInstanceJobSetID"` | |||||
| UpdateType string `json:"updateType"` | |||||
| SubJobs []JobID `json:"subJobs"` | |||||
| Operate string `json:"operate"` | |||||
| } | |||||
| type ModelJobInfo struct { | |||||
| Type string `json:"type"` | |||||
| ModelID ModelID `json:"modelID"` | |||||
| CustomModelName ModelName `json:"customModelName"` | |||||
| Command string `json:"command"` | |||||
| } | } | ||||
| // InstanceJobInfo 单实例(推理任务) | |||||
| type InstanceJobInfo struct { | type InstanceJobInfo struct { | ||||
| serder.Metadata `union:"Instance"` | serder.Metadata `union:"Instance"` | ||||
| JobInfoBase | JobInfoBase | ||||
| Type string `json:"type"` | |||||
| LocalJobID string `json:"multiInstJobID"` | |||||
| Files JobFilesInfo `json:"files"` | |||||
| Runtime JobRuntimeInfo `json:"runtime"` | |||||
| Resources JobResourcesInfo `json:"resources"` | |||||
| Type string `json:"type"` | |||||
| LocalJobID string `json:"multiInstJobID"` | |||||
| Files JobFilesInfo `json:"files"` | |||||
| Runtime JobRuntimeInfo `json:"runtime"` | |||||
| Resources JobResourcesInfo `json:"resources"` | |||||
| ModelJobInfo ModelJobInfo `json:"modelJobInfo"` | |||||
| } | } | ||||
| type JobFilesInfo struct { | type JobFilesInfo struct { | ||||
| @@ -219,6 +282,26 @@ func (b *NoEnvBootstrap) GetBootstrapType() string { | |||||
| } | } | ||||
| const ( | const ( | ||||
| JobDataInEnv = "SCH_DATA_IN" | |||||
| JobDataOutEnv = "SCH_DATA_OUT" | |||||
| JobDataInEnv = "SCH_DATA_IN" | |||||
| JobDataOutEnv = "SCH_DATA_OUT" | |||||
| FinetuningOutEnv = "FINETUNING_OUT" | |||||
| AccessPath = "ACCESS_PATH" | |||||
| ) | ) | ||||
| type Rclone struct { | |||||
| CDSRcloneID string `json:"cds_rcloneID"` | |||||
| CDSRcloneConfigID string `json:"cds_rcloneConfigID"` | |||||
| } | |||||
| type InferencePlatform struct { | |||||
| PlatformName string `json:"platformName"` | |||||
| ApiBaseUrl string `json:"apiBaseUrl"` | |||||
| ApiKey string `json:"apiKey"` | |||||
| ApiProxy string `json:"apiProxy"` | |||||
| LlmModel string `json:"llmModel"` | |||||
| EmbedModel string `json:"embedModel"` | |||||
| ChunkMaxLength string `json:"chunkMaxLength"` | |||||
| StartChunkThreshold string `json:"startChunkThreshold"` | |||||
| SimilarityThreshold string `json:"similarityThreshold"` | |||||
| EntriesPerFile string `json:"entriesPerFile"` | |||||
| } | |||||
| @@ -72,7 +72,7 @@ func (b *RepRedundancy) Value() (driver.Value, error) { | |||||
| return serder.ObjectToJSONEx[Redundancy](b) | return serder.ObjectToJSONEx[Redundancy](b) | ||||
| } | } | ||||
| var DefaultECRedundancy = *NewECRedundancy(2, 3, 1024*1024*5) | |||||
| var DefaultECRedundancy = *NewECRedundancy(3, 6, 1024*1024*5) | |||||
| type ECRedundancy struct { | type ECRedundancy struct { | ||||
| serder.Metadata `union:"ec"` | serder.Metadata `union:"ec"` | ||||
| @@ -138,7 +138,10 @@ func (c *ObjectService) Download(req ObjectDownload) (*DownloadingObject, error) | |||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| startTime := time.Now() | |||||
| file, err := files.MoveNext() | file, err := files.MoveNext() | ||||
| endTime := time.Now() | |||||
| fmt.Printf("files.MoveNext(), spend time: %.0f s", endTime.Sub(startTime).Seconds()) | |||||
| if err == iterator.ErrNoMoreItem { | if err == iterator.ErrNoMoreItem { | ||||
| return nil, fmt.Errorf("no file found in response") | return nil, fmt.Errorf("no file found in response") | ||||
| } | } | ||||
| @@ -0,0 +1,256 @@ | |||||
| package uopsdk | |||||
| // CPU | |||||
| func shuguang() (*[]ResourceData, error) { | |||||
| var ret []ResourceData | |||||
| cpuResourceData := CPUResourceData{ | |||||
| Name: ResourceTypeCPU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 600, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 500, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &cpuResourceData) | |||||
| npuResourceData := NPUResourceData{ | |||||
| Name: ResourceTypeNPU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &npuResourceData) | |||||
| gpuResourceData := GPUResourceData{ | |||||
| Name: ResourceTypeGPU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &gpuResourceData) | |||||
| mluResourceData := MLUResourceData{ | |||||
| Name: ResourceTypeMLU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &mluResourceData) | |||||
| storageResourceData := StorageResourceData{ | |||||
| Name: ResourceTypeStorage, | |||||
| Total: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| Available: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &storageResourceData) | |||||
| memoryResourceData := MemoryResourceData{ | |||||
| Name: ResourceTypeMemory, | |||||
| Total: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| Available: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &memoryResourceData) | |||||
| return &ret, nil | |||||
| } | |||||
| // GPU | |||||
| func modelarts() (*[]ResourceData, error) { | |||||
| var ret []ResourceData | |||||
| cpuResourceData := CPUResourceData{ | |||||
| Name: ResourceTypeCPU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &cpuResourceData) | |||||
| npuResourceData := NPUResourceData{ | |||||
| Name: ResourceTypeNPU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &npuResourceData) | |||||
| gpuResourceData := GPUResourceData{ | |||||
| Name: ResourceTypeGPU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 600, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 500, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &gpuResourceData) | |||||
| mluResourceData := MLUResourceData{ | |||||
| Name: ResourceTypeMLU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &mluResourceData) | |||||
| storageResourceData := StorageResourceData{ | |||||
| Name: ResourceTypeStorage, | |||||
| Total: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| Available: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &storageResourceData) | |||||
| memoryResourceData := MemoryResourceData{ | |||||
| Name: ResourceTypeMemory, | |||||
| Total: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| Available: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &memoryResourceData) | |||||
| return &ret, nil | |||||
| } | |||||
| // NPU | |||||
| func hanwuji() (*[]ResourceData, error) { | |||||
| var ret []ResourceData | |||||
| cpuResourceData := CPUResourceData{ | |||||
| Name: ResourceTypeCPU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &cpuResourceData) | |||||
| npuResourceData := NPUResourceData{ | |||||
| Name: ResourceTypeNPU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 600, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 500, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &npuResourceData) | |||||
| gpuResourceData := GPUResourceData{ | |||||
| Name: ResourceTypeGPU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &gpuResourceData) | |||||
| mluResourceData := MLUResourceData{ | |||||
| Name: ResourceTypeMLU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &mluResourceData) | |||||
| storageResourceData := StorageResourceData{ | |||||
| Name: ResourceTypeStorage, | |||||
| Total: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| Available: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &storageResourceData) | |||||
| memoryResourceData := MemoryResourceData{ | |||||
| Name: ResourceTypeMemory, | |||||
| Total: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| Available: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &memoryResourceData) | |||||
| return &ret, nil | |||||
| } | |||||
| @@ -223,302 +223,53 @@ func (c *Client) GetMemoryData(node GetOneResourceDataReq) (*MemoryResourceData, | |||||
| } | } | ||||
| func (c *Client) GetIndicatorData(node GetOneResourceDataReq) (*[]ResourceData, error) { | func (c *Client) GetIndicatorData(node GetOneResourceDataReq) (*[]ResourceData, error) { | ||||
| //url, err := url.JoinPath(c.baseURL, "/cmdb/resApi/getIndicatorData") | |||||
| //if err != nil { | |||||
| // return nil, err | |||||
| //} | |||||
| //resp, err := myhttp.PostJSON(url, myhttp.RequestParam{ | |||||
| // Body: node, | |||||
| //}) | |||||
| //if err != nil { | |||||
| // return nil, err | |||||
| //} | |||||
| // | |||||
| //contType := resp.Header.Get("Content-Type") | |||||
| //if strings.Contains(contType, myhttp.ContentTypeJSON) { | |||||
| // | |||||
| // var codeResp response[[]map[string]any] | |||||
| // if err := serder.JSONToObjectStream(resp.Body, &codeResp); err != nil { | |||||
| // return nil, fmt.Errorf("parsing response: %w", err) | |||||
| // } | |||||
| // | |||||
| // if codeResp.Code != CORRECT_CODE { | |||||
| // return nil, codeResp.ToError() | |||||
| // } | |||||
| // | |||||
| // var ret []ResourceData | |||||
| // for _, mp := range codeResp.Data { | |||||
| // var data ResourceData | |||||
| // err := serder.MapToObject(mp, &data) | |||||
| // if err != nil { | |||||
| // return nil, err | |||||
| // } | |||||
| // ret = append(ret, data) | |||||
| // } | |||||
| // | |||||
| // return &ret, nil | |||||
| //} | |||||
| // | |||||
| //return nil, fmt.Errorf("unknow response content type: %s", contType) | |||||
| if node.SlwNodeID == 1 { | |||||
| return mockData1() | |||||
| } | |||||
| if node.SlwNodeID == 2 { | |||||
| return mockData2() | |||||
| } | |||||
| return mockData3() | |||||
| } | |||||
| func mockData1() (*[]ResourceData, error) { | |||||
| var ret []ResourceData | |||||
| cpuResourceData := CPUResourceData{ | |||||
| Name: ResourceTypeCPU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &cpuResourceData) | |||||
| npuResourceData := NPUResourceData{ | |||||
| Name: ResourceTypeNPU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 0, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 0, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &npuResourceData) | |||||
| gpuResourceData := GPUResourceData{ | |||||
| Name: ResourceTypeGPU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 0, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 0, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &gpuResourceData) | |||||
| mluResourceData := MLUResourceData{ | |||||
| Name: ResourceTypeMLU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &mluResourceData) | |||||
| storageResourceData := StorageResourceData{ | |||||
| Name: ResourceTypeStorage, | |||||
| Total: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| Available: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &storageResourceData) | |||||
| memoryResourceData := MemoryResourceData{ | |||||
| Name: ResourceTypeMemory, | |||||
| Total: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| Available: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &memoryResourceData) | |||||
| return &ret, nil | |||||
| } | |||||
| func mockData2() (*[]ResourceData, error) { | |||||
| var ret []ResourceData | |||||
| cpuResourceData := CPUResourceData{ | |||||
| Name: ResourceTypeCPU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &cpuResourceData) | |||||
| npuResourceData := NPUResourceData{ | |||||
| Name: ResourceTypeNPU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &npuResourceData) | |||||
| gpuResourceData := GPUResourceData{ | |||||
| Name: ResourceTypeGPU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 0, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 0, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &gpuResourceData) | |||||
| mluResourceData := MLUResourceData{ | |||||
| Name: ResourceTypeMLU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 0, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 0, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &mluResourceData) | |||||
| storageResourceData := StorageResourceData{ | |||||
| Name: ResourceTypeStorage, | |||||
| Total: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| Available: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &storageResourceData) | |||||
| memoryResourceData := MemoryResourceData{ | |||||
| Name: ResourceTypeMemory, | |||||
| Total: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| Available: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &memoryResourceData) | |||||
| return &ret, nil | |||||
| switch node.SlwNodeID { | |||||
| case 1: | |||||
| return shuguang() | |||||
| case 2: | |||||
| return modelarts() | |||||
| case 3: | |||||
| return hanwuji() | |||||
| } | |||||
| return nil, nil | |||||
| } | } | ||||
| func mockData3() (*[]ResourceData, error) { | |||||
| var ret []ResourceData | |||||
| cpuResourceData := CPUResourceData{ | |||||
| Name: ResourceTypeCPU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &cpuResourceData) | |||||
| npuResourceData := NPUResourceData{ | |||||
| Name: ResourceTypeNPU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 0, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 0, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &npuResourceData) | |||||
| gpuResourceData := GPUResourceData{ | |||||
| Name: ResourceTypeGPU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 100, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &gpuResourceData) | |||||
| mluResourceData := MLUResourceData{ | |||||
| Name: ResourceTypeMLU, | |||||
| Total: UnitValue[int64]{ | |||||
| Value: 0, | |||||
| Unit: "", | |||||
| }, | |||||
| Available: UnitValue[int64]{ | |||||
| Value: 0, | |||||
| Unit: "", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &mluResourceData) | |||||
| storageResourceData := StorageResourceData{ | |||||
| Name: ResourceTypeStorage, | |||||
| Total: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| Available: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &storageResourceData) | |||||
| memoryResourceData := MemoryResourceData{ | |||||
| Name: ResourceTypeMemory, | |||||
| Total: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| Available: UnitValue[float64]{ | |||||
| Value: 100, | |||||
| Unit: "GB", | |||||
| }, | |||||
| } | |||||
| ret = append(ret, &memoryResourceData) | |||||
| return &ret, nil | |||||
| } | |||||
| //func (c *Client) GetIndicatorData(node GetOneResourceDataReq) (*[]ResourceData, error) { | |||||
| //url, err := url.JoinPath(c.baseURL, "/cmdb/resApi/getIndicatorData") | |||||
| //if err != nil { | |||||
| // return nil, err | |||||
| //} | |||||
| //resp, err := myhttp.PostJSON(url, myhttp.RequestParam{ | |||||
| // Body: node, | |||||
| //}) | |||||
| //if err != nil { | |||||
| // return nil, err | |||||
| //} | |||||
| // | |||||
| //contType := resp.Header.Get("Content-Type") | |||||
| //if strings.Contains(contType, myhttp.ContentTypeJSON) { | |||||
| // | |||||
| // var codeResp response[[]map[string]any] | |||||
| // if err := serder.JSONToObjectStream(resp.Body, &codeResp); err != nil { | |||||
| // return nil, fmt.Errorf("parsing response: %w", err) | |||||
| // } | |||||
| // | |||||
| // if codeResp.Code != CORRECT_CODE { | |||||
| // return nil, codeResp.ToError() | |||||
| // } | |||||
| // | |||||
| // var ret []ResourceData | |||||
| // for _, mp := range codeResp.Data { | |||||
| // var data ResourceData | |||||
| // err := serder.MapToObject(mp, &data) | |||||
| // if err != nil { | |||||
| // return nil, err | |||||
| // } | |||||
| // ret = append(ret, data) | |||||
| // } | |||||
| // | |||||
| // return &ret, nil | |||||
| //} | |||||
| // | |||||
| //return nil, fmt.Errorf("unknow response content type: %s", contType) | |||||
| //} | |||||
| @@ -6,6 +6,7 @@ import ( | |||||
| "github.com/imdario/mergo" | "github.com/imdario/mergo" | ||||
| "os" | "os" | ||||
| "path/filepath" | "path/filepath" | ||||
| "strings" | |||||
| ) | ) | ||||
| // Load 加载配置文件 | // Load 加载配置文件 | ||||
| @@ -26,6 +27,18 @@ func DefaultLoad(modeulName string, defCfg interface{}) error { | |||||
| return err | return err | ||||
| } | } | ||||
| if strings.Contains(execPath, "scheduler") { | |||||
| execPath = "D:\\Work\\Codes\\new\\workspace\\workspace\\scheduler\\common\\assets\\confs\\" | |||||
| } | |||||
| if strings.Contains(execPath, "storage") { | |||||
| execPath = "D:\\Work\\Codes\\new\\workspace\\workspace\\storage\\common\\assets\\confs\\" | |||||
| } | |||||
| if strings.Contains(execPath, "gateway") { | |||||
| execPath = "D:\\Work\\Codes\\new\\workspace\\workspace\\gateway\\assets\\confs\\" | |||||
| } | |||||
| // TODO 可以考虑根据环境变量读取不同的配置 | // TODO 可以考虑根据环境变量读取不同的配置 | ||||
| configFilePath := filepath.Join(filepath.Dir(execPath), "..", "confs", fmt.Sprintf("%s.config.json", modeulName)) | configFilePath := filepath.Join(filepath.Dir(execPath), "..", "confs", fmt.Sprintf("%s.config.json", modeulName)) | ||||
| return Load(configFilePath, defCfg) | return Load(configFilePath, defCfg) | ||||
| @@ -56,6 +56,27 @@ func GetJSON(url string, param RequestParam) (*http.Response, error) { | |||||
| return defaultClient.Do(req) | return defaultClient.Do(req) | ||||
| } | } | ||||
| func DeleteJSON(url string, param RequestParam) (*http.Response, error) { | |||||
| req, err := http.NewRequest(http.MethodDelete, url, nil) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| if err = prepareQuery(req, param.Query); err != nil { | |||||
| return nil, err | |||||
| } | |||||
| if err = prepareHeader(req, param.Header); err != nil { | |||||
| return nil, err | |||||
| } | |||||
| if err = prepareJSONBody(req, param.Body); err != nil { | |||||
| return nil, err | |||||
| } | |||||
| return defaultClient.Do(req) | |||||
| } | |||||
| func GetForm(url string, param RequestParam) (*http.Response, error) { | func GetForm(url string, param RequestParam) (*http.Response, error) { | ||||
| req, err := http.NewRequest(http.MethodGet, url, nil) | req, err := http.NewRequest(http.MethodGet, url, nil) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -98,6 +119,45 @@ func PostJSON(url string, param RequestParam) (*http.Response, error) { | |||||
| return defaultClient.Do(req) | return defaultClient.Do(req) | ||||
| } | } | ||||
| func PostJSONRow(url string, param RequestParam) (*http.Response, error) { | |||||
| req, err := http.NewRequest(http.MethodPost, url, nil) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| if err = prepareQuery(req, param.Query); err != nil { | |||||
| return nil, err | |||||
| } | |||||
| if err = prepareHeader(req, param.Header); err != nil { | |||||
| return nil, err | |||||
| } | |||||
| //if err = prepareJSONBody(req, param.Body); err != nil { | |||||
| // return nil, err | |||||
| //} | |||||
| setHeader(req.Header, "Content-Type", ContentTypeJSON) | |||||
| if param.Body == nil { | |||||
| return nil, nil | |||||
| } | |||||
| switch body := param.Body.(type) { | |||||
| case nil: | |||||
| case string: | |||||
| req.ContentLength = int64(len(body)) | |||||
| req.Body = io.NopCloser(bytes.NewReader([]byte(body))) | |||||
| case []byte: | |||||
| req.ContentLength = int64(len(body)) | |||||
| req.Body = io.NopCloser(bytes.NewReader(body)) | |||||
| default: | |||||
| return nil, fmt.Errorf("body error") | |||||
| } | |||||
| return defaultClient.Do(req) | |||||
| } | |||||
| func PostForm(url string, param RequestParam) (*http.Response, error) { | func PostForm(url string, param RequestParam) (*http.Response, error) { | ||||
| req, err := http.NewRequest(http.MethodPost, url, nil) | req, err := http.NewRequest(http.MethodPost, url, nil) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -0,0 +1,104 @@ | |||||
| package time2 | |||||
| import ( | |||||
| "fmt" | |||||
| "path" | |||||
| "runtime" | |||||
| "strings" | |||||
| "time" | |||||
| ) | |||||
| type Measurement struct { | |||||
| startTime time.Time | |||||
| lastPointTime time.Time | |||||
| printer func(string) | |||||
| on bool | |||||
| title string | |||||
| } | |||||
| func NewMeasurement(printer func(string)) Measurement { | |||||
| return Measurement{ | |||||
| printer: printer, | |||||
| } | |||||
| } | |||||
| func (m *Measurement) Begin(on bool, title ...string) { | |||||
| if m == nil { | |||||
| return | |||||
| } | |||||
| m.on = on | |||||
| m.title = strings.Join(title, ".") | |||||
| if on { | |||||
| m.startTime = time.Now() | |||||
| m.lastPointTime = m.startTime | |||||
| _, file, line, ok := runtime.Caller(1) | |||||
| titlePart := "" | |||||
| if m.title != "" { | |||||
| titlePart = fmt.Sprintf(":%s", m.title) | |||||
| } | |||||
| if ok { | |||||
| m.printer(fmt.Sprintf("[begin%v]%v:%v", titlePart, path.Base(file), line)) | |||||
| } else { | |||||
| m.printer(fmt.Sprintf("[begin%v]unknown point", titlePart)) | |||||
| } | |||||
| } | |||||
| } | |||||
| func (m *Measurement) Point(head ...string) { | |||||
| if m == nil { | |||||
| return | |||||
| } | |||||
| if m.on { | |||||
| m.printer(m.makePointString(strings.Join(head, "."))) | |||||
| } | |||||
| } | |||||
| func (m *Measurement) makePointString(head string) string { | |||||
| last := m.lastPointTime | |||||
| now := time.Now() | |||||
| m.lastPointTime = now | |||||
| _, file, line, ok := runtime.Caller(2) | |||||
| prefixCont := "" | |||||
| if m.title != "" { | |||||
| prefixCont = m.title | |||||
| } | |||||
| if head != "" { | |||||
| if prefixCont == "" { | |||||
| prefixCont = head | |||||
| } else { | |||||
| prefixCont = fmt.Sprintf("%s.%s", prefixCont, head) | |||||
| } | |||||
| } | |||||
| prefixPart := "" | |||||
| if prefixCont != "" { | |||||
| prefixPart = fmt.Sprintf("[%s]", prefixCont) | |||||
| } | |||||
| if ok { | |||||
| return fmt.Sprintf("%v%v:%v@%v(%v)", prefixPart, path.Base(file), line, now.Sub(last), now.Sub(m.startTime)) | |||||
| } | |||||
| return fmt.Sprintf("%vunknown point@%v(%v)", prefixPart, now.Sub(last), now.Sub(m.startTime)) | |||||
| } | |||||
| func (m *Measurement) End(head ...string) { | |||||
| if m == nil { | |||||
| return | |||||
| } | |||||
| if m.on { | |||||
| m.printer(fmt.Sprintf("[end]%v\n", m.makePointString(strings.Join(head, ".")))) | |||||
| } | |||||
| } | |||||