Files
Yeuoly b6906f7eb5 feat: Generate HTTP server routes from template (#306)
* feat: Generate HTTP server routes from template

- Added a new file `http_server.gen.go` to automatically generate HTTP server routes based on defined dispatchers.
- Refactored existing route definitions in `http_server.go` to utilize the generated routes, improving maintainability.
- Introduced a code generation function in `generator.go` to create the HTTP server file, enhancing the plugin development workflow.
- Updated the template for HTTP server generation to streamline route creation for various controllers.

* fix: Update OAuth paths in PluginDispatchers for consistency

- Changed the path for authorization URL from `/oauth/authorization_url` to `/oauth/get_authorization_url`.
- Updated the path for credentials from `/oauth/credentials` to `/oauth/get_credentials` to align with naming conventions.
2025-05-23 15:27:43 +08:00

243 lines
6.9 KiB
Go

package generator
import (
"fmt"
"go/format"
"os"
"path/filepath"
"reflect"
"strings"
"text/template"
"github.com/langgenius/dify-plugin-daemon/internal/core/plugin_daemon/access_types"
"github.com/langgenius/dify-plugin-daemon/internal/server/controllers/definitions"
"github.com/langgenius/dify-plugin-daemon/internal/utils/mapping"
"golang.org/x/tools/imports"
)
// GenerateController generates a controller file for the given access type
func GenerateController(accessType access_types.PluginAccessType, dispatchers []*definitions.PluginDispatcher) error {
// Create template
tmpl := template.Must(template.New("controller").Parse(controllerTemplate))
// Create output file
outputPath := filepath.Join("internal", "server", "controllers", strings.ToLower(string(accessType))+".gen.go")
// Execute template
var buf strings.Builder
if err := tmpl.Execute(&buf, struct {
AccessType access_types.PluginAccessType
Dispatchers []*definitions.PluginDispatcher
}{
AccessType: accessType,
Dispatchers: dispatchers,
}); err != nil {
return fmt.Errorf("failed to execute template: %v", err)
}
// Format code
src, err := format.Source([]byte(buf.String()))
if err != nil {
fmt.Println(buf.String())
return fmt.Errorf("failed to format code: %v", err)
}
// imports necessary packages
output, err := imports.Process(outputPath, src, nil)
if err != nil {
return fmt.Errorf("failed to process imports: %v", err)
}
f, err := os.Create(outputPath)
if err != nil {
return fmt.Errorf("failed to create file: %v", err)
}
defer f.Close()
// Write to file
if _, err := f.Write(output); err != nil {
return fmt.Errorf("failed to write file: %v", err)
}
return nil
}
// GenerateService generates a service file for the given access type
func GenerateService(accessType access_types.PluginAccessType, dispatchers []*definitions.PluginDispatcher) error {
// Create template
tmpl := template.Must(template.New("service").Parse(serviceTemplate))
// Create output file
outputPath := filepath.Join("internal", "service", strings.ToLower(string(accessType))+".gen.go")
// Execute template
var buf strings.Builder
if err := tmpl.Execute(&buf, struct {
AccessType access_types.PluginAccessType
Dispatchers []*definitions.PluginDispatcher
}{
AccessType: accessType,
Dispatchers: dispatchers,
}); err != nil {
return fmt.Errorf("failed to execute template: %v", err)
}
// Format code
src, err := format.Source([]byte(buf.String()))
if err != nil {
return fmt.Errorf("failed to format code: %v", err)
}
// imports necessary packages
output, err := imports.Process(outputPath, src, nil)
if err != nil {
return fmt.Errorf("failed to process imports: %v", err)
}
f, err := os.Create(outputPath)
if err != nil {
return fmt.Errorf("failed to create file: %v", err)
}
defer f.Close()
// Write to file
if _, err := f.Write(output); err != nil {
return fmt.Errorf("failed to write file: %v", err)
}
return nil
}
// GeneratePluginDaemon generates a plugin daemon file for the given access type
func GeneratePluginDaemon(accessType access_types.PluginAccessType, dispatchers []*definitions.PluginDispatcher) error {
// Create template
tmpl := template.Must(template.New("pluginDaemon").Parse(pluginDaemonTemplate))
// Create output file
outputPath := filepath.Join("internal", "core", "plugin_daemon", strings.ToLower(string(accessType))+".gen.go")
// Execute template
var buf strings.Builder
if err := tmpl.Execute(&buf, struct {
AccessType access_types.PluginAccessType
Dispatchers []*definitions.PluginDispatcher
}{
AccessType: accessType,
Dispatchers: dispatchers,
}); err != nil {
return fmt.Errorf("failed to execute template: %v", err)
}
// Format code
src, err := format.Source([]byte(buf.String()))
if err != nil {
return fmt.Errorf("failed to format code: %v", err)
}
// imports necessary packages
output, err := imports.Process(outputPath, src, nil)
if err != nil {
return fmt.Errorf("failed to process imports: %v", err)
}
f, err := os.Create(outputPath)
if err != nil {
return fmt.Errorf("failed to create file: %v", err)
}
defer f.Close()
// Write to file
if _, err := f.Write(output); err != nil {
return fmt.Errorf("failed to write file: %v", err)
}
return nil
}
// GenerateHTTPServer generates a http server file for the given access type
func GenerateHTTPServer(dispatchers []*definitions.PluginDispatcher) error {
// Create template
tmpl := template.Must(template.New("httpServer").Parse(httpServerTemplate))
// Create output file
outputPath := filepath.Join("internal", "server", "http_server.gen.go")
// Execute template
var buf strings.Builder
if err := tmpl.Execute(&buf, struct {
Dispatchers []*definitions.PluginDispatcher
}{
Dispatchers: dispatchers,
}); err != nil {
return fmt.Errorf("failed to execute template: %v", err)
}
// Format code
src, err := format.Source([]byte(buf.String()))
if err != nil {
return fmt.Errorf("failed to format code: %v", err)
}
// imports necessary packages
output, err := imports.Process(outputPath, src, nil)
if err != nil {
return fmt.Errorf("failed to process imports: %v", err)
}
f, err := os.Create(outputPath)
if err != nil {
return fmt.Errorf("failed to create file: %v", err)
}
defer f.Close()
// Write to file
if _, err := f.Write(output); err != nil {
return fmt.Errorf("failed to write file: %v", err)
}
return nil
}
// GenerateAll generates all controller and service files based on dispatchers
func GenerateAll() error {
// Group dispatchers by access type
dispatchersByType := make(map[access_types.PluginAccessType][]*definitions.PluginDispatcher)
for _, dispatcher := range definitions.PluginDispatchers {
dispatchersByType[dispatcher.AccessType] = append(dispatchersByType[dispatcher.AccessType], &dispatcher)
}
// Override RequestType and ResponseType to be the actual type by using reflection
for _, dispatchers := range dispatchersByType {
for _, dispatcher := range dispatchers {
dispatcher.RequestTypeString = reflect.TypeOf(dispatcher.RequestType).String()
dispatcher.ResponseTypeString = reflect.TypeOf(dispatcher.ResponseType).String()
}
}
// Generate files for each access type
for accessType, dispatchers := range dispatchersByType {
if err := GenerateController(accessType, dispatchers); err != nil {
return fmt.Errorf("failed to generate controller for %s: %v", accessType, err)
}
if err := GenerateService(accessType, dispatchers); err != nil {
return fmt.Errorf("failed to generate service for %s: %v", accessType, err)
}
if err := GeneratePluginDaemon(accessType, dispatchers); err != nil {
return fmt.Errorf("failed to generate plugin daemon for %s: %v", accessType, err)
}
}
if err := GenerateHTTPServer(
mapping.MapArray(
definitions.PluginDispatchers,
func(dispatcher definitions.PluginDispatcher) *definitions.PluginDispatcher {
return &dispatcher
},
),
); err != nil {
return fmt.Errorf("failed to generate http server: %v", err)
}
return nil
}