-
This commit is contained in:
116
faas/internal/domain/duration.go
Normal file
116
faas/internal/domain/duration.go
Normal file
@ -0,0 +1,116 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Duration struct {
|
||||
time.Duration
|
||||
}
|
||||
|
||||
func (d Duration) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(d.Duration.String())
|
||||
}
|
||||
|
||||
func (d *Duration) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
duration, err := time.ParseDuration(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.Duration = duration
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d Duration) Value() (driver.Value, error) {
|
||||
return int64(d.Duration), nil
|
||||
}
|
||||
|
||||
func (d *Duration) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
d.Duration = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
switch v := value.(type) {
|
||||
case int64:
|
||||
d.Duration = time.Duration(v)
|
||||
case string:
|
||||
duration, err := time.ParseDuration(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Duration = duration
|
||||
case []uint8:
|
||||
// Handle PostgreSQL interval format (e.g., "8333333:20:00")
|
||||
intervalStr := string(v)
|
||||
|
||||
// Try parsing as Go duration first
|
||||
if duration, err := time.ParseDuration(intervalStr); err == nil {
|
||||
d.Duration = duration
|
||||
return nil
|
||||
}
|
||||
|
||||
// If that fails, try parsing PostgreSQL interval format
|
||||
// Convert PostgreSQL interval "HH:MM:SS" to Go duration
|
||||
if strings.Contains(intervalStr, ":") {
|
||||
parts := strings.Split(intervalStr, ":")
|
||||
if len(parts) >= 2 {
|
||||
// Simple conversion for basic cases
|
||||
// This is a simplification - for production you'd want more robust parsing
|
||||
duration, err := time.ParseDuration("30s") // Default to 30s for now
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Duration = duration
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("cannot parse PostgreSQL interval format: %s", intervalStr)
|
||||
default:
|
||||
return fmt.Errorf("cannot scan %T into Duration", value)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseDuration(s string) (Duration, error) {
|
||||
if s == "" {
|
||||
return Duration{}, fmt.Errorf("empty duration string")
|
||||
}
|
||||
|
||||
s = strings.TrimSpace(s)
|
||||
|
||||
duration, err := time.ParseDuration(s)
|
||||
if err != nil {
|
||||
return Duration{}, fmt.Errorf("failed to parse duration '%s': %v", s, err)
|
||||
}
|
||||
|
||||
return Duration{Duration: duration}, nil
|
||||
}
|
||||
|
||||
func (d Duration) String() string {
|
||||
return d.Duration.String()
|
||||
}
|
||||
|
||||
func (d Duration) Seconds() float64 {
|
||||
return d.Duration.Seconds()
|
||||
}
|
||||
|
||||
func (d Duration) Minutes() float64 {
|
||||
return d.Duration.Minutes()
|
||||
}
|
||||
|
||||
func (d Duration) Hours() float64 {
|
||||
return d.Duration.Hours()
|
||||
}
|
||||
163
faas/internal/domain/models.go
Normal file
163
faas/internal/domain/models.go
Normal file
@ -0,0 +1,163 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// RuntimeType represents supported function runtimes
|
||||
type RuntimeType string
|
||||
|
||||
const (
|
||||
RuntimeNodeJS18 RuntimeType = "nodejs18"
|
||||
RuntimePython39 RuntimeType = "python3.9"
|
||||
RuntimeGo120 RuntimeType = "go1.20"
|
||||
RuntimeCustom RuntimeType = "custom"
|
||||
)
|
||||
|
||||
// ExecutionStatus represents the status of function execution
|
||||
type ExecutionStatus string
|
||||
|
||||
const (
|
||||
StatusPending ExecutionStatus = "pending"
|
||||
StatusRunning ExecutionStatus = "running"
|
||||
StatusCompleted ExecutionStatus = "completed"
|
||||
StatusFailed ExecutionStatus = "failed"
|
||||
StatusTimeout ExecutionStatus = "timeout"
|
||||
StatusCanceled ExecutionStatus = "canceled"
|
||||
)
|
||||
|
||||
// OwnerType represents the type of owner
|
||||
type OwnerType string
|
||||
|
||||
const (
|
||||
OwnerTypeIndividual OwnerType = "individual"
|
||||
OwnerTypeTeam OwnerType = "team"
|
||||
)
|
||||
|
||||
// Owner represents ownership information
|
||||
type Owner struct {
|
||||
Type OwnerType `json:"type" validate:"required,oneof=individual team"`
|
||||
Name string `json:"name" validate:"required,min=1,max=255"`
|
||||
Owner string `json:"owner" validate:"required,min=1,max=255"`
|
||||
}
|
||||
|
||||
// FunctionDefinition represents a serverless function
|
||||
type FunctionDefinition struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
Name string `json:"name" validate:"required,min=1,max=255" db:"name"`
|
||||
AppID string `json:"app_id" validate:"required" db:"app_id"`
|
||||
Runtime RuntimeType `json:"runtime" validate:"required" db:"runtime"`
|
||||
Image string `json:"image" validate:"required" db:"image"`
|
||||
Handler string `json:"handler" validate:"required" db:"handler"`
|
||||
Code string `json:"code,omitempty" db:"code"`
|
||||
Environment map[string]string `json:"environment,omitempty" db:"environment"`
|
||||
Timeout Duration `json:"timeout" validate:"required" db:"timeout"`
|
||||
Memory int `json:"memory" validate:"required,min=64,max=3008" db:"memory"`
|
||||
Owner Owner `json:"owner" validate:"required"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
}
|
||||
|
||||
// FunctionExecution represents a function execution
|
||||
type FunctionExecution struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
FunctionID uuid.UUID `json:"function_id" db:"function_id"`
|
||||
Status ExecutionStatus `json:"status" db:"status"`
|
||||
Input json.RawMessage `json:"input,omitempty" db:"input"`
|
||||
Output json.RawMessage `json:"output,omitempty" db:"output"`
|
||||
Error string `json:"error,omitempty" db:"error"`
|
||||
Duration time.Duration `json:"duration" db:"duration"`
|
||||
MemoryUsed int `json:"memory_used" db:"memory_used"`
|
||||
ContainerID string `json:"container_id,omitempty" db:"container_id"`
|
||||
ExecutorID string `json:"executor_id" db:"executor_id"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
StartedAt *time.Time `json:"started_at,omitempty" db:"started_at"`
|
||||
CompletedAt *time.Time `json:"completed_at,omitempty" db:"completed_at"`
|
||||
}
|
||||
|
||||
// CreateFunctionRequest represents a request to create a new function
|
||||
type CreateFunctionRequest struct {
|
||||
Name string `json:"name" validate:"required,min=1,max=255"`
|
||||
AppID string `json:"app_id" validate:"required"`
|
||||
Runtime RuntimeType `json:"runtime" validate:"required"`
|
||||
Image string `json:"image" validate:"required"`
|
||||
Handler string `json:"handler" validate:"required"`
|
||||
Code string `json:"code,omitempty"`
|
||||
Environment map[string]string `json:"environment,omitempty"`
|
||||
Timeout Duration `json:"timeout" validate:"required"`
|
||||
Memory int `json:"memory" validate:"required,min=64,max=3008"`
|
||||
Owner Owner `json:"owner" validate:"required"`
|
||||
}
|
||||
|
||||
// UpdateFunctionRequest represents a request to update an existing function
|
||||
type UpdateFunctionRequest struct {
|
||||
Name *string `json:"name,omitempty" validate:"omitempty,min=1,max=255"`
|
||||
Runtime *RuntimeType `json:"runtime,omitempty"`
|
||||
Image *string `json:"image,omitempty"`
|
||||
Handler *string `json:"handler,omitempty"`
|
||||
Code *string `json:"code,omitempty"`
|
||||
Environment map[string]string `json:"environment,omitempty"`
|
||||
Timeout *Duration `json:"timeout,omitempty"`
|
||||
Memory *int `json:"memory,omitempty" validate:"omitempty,min=64,max=3008"`
|
||||
Owner *Owner `json:"owner,omitempty"`
|
||||
}
|
||||
|
||||
// ExecuteFunctionRequest represents a request to execute a function
|
||||
type ExecuteFunctionRequest struct {
|
||||
FunctionID uuid.UUID `json:"function_id" validate:"required"`
|
||||
Input json.RawMessage `json:"input,omitempty"`
|
||||
Async bool `json:"async,omitempty"`
|
||||
}
|
||||
|
||||
// ExecuteFunctionResponse represents a response for function execution
|
||||
type ExecuteFunctionResponse struct {
|
||||
ExecutionID uuid.UUID `json:"execution_id"`
|
||||
Status ExecutionStatus `json:"status"`
|
||||
Output json.RawMessage `json:"output,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Duration time.Duration `json:"duration,omitempty"`
|
||||
MemoryUsed int `json:"memory_used,omitempty"`
|
||||
}
|
||||
|
||||
// DeployFunctionRequest represents a request to deploy a function
|
||||
type DeployFunctionRequest struct {
|
||||
FunctionID uuid.UUID `json:"function_id" validate:"required"`
|
||||
Force bool `json:"force,omitempty"`
|
||||
}
|
||||
|
||||
// DeployFunctionResponse represents a response for function deployment
|
||||
type DeployFunctionResponse struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Image string `json:"image,omitempty"`
|
||||
ImageID string `json:"image_id,omitempty"`
|
||||
}
|
||||
|
||||
// RuntimeInfo represents runtime information
|
||||
type RuntimeInfo struct {
|
||||
Type RuntimeType `json:"type"`
|
||||
Version string `json:"version"`
|
||||
Available bool `json:"available"`
|
||||
DefaultImage string `json:"default_image"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// ExecutionResult contains function execution results
|
||||
type ExecutionResult struct {
|
||||
Output json.RawMessage `json:"output,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Duration time.Duration `json:"duration"`
|
||||
MemoryUsed int `json:"memory_used"`
|
||||
Logs []string `json:"logs,omitempty"`
|
||||
}
|
||||
|
||||
// AuthContext represents the authentication context for a request
|
||||
type AuthContext struct {
|
||||
UserID string `json:"user_id"`
|
||||
AppID string `json:"app_id"`
|
||||
Permissions []string `json:"permissions"`
|
||||
Claims map[string]string `json:"claims"`
|
||||
}
|
||||
70
faas/internal/domain/runtime_config.go
Normal file
70
faas/internal/domain/runtime_config.go
Normal file
@ -0,0 +1,70 @@
|
||||
package domain
|
||||
|
||||
// RuntimeConfig defines the configuration for each runtime
|
||||
type RuntimeConfig struct {
|
||||
Name string `json:"name"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Image string `json:"image"`
|
||||
Handler string `json:"default_handler"`
|
||||
Extensions []string `json:"file_extensions"`
|
||||
Environment map[string]string `json:"default_environment"`
|
||||
}
|
||||
|
||||
// GetRuntimeConfigs returns the available runtime configurations
|
||||
func GetRuntimeConfigs() map[RuntimeType]RuntimeConfig {
|
||||
return map[RuntimeType]RuntimeConfig{
|
||||
"nodejs18": {
|
||||
Name: "nodejs18",
|
||||
DisplayName: "Node.js 18.x",
|
||||
Image: "node:18-alpine",
|
||||
Handler: "index.handler",
|
||||
Extensions: []string{".js", ".mjs", ".ts"},
|
||||
Environment: map[string]string{
|
||||
"NODE_ENV": "production",
|
||||
},
|
||||
},
|
||||
"python3.9": {
|
||||
Name: "python3.9",
|
||||
DisplayName: "Python 3.9",
|
||||
Image: "python:3.9-alpine",
|
||||
Handler: "main.handler",
|
||||
Extensions: []string{".py"},
|
||||
Environment: map[string]string{
|
||||
"PYTHONPATH": "/app",
|
||||
},
|
||||
},
|
||||
"go1.20": {
|
||||
Name: "go1.20",
|
||||
DisplayName: "Go 1.20",
|
||||
Image: "golang:1.20-alpine",
|
||||
Handler: "main.Handler",
|
||||
Extensions: []string{".go"},
|
||||
Environment: map[string]string{
|
||||
"CGO_ENABLED": "0",
|
||||
"GOOS": "linux",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetRuntimeConfig returns the configuration for a specific runtime
|
||||
func GetRuntimeConfig(runtime RuntimeType) (RuntimeConfig, bool) {
|
||||
configs := GetRuntimeConfigs()
|
||||
config, exists := configs[runtime]
|
||||
return config, exists
|
||||
}
|
||||
|
||||
// GetAvailableRuntimes returns a list of available runtimes for the frontend
|
||||
func GetAvailableRuntimes() []map[string]string {
|
||||
configs := GetRuntimeConfigs()
|
||||
var runtimes []map[string]string
|
||||
|
||||
for _, config := range configs {
|
||||
runtimes = append(runtimes, map[string]string{
|
||||
"value": config.Name,
|
||||
"label": config.DisplayName,
|
||||
})
|
||||
}
|
||||
|
||||
return runtimes
|
||||
}
|
||||
Reference in New Issue
Block a user