mirror of
https://github.com/DeBrosOfficial/network.git
synced 2026-01-30 17:23:03 +00:00
547 lines
10 KiB
Markdown
547 lines
10 KiB
Markdown
# Orama Network Client SDK
|
|
|
|
## Overview
|
|
|
|
The Orama Network Client SDK provides a clean, type-safe Go interface for interacting with the Orama Network. It abstracts away the complexity of HTTP requests, authentication, and error handling.
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
go get github.com/DeBrosOfficial/network/pkg/client
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
|
|
"github.com/DeBrosOfficial/network/pkg/client"
|
|
)
|
|
|
|
func main() {
|
|
// Create client configuration
|
|
cfg := client.DefaultClientConfig()
|
|
cfg.GatewayURL = "https://api.orama.network"
|
|
cfg.APIKey = "your-api-key-here"
|
|
|
|
// Create client
|
|
c := client.NewNetworkClient(cfg)
|
|
|
|
// Use the client
|
|
ctx := context.Background()
|
|
|
|
// Upload to storage
|
|
data := []byte("Hello, Orama!")
|
|
resp, err := c.Storage().Upload(ctx, data, "hello.txt")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Printf("Uploaded: CID=%s\n", resp.CID)
|
|
}
|
|
```
|
|
|
|
## Configuration
|
|
|
|
### ClientConfig
|
|
|
|
```go
|
|
type ClientConfig struct {
|
|
// Gateway URL (e.g., "https://api.orama.network")
|
|
GatewayURL string
|
|
|
|
// Authentication (choose one)
|
|
APIKey string // API key authentication
|
|
JWTToken string // JWT token authentication
|
|
|
|
// Client options
|
|
Timeout time.Duration // Request timeout (default: 30s)
|
|
UserAgent string // Custom user agent
|
|
|
|
// Network client namespace
|
|
Namespace string // Default namespace for operations
|
|
}
|
|
```
|
|
|
|
### Creating a Client
|
|
|
|
```go
|
|
// Default configuration
|
|
cfg := client.DefaultClientConfig()
|
|
cfg.GatewayURL = "https://api.orama.network"
|
|
cfg.APIKey = "your-api-key"
|
|
|
|
c := client.NewNetworkClient(cfg)
|
|
```
|
|
|
|
## Authentication
|
|
|
|
### API Key Authentication
|
|
|
|
```go
|
|
cfg := client.DefaultClientConfig()
|
|
cfg.APIKey = "your-api-key-here"
|
|
c := client.NewNetworkClient(cfg)
|
|
```
|
|
|
|
### JWT Token Authentication
|
|
|
|
```go
|
|
cfg := client.DefaultClientConfig()
|
|
cfg.JWTToken = "your-jwt-token-here"
|
|
c := client.NewNetworkClient(cfg)
|
|
```
|
|
|
|
### Obtaining Credentials
|
|
|
|
```go
|
|
// 1. Login with wallet signature (not yet implemented in SDK)
|
|
// Use the gateway API directly: POST /v1/auth/challenge + /v1/auth/verify
|
|
|
|
// 2. Issue API key after authentication
|
|
// POST /v1/auth/apikey with JWT token
|
|
```
|
|
|
|
## Storage Client
|
|
|
|
Upload, download, pin, and unpin files to IPFS.
|
|
|
|
### Upload File
|
|
|
|
```go
|
|
data := []byte("Hello, World!")
|
|
resp, err := c.Storage().Upload(ctx, data, "hello.txt")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Printf("CID: %s\n", resp.CID)
|
|
```
|
|
|
|
### Upload with Options
|
|
|
|
```go
|
|
opts := &client.StorageUploadOptions{
|
|
Pin: true, // Pin after upload
|
|
Encrypt: true, // Encrypt before upload
|
|
ReplicationFactor: 3, // Number of replicas
|
|
}
|
|
resp, err := c.Storage().UploadWithOptions(ctx, data, "file.txt", opts)
|
|
```
|
|
|
|
### Get File
|
|
|
|
```go
|
|
cid := "QmXxx..."
|
|
data, err := c.Storage().Get(ctx, cid)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Printf("Downloaded %d bytes\n", len(data))
|
|
```
|
|
|
|
### Pin File
|
|
|
|
```go
|
|
cid := "QmXxx..."
|
|
resp, err := c.Storage().Pin(ctx, cid)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Printf("Pinned: %s\n", resp.CID)
|
|
```
|
|
|
|
### Unpin File
|
|
|
|
```go
|
|
cid := "QmXxx..."
|
|
err := c.Storage().Unpin(ctx, cid)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Println("Unpinned successfully")
|
|
```
|
|
|
|
### Check Pin Status
|
|
|
|
```go
|
|
cid := "QmXxx..."
|
|
status, err := c.Storage().Status(ctx, cid)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Printf("Status: %s, Replicas: %d\n", status.Status, status.Replicas)
|
|
```
|
|
|
|
## Cache Client
|
|
|
|
Distributed key-value cache using Olric.
|
|
|
|
### Set Value
|
|
|
|
```go
|
|
key := "user:123"
|
|
value := map[string]interface{}{
|
|
"name": "Alice",
|
|
"email": "alice@example.com",
|
|
}
|
|
ttl := 5 * time.Minute
|
|
|
|
err := c.Cache().Set(ctx, key, value, ttl)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
```
|
|
|
|
### Get Value
|
|
|
|
```go
|
|
key := "user:123"
|
|
var user map[string]interface{}
|
|
err := c.Cache().Get(ctx, key, &user)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Printf("User: %+v\n", user)
|
|
```
|
|
|
|
### Delete Value
|
|
|
|
```go
|
|
key := "user:123"
|
|
err := c.Cache().Delete(ctx, key)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
```
|
|
|
|
### Multi-Get
|
|
|
|
```go
|
|
keys := []string{"user:1", "user:2", "user:3"}
|
|
results, err := c.Cache().MGet(ctx, keys)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
for key, value := range results {
|
|
fmt.Printf("%s: %v\n", key, value)
|
|
}
|
|
```
|
|
|
|
## Database Client
|
|
|
|
Query RQLite distributed SQL database.
|
|
|
|
### Execute Query (Write)
|
|
|
|
```go
|
|
sql := "INSERT INTO users (name, email) VALUES (?, ?)"
|
|
args := []interface{}{"Alice", "alice@example.com"}
|
|
|
|
result, err := c.Database().Execute(ctx, sql, args...)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Printf("Inserted %d rows\n", result.RowsAffected)
|
|
```
|
|
|
|
### Query (Read)
|
|
|
|
```go
|
|
sql := "SELECT id, name, email FROM users WHERE id = ?"
|
|
args := []interface{}{123}
|
|
|
|
rows, err := c.Database().Query(ctx, sql, args...)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
type User struct {
|
|
ID int `json:"id"`
|
|
Name string `json:"name"`
|
|
Email string `json:"email"`
|
|
}
|
|
|
|
var users []User
|
|
for _, row := range rows {
|
|
var user User
|
|
// Parse row into user struct
|
|
// (manual parsing required, or use ORM layer)
|
|
users = append(users, user)
|
|
}
|
|
```
|
|
|
|
### Create Table
|
|
|
|
```go
|
|
schema := `CREATE TABLE IF NOT EXISTS users (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL,
|
|
email TEXT UNIQUE NOT NULL,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
)`
|
|
|
|
_, err := c.Database().Execute(ctx, schema)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
```
|
|
|
|
### Transaction
|
|
|
|
```go
|
|
tx, err := c.Database().Begin(ctx)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
_, err = tx.Execute(ctx, "INSERT INTO users (name) VALUES (?)", "Alice")
|
|
if err != nil {
|
|
tx.Rollback(ctx)
|
|
log.Fatal(err)
|
|
}
|
|
|
|
_, err = tx.Execute(ctx, "INSERT INTO users (name) VALUES (?)", "Bob")
|
|
if err != nil {
|
|
tx.Rollback(ctx)
|
|
log.Fatal(err)
|
|
}
|
|
|
|
err = tx.Commit(ctx)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
```
|
|
|
|
## PubSub Client
|
|
|
|
Publish and subscribe to topics.
|
|
|
|
### Publish Message
|
|
|
|
```go
|
|
topic := "chat"
|
|
message := []byte("Hello, everyone!")
|
|
|
|
err := c.PubSub().Publish(ctx, topic, message)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
```
|
|
|
|
### Subscribe to Topic
|
|
|
|
```go
|
|
topic := "chat"
|
|
handler := func(ctx context.Context, msg []byte) error {
|
|
fmt.Printf("Received: %s\n", string(msg))
|
|
return nil
|
|
}
|
|
|
|
unsubscribe, err := c.PubSub().Subscribe(ctx, topic, handler)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// Later: unsubscribe
|
|
defer unsubscribe()
|
|
```
|
|
|
|
### List Topics
|
|
|
|
```go
|
|
topics, err := c.PubSub().ListTopics(ctx)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Printf("Topics: %v\n", topics)
|
|
```
|
|
|
|
## Serverless Client
|
|
|
|
Deploy and invoke WebAssembly functions.
|
|
|
|
### Deploy Function
|
|
|
|
```go
|
|
// Read WASM file
|
|
wasmBytes, err := os.ReadFile("function.wasm")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// Function definition
|
|
def := &client.FunctionDefinition{
|
|
Name: "hello-world",
|
|
Namespace: "default",
|
|
Description: "Hello world function",
|
|
MemoryLimit: 64, // MB
|
|
Timeout: 30, // seconds
|
|
}
|
|
|
|
// Deploy
|
|
fn, err := c.Serverless().Deploy(ctx, def, wasmBytes)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Printf("Deployed: %s (CID: %s)\n", fn.Name, fn.WASMCID)
|
|
```
|
|
|
|
### Invoke Function
|
|
|
|
```go
|
|
functionName := "hello-world"
|
|
input := map[string]interface{}{
|
|
"name": "Alice",
|
|
}
|
|
|
|
output, err := c.Serverless().Invoke(ctx, functionName, input)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Printf("Result: %s\n", output)
|
|
```
|
|
|
|
### List Functions
|
|
|
|
```go
|
|
functions, err := c.Serverless().List(ctx)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
for _, fn := range functions {
|
|
fmt.Printf("- %s: %s\n", fn.Name, fn.Description)
|
|
}
|
|
```
|
|
|
|
### Delete Function
|
|
|
|
```go
|
|
functionName := "hello-world"
|
|
err := c.Serverless().Delete(ctx, functionName)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
```
|
|
|
|
### Get Function Logs
|
|
|
|
```go
|
|
functionName := "hello-world"
|
|
logs, err := c.Serverless().GetLogs(ctx, functionName, 100)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
for _, log := range logs {
|
|
fmt.Printf("[%s] %s: %s\n", log.Timestamp, log.Level, log.Message)
|
|
}
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
All client methods return typed errors that can be checked:
|
|
|
|
```go
|
|
import "github.com/DeBrosOfficial/network/pkg/errors"
|
|
|
|
resp, err := c.Storage().Upload(ctx, data, "file.txt")
|
|
if err != nil {
|
|
if errors.IsNotFound(err) {
|
|
fmt.Println("Resource not found")
|
|
} else if errors.IsUnauthorized(err) {
|
|
fmt.Println("Authentication failed")
|
|
} else if errors.IsValidation(err) {
|
|
fmt.Println("Validation error")
|
|
} else {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
```
|
|
|
|
## Advanced Usage
|
|
|
|
### Custom Timeout
|
|
|
|
```go
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
resp, err := c.Storage().Upload(ctx, data, "file.txt")
|
|
```
|
|
|
|
### Retry Logic
|
|
|
|
```go
|
|
import "github.com/DeBrosOfficial/network/pkg/errors"
|
|
|
|
maxRetries := 3
|
|
for i := 0; i < maxRetries; i++ {
|
|
resp, err := c.Storage().Upload(ctx, data, "file.txt")
|
|
if err == nil {
|
|
break
|
|
}
|
|
if !errors.ShouldRetry(err) {
|
|
return err
|
|
}
|
|
time.Sleep(time.Second * time.Duration(i+1))
|
|
}
|
|
```
|
|
|
|
### Multiple Namespaces
|
|
|
|
```go
|
|
// Default namespace
|
|
c1 := client.NewNetworkClient(cfg)
|
|
c1.Storage().Upload(ctx, data, "file.txt") // Uses default namespace
|
|
|
|
// Override namespace per request
|
|
opts := &client.StorageUploadOptions{
|
|
Namespace: "custom-namespace",
|
|
}
|
|
c1.Storage().UploadWithOptions(ctx, data, "file.txt", opts)
|
|
```
|
|
|
|
## Testing
|
|
|
|
### Mock Client
|
|
|
|
```go
|
|
// Create a mock client for testing
|
|
mockClient := &MockNetworkClient{
|
|
StorageClient: &MockStorageClient{
|
|
UploadFunc: func(ctx context.Context, data []byte, filename string) (*UploadResponse, error) {
|
|
return &UploadResponse{CID: "QmMock"}, nil
|
|
},
|
|
},
|
|
}
|
|
|
|
// Use in tests
|
|
resp, err := mockClient.Storage().Upload(ctx, data, "test.txt")
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "QmMock", resp.CID)
|
|
```
|
|
|
|
## Examples
|
|
|
|
See the `examples/` directory for complete examples:
|
|
|
|
- `examples/storage/` - Storage upload/download examples
|
|
- `examples/cache/` - Cache operations
|
|
- `examples/database/` - Database queries
|
|
- `examples/pubsub/` - Pub/sub messaging
|
|
- `examples/serverless/` - Serverless functions
|
|
|
|
## API Reference
|
|
|
|
Complete API documentation is available at:
|
|
- GoDoc: https://pkg.go.dev/github.com/DeBrosOfficial/network/pkg/client
|
|
- OpenAPI: `openapi/gateway.yaml`
|
|
|
|
## Support
|
|
|
|
- GitHub Issues: https://github.com/DeBrosOfficial/network/issues
|
|
- Documentation: https://github.com/DeBrosOfficial/network/tree/main/docs
|