From 43f43a61f58943d9b0b54d4f1bc22412201fece9 Mon Sep 17 00:00:00 2001 From: Caleb <48746895+calebax@users.noreply.github.com> Date: Mon, 24 Nov 2025 18:24:32 +0800 Subject: [PATCH 1/3] fix: update go.mod module path --- sdk/go/go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/go/go.mod b/sdk/go/go.mod index 2a909a1e..8c3609a2 100644 --- a/sdk/go/go.mod +++ b/sdk/go/go.mod @@ -1,3 +1,3 @@ -module github.com/keithang/microsandbox/sdk/go +module github.com/microsandbox/microsandbox/sdk/go go 1.24 From 58779243751221a4af0e02168dffd32753a91dd3 Mon Sep 17 00:00:00 2001 From: caleb Date: Mon, 24 Nov 2025 19:05:00 +0800 Subject: [PATCH 2/3] fix: update import path for microsandbox SDK --- sdk/go/cmd/command-example/main.go | 2 +- sdk/go/cmd/concurrent-example/main.go | 2 +- sdk/go/cmd/metrics-example/main.go | 3 +-- sdk/go/cmd/node-example/main.go | 2 +- sdk/go/cmd/repl-example/main.go | 3 +-- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/sdk/go/cmd/command-example/main.go b/sdk/go/cmd/command-example/main.go index 955bb240..4b2626a3 100644 --- a/sdk/go/cmd/command-example/main.go +++ b/sdk/go/cmd/command-example/main.go @@ -4,7 +4,7 @@ import ( "fmt" "log" - msb "github.com/keithang/microsandbox/sdk/go" + msb "github.com/microsandbox/microsandbox/sdk/go" ) // basicExample demonstrates basic command execution with proper lifecycle management. diff --git a/sdk/go/cmd/concurrent-example/main.go b/sdk/go/cmd/concurrent-example/main.go index b14a909d..0b3767fc 100644 --- a/sdk/go/cmd/concurrent-example/main.go +++ b/sdk/go/cmd/concurrent-example/main.go @@ -8,7 +8,7 @@ import ( "sync" "time" - msb "github.com/keithang/microsandbox/sdk/go" + msb "github.com/microsandbox/microsandbox/sdk/go" ) // sequentialExample demonstrates basic sequential usage. diff --git a/sdk/go/cmd/metrics-example/main.go b/sdk/go/cmd/metrics-example/main.go index 5f10d7dd..2d6d2fb4 100644 --- a/sdk/go/cmd/metrics-example/main.go +++ b/sdk/go/cmd/metrics-example/main.go @@ -5,7 +5,7 @@ import ( "log" "time" - msb "github.com/keithang/microsandbox/sdk/go" + msb "github.com/microsandbox/microsandbox/sdk/go" ) // basicMetricsExample demonstrates how to get individual metrics for a sandbox. @@ -297,4 +297,3 @@ func main() { fmt.Println("\nAll examples completed!") } - diff --git a/sdk/go/cmd/node-example/main.go b/sdk/go/cmd/node-example/main.go index a88e7fd1..4c78849e 100644 --- a/sdk/go/cmd/node-example/main.go +++ b/sdk/go/cmd/node-example/main.go @@ -4,7 +4,7 @@ import ( "fmt" "log" - msb "github.com/keithang/microsandbox/sdk/go" + msb "github.com/microsandbox/microsandbox/sdk/go" ) // basicExample demonstrates basic JavaScript code execution. diff --git a/sdk/go/cmd/repl-example/main.go b/sdk/go/cmd/repl-example/main.go index 64b429f7..54cfea0e 100644 --- a/sdk/go/cmd/repl-example/main.go +++ b/sdk/go/cmd/repl-example/main.go @@ -4,7 +4,7 @@ import ( "fmt" "log" - msb "github.com/keithang/microsandbox/sdk/go" + msb "github.com/microsandbox/microsandbox/sdk/go" ) // contextManagerEquivalentExample demonstrates the Go equivalent of Python's context manager pattern. @@ -325,4 +325,3 @@ func main() { fmt.Println("\nAll examples completed!") } - From c882e32189937ba00505a0aa410bcb29a9bfeebd Mon Sep 17 00:00:00 2001 From: caleb Date: Mon, 24 Nov 2025 20:18:25 +0800 Subject: [PATCH 3/3] feat: add uuid package and use it as default request ID generator --- sdk/go/config.go | 6 ++ sdk/go/option.go | 3 + sdk/go/uuid/uuid.go | 175 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 sdk/go/uuid/uuid.go diff --git a/sdk/go/config.go b/sdk/go/config.go index 5a2fcecf..0f0b34f5 100644 --- a/sdk/go/config.go +++ b/sdk/go/config.go @@ -1,5 +1,7 @@ package msb +import "github.com/microsandbox/microsandbox/sdk/go/uuid" + type ReqIdProducer func() string type config struct { @@ -16,3 +18,7 @@ const ( defaultNamespace = "default" defaultNameTemplate = "sandbox-%08x" // 8-char hex value (0-padded if shorter) ) + +var defaultReqIdProducer ReqIdProducer = func() string { + return uuid.MustUUIDv4().String() +} diff --git a/sdk/go/option.go b/sdk/go/option.go index 2fea6120..c4ac6ac8 100644 --- a/sdk/go/option.go +++ b/sdk/go/option.go @@ -96,6 +96,9 @@ func fillDefaultConfigs() Option { panic(ErrAPIKeyMustBeSpecified) } } + if msb.cfg.reqIDPrd == nil { + msb.cfg.reqIDPrd = defaultReqIdProducer + } } } diff --git a/sdk/go/uuid/uuid.go b/sdk/go/uuid/uuid.go new file mode 100644 index 00000000..50836910 --- /dev/null +++ b/sdk/go/uuid/uuid.go @@ -0,0 +1,175 @@ +package uuid + +import ( + "crypto/rand" + "database/sql/driver" + "encoding/hex" + "errors" + "fmt" + "io" +) + +type UUID [16]byte + +var Nil UUID + +// Errors +var ( + ErrInvalidUUIDFormat = errors.New("invalid UUID format") + ErrInvalidLength = errors.New("invalid UUID length") +) + +func NewUUIDv4() (UUID, error) { + var u UUID + _, err := io.ReadFull(rand.Reader, u[:]) + if err != nil { + return Nil, err + } + u[6] = (u[6] & 0x0f) | 0x40 + u[8] = (u[8] & 0x3f) | 0x80 + return u, nil +} + +func MustUUIDv4() UUID { + u, err := NewUUIDv4() + if err != nil { + panic(err) + } + return u +} + +func (u UUID) String() string { + var buf [36]byte + encodeHex(buf[:], u) + return string(buf[:]) +} + +func Parse(s string) (UUID, error) { + var u UUID + if len(s) != 36 { + return Nil, ErrInvalidLength + } + if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { + return Nil, ErrInvalidUUIDFormat + } + + for i, x := range []int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} { + v, ok := xtob(s[x], s[x+1]) + if !ok { + return Nil, ErrInvalidUUIDFormat + } + u[i] = v + } + return u, nil +} + +func MustParse(s string) UUID { + u, err := Parse(s) + if err != nil { + panic(err) + } + return u +} + +func Validate(s string) error { + _, err := Parse(s) + return err +} + +func (u UUID) MarshalText() ([]byte, error) { + var buf [36]byte + encodeHex(buf[:], u) + return buf[:], nil +} + +func (u *UUID) UnmarshalText(data []byte) error { + id, err := Parse(string(data)) + if err != nil { + return err + } + *u = id + return nil +} + +func (u UUID) MarshalBinary() ([]byte, error) { + return u[:], nil +} + +func (u *UUID) UnmarshalBinary(data []byte) error { + if len(data) != 16 { + return ErrInvalidLength + } + copy(u[:], data) + return nil +} + +func (u UUID) Value() (driver.Value, error) { + return u.String(), nil +} + +func (u *UUID) Scan(src interface{}) error { + switch src := src.(type) { + case UUID: + *u = src + return nil + case []byte: + if len(src) == 16 { + copy(u[:], src) + return nil + } + return u.UnmarshalText(src) + case string: + return u.UnmarshalText([]byte(src)) + case nil: + *u = Nil + return nil + } + return fmt.Errorf("uuid: cannot convert %T to UUID", src) +} + +func (u UUID) Version() int { + return int(u[6] >> 4) +} + +func (u UUID) Variant() int { + return int((u[8] >> 5) ^ 0x04) +} + +func encodeHex(dst []byte, u UUID) { + hex.Encode(dst[0:8], u[0:4]) + dst[8] = '-' + hex.Encode(dst[9:13], u[4:6]) + dst[13] = '-' + hex.Encode(dst[14:18], u[6:8]) + dst[18] = '-' + hex.Encode(dst[19:23], u[8:10]) + dst[23] = '-' + hex.Encode(dst[24:], u[10:]) +} + +func xtob(a, b byte) (byte, bool) { + var v byte + // High nibble + switch { + case '0' <= a && a <= '9': + v = (a - '0') << 4 + case 'a' <= a && a <= 'f': + v = (a - 'a' + 10) << 4 + case 'A' <= a && a <= 'F': + v = (a - 'A' + 10) << 4 + default: + return 0, false + } + // Low nibble + switch { + case '0' <= b && b <= '9': + v |= (b - '0') + case 'a' <= b && b <= 'f': + v |= (b - 'a' + 10) + case 'A' <= b && b <= 'F': + v |= (b - 'A' + 10) + default: + return 0, false + } + return v, true +}