Yeuoly преди 11 месеца
родител
ревизия
8dd58b32c4

+ 2 - 2
internal/cluster/plugin.go

@@ -12,7 +12,7 @@ import (
 )
 
 type pluginLifeTime struct {
-	lifetime          plugin_entities.PluginRuntimeTimeLifeInterface
+	lifetime          plugin_entities.PluginLifetime
 	last_scheduled_at time.Time
 }
 
@@ -22,7 +22,7 @@ type pluginState struct {
 }
 
 // RegisterPlugin registers a plugin to the cluster, and start to be scheduled
-func (c *Cluster) RegisterPlugin(lifetime plugin_entities.PluginRuntimeTimeLifeInterface) error {
+func (c *Cluster) RegisterPlugin(lifetime plugin_entities.PluginLifetime) error {
 	identity, err := lifetime.Identity()
 	if err != nil {
 		return err

+ 8 - 0
internal/cluster/plugin_test.go

@@ -6,6 +6,7 @@ import (
 
 	"github.com/google/uuid"
 	"github.com/langgenius/dify-plugin-daemon/internal/core/plugin_manager/positive_manager"
+	"github.com/langgenius/dify-plugin-daemon/internal/types/entities"
 	"github.com/langgenius/dify-plugin-daemon/internal/types/entities/plugin_entities"
 )
 
@@ -38,6 +39,13 @@ func (r *fakePlugin) Wait() (<-chan bool, error) {
 	return nil, nil
 }
 
+func (r *fakePlugin) Listen(string) *entities.Broadcast[plugin_entities.SessionMessage] {
+	return nil
+}
+
+func (r *fakePlugin) Write(string, []byte) {
+}
+
 func getRandomPluginRuntime() fakePlugin {
 	return fakePlugin{
 		PluginRuntime: plugin_entities.PluginRuntime{

+ 7 - 10
internal/core/plugin_manager/aws_manager/environment.go

@@ -16,10 +16,6 @@ var (
 )
 
 func (r *AWSPluginRuntime) InitEnvironment() error {
-	if err := r.initEnvironment(); err != nil {
-		return err
-	}
-
 	// init http client
 	r.client = &http.Client{
 		Transport: &http.Transport{
@@ -38,7 +34,8 @@ func (r *AWSPluginRuntime) Identity() (plugin_entities.PluginUniqueIdentifier, e
 	return plugin_entities.PluginUniqueIdentifier(fmt.Sprintf("%s@%s", r.Config.Identity(), r.Checksum())), nil
 }
 
-func (r *AWSPluginRuntime) initEnvironment() error {
+// UploadPlugin uploads the plugin to the AWS Lambda
+func (r *AWSPluginRuntime) UploadPlugin() error {
 	r.Log("Starting to initialize environment")
 	// check if the plugin has already been initialized, at most 300s
 	if err := cache.Lock(AWS_LAUNCH_LOCK_PREFIX+r.Checksum(), 300*time.Second, 300*time.Second); err != nil {
@@ -58,9 +55,9 @@ func (r *AWSPluginRuntime) initEnvironment() error {
 		}
 	} else {
 		// found, return directly
-		r.lambda_url = function.FunctionURL
-		r.lambda_name = function.FunctionName
-		r.Log(fmt.Sprintf("Found existing lambda function: %s", r.lambda_name))
+		r.LambdaURL = function.FunctionURL
+		r.LambdaName = function.FunctionName
+		r.Log(fmt.Sprintf("Found existing lambda function: %s", r.LambdaName))
 		return nil
 	}
 
@@ -91,9 +88,9 @@ func (r *AWSPluginRuntime) initEnvironment() error {
 		case Error:
 			return fmt.Errorf("error: %s", response.Message)
 		case LambdaUrl:
-			r.lambda_url = response.Message
+			r.LambdaURL = response.Message
 		case Lambda:
-			r.lambda_name = response.Message
+			r.LambdaName = response.Message
 		case Info:
 			r.Log(fmt.Sprintf("installing: %s", response.Message))
 		}

+ 1 - 1
internal/core/plugin_manager/aws_manager/io.go

@@ -31,7 +31,7 @@ func (r *AWSPluginRuntime) Write(session_id string, data []byte) {
 		return
 	}
 
-	url, err := url.JoinPath(r.lambda_url, "invoke")
+	url, err := url.JoinPath(r.LambdaURL, "invoke")
 	if err != nil {
 		r.Error(fmt.Sprintf("Error creating request: %v", err))
 		return

+ 2 - 2
internal/core/plugin_manager/aws_manager/packager.go

@@ -19,11 +19,11 @@ import (
 )
 
 type Packager struct {
-	runtime plugin_entities.PluginRuntimeInterface
+	runtime plugin_entities.PluginLifetime
 	decoder decoder.PluginDecoder
 }
 
-func NewPackager(runtime plugin_entities.PluginRuntimeInterface, decoder decoder.PluginDecoder) *Packager {
+func NewPackager(runtime plugin_entities.PluginLifetime, decoder decoder.PluginDecoder) *Packager {
 	return &Packager{
 		runtime: runtime,
 		decoder: decoder,

+ 2 - 2
internal/core/plugin_manager/aws_manager/type.go

@@ -14,8 +14,8 @@ type AWSPluginRuntime struct {
 	plugin_entities.PluginRuntime
 
 	// access url for the lambda function
-	lambda_url  string
-	lambda_name string
+	LambdaURL  string
+	LambdaName string
 
 	// listeners mapping session id to the listener
 	listeners mapping.Map[string, *entities.Broadcast[plugin_entities.SessionMessage]]

+ 5 - 1
internal/core/plugin_manager/lifetime.go

@@ -7,7 +7,7 @@ import (
 	"github.com/langgenius/dify-plugin-daemon/internal/utils/log"
 )
 
-func (p *PluginManager) lifetime(r plugin_entities.PluginRuntimeInterface) {
+func (p *PluginManager) localLifetime(r plugin_entities.PluginFullDuplexLifetime) {
 	configuration := r.Configuration()
 
 	log.Info("new plugin logged in: %s", configuration.Identity())
@@ -86,3 +86,7 @@ func (p *PluginManager) lifetime(r plugin_entities.PluginRuntimeInterface) {
 		r.AddRestarts()
 	}
 }
+
+func (p *PluginManager) serverlessLifetime(r plugin_entities.PluginServerlessLifetime, onStop func()) {
+	//
+}

+ 21 - 20
internal/core/plugin_manager/manager.go

@@ -2,7 +2,6 @@ package plugin_manager
 
 import (
 	"fmt"
-	"sync"
 
 	"github.com/langgenius/dify-plugin-daemon/internal/cluster"
 	"github.com/langgenius/dify-plugin-daemon/internal/core/dify_invocation"
@@ -16,7 +15,7 @@ import (
 )
 
 type PluginManager struct {
-	m sync.Map
+	m mapping.Map[string, plugin_entities.PluginLifetime]
 
 	cluster *cluster.Cluster
 
@@ -30,6 +29,7 @@ type PluginManager struct {
 	runningPluginInStorage mapping.Map[string, string]
 	// start process lock
 	startProcessLock *lock.HighGranularityLock
+	// serverless runtime
 }
 
 var (
@@ -54,33 +54,32 @@ func GetGlobalPluginManager() *PluginManager {
 	return manager
 }
 
-func (p *PluginManager) Add(plugin plugin_entities.PluginRuntimeInterface) error {
+func (p *PluginManager) Add(
+	plugin plugin_entities.PluginLifetime,
+) error {
 	identity, err := plugin.Identity()
 	if err != nil {
 		return err
 	}
+
 	p.m.Store(identity.String(), plugin)
 	return nil
 }
 
-func (p *PluginManager) List() []plugin_entities.PluginRuntimeInterface {
-	var runtimes []plugin_entities.PluginRuntimeInterface
-	p.m.Range(func(key, value interface{}) bool {
-		if v, ok := value.(plugin_entities.PluginRuntimeInterface); ok {
-			runtimes = append(runtimes, v)
-		}
-		return true
-	})
-	return runtimes
-}
-
-func (p *PluginManager) Get(identity plugin_entities.PluginUniqueIdentifier) plugin_entities.PluginRuntimeInterface {
+func (p *PluginManager) Get(
+	identity plugin_entities.PluginUniqueIdentifier,
+) plugin_entities.PluginLifetime {
 	if v, ok := p.m.Load(identity.String()); ok {
-		if r, ok := v.(plugin_entities.PluginRuntimeInterface); ok {
-			return r
-		}
+		return v
 	}
-	return nil
+
+	// check if plugin is a serverless runtime
+	plugin_session_interface, err := p.getServerlessPluginRuntime(identity)
+	if err != nil {
+		return nil
+	}
+
+	return plugin_session_interface
 }
 
 func (p *PluginManager) GetAsset(id string) ([]byte, error) {
@@ -106,7 +105,9 @@ func (p *PluginManager) Init(configuration *app.Config) {
 	}
 
 	// start local watcher
-	p.startLocalWatcher(configuration)
+	if configuration.Platform == app.PLATFORM_LOCAL {
+		p.startLocalWatcher(configuration)
+	}
 
 	// start remote watcher
 	p.startRemoteWatcher(configuration)

+ 3 - 3
internal/core/plugin_manager/positive_manager/environment.go

@@ -22,11 +22,11 @@ func (r *PositivePluginRuntime) calculateChecksum() string {
 }
 
 func (r *PositivePluginRuntime) Checksum() string {
-	if r.checksum == "" {
-		r.checksum = r.calculateChecksum()
+	if r.InnerChecksum == "" {
+		r.InnerChecksum = r.calculateChecksum()
 	}
 
-	return r.checksum
+	return r.InnerChecksum
 }
 
 func (r *PositivePluginRuntime) Cleanup() {

+ 1 - 1
internal/core/plugin_manager/positive_manager/types.go

@@ -13,5 +13,5 @@ type PositivePluginRuntime struct {
 	// plugin decoder used to manage the plugin
 	Decoder decoder.PluginDecoder
 
-	checksum string
+	InnerChecksum string
 }

+ 95 - 0
internal/core/plugin_manager/serverless.go

@@ -0,0 +1,95 @@
+package plugin_manager
+
+import (
+	"errors"
+	"fmt"
+	"time"
+
+	"github.com/langgenius/dify-plugin-daemon/internal/core/plugin_manager/aws_manager"
+	"github.com/langgenius/dify-plugin-daemon/internal/core/plugin_manager/basic_manager"
+	"github.com/langgenius/dify-plugin-daemon/internal/core/plugin_manager/positive_manager"
+	"github.com/langgenius/dify-plugin-daemon/internal/db"
+	"github.com/langgenius/dify-plugin-daemon/internal/types/entities/plugin_entities"
+	"github.com/langgenius/dify-plugin-daemon/internal/types/models"
+	"github.com/langgenius/dify-plugin-daemon/internal/utils/cache"
+)
+
+const (
+	PLUGIN_SERVERLESS_CACHE_KEY = "serverless:runtime:%s"
+)
+
+func (p *PluginManager) getServerlessRuntimeCacheKey(
+	identity plugin_entities.PluginUniqueIdentifier,
+) string {
+	return fmt.Sprintf(PLUGIN_SERVERLESS_CACHE_KEY, identity.String())
+}
+
+func (p *PluginManager) getServerlessPluginRuntime(
+	identity plugin_entities.PluginUniqueIdentifier,
+) (plugin_entities.PluginLifetime, error) {
+	model, err := p.getServerlessPluginRuntimeModel(identity)
+	if err != nil {
+		return nil, err
+	}
+
+	declaration, err := model.GetDeclaration()
+	if err != nil {
+		return nil, err
+	}
+
+	// init runtime entity
+	runtime_entity := plugin_entities.PluginRuntime{
+		Config: *declaration,
+	}
+	runtime_entity.InitState()
+
+	// convert to plugin runtime
+	plugin_runtime := aws_manager.AWSPluginRuntime{
+		PositivePluginRuntime: positive_manager.PositivePluginRuntime{
+			BasicPluginRuntime: basic_manager.NewBasicPluginRuntime(p.mediaManager),
+			InnerChecksum:      model.Checksum,
+		},
+		PluginRuntime: runtime_entity,
+		LambdaURL:     model.FunctionURL,
+		LambdaName:    model.FunctionName,
+	}
+
+	if err := plugin_runtime.InitEnvironment(); err != nil {
+		return nil, err
+	}
+
+	return &plugin_runtime, nil
+}
+
+func (p *PluginManager) getServerlessPluginRuntimeModel(
+	identity plugin_entities.PluginUniqueIdentifier,
+) (*models.ServerlessRuntime, error) {
+	// check if plugin is a serverless runtime
+	runtime, err := cache.Get[models.ServerlessRuntime](
+		p.getServerlessRuntimeCacheKey(identity),
+	)
+	if err != nil && err != cache.ErrNotFound {
+		return nil, errors.New("plugin not found")
+	}
+
+	if err == cache.ErrNotFound {
+		runtime_model, err := db.GetOne[models.ServerlessRuntime](
+			db.Equal("plugin_unique_identifier", identity.String()),
+		)
+
+		if err == db.ErrDatabaseNotFound {
+			return nil, errors.New("plugin not found")
+		}
+
+		if err != nil {
+			return nil, fmt.Errorf("failed to load serverless runtime from db: %v", err)
+		}
+
+		cache.Store(p.getServerlessRuntimeCacheKey(identity), runtime_model, time.Minute*30)
+		runtime = &runtime_model
+	} else if err != nil {
+		return nil, fmt.Errorf("failed to load serverless runtime from cache: %v", err)
+	}
+
+	return runtime, nil
+}

+ 23 - 49
internal/core/plugin_manager/watcher.go

@@ -8,7 +8,6 @@ import (
 	"path"
 	"time"
 
-	"github.com/langgenius/dify-plugin-daemon/internal/core/plugin_manager/aws_manager"
 	"github.com/langgenius/dify-plugin-daemon/internal/core/plugin_manager/basic_manager"
 	"github.com/langgenius/dify-plugin-daemon/internal/core/plugin_manager/local_manager"
 	"github.com/langgenius/dify-plugin-daemon/internal/core/plugin_manager/positive_manager"
@@ -25,9 +24,9 @@ import (
 func (p *PluginManager) startLocalWatcher(config *app.Config) {
 	go func() {
 		log.Info("start to handle new plugins in path: %s", config.PluginStoragePath)
-		p.handleNewPlugins(config)
+		p.handleNewLocalPlugins(config)
 		for range time.NewTicker(time.Second * 30).C {
-			p.handleNewPlugins(config)
+			p.handleNewLocalPlugins(config)
 		}
 	}()
 }
@@ -44,17 +43,15 @@ func (p *PluginManager) startRemoteWatcher(config *app.Config) {
 		}()
 		go func() {
 			server.Wrap(func(rpr *remote_manager.RemotePluginRuntime) {
-				p.lifetime(rpr)
+				p.localLifetime(rpr)
 			})
 		}()
 	}
 }
 
-func (p *PluginManager) handleNewPlugins(config *app.Config) {
+func (p *PluginManager) handleNewLocalPlugins(config *app.Config) {
 	// load local plugins firstly
-	for plugin := range p.loadNewPlugins(config.PluginStoragePath) {
-		var plugin_interface plugin_entities.PluginRuntimeInterface
-
+	for plugin := range p.loadNewLocalPlugins(config.PluginStoragePath) {
 		// get assets
 		assets, err := plugin.Decoder.Assets()
 		if err != nil {
@@ -62,48 +59,24 @@ func (p *PluginManager) handleNewPlugins(config *app.Config) {
 			continue
 		}
 
-		if config.Platform == app.PLATFORM_AWS_LAMBDA {
-			aws_plugin_runtime := &aws_manager.AWSPluginRuntime{
-				PluginRuntime: plugin.Runtime,
-				PositivePluginRuntime: positive_manager.PositivePluginRuntime{
-					BasicPluginRuntime: basic_manager.NewBasicPluginRuntime(p.mediaManager),
-					LocalPackagePath:   plugin.Runtime.State.AbsolutePath,
-					WorkingPath:        plugin.Runtime.State.WorkingPath,
-					Decoder:            plugin.Decoder,
-				},
-			}
-			if err := aws_plugin_runtime.RemapAssets(
-				&aws_plugin_runtime.Config,
-				assets,
-			); err != nil {
-				log.Error("remap plugin assets error: %v", err)
-				continue
-			}
-			plugin_interface = aws_plugin_runtime
-		} else if config.Platform == app.PLATFORM_LOCAL {
-			local_plugin_runtime := &local_manager.LocalPluginRuntime{
-				PluginRuntime: plugin.Runtime,
-				PositivePluginRuntime: positive_manager.PositivePluginRuntime{
-					BasicPluginRuntime: basic_manager.NewBasicPluginRuntime(p.mediaManager),
-					LocalPackagePath:   plugin.Runtime.State.AbsolutePath,
-					WorkingPath:        plugin.Runtime.State.WorkingPath,
-					Decoder:            plugin.Decoder,
-				},
-			}
-			if err := local_plugin_runtime.RemapAssets(
-				&local_plugin_runtime.Config,
-				assets,
-			); err != nil {
-				log.Error("remap plugin assets error: %v", err)
-				continue
-			}
-			plugin_interface = local_plugin_runtime
-		} else {
-			log.Error("unsupported platform: %s for plugin: %s", config.Platform, plugin.Runtime.Config.Name)
+		local_plugin_runtime := &local_manager.LocalPluginRuntime{
+			PluginRuntime: plugin.Runtime,
+			PositivePluginRuntime: positive_manager.PositivePluginRuntime{
+				BasicPluginRuntime: basic_manager.NewBasicPluginRuntime(p.mediaManager),
+				LocalPackagePath:   plugin.Runtime.State.AbsolutePath,
+				WorkingPath:        plugin.Runtime.State.WorkingPath,
+				Decoder:            plugin.Decoder,
+			},
+		}
+		if err := local_plugin_runtime.RemapAssets(
+			&local_plugin_runtime.Config,
+			assets,
+		); err != nil {
+			log.Error("remap plugin assets error: %v", err)
 			continue
 		}
 
-		identity, err := plugin_interface.Identity()
+		identity, err := local_plugin_runtime.Identity()
 		if err != nil {
 			log.Error("get plugin identity error: %v", err)
 			continue
@@ -112,6 +85,7 @@ func (p *PluginManager) handleNewPlugins(config *app.Config) {
 		// store the plugin in the storage, avoid duplicate loading
 		p.runningPluginInStorage.Store(plugin.Runtime.State.AbsolutePath, identity.String())
 
+		// local plugin
 		routine.Submit(func() {
 			defer func() {
 				if r := recover(); r != nil {
@@ -120,7 +94,7 @@ func (p *PluginManager) handleNewPlugins(config *app.Config) {
 			}()
 			// delete the plugin from the storage when the plugin is stopped
 			defer p.runningPluginInStorage.Delete(plugin.Runtime.State.AbsolutePath)
-			p.lifetime(plugin_interface)
+			p.localLifetime(local_plugin_runtime)
 		})
 	}
 }
@@ -131,7 +105,7 @@ type pluginRuntimeWithDecoder struct {
 }
 
 // chan should be closed after using that
-func (p *PluginManager) loadNewPlugins(root_path string) <-chan *pluginRuntimeWithDecoder {
+func (p *PluginManager) loadNewLocalPlugins(root_path string) <-chan *pluginRuntimeWithDecoder {
 	ch := make(chan *pluginRuntimeWithDecoder)
 
 	plugins, err := os.ReadDir(root_path)

+ 5 - 5
internal/core/session_manager/session.go

@@ -22,9 +22,9 @@ var (
 
 // session need to implement the backwards_invocation.BackwardsInvocationWriter interface
 type Session struct {
-	ID          string                                 `json:"id"`
-	runtime     plugin_entities.PluginRuntimeInterface `json:"-"`
-	persistence *persistence.Persistence               `json:"-"`
+	ID          string                         `json:"id"`
+	runtime     plugin_entities.PluginLifetime `json:"-"`
+	persistence *persistence.Persistence       `json:"-"`
 
 	TenantID               string                                 `json:"tenant_id"`
 	UserID                 string                                 `json:"user_id"`
@@ -102,11 +102,11 @@ func (s *Session) Close() {
 	DeleteSession(s.ID)
 }
 
-func (s *Session) BindRuntime(runtime plugin_entities.PluginRuntimeInterface) {
+func (s *Session) BindRuntime(runtime plugin_entities.PluginLifetime) {
 	s.runtime = runtime
 }
 
-func (s *Session) Runtime() plugin_entities.PluginRuntimeInterface {
+func (s *Session) Runtime() plugin_entities.PluginLifetime {
 	return s.runtime
 }
 

+ 1 - 0
internal/db/init.go

@@ -81,6 +81,7 @@ func autoMigrate() error {
 		models.Plugin{},
 		models.PluginInstallation{},
 		models.Endpoint{},
+		models.ServerlessRuntime{},
 	)
 }
 

+ 1 - 1
internal/service/install_service/state.go

@@ -14,7 +14,7 @@ import (
 func InstallPlugin(
 	tenant_id string,
 	user_id string,
-	runtime plugin_entities.PluginRuntimeInterface,
+	runtime plugin_entities.PluginLifetime,
 ) (*models.Plugin, *models.PluginInstallation, error) {
 	identity, err := runtime.Identity()
 	if err != nil {

+ 46 - 34
internal/types/entities/plugin_entities/runtime.go

@@ -19,45 +19,23 @@ type (
 		onStopped []func()           `json:"-"`
 	}
 
-	PluginRuntimeInterface interface {
-		PluginRuntimeTimeLifeInterface
+	PluginLifetime interface {
+		PluginBasicInfoInterface
 		PluginRuntimeSessionIOInterface
-		PluginRuntimeDockerInterface
-		PluginRuntimeLogInterface
+		PluginClusterLifetime
 	}
 
-	PluginRuntimeTimeLifeInterface interface {
-		// returns the plugin configuration
-		Configuration() *PluginDeclaration
-		// unique identity of the plugin
-		Identity() (PluginUniqueIdentifier, error)
-		// hashed identity of the plugin
-		HashedIdentity() (string, error)
+	PluginFullDuplexLifetime interface {
+		PluginLifetime
+
 		// before the plugin starts, it will call this method to initialize the environment
 		InitEnvironment() error
 		// start the plugin, returns errors if the plugin fails to start and hangs until the plugin stops
 		StartPlugin() error
-		// returns true if the plugin is stopped
-		Stopped() bool
-		// stop the plugin
-		Stop()
-		// add a function to be called when the plugin stops
-		OnStop(func())
-		// trigger the stop event
-		TriggerStop()
-		// returns the runtime state of the plugin
-		RuntimeState() PluginRuntimeState
-		// Update the runtime state of the plugin
-		UpdateScheduledAt(t time.Time)
-		// returns the checksum of the plugin
-		Checksum() string
 		// wait for the plugin to stop
 		Wait() (<-chan bool, error)
-		// returns the runtime type of the plugin
-		Type() PluginRuntimeType
 		// Cleanup the plugin runtime
 		Cleanup()
-
 		// set the plugin to active
 		SetActive()
 		// set the plugin to launching
@@ -74,7 +52,22 @@ type (
 		AddRestarts()
 	}
 
-	PluginRuntimeLogInterface interface {
+	PluginServerlessLifetime interface {
+		PluginLifetime
+
+		// before the plugin starts, it will call this method to initialize the environment
+		InitEnvironment() error
+		// UploadPlugin uploads the plugin to the AWS Lambda
+		UploadPlugin() error
+	}
+
+	PluginRuntimeSessionIOInterface interface {
+		PluginBasicInfoInterface
+
+		// Listen listens for messages from the plugin
+		Listen(session_id string) *entities.Broadcast[SessionMessage]
+		// Write writes a message to the plugin
+		Write(session_id string, data []byte)
 		// Log adds a log to the plugin runtime state
 		Log(string)
 		// Warn adds a warning to the plugin runtime state
@@ -83,13 +76,32 @@ type (
 		Error(string)
 	}
 
-	PluginRuntimeSessionIOInterface interface {
-		Listen(session_id string) *entities.Broadcast[SessionMessage]
-		Write(session_id string, data []byte)
+	PluginClusterLifetime interface {
+		// stop the plugin
+		Stop()
+		// add a function to be called when the plugin stops
+		OnStop(func())
+		// trigger the stop event
+		TriggerStop()
+		// returns true if the plugin is stopped
+		Stopped() bool
+		// returns the runtime state of the plugin
+		RuntimeState() PluginRuntimeState
+		// Update the runtime state of the plugin
+		UpdateScheduledAt(t time.Time)
 	}
 
-	PluginRuntimeDockerInterface interface {
-		// returns the docker image and the delete function, always call the delete function when the image is no longer needed
+	PluginBasicInfoInterface interface {
+		// returns the runtime type of the plugin
+		Type() PluginRuntimeType
+		// returns the plugin configuration
+		Configuration() *PluginDeclaration
+		// unique identity of the plugin
+		Identity() (PluginUniqueIdentifier, error)
+		// hashed identity of the plugin
+		HashedIdentity() (string, error)
+		// returns the checksum of the plugin
+		Checksum() string
 	}
 )
 

+ 36 - 2
internal/types/models/plugin.go

@@ -17,6 +17,40 @@ type Plugin struct {
 	Declaration  string                            `json:"declaration" orm:"type:text;size:65535"`
 }
 
-func (p *Plugin) GetDeclaration() (plugin_entities.PluginDeclaration, error) {
-	return parser.UnmarshalJson[plugin_entities.PluginDeclaration](p.Declaration)
+func (p *Plugin) GetDeclaration() (*plugin_entities.PluginDeclaration, error) {
+	declaration, err := parser.UnmarshalJson[plugin_entities.PluginDeclaration](p.Declaration)
+	if err != nil {
+		return nil, err
+	}
+
+	return &declaration, nil
+}
+
+type ServerlessRuntimeType string
+
+const (
+	SERVERLESS_RUNTIME_TYPE_AWS_LAMBDA ServerlessRuntimeType = "aws_lambda"
+)
+
+type ServerlessRuntime struct {
+	Model
+	PluginUniqueIdentifier string                `json:"plugin_unique_identifier" orm:"index;size:127"`
+	FunctionURL            string                `json:"function_url" orm:"size:255"`
+	FunctionName           string                `json:"function_name" orm:"size:127"`
+	Type                   ServerlessRuntimeType `json:"type" orm:"size:127"`
+	Declaration            string                `json:"declaration" orm:"type:text;size:65535"`
+	Checksum               string                `json:"checksum" orm:"size:127"`
+}
+
+func (p *ServerlessRuntime) GetDeclaration() (*plugin_entities.PluginDeclaration, error) {
+	declaration, err := parser.UnmarshalJson[plugin_entities.PluginDeclaration](p.Declaration)
+	if err != nil {
+		return nil, err
+	}
+
+	return &declaration, nil
+}
+
+func (p *ServerlessRuntime) SetDeclaration(declaration *plugin_entities.PluginDeclaration) {
+	p.Declaration = parser.MarshalJson(declaration)
 }