mirror of
https://github.com/oarkflow/mq.git
synced 2025-10-08 01:10:09 +08:00
update
This commit is contained in:
854
workflow/json-engine/engine.go
Normal file
854
workflow/json-engine/engine.go
Normal file
@@ -0,0 +1,854 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
htmlTemplate "text/template"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||
"github.com/gofiber/fiber/v2/middleware/recover"
|
||||
)
|
||||
|
||||
// NewJSONEngine creates a new JSON-driven workflow engine
|
||||
func NewJSONEngine() *JSONEngine {
|
||||
return &JSONEngine{
|
||||
templates: make(map[string]*Template),
|
||||
workflows: make(map[string]*Workflow),
|
||||
functions: make(map[string]*Function),
|
||||
validators: make(map[string]*Validator),
|
||||
middleware: make(map[string]*Middleware),
|
||||
data: make(map[string]interface{}),
|
||||
}
|
||||
}
|
||||
|
||||
// LoadConfiguration loads and parses JSON configuration
|
||||
func (e *JSONEngine) LoadConfiguration(configPath string) error {
|
||||
data, err := ioutil.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read config file: %v", err)
|
||||
}
|
||||
|
||||
var config AppConfiguration
|
||||
if err := json.Unmarshal(data, &config); err != nil {
|
||||
return fmt.Errorf("failed to parse JSON config: %v", err)
|
||||
}
|
||||
|
||||
e.config = &config
|
||||
return nil
|
||||
}
|
||||
|
||||
// Compile compiles the JSON configuration into executable components
|
||||
func (e *JSONEngine) Compile() error {
|
||||
log.Println("🔨 Compiling JSON configuration...")
|
||||
|
||||
// 1. Compile templates
|
||||
if err := e.compileTemplates(); err != nil {
|
||||
return fmt.Errorf("template compilation failed: %v", err)
|
||||
}
|
||||
|
||||
// 2. Compile functions
|
||||
if err := e.compileFunctions(); err != nil {
|
||||
return fmt.Errorf("function compilation failed: %v", err)
|
||||
}
|
||||
|
||||
// 3. Compile validators
|
||||
if err := e.compileValidators(); err != nil {
|
||||
return fmt.Errorf("validator compilation failed: %v", err)
|
||||
}
|
||||
|
||||
// 4. Compile workflows
|
||||
if err := e.compileWorkflows(); err != nil {
|
||||
return fmt.Errorf("workflow compilation failed: %v", err)
|
||||
}
|
||||
|
||||
// 5. Compile middleware
|
||||
if err := e.compileMiddleware(); err != nil {
|
||||
return fmt.Errorf("middleware compilation failed: %v", err)
|
||||
}
|
||||
|
||||
// 6. Store global data
|
||||
e.data = e.config.Data
|
||||
|
||||
log.Println("✅ JSON configuration compiled successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start starts the HTTP server with compiled configuration
|
||||
func (e *JSONEngine) Start() error {
|
||||
// Create Fiber app
|
||||
e.app = fiber.New(fiber.Config{
|
||||
AppName: e.config.App.Name,
|
||||
})
|
||||
|
||||
// Add default middleware
|
||||
e.app.Use(cors.New())
|
||||
e.app.Use(logger.New())
|
||||
e.app.Use(recover.New())
|
||||
|
||||
// Setup middleware
|
||||
if err := e.setupMiddleware(); err != nil {
|
||||
return fmt.Errorf("middleware setup failed: %v", err)
|
||||
}
|
||||
|
||||
// Setup routes
|
||||
if err := e.setupRoutes(); err != nil {
|
||||
return fmt.Errorf("route setup failed: %v", err)
|
||||
}
|
||||
|
||||
// Start server
|
||||
host := e.config.App.Host
|
||||
if host == "" {
|
||||
host = "localhost"
|
||||
}
|
||||
port := e.config.App.Port
|
||||
if port == "" {
|
||||
port = "3000"
|
||||
}
|
||||
|
||||
address := host + ":" + port
|
||||
log.Printf("🚀 %s started on http://%s", e.config.App.Name, address)
|
||||
log.Printf("📖 Description: %s", e.config.App.Description)
|
||||
log.Printf("🔢 Version: %s", e.config.App.Version)
|
||||
|
||||
return e.app.Listen(":" + port)
|
||||
}
|
||||
|
||||
// compileTemplates compiles all HTML templates
|
||||
func (e *JSONEngine) compileTemplates() error {
|
||||
for id, templateConfig := range e.config.Templates {
|
||||
log.Printf("Compiling template: %s", id)
|
||||
|
||||
// Create template
|
||||
tmpl, err := htmlTemplate.New(id).Parse(templateConfig.Template)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse template %s: %v", id, err)
|
||||
}
|
||||
|
||||
e.templates[id] = &Template{
|
||||
ID: id,
|
||||
Config: templateConfig,
|
||||
Compiled: tmpl,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// compileFunctions compiles all function definitions
|
||||
func (e *JSONEngine) compileFunctions() error {
|
||||
for id, functionConfig := range e.config.Functions {
|
||||
log.Printf("Compiling function: %s", id)
|
||||
|
||||
function := &Function{
|
||||
ID: id,
|
||||
Config: functionConfig,
|
||||
}
|
||||
|
||||
// Compile function based on type
|
||||
switch functionConfig.Type {
|
||||
case "http":
|
||||
function.Handler = e.createHTTPFunction(functionConfig)
|
||||
case "expression":
|
||||
function.Handler = e.createExpressionFunction(functionConfig)
|
||||
case "template":
|
||||
function.Handler = e.createTemplateFunction(functionConfig)
|
||||
case "js":
|
||||
function.Handler = e.createJSFunction(functionConfig)
|
||||
default:
|
||||
return fmt.Errorf("unknown function type: %s", functionConfig.Type)
|
||||
}
|
||||
|
||||
e.functions[id] = function
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// compileValidators compiles all validators
|
||||
func (e *JSONEngine) compileValidators() error {
|
||||
for id, validatorConfig := range e.config.Validators {
|
||||
log.Printf("Compiling validator: %s", id)
|
||||
|
||||
e.validators[id] = &Validator{
|
||||
ID: id,
|
||||
Config: validatorConfig,
|
||||
Rules: validatorConfig.Rules,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// compileWorkflows compiles all workflows
|
||||
func (e *JSONEngine) compileWorkflows() error {
|
||||
for _, workflowConfig := range e.config.Workflows {
|
||||
log.Printf("Compiling workflow: %s", workflowConfig.ID)
|
||||
|
||||
workflow := &Workflow{
|
||||
ID: workflowConfig.ID,
|
||||
Config: workflowConfig,
|
||||
Nodes: make(map[string]*Node),
|
||||
Edges: make([]*Edge, 0),
|
||||
Runtime: &WorkflowRuntime{
|
||||
Context: make(map[string]interface{}),
|
||||
Variables: workflowConfig.Variables,
|
||||
Status: "ready",
|
||||
},
|
||||
}
|
||||
|
||||
// Compile nodes
|
||||
for _, nodeConfig := range workflowConfig.Nodes {
|
||||
node := &Node{
|
||||
ID: nodeConfig.ID,
|
||||
Config: nodeConfig,
|
||||
Inputs: make(map[string]interface{}),
|
||||
Outputs: make(map[string]interface{}),
|
||||
}
|
||||
|
||||
// Link function if specified
|
||||
if nodeConfig.Function != "" {
|
||||
if function, exists := e.functions[nodeConfig.Function]; exists {
|
||||
node.Function = function
|
||||
}
|
||||
}
|
||||
|
||||
workflow.Nodes[nodeConfig.ID] = node
|
||||
}
|
||||
|
||||
// Compile edges
|
||||
for _, edgeConfig := range workflowConfig.Edges {
|
||||
edge := &Edge{
|
||||
ID: edgeConfig.ID,
|
||||
Config: edgeConfig,
|
||||
From: workflow.Nodes[edgeConfig.From],
|
||||
To: workflow.Nodes[edgeConfig.To],
|
||||
}
|
||||
workflow.Edges = append(workflow.Edges, edge)
|
||||
}
|
||||
|
||||
e.workflows[workflowConfig.ID] = workflow
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// compileMiddleware compiles all middleware
|
||||
func (e *JSONEngine) compileMiddleware() error {
|
||||
for _, middlewareConfig := range e.config.Middleware {
|
||||
if !middlewareConfig.Enabled {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("Compiling middleware: %s", middlewareConfig.ID)
|
||||
|
||||
middleware := &Middleware{
|
||||
ID: middlewareConfig.ID,
|
||||
Config: middlewareConfig,
|
||||
}
|
||||
|
||||
// Create middleware handler based on type
|
||||
switch middlewareConfig.Type {
|
||||
case "auth":
|
||||
middleware.Handler = e.createAuthMiddleware(middlewareConfig)
|
||||
case "logging":
|
||||
middleware.Handler = e.createLoggingMiddleware(middlewareConfig)
|
||||
case "ratelimit":
|
||||
middleware.Handler = e.createRateLimitMiddleware(middlewareConfig)
|
||||
case "custom":
|
||||
middleware.Handler = e.createCustomMiddleware(middlewareConfig)
|
||||
default:
|
||||
log.Printf("Unknown middleware type: %s", middlewareConfig.Type)
|
||||
continue
|
||||
}
|
||||
|
||||
e.middleware[middlewareConfig.ID] = middleware
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// setupMiddleware sets up middleware in the Fiber app
|
||||
func (e *JSONEngine) setupMiddleware() error {
|
||||
// Sort middleware by priority
|
||||
middlewares := make([]*Middleware, 0, len(e.middleware))
|
||||
for _, middleware := range e.middleware {
|
||||
middlewares = append(middlewares, middleware)
|
||||
}
|
||||
|
||||
// Simple priority sort (lower number = higher priority)
|
||||
for i := 0; i < len(middlewares)-1; i++ {
|
||||
for j := i + 1; j < len(middlewares); j++ {
|
||||
if middlewares[i].Config.Priority > middlewares[j].Config.Priority {
|
||||
middlewares[i], middlewares[j] = middlewares[j], middlewares[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply middleware
|
||||
for _, middleware := range middlewares {
|
||||
e.app.Use(middleware.Handler)
|
||||
log.Printf("Applied middleware: %s (priority: %d)", middleware.Config.Name, middleware.Config.Priority)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// setupRoutes sets up all routes from configuration
|
||||
func (e *JSONEngine) setupRoutes() error {
|
||||
for _, routeConfig := range e.config.Routes {
|
||||
log.Printf("Setting up route: %s %s", routeConfig.Method, routeConfig.Path)
|
||||
|
||||
handler := e.createRouteHandler(routeConfig)
|
||||
|
||||
// Apply route to Fiber app
|
||||
switch strings.ToUpper(routeConfig.Method) {
|
||||
case "GET":
|
||||
e.app.Get(routeConfig.Path, handler)
|
||||
case "POST":
|
||||
e.app.Post(routeConfig.Path, handler)
|
||||
case "PUT":
|
||||
e.app.Put(routeConfig.Path, handler)
|
||||
case "DELETE":
|
||||
e.app.Delete(routeConfig.Path, handler)
|
||||
case "PATCH":
|
||||
e.app.Patch(routeConfig.Path, handler)
|
||||
default:
|
||||
return fmt.Errorf("unsupported HTTP method: %s", routeConfig.Method)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// createRouteHandler creates a Fiber handler for a route configuration
|
||||
func (e *JSONEngine) createRouteHandler(routeConfig RouteConfig) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
log.Printf("Handler called for route: %s %s", routeConfig.Method, routeConfig.Path)
|
||||
|
||||
// Create execution context
|
||||
ctx := &ExecutionContext{
|
||||
Request: c,
|
||||
Data: make(map[string]interface{}),
|
||||
Variables: make(map[string]interface{}),
|
||||
Session: make(map[string]interface{}),
|
||||
User: make(map[string]interface{}),
|
||||
Functions: e.functions,
|
||||
Validators: e.validators,
|
||||
}
|
||||
|
||||
// Apply route middleware - skip auth middleware as we handle it below
|
||||
for _, middlewareID := range routeConfig.Middleware {
|
||||
if middlewareID == "auth" {
|
||||
continue // Skip auth middleware, handle it in route
|
||||
}
|
||||
if middleware, exists := e.middleware[middlewareID]; exists {
|
||||
if err := middleware.Handler(c); err != nil {
|
||||
log.Printf("Middleware %s failed: %v", middlewareID, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check authentication if required
|
||||
if routeConfig.Auth != nil && routeConfig.Auth.Required {
|
||||
if err := e.checkAuthentication(ctx, routeConfig.Auth); err != nil {
|
||||
if routeConfig.Auth.Redirect != "" {
|
||||
return c.Redirect(routeConfig.Auth.Redirect)
|
||||
}
|
||||
return c.Status(401).JSON(fiber.Map{"error": "Authentication required"})
|
||||
}
|
||||
}
|
||||
|
||||
// Execute handler based on type
|
||||
switch routeConfig.Handler.Type {
|
||||
case "template":
|
||||
return e.handleTemplate(ctx, routeConfig)
|
||||
case "workflow":
|
||||
return e.handleWorkflow(ctx, routeConfig)
|
||||
case "function":
|
||||
return e.handleFunction(ctx, routeConfig)
|
||||
case "redirect":
|
||||
return c.Redirect(routeConfig.Handler.Target)
|
||||
case "static":
|
||||
return e.handleStatic(ctx, routeConfig)
|
||||
default:
|
||||
return c.Status(500).JSON(fiber.Map{"error": "Unknown handler type: " + routeConfig.Handler.Type})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Template execution methods will be implemented next...
|
||||
func (e *JSONEngine) handleTemplate(ctx *ExecutionContext, routeConfig RouteConfig) error {
|
||||
templateID := routeConfig.Handler.Target
|
||||
template, exists := e.templates[templateID]
|
||||
if !exists {
|
||||
return ctx.Request.Status(404).JSON(fiber.Map{"error": "Template not found: " + templateID})
|
||||
}
|
||||
|
||||
// Prepare template data
|
||||
data := make(map[string]interface{})
|
||||
|
||||
// Add global data
|
||||
for k, v := range e.data {
|
||||
data[k] = v
|
||||
}
|
||||
|
||||
// Add template-specific data
|
||||
for k, v := range template.Config.Data {
|
||||
data[k] = v
|
||||
}
|
||||
|
||||
// Add input data from handler configuration
|
||||
for k, v := range routeConfig.Handler.Input {
|
||||
data[k] = v
|
||||
}
|
||||
|
||||
// Add request data
|
||||
data["request"] = map[string]interface{}{
|
||||
"method": ctx.Request.Method(),
|
||||
"path": ctx.Request.Path(),
|
||||
"query": ctx.Request.Queries(),
|
||||
"headers": ctx.Request.GetReqHeaders(),
|
||||
"body": string(ctx.Request.Body()),
|
||||
}
|
||||
|
||||
// Add context data
|
||||
data["user"] = ctx.User
|
||||
data["session"] = ctx.Session
|
||||
data["variables"] = ctx.Variables
|
||||
|
||||
// Execute template
|
||||
tmpl := template.Compiled.(*htmlTemplate.Template)
|
||||
var buf strings.Builder
|
||||
if err := tmpl.Execute(&buf, data); err != nil {
|
||||
return ctx.Request.Status(500).JSON(fiber.Map{"error": "Template execution failed: " + err.Error()})
|
||||
}
|
||||
|
||||
// Set response type
|
||||
contentType := "text/html; charset=utf-8"
|
||||
if template.Config.Type == "json" {
|
||||
contentType = "application/json"
|
||||
} else if template.Config.Type == "xml" {
|
||||
contentType = "application/xml"
|
||||
} else if template.Config.Type == "text" {
|
||||
contentType = "text/plain"
|
||||
}
|
||||
|
||||
ctx.Request.Set("Content-Type", contentType)
|
||||
return ctx.Request.Send([]byte(buf.String()))
|
||||
}
|
||||
|
||||
func (e *JSONEngine) handleWorkflow(ctx *ExecutionContext, routeConfig RouteConfig) error {
|
||||
workflowID := routeConfig.Handler.Target
|
||||
log.Printf("Looking for workflow: %s", workflowID)
|
||||
log.Printf("Available workflows: %v", func() []string {
|
||||
keys := make([]string, 0, len(e.workflows))
|
||||
for k := range e.workflows {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return keys
|
||||
}())
|
||||
|
||||
workflow, exists := e.workflows[workflowID]
|
||||
if !exists {
|
||||
return ctx.Request.Status(404).JSON(fiber.Map{"error": "Workflow not found: " + workflowID})
|
||||
}
|
||||
|
||||
// Execute workflow
|
||||
result, err := e.executeWorkflow(ctx, workflow, routeConfig.Handler.Input)
|
||||
if err != nil {
|
||||
return ctx.Request.Status(500).JSON(fiber.Map{"error": "Workflow execution failed: " + err.Error()})
|
||||
}
|
||||
|
||||
// Return result based on response configuration
|
||||
if routeConfig.Response.Type == "json" {
|
||||
return ctx.Request.JSON(result)
|
||||
} else if routeConfig.Response.Type == "html" && routeConfig.Response.Template != "" {
|
||||
// Render result using template
|
||||
template, exists := e.templates[routeConfig.Response.Template]
|
||||
if !exists {
|
||||
return ctx.Request.Status(500).JSON(fiber.Map{"error": "Response template not found"})
|
||||
}
|
||||
|
||||
tmpl := template.Compiled.(*htmlTemplate.Template)
|
||||
var buf strings.Builder
|
||||
if err := tmpl.Execute(&buf, result); err != nil {
|
||||
return ctx.Request.Status(500).JSON(fiber.Map{"error": "Response template execution failed"})
|
||||
}
|
||||
|
||||
return ctx.Request.Type("text/html").Send([]byte(buf.String()))
|
||||
}
|
||||
|
||||
return ctx.Request.JSON(result)
|
||||
}
|
||||
|
||||
func (e *JSONEngine) handleFunction(ctx *ExecutionContext, routeConfig RouteConfig) error {
|
||||
functionID := routeConfig.Handler.Target
|
||||
|
||||
// Handle special built-in functions
|
||||
switch functionID {
|
||||
case "authenticate_user":
|
||||
return e.handleAuthFunction(ctx)
|
||||
default:
|
||||
function, exists := e.functions[functionID]
|
||||
if !exists {
|
||||
return ctx.Request.Status(404).JSON(fiber.Map{"error": "Function not found: " + functionID})
|
||||
}
|
||||
|
||||
// Execute function
|
||||
result, err := e.executeFunction(ctx, function, routeConfig.Handler.Input)
|
||||
if err != nil {
|
||||
return ctx.Request.Status(500).JSON(fiber.Map{"error": "Function execution failed: " + err.Error()})
|
||||
}
|
||||
|
||||
return ctx.Request.JSON(result)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *JSONEngine) handleStatic(ctx *ExecutionContext, routeConfig RouteConfig) error {
|
||||
// Serve static content
|
||||
return ctx.Request.SendFile(routeConfig.Handler.Target)
|
||||
}
|
||||
|
||||
// handleAuthFunction handles user authentication
|
||||
func (e *JSONEngine) handleAuthFunction(ctx *ExecutionContext) error {
|
||||
var credentials struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
if err := ctx.Request.BodyParser(&credentials); err != nil {
|
||||
return ctx.Request.Status(400).JSON(fiber.Map{"error": "Invalid request body"})
|
||||
}
|
||||
|
||||
// Simple authentication using demo users from data
|
||||
demoUsers, ok := e.data["demo_users"].([]interface{})
|
||||
if !ok {
|
||||
return ctx.Request.Status(500).JSON(fiber.Map{"error": "User data not configured"})
|
||||
}
|
||||
|
||||
for _, userInterface := range demoUsers {
|
||||
user, ok := userInterface.(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
username, _ := user["username"].(string)
|
||||
password, _ := user["password"].(string)
|
||||
role, _ := user["role"].(string)
|
||||
|
||||
if username == credentials.Username && password == credentials.Password {
|
||||
// Generate simple token (in production, use JWT)
|
||||
token := fmt.Sprintf("token_%s_%d", username, time.Now().Unix())
|
||||
|
||||
return ctx.Request.JSON(fiber.Map{
|
||||
"success": true,
|
||||
"token": token,
|
||||
"user": map[string]interface{}{
|
||||
"username": username,
|
||||
"role": role,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return ctx.Request.Status(401).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"error": "Invalid credentials",
|
||||
})
|
||||
}
|
||||
|
||||
// Utility methods for creating different types of handlers and middleware
|
||||
func (e *JSONEngine) checkAuthentication(ctx *ExecutionContext, auth *AuthConfig) error {
|
||||
// Simple session-based authentication for demo
|
||||
if auth.Type == "session" {
|
||||
token := ctx.Request.Get("Authorization")
|
||||
if token == "" {
|
||||
// Check for token in query params or body
|
||||
token = ctx.Request.Query("token")
|
||||
}
|
||||
if token == "" && ctx.Request.Method() == "POST" {
|
||||
var body map[string]interface{}
|
||||
if err := ctx.Request.BodyParser(&body); err == nil {
|
||||
if t, ok := body["token"].(string); ok {
|
||||
token = t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if token == "" {
|
||||
return fmt.Errorf("no authentication token provided")
|
||||
}
|
||||
|
||||
// Simple token validation (in real app, validate JWT or session)
|
||||
ctx.User = map[string]interface{}{
|
||||
"id": "user_" + token,
|
||||
"username": "demo_user",
|
||||
"role": "user",
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Function executors
|
||||
func (e *JSONEngine) createHTTPFunction(config FunctionConfig) interface{} {
|
||||
return func(ctx *ExecutionContext, input map[string]interface{}) (map[string]interface{}, error) {
|
||||
client := &http.Client{Timeout: 30 * time.Second}
|
||||
|
||||
method := config.Method
|
||||
if method == "" {
|
||||
method = "GET"
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, config.URL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Add headers
|
||||
for k, v := range config.Headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result map[string]interface{}
|
||||
if err := json.Unmarshal(body, &result); err != nil {
|
||||
// If not JSON, return as string
|
||||
result = map[string]interface{}{
|
||||
"status": resp.StatusCode,
|
||||
"body": string(body),
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (e *JSONEngine) createExpressionFunction(config FunctionConfig) interface{} {
|
||||
return func(ctx *ExecutionContext, input map[string]interface{}) (map[string]interface{}, error) {
|
||||
// Simple expression evaluation (would use a proper expression engine in production)
|
||||
result := map[string]interface{}{
|
||||
"result": config.Code, // Placeholder
|
||||
"input": input,
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (e *JSONEngine) createTemplateFunction(config FunctionConfig) interface{} {
|
||||
return func(ctx *ExecutionContext, input map[string]interface{}) (map[string]interface{}, error) {
|
||||
tmpl, err := htmlTemplate.New("function").Parse(config.Code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var buf strings.Builder
|
||||
if err := tmpl.Execute(&buf, input); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"result": buf.String(),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (e *JSONEngine) createJSFunction(config FunctionConfig) interface{} {
|
||||
return func(ctx *ExecutionContext, input map[string]interface{}) (map[string]interface{}, error) {
|
||||
// Placeholder for JavaScript execution (would use goja or similar in production)
|
||||
return map[string]interface{}{
|
||||
"result": "JavaScript execution not implemented in demo",
|
||||
"code": config.Code,
|
||||
"input": input,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Middleware creators
|
||||
func (e *JSONEngine) createAuthMiddleware(config MiddlewareConfig) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
// Simple auth middleware
|
||||
if config.Config["skip_paths"] != nil {
|
||||
skipPaths := config.Config["skip_paths"].([]interface{})
|
||||
for _, path := range skipPaths {
|
||||
if c.Path() == path.(string) {
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
}
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func (e *JSONEngine) createLoggingMiddleware(config MiddlewareConfig) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
start := time.Now()
|
||||
err := c.Next()
|
||||
log.Printf("[%s] %s %s - %v", config.Name, c.Method(), c.Path(), time.Since(start))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (e *JSONEngine) createRateLimitMiddleware(config MiddlewareConfig) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
// Simple rate limiting placeholder
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func (e *JSONEngine) createCustomMiddleware(config MiddlewareConfig) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
// Execute custom functions if specified
|
||||
for _, functionID := range config.Functions {
|
||||
if function, exists := e.functions[functionID]; exists {
|
||||
ctx := &ExecutionContext{Request: c}
|
||||
_, err := e.executeFunction(ctx, function, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// Workflow execution
|
||||
func (e *JSONEngine) executeWorkflow(ctx *ExecutionContext, workflow *Workflow, input map[string]interface{}) (map[string]interface{}, error) {
|
||||
ctx.Workflow = workflow
|
||||
|
||||
// Initialize workflow context
|
||||
workflowCtx := make(map[string]interface{})
|
||||
for k, v := range input {
|
||||
workflowCtx[k] = v
|
||||
}
|
||||
for k, v := range workflow.Runtime.Variables {
|
||||
workflowCtx[k] = v
|
||||
}
|
||||
|
||||
// Simple sequential execution (in production, would handle parallel execution, conditions, etc.)
|
||||
result := make(map[string]interface{})
|
||||
|
||||
for _, node := range workflow.Nodes {
|
||||
ctx.Node = node
|
||||
nodeResult, err := e.executeNode(ctx, node, workflowCtx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("node %s failed: %v", node.ID, err)
|
||||
}
|
||||
|
||||
// Merge results
|
||||
for k, v := range nodeResult {
|
||||
result[k] = v
|
||||
workflowCtx[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (e *JSONEngine) executeNode(ctx *ExecutionContext, node *Node, input map[string]interface{}) (map[string]interface{}, error) {
|
||||
switch node.Config.Type {
|
||||
case "function":
|
||||
if node.Function != nil {
|
||||
return e.executeFunction(ctx, node.Function, input)
|
||||
}
|
||||
return map[string]interface{}{}, nil
|
||||
|
||||
case "http":
|
||||
url := node.Config.Config["url"].(string)
|
||||
method := "GET"
|
||||
if m, ok := node.Config.Config["method"].(string); ok {
|
||||
method = m
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 30 * time.Second}
|
||||
req, err := http.NewRequest(method, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"status": resp.StatusCode,
|
||||
"body": string(body),
|
||||
}, nil
|
||||
|
||||
case "template":
|
||||
templateID := node.Config.Config["template"].(string)
|
||||
template, exists := e.templates[templateID]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("template not found: %s", templateID)
|
||||
}
|
||||
|
||||
tmpl := template.Compiled.(*htmlTemplate.Template)
|
||||
var buf strings.Builder
|
||||
if err := tmpl.Execute(&buf, input); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"output": buf.String(),
|
||||
}, nil
|
||||
|
||||
case "validator":
|
||||
validatorID := node.Config.Config["validator"].(string)
|
||||
validator, exists := e.validators[validatorID]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("validator not found: %s", validatorID)
|
||||
}
|
||||
|
||||
// Simple validation
|
||||
field := validator.Config.Field
|
||||
if value, ok := input[field]; ok {
|
||||
for _, rule := range validator.Rules {
|
||||
if rule.Type == "required" && value == nil {
|
||||
return nil, fmt.Errorf("validation failed: %s", rule.Message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"valid": true,
|
||||
}, nil
|
||||
|
||||
default:
|
||||
return map[string]interface{}{
|
||||
"node_type": node.Config.Type,
|
||||
"input": input,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (e *JSONEngine) executeFunction(ctx *ExecutionContext, function *Function, input map[string]interface{}) (map[string]interface{}, error) {
|
||||
if function.Handler == nil {
|
||||
return nil, fmt.Errorf("function handler not compiled")
|
||||
}
|
||||
|
||||
switch handler := function.Handler.(type) {
|
||||
case func(*ExecutionContext, map[string]interface{}) (map[string]interface{}, error):
|
||||
return handler(ctx, input)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown function handler type")
|
||||
}
|
||||
}
|
19
workflow/json-engine/go.mod
Normal file
19
workflow/json-engine/go.mod
Normal file
@@ -0,0 +1,19 @@
|
||||
module json-sms-engine
|
||||
|
||||
go 1.21
|
||||
|
||||
require github.com/gofiber/fiber/v2 v2.52.9
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.51.0 // indirect
|
||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
)
|
27
workflow/json-engine/go.sum
Normal file
27
workflow/json-engine/go.sum
Normal file
@@ -0,0 +1,27 @@
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/gofiber/fiber/v2 v2.52.9 h1:YjKl5DOiyP3j0mO61u3NTmK7or8GzzWzCFzkboyP5cw=
|
||||
github.com/gofiber/fiber/v2 v2.52.9/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
|
||||
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
|
||||
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
32
workflow/json-engine/main.go
Normal file
32
workflow/json-engine/main.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Check for config file argument
|
||||
configPath := "sms-app.json"
|
||||
if len(os.Args) > 1 {
|
||||
configPath = os.Args[1]
|
||||
}
|
||||
|
||||
// Create JSON engine
|
||||
engine := NewJSONEngine()
|
||||
|
||||
// Load configuration
|
||||
if err := engine.LoadConfiguration(configPath); err != nil {
|
||||
log.Fatalf("Failed to load configuration: %v", err)
|
||||
}
|
||||
|
||||
// Compile configuration
|
||||
if err := engine.Compile(); err != nil {
|
||||
log.Fatalf("Failed to compile configuration: %v", err)
|
||||
}
|
||||
|
||||
// Start server
|
||||
if err := engine.Start(); err != nil {
|
||||
log.Fatalf("Failed to start server: %v", err)
|
||||
}
|
||||
}
|
327
workflow/json-engine/sms-app.json
Normal file
327
workflow/json-engine/sms-app.json
Normal file
File diff suppressed because one or more lines are too long
BIN
workflow/json-engine/sms-json-engine
Executable file
BIN
workflow/json-engine/sms-json-engine
Executable file
Binary file not shown.
304
workflow/json-engine/types.go
Normal file
304
workflow/json-engine/types.go
Normal file
@@ -0,0 +1,304 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// AppConfiguration represents the complete JSON configuration for an application
|
||||
type AppConfiguration struct {
|
||||
App AppMetadata `json:"app"`
|
||||
Routes []RouteConfig `json:"routes"`
|
||||
Middleware []MiddlewareConfig `json:"middleware"`
|
||||
Templates map[string]TemplateConfig `json:"templates"`
|
||||
Workflows []WorkflowConfig `json:"workflows"`
|
||||
Data map[string]interface{} `json:"data"`
|
||||
Functions map[string]FunctionConfig `json:"functions"`
|
||||
Validators map[string]ValidatorConfig `json:"validators"`
|
||||
}
|
||||
|
||||
// AppMetadata contains basic app information
|
||||
type AppMetadata struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Description string `json:"description"`
|
||||
Port string `json:"port"`
|
||||
Host string `json:"host"`
|
||||
}
|
||||
|
||||
// RouteConfig defines HTTP routes
|
||||
type RouteConfig struct {
|
||||
ID string `json:"id"`
|
||||
Method string `json:"method"`
|
||||
Path string `json:"path"`
|
||||
Description string `json:"description"`
|
||||
Middleware []string `json:"middleware"`
|
||||
Handler HandlerConfig `json:"handler"`
|
||||
Auth *AuthConfig `json:"auth,omitempty"`
|
||||
Response ResponseConfig `json:"response"`
|
||||
Parameters map[string]interface{} `json:"parameters,omitempty"`
|
||||
}
|
||||
|
||||
// HandlerConfig defines route handler behavior
|
||||
type HandlerConfig struct {
|
||||
Type string `json:"type"` // "template", "workflow", "function", "redirect", "static"
|
||||
Target string `json:"target"`
|
||||
Input map[string]interface{} `json:"input,omitempty"`
|
||||
Transform []TransformConfig `json:"transform,omitempty"`
|
||||
Conditions []ConditionConfig `json:"conditions,omitempty"`
|
||||
}
|
||||
|
||||
// MiddlewareConfig defines middleware behavior
|
||||
type MiddlewareConfig struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"` // "auth", "cors", "logging", "ratelimit", "custom"
|
||||
Priority int `json:"priority"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Config map[string]interface{} `json:"config"`
|
||||
Conditions []ConditionConfig `json:"conditions,omitempty"`
|
||||
Functions []string `json:"functions,omitempty"`
|
||||
}
|
||||
|
||||
// TemplateConfig defines HTML templates
|
||||
type TemplateConfig struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"` // "html", "json", "xml", "text"
|
||||
Template string `json:"template"`
|
||||
Layout string `json:"layout,omitempty"`
|
||||
Partials []string `json:"partials,omitempty"`
|
||||
Data map[string]interface{} `json:"data,omitempty"`
|
||||
Scripts []ScriptConfig `json:"scripts,omitempty"`
|
||||
Styles []StyleConfig `json:"styles,omitempty"`
|
||||
Components []ComponentConfig `json:"components,omitempty"`
|
||||
}
|
||||
|
||||
// WorkflowConfig defines workflow nodes and execution
|
||||
type WorkflowConfig struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Version string `json:"version"`
|
||||
Nodes []NodeConfig `json:"nodes"`
|
||||
Edges []EdgeConfig `json:"edges"`
|
||||
Variables map[string]interface{} `json:"variables"`
|
||||
Triggers []TriggerConfig `json:"triggers"`
|
||||
Options ExecutionOptions `json:"options"`
|
||||
}
|
||||
|
||||
// NodeConfig defines workflow node behavior
|
||||
type NodeConfig struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"` // "function", "http", "template", "validator", "transformer", "condition", "loop", "parallel"
|
||||
Description string `json:"description"`
|
||||
Function string `json:"function,omitempty"`
|
||||
Input map[string]interface{} `json:"input,omitempty"`
|
||||
Output map[string]interface{} `json:"output,omitempty"`
|
||||
Config map[string]interface{} `json:"config,omitempty"`
|
||||
Conditions []ConditionConfig `json:"conditions,omitempty"`
|
||||
Retry *RetryConfig `json:"retry,omitempty"`
|
||||
Timeout string `json:"timeout,omitempty"`
|
||||
}
|
||||
|
||||
// EdgeConfig defines connections between nodes
|
||||
type EdgeConfig struct {
|
||||
ID string `json:"id"`
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
Conditions []ConditionConfig `json:"conditions,omitempty"`
|
||||
Transform *TransformConfig `json:"transform,omitempty"`
|
||||
}
|
||||
|
||||
// FunctionConfig defines reusable functions
|
||||
type FunctionConfig struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"` // "js", "expression", "http", "sql", "template"
|
||||
Code string `json:"code,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Method string `json:"method,omitempty"`
|
||||
Headers map[string]string `json:"headers,omitempty"`
|
||||
Body string `json:"body,omitempty"`
|
||||
Query string `json:"query,omitempty"`
|
||||
Parameters map[string]interface{} `json:"parameters,omitempty"`
|
||||
Response ResponseConfig `json:"response,omitempty"`
|
||||
}
|
||||
|
||||
// ValidatorConfig defines validation rules
|
||||
type ValidatorConfig struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"` // "required", "email", "phone", "regex", "length", "range", "custom"
|
||||
Field string `json:"field"`
|
||||
Rules []ValidationRule `json:"rules"`
|
||||
Message string `json:"message"`
|
||||
Parameters map[string]interface{} `json:"parameters,omitempty"`
|
||||
}
|
||||
|
||||
// Supporting types
|
||||
type AuthConfig struct {
|
||||
Required bool `json:"required"`
|
||||
Type string `json:"type"` // "session", "token", "basic", "oauth"
|
||||
Provider string `json:"provider,omitempty"`
|
||||
Redirect string `json:"redirect,omitempty"`
|
||||
Permissions []string `json:"permissions,omitempty"`
|
||||
Config map[string]interface{} `json:"config,omitempty"`
|
||||
}
|
||||
|
||||
type ResponseConfig struct {
|
||||
Type string `json:"type"` // "json", "html", "redirect", "file", "stream"
|
||||
Template string `json:"template,omitempty"`
|
||||
Data map[string]interface{} `json:"data,omitempty"`
|
||||
Status int `json:"status,omitempty"`
|
||||
Headers map[string]string `json:"headers,omitempty"`
|
||||
ContentType string `json:"content_type,omitempty"`
|
||||
}
|
||||
|
||||
type TransformConfig struct {
|
||||
Type string `json:"type"` // "map", "filter", "reduce", "expression", "template"
|
||||
Expression string `json:"expression,omitempty"`
|
||||
Template string `json:"template,omitempty"`
|
||||
Source string `json:"source,omitempty"`
|
||||
Target string `json:"target,omitempty"`
|
||||
Function string `json:"function,omitempty"`
|
||||
Parameters map[string]interface{} `json:"parameters,omitempty"`
|
||||
}
|
||||
|
||||
type ConditionConfig struct {
|
||||
Type string `json:"type"` // "equals", "contains", "exists", "expression", "function"
|
||||
Field string `json:"field,omitempty"`
|
||||
Value interface{} `json:"value,omitempty"`
|
||||
Expression string `json:"expression,omitempty"`
|
||||
Function string `json:"function,omitempty"`
|
||||
Operator string `json:"operator,omitempty"` // "and", "or", "not"
|
||||
}
|
||||
|
||||
type ScriptConfig struct {
|
||||
Type string `json:"type"` // "inline", "file", "url"
|
||||
Content string `json:"content"`
|
||||
Src string `json:"src,omitempty"`
|
||||
}
|
||||
|
||||
type StyleConfig struct {
|
||||
Type string `json:"type"` // "inline", "file", "url"
|
||||
Content string `json:"content"`
|
||||
Href string `json:"href,omitempty"`
|
||||
}
|
||||
|
||||
type ComponentConfig struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Template string `json:"template"`
|
||||
Data map[string]interface{} `json:"data,omitempty"`
|
||||
Props map[string]interface{} `json:"props,omitempty"`
|
||||
}
|
||||
|
||||
type TriggerConfig struct {
|
||||
Type string `json:"type"` // "http", "schedule", "event", "webhook"
|
||||
Schedule string `json:"schedule,omitempty"`
|
||||
Event string `json:"event,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
Method string `json:"method,omitempty"`
|
||||
Conditions []ConditionConfig `json:"conditions,omitempty"`
|
||||
}
|
||||
|
||||
type ExecutionOptions struct {
|
||||
Async bool `json:"async"`
|
||||
Timeout string `json:"timeout,omitempty"`
|
||||
Retry *RetryConfig `json:"retry,omitempty"`
|
||||
Priority string `json:"priority,omitempty"`
|
||||
MaxNodes int `json:"max_nodes,omitempty"`
|
||||
}
|
||||
|
||||
type RetryConfig struct {
|
||||
MaxAttempts int `json:"max_attempts"`
|
||||
Delay string `json:"delay"`
|
||||
BackoffType string `json:"backoff_type"` // "fixed", "exponential", "linear"
|
||||
}
|
||||
|
||||
type ValidationRule struct {
|
||||
Type string `json:"type"`
|
||||
Value interface{} `json:"value,omitempty"`
|
||||
Message string `json:"message"`
|
||||
Parameters map[string]interface{} `json:"parameters,omitempty"`
|
||||
}
|
||||
|
||||
// Runtime types for the JSON engine
|
||||
type JSONEngine struct {
|
||||
app *fiber.App
|
||||
config *AppConfiguration
|
||||
templates map[string]*Template
|
||||
workflows map[string]*Workflow
|
||||
functions map[string]*Function
|
||||
validators map[string]*Validator
|
||||
middleware map[string]*Middleware
|
||||
data map[string]interface{}
|
||||
}
|
||||
|
||||
type Template struct {
|
||||
ID string
|
||||
Config TemplateConfig
|
||||
Compiled interface{}
|
||||
}
|
||||
|
||||
type Workflow struct {
|
||||
ID string
|
||||
Config WorkflowConfig
|
||||
Nodes map[string]*Node
|
||||
Edges []*Edge
|
||||
Runtime *WorkflowRuntime
|
||||
}
|
||||
|
||||
type Node struct {
|
||||
ID string
|
||||
Config NodeConfig
|
||||
Function *Function
|
||||
Inputs map[string]interface{}
|
||||
Outputs map[string]interface{}
|
||||
}
|
||||
|
||||
type Edge struct {
|
||||
ID string
|
||||
Config EdgeConfig
|
||||
From *Node
|
||||
To *Node
|
||||
}
|
||||
|
||||
type Function struct {
|
||||
ID string
|
||||
Config FunctionConfig
|
||||
Handler interface{}
|
||||
}
|
||||
|
||||
type Validator struct {
|
||||
ID string
|
||||
Config ValidatorConfig
|
||||
Rules []ValidationRule
|
||||
}
|
||||
|
||||
type Middleware struct {
|
||||
ID string
|
||||
Config MiddlewareConfig
|
||||
Handler fiber.Handler
|
||||
}
|
||||
|
||||
type WorkflowRuntime struct {
|
||||
Context map[string]interface{}
|
||||
Variables map[string]interface{}
|
||||
Status string
|
||||
Error error
|
||||
}
|
||||
|
||||
// Execution context for runtime
|
||||
type ExecutionContext struct {
|
||||
Request *fiber.Ctx
|
||||
Data map[string]interface{}
|
||||
Variables map[string]interface{}
|
||||
Session map[string]interface{}
|
||||
User map[string]interface{}
|
||||
Workflow *Workflow
|
||||
Node *Node
|
||||
Functions map[string]*Function
|
||||
Validators map[string]*Validator
|
||||
}
|
Reference in New Issue
Block a user