feat(plugins): New Plugin System with multi-language PDK support (#4833)
* chore(plugins): remove the old plugins system implementation Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): implement new plugin system with using Extism Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): add capability detection for plugins based on exported functions Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): add auto-reload functionality for plugins with file watcher support Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): add auto-reload functionality for plugins with file watcher support Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): standardize variable names and remove superfluous wrapper functions Signed-off-by: Deluan <deluan@navidrome.org> * fix(plugins): improve error handling and logging in plugin manager Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): implement plugin function call helper and refactor MetadataAgent methods Signed-off-by: Deluan <deluan@navidrome.org> * fix(plugins): race condition in plugin manager * tests(plugins): change BeforeEach to BeforeAll in MetadataAgent tests Signed-off-by: Deluan <deluan@navidrome.org> * tests(plugins): optimize tests Signed-off-by: Deluan <deluan@navidrome.org> * tests(plugins): more optimizations Signed-off-by: Deluan <deluan@navidrome.org> * test(plugins): ignore goroutine leaks from notify library in tests Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): add Wikimedia plugin for Navidrome to fetch artist metadata Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): enhance plugin logging and set User-Agent header Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): implement scrobbler plugin with authorization and scrobbling capabilities Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): integrate logs Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): clean up manifest struct and improve plugin loading logic Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): add metadata agent and scrobbler schemas for bootstrapping plugins Signed-off-by: Deluan <deluan@navidrome.org> * feat(hostgen): add hostgen tool for generating Extism host function wrappers - Implemented hostgen tool to generate wrappers from annotated Go interfaces. - Added command-line flags for input/output directories and package name. - Introduced parsing and code generation logic for host services. - Created test data for various service interfaces and expected generated code. - Added documentation for host services and annotations for code generation. - Implemented SubsonicAPI service with corresponding generated code. * feat(subsonicapi): update Call method to return JSON string response Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): implement SubsonicAPI host function integration with permissions Signed-off-by: Deluan <deluan@navidrome.org> * fix(generator): error-only methods in response handling Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): generate client wrappers for host functions Signed-off-by: Deluan <deluan@navidrome.org> * refactor(generator): remove error handling for response.Error in client templates Signed-off-by: Deluan <deluan@navidrome.org> * feat(scheduler): add Scheduler service interface with host function wrappers for scheduling tasks * feat(plugins): add WASI build constraints to client wrapper templates, to avoid lint errors Signed-off-by: Deluan <deluan@navidrome.org> * feat(scheduler): implement Scheduler service with one-time and recurring scheduling capabilities Signed-off-by: Deluan <deluan@navidrome.org> * refactor(manifest): remove unused ConfigPermission from permissions schema Signed-off-by: Deluan <deluan@navidrome.org> * feat(scheduler): add scheduler callback schema and implementation for plugins Signed-off-by: Deluan <deluan@navidrome.org> * refactor(scheduler): streamline scheduling logic and remove unused callback tracking Signed-off-by: Deluan <deluan@navidrome.org> * refactor(scheduler): add Close method for resource cleanup on plugin unload Signed-off-by: Deluan <deluan@navidrome.org> * docs(scheduler): clarify SchedulerCallback requirement for scheduling functions Signed-off-by: Deluan <deluan@navidrome.org> * fix: update wasm build rule to include all Go files in the directory Signed-off-by: Deluan <deluan@navidrome.org> * feat: rewrite the wikimedia plugin using the XTP CLI Signed-off-by: Deluan <deluan@navidrome.org> * refactor(scheduler): replace uuid with id.NewRandom for schedule ID generation Signed-off-by: Deluan <deluan@navidrome.org> * refactor: capabilities registration Signed-off-by: Deluan <deluan@navidrome.org> * test: add scheduler service isolation test for plugin instances Signed-off-by: Deluan <deluan@navidrome.org> * refactor: update plugin manager initialization and encapsulate logic Signed-off-by: Deluan <deluan@navidrome.org> * feat: add WebSocket service definitions for plugin communication Signed-off-by: Deluan <deluan@navidrome.org> * feat: implement WebSocket service for plugin integration and connection management Signed-off-by: Deluan <deluan@navidrome.org> * feat: add Crypto Ticker example plugin for real-time cryptocurrency price updates via Coinbase WebSocket API Also add the lifecycle capability Signed-off-by: Deluan <deluan@navidrome.org> * fix: use context.Background() in invokeCallback for scheduled tasks Signed-off-by: Deluan <deluan@navidrome.org> * refactor: rename plugin.create() to plugin.instance() Signed-off-by: Deluan <deluan@navidrome.org> * refactor: rename pluginInstance to plugin for consistency across the codebase Signed-off-by: Deluan <deluan@navidrome.org> * refactor: simplify schedule cloning in Close method and enhance plugin cleanup error handling Signed-off-by: Deluan <deluan@navidrome.org> * feat: implement Artwork service for generating artwork URLs in Navidrome plugins - WIP Signed-off-by: Deluan <deluan@navidrome.org> * refactor: moved public URL builders to avoid import cycles Signed-off-by: Deluan <deluan@navidrome.org> * feat: add Cache service for in-memory TTL-based caching in plugins Signed-off-by: Deluan <deluan@navidrome.org> * feat: add Discord Rich Presence example plugin for Navidrome integration Signed-off-by: Deluan <deluan@navidrome.org> * refactor: host function wrappers to use structured request and response types - Updated the host function signatures in `nd_host_artwork.go`, `nd_host_scheduler.go`, `nd_host_subsonicapi.go`, and `nd_host_websocket.go` to accept a single parameter for JSON requests. - Introduced structured request and response types for various cache operations in `nd_host_cache.go`. - Modified cache functions to marshal requests to JSON and unmarshal responses, improving error handling and code clarity. - Removed redundant memory allocation for string parameters in favor of JSON marshaling. - Enhanced error handling in WebSocket and cache operations to return structured error responses. * refactor: error handling in various plugins to convert response.Error to Go errors - Updated error handling in `nd_host_scheduler.go`, `nd_host_websocket.go`, `nd_host_artwork.go`, `nd_host_cache.go`, and `nd_host_subsonicapi.go` to convert string errors from responses into Go errors. - Removed redundant error checks in test data plugins for cleaner code. - Ensured consistent error handling across all plugins to improve reliability and maintainability. * refactor: rename fake plugins to test plugins for clarity in integration tests Signed-off-by: Deluan <deluan@navidrome.org> * feat: add help target to Makefile for plugin usage instructions Signed-off-by: Deluan <deluan@navidrome.org> * feat: add Cover Art Archive plugin as an example of Python plugin Signed-off-by: Deluan <deluan@navidrome.org> * feat: update Makefile and README to clarify Go plugin usage Signed-off-by: Deluan <deluan@navidrome.org> * feat: include plugin capabilities in loading log message Signed-off-by: Deluan <deluan@navidrome.org> * feat: add trace logging for plugin availability and error handling in agents Signed-off-by: Deluan <deluan@navidrome.org> * feat: add Now Playing Logger plugin to showcase calling host functions from Python plugins Signed-off-by: Deluan <deluan@navidrome.org> * feat: generate Python client wrappers for various host services Signed-off-by: Deluan <deluan@navidrome.org> * feat: add generated host function wrappers for Scheduler and SubsonicAPI services Signed-off-by: Deluan <deluan@navidrome.org> * feat: update Python plugin documentation and usage instructions for host function wrappers Signed-off-by: Deluan <deluan@navidrome.org> * feat: add Webhook Scrobbler plugin in Rust to send HTTP notifications on scrobble events Signed-off-by: Deluan <deluan@navidrome.org> * feat: enable parallel loading of plugins during startup Signed-off-by: Deluan <deluan@navidrome.org> * docs: update README to include WebSocket callback schema in plugin documentation Signed-off-by: Deluan <deluan@navidrome.org> * feat: extend plugin watcher with improved logging and debounce duration adjustment Signed-off-by: Deluan <deluan@navidrome.org> * add trace message for plugin recompiles Signed-off-by: Deluan <deluan@navidrome.org> * feat: implement plugin cache purging functionality Signed-off-by: Deluan <deluan@navidrome.org> * test: move purgeCacheBySize unit tests Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins UI): add plugin repository and database support Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins UI): add plugin management routes and middleware Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins UI): implement plugin synchronization with database for add, update, and remove actions Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins UI): add PluginList and PluginShow components with plugin management functionality Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): optimize plugin change detection Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins UI): improve PluginList structure Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins UI): enhance PluginShow with author, website, and permissions display Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins UI): refactor to use MUI and RA components Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins UI): add error handling for plugin enable/disable actions Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): inject PluginManager into native API Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): update GetManager to accept DataStore parameter Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): add subsonicRouter to Manager and refactor host service registration Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): enhance debug logging for plugin actions and recompile logic Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): break manager.go into smaller, focused files Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): streamline error handling and improve plugin retrieval logic Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): update newWebSocketService to use WebSocketPermission for allowed hosts Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): introduce ToggleEnabledSwitch for managing plugin enable/disable state Signed-off-by: Deluan <deluan@navidrome.org> * docs: update READMEs Signed-off-by: Deluan <deluan@navidrome.org> * feat(library): add Library service for metadata access and filesystem integration Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): add Library Inspector plugin for periodic library inspection and file size logging Signed-off-by: Deluan <deluan@navidrome.org> * docs: update README to reflect JSON configuration format for plugins Signed-off-by: Deluan <deluan@navidrome.org> * fix(build): update target to wasm32-wasip1 for improved WASI support Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): implement configuration management UI with key-value pairs support Signed-off-by: Deluan <deluan@navidrome.org> * feat(ui): adjust grid layout in InfoRow component for improved responsiveness Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): rename ErrorIndicator to EnabledOrErrorField and enhance error handling logic Signed-off-by: Deluan <deluan@navidrome.org> * feat(i18n): add Portuguese translations for plugin management and notifications Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): add support for .ndp plugin packages and update build process Signed-off-by: Deluan <deluan@navidrome.org> * docs: update README for .ndp plugin packaging and installation instructions Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): implement KVStore service for persistent key-value storage Signed-off-by: Deluan <deluan@navidrome.org> * docs: enhance README with Extism plugin development resources and recommendations Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): integrate event broker into plugin manager Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): update config handling in PluginShow to track last record state Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): add Rust host function library and example implementation of Discord Rich Presence plugin in Rust Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): generate Rust lib.rs file to expose host function wrappers Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): update JSON field names to camelCase for consistency Signed-off-by: Deluan <deluan@navidrome.org> * refactor: reduce cyclomatic complexity by refactoring main function Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): enhance Rust code generation with typed struct support and improved type handling Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): add Go client library with host function wrappers and documentation Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): generate Go client stubs for non-WASM platforms Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): update client template file names for consistency Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): add initial implementation of the Navidrome Plugin Development Kit code generator - Pahse 1 Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 2 Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 2 (2) Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 3 Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 4 Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): implementation of the Navidrome Plugin Development Kit with generated client wrappers and service interfaces - Phase 5 Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): consistent naming/types across PDK Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): streamline plugin function signatures and error handling Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): update scrobbler interface to return errors directly instead of response structs Signed-off-by: Deluan <deluan@navidrome.org> * test: make all test plugins use the PDK Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): reorganize and sort type definitions for consistency Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): update error handling for methods to return errors directly Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): update function signatures to return values directly instead of response structs Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): update request/response types to use private naming conventions Signed-off-by: Deluan <deluan@navidrome.org> * build: mark .wasm files as intermediate for cleanup after building .ndp Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): consolidate PDK module path and update Go version to 1.25 Signed-off-by: Deluan <deluan@navidrome.org> * feat: implement Rust PDK Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): reorganize Rust output structure to follow standard conventions Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): update Discord Rich Presence and Library Inspector plugins to use nd-pdk for service calls and implement lifecycle management Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): update macro names for websocket and metadata registration to improve clarity and consistency Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): rename scheduler callback methods for consistency and clarity Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): update export wrappers to use `//go:wasmexport` for WebAssembly compatibility Signed-off-by: Deluan <deluan@navidrome.org> * docs: update plugin registration docs Signed-off-by: Deluan <deluan@navidrome.org> * fix(plugins): generate host wrappers Signed-off-by: Deluan <deluan@navidrome.org> * test(plugins): conditionally run goleak checks based on CI environment Signed-off-by: Deluan <deluan@navidrome.org> * docs: update README to reflect changes in plugin import paths Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): update plugin instance creation to accept context for cancellation support Signed-off-by: Deluan <deluan@navidrome.org> * fix(plugins): update return types in metadata interfaces to use pointers Signed-off-by: Deluan <deluan@navidrome.org> * fix(plugins): enhance type handling for Rust and XTP output in capability generation Signed-off-by: Deluan <deluan@navidrome.org> * fix(plugins): update IsAuthorized method to return boolean instead of response object Signed-off-by: Deluan <deluan@navidrome.org> * test(plugins): add unit tests for rustOutputType and isPrimitiveRustType functions Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): implement XTP JSONSchema validation for generated schemas Signed-off-by: Deluan <deluan@navidrome.org> * fix(plugins): update response types in testMetadataAgent methods to use pointers Signed-off-by: Deluan <deluan@navidrome.org> * docs: update Go and Rust plugin developer sections for clarity Signed-off-by: Deluan <deluan@navidrome.org> * docs: correct example link for library inspector in README Signed-off-by: Deluan <deluan@navidrome.org> * docs: clarify artwork URL generation capabilities in service descriptions Signed-off-by: Deluan <deluan@navidrome.org> * docs: update README to include Rust PDK crate information for plugin developers Signed-off-by: Deluan <deluan@navidrome.org> * fix: handle URL parsing errors and use atomic upsert in plugin repository Added proper error handling for url.Parse calls in PublicURL and AbsoluteURL functions. When parsing fails, PublicURL now falls back to AbsoluteURL, and AbsoluteURL logs the error and returns an empty string, preventing malformed URLs from being generated. Replaced the non-atomic UPDATE-then-INSERT pattern in plugin repository Put method with a single atomic INSERT ... ON CONFLICT statement. This eliminates potential race conditions and improves consistency with the upsert pattern already used in host_kvstore.go. * feat: implement mock service instances for non-WASM builds using testify/mock Signed-off-by: Deluan <deluan@navidrome.org> * refactor: Discord RPC struct to encapsulate WebSocket logic Signed-off-by: Deluan <deluan@navidrome.org> * feat: add support for experimental WebAssembly threads Signed-off-by: Deluan <deluan@navidrome.org> * feat: add PDK abstraction layer with mock support for non-WASM builds Signed-off-by: Deluan <deluan@navidrome.org> * feat: add unit tests for Discord plugin and RPC functionality Signed-off-by: Deluan <deluan@navidrome.org> * fix: update return types in minimalPlugin and wikimediaPlugin methods to use pointers Signed-off-by: Deluan <deluan@navidrome.org> * fix: context cancellation and implement WebSocket callback timeout for improved error handling Signed-off-by: Deluan <deluan@navidrome.org> * feat: conditionally include error handling in generated client code templates Signed-off-by: Deluan <deluan@navidrome.org> * feat: implement ConfigService for plugin configuration management Signed-off-by: Deluan <deluan@navidrome.org> * feat: enhance plugin manager to support metrics recording Signed-off-by: Deluan <deluan@navidrome.org> * refactor: make MockPDK private Signed-off-by: Deluan <deluan@navidrome.org> * refactor: update interface types to use 'any' in plugin repository methods Signed-off-by: Deluan <deluan@navidrome.org> * refactor: rename List method to Keys for clarity in configuration management Signed-off-by: Deluan <deluan@navidrome.org> * test: add ndpgen plugin tests in the pipeline and update Makefile Signed-off-by: Deluan <deluan@navidrome.org> * feat: add users permission management to plugin system Signed-off-by: Deluan <deluan@navidrome.org> * refactor: streamline users integration tests and enhance plugin user management Signed-off-by: Deluan <deluan@navidrome.org> * refactor: remove UserID from scrobbler request structure Signed-off-by: Deluan <deluan@navidrome.org> * test: add integration tests for UsersService enable gate behavior Signed-off-by: Deluan <deluan@navidrome.org> * feat: implement user permissions for SubsonicAPI and scrobbler plugins Signed-off-by: Deluan <deluan@navidrome.org> * fix: show proper error in the UI when enabling a plugin fails Signed-off-by: Deluan <deluan@navidrome.org> * feat: add library permission management to plugin system Signed-off-by: Deluan <deluan@navidrome.org> * feat: add user permission for processing scrobbles in Discord Rich Presence plugin Signed-off-by: Deluan <deluan@navidrome.org> * fix: implement dynamic loading for buffered scrobbler plugins Signed-off-by: Deluan <deluan@navidrome.org> * feat: add GetAdmins method to retrieve admin users from the plugin Signed-off-by: Deluan <deluan@navidrome.org> * feat: update Portuguese translations for user and library permissions Signed-off-by: Deluan <deluan@navidrome.org> * reorder migrations Signed-off-by: Deluan <deluan@navidrome.org> * fix: remove unnecessary bulkActionButtons prop from PluginList component * feat: add manual plugin rescan functionality and corresponding UI action Signed-off-by: Deluan <deluan@navidrome.org> * feat: implement user/library and plugin management integration with cleanup on deletion Signed-off-by: Deluan <deluan@navidrome.org> * feat: replace core mock services with test-specific implementations to avoid import cycles * feat: add ID fields to Artist and Song structs and enhance track loading logic by prioritizing ID matches Signed-off-by: Deluan <deluan@navidrome.org> * feat: update plugin permissions from allowedHosts to requiredHosts for better clarity and consistency * feat: refactor plugin host permissions to use RequiredHosts directly for improved clarity * fix: don't record metrics for plugin calls that aren't implemented at all Signed-off-by: Deluan <deluan@navidrome.org> * fix: enhance connection management with improved error handling and cleanup logic Signed-off-by: Deluan <deluan@navidrome.org> * feat: introduce ArtistRef struct for better artist representation and update track metadata handling Signed-off-by: Deluan <deluan@navidrome.org> * feat: update user configuration handling to use user key prefix for improved clarity Signed-off-by: Deluan <deluan@navidrome.org> * feat: enhance ConfigCard input fields with multiline support and vertical resizing Signed-off-by: Deluan <deluan@navidrome.org> * fix: rust plugin compilation error Signed-off-by: Deluan <deluan@navidrome.org> * feat: implement IsOptionPattern method for better return type handling in Rust PDK generation Signed-off-by: Deluan <deluan@navidrome.org> --------- Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
package host
|
||||
|
||||
import "context"
|
||||
|
||||
// ArtworkService provides artwork public URL generation capabilities for plugins.
|
||||
//
|
||||
// This service allows plugins to generate public URLs for artwork images of
|
||||
// various entity types (artists, albums, tracks, playlists). The generated URLs
|
||||
// include authentication tokens and can be used to display artwork in external
|
||||
// services or custom UIs.
|
||||
//
|
||||
//nd:hostservice name=Artwork permission=artwork
|
||||
type ArtworkService interface {
|
||||
// GetArtistUrl generates a public URL for an artist's artwork.
|
||||
//
|
||||
// Parameters:
|
||||
// - id: The artist's unique identifier
|
||||
// - size: Desired image size in pixels (0 for original size)
|
||||
//
|
||||
// Returns the public URL for the artwork, or an error if generation fails.
|
||||
//nd:hostfunc
|
||||
GetArtistUrl(ctx context.Context, id string, size int32) (url string, err error)
|
||||
|
||||
// GetAlbumUrl generates a public URL for an album's artwork.
|
||||
//
|
||||
// Parameters:
|
||||
// - id: The album's unique identifier
|
||||
// - size: Desired image size in pixels (0 for original size)
|
||||
//
|
||||
// Returns the public URL for the artwork, or an error if generation fails.
|
||||
//nd:hostfunc
|
||||
GetAlbumUrl(ctx context.Context, id string, size int32) (url string, err error)
|
||||
|
||||
// GetTrackUrl generates a public URL for a track's artwork.
|
||||
//
|
||||
// Parameters:
|
||||
// - id: The track's (media file) unique identifier
|
||||
// - size: Desired image size in pixels (0 for original size)
|
||||
//
|
||||
// Returns the public URL for the artwork, or an error if generation fails.
|
||||
//nd:hostfunc
|
||||
GetTrackUrl(ctx context.Context, id string, size int32) (url string, err error)
|
||||
|
||||
// GetPlaylistUrl generates a public URL for a playlist's artwork.
|
||||
//
|
||||
// Parameters:
|
||||
// - id: The playlist's unique identifier
|
||||
// - size: Desired image size in pixels (0 for original size)
|
||||
//
|
||||
// Returns the public URL for the artwork, or an error if generation fails.
|
||||
//nd:hostfunc
|
||||
GetPlaylistUrl(ctx context.Context, id string, size int32) (url string, err error)
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/artwork/artwork.proto
|
||||
|
||||
package artwork
|
||||
|
||||
import (
|
||||
context "context"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type GetArtworkUrlRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Size int32 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"` // Optional, 0 means original size
|
||||
}
|
||||
|
||||
func (x *GetArtworkUrlRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *GetArtworkUrlRequest) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GetArtworkUrlRequest) GetSize() int32 {
|
||||
if x != nil {
|
||||
return x.Size
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type GetArtworkUrlResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
|
||||
}
|
||||
|
||||
func (x *GetArtworkUrlResponse) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *GetArtworkUrlResponse) GetUrl() string {
|
||||
if x != nil {
|
||||
return x.Url
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// go:plugin type=host version=1
|
||||
type ArtworkService interface {
|
||||
GetArtistUrl(context.Context, *GetArtworkUrlRequest) (*GetArtworkUrlResponse, error)
|
||||
GetAlbumUrl(context.Context, *GetArtworkUrlRequest) (*GetArtworkUrlResponse, error)
|
||||
GetTrackUrl(context.Context, *GetArtworkUrlRequest) (*GetArtworkUrlResponse, error)
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package artwork;
|
||||
|
||||
option go_package = "github.com/navidrome/navidrome/plugins/host/artwork;artwork";
|
||||
|
||||
// go:plugin type=host version=1
|
||||
service ArtworkService {
|
||||
rpc GetArtistUrl(GetArtworkUrlRequest) returns (GetArtworkUrlResponse);
|
||||
rpc GetAlbumUrl(GetArtworkUrlRequest) returns (GetArtworkUrlResponse);
|
||||
rpc GetTrackUrl(GetArtworkUrlRequest) returns (GetArtworkUrlResponse);
|
||||
}
|
||||
|
||||
message GetArtworkUrlRequest {
|
||||
string id = 1;
|
||||
int32 size = 2; // Optional, 0 means original size
|
||||
}
|
||||
|
||||
message GetArtworkUrlResponse {
|
||||
string url = 1;
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
//go:build !wasip1
|
||||
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/artwork/artwork.proto
|
||||
|
||||
package artwork
|
||||
|
||||
import (
|
||||
context "context"
|
||||
wasm "github.com/knqyf263/go-plugin/wasm"
|
||||
wazero "github.com/tetratelabs/wazero"
|
||||
api "github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
|
||||
const (
|
||||
i32 = api.ValueTypeI32
|
||||
i64 = api.ValueTypeI64
|
||||
)
|
||||
|
||||
type _artworkService struct {
|
||||
ArtworkService
|
||||
}
|
||||
|
||||
// Instantiate a Go-defined module named "env" that exports host functions.
|
||||
func Instantiate(ctx context.Context, r wazero.Runtime, hostFunctions ArtworkService) error {
|
||||
envBuilder := r.NewHostModuleBuilder("env")
|
||||
h := _artworkService{hostFunctions}
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._GetArtistUrl), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("get_artist_url")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._GetAlbumUrl), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("get_album_url")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._GetTrackUrl), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("get_track_url")
|
||||
|
||||
_, err := envBuilder.Instantiate(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
func (h _artworkService) _GetArtistUrl(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(GetArtworkUrlRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.GetArtistUrl(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
func (h _artworkService) _GetAlbumUrl(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(GetArtworkUrlRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.GetAlbumUrl(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
func (h _artworkService) _GetTrackUrl(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(GetArtworkUrlRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.GetTrackUrl(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
//go:build wasip1
|
||||
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/artwork/artwork.proto
|
||||
|
||||
package artwork
|
||||
|
||||
import (
|
||||
context "context"
|
||||
wasm "github.com/knqyf263/go-plugin/wasm"
|
||||
_ "unsafe"
|
||||
)
|
||||
|
||||
type artworkService struct{}
|
||||
|
||||
func NewArtworkService() ArtworkService {
|
||||
return artworkService{}
|
||||
}
|
||||
|
||||
//go:wasmimport env get_artist_url
|
||||
func _get_artist_url(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h artworkService) GetArtistUrl(ctx context.Context, request *GetArtworkUrlRequest) (*GetArtworkUrlResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _get_artist_url(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(GetArtworkUrlResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env get_album_url
|
||||
func _get_album_url(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h artworkService) GetAlbumUrl(ctx context.Context, request *GetArtworkUrlRequest) (*GetArtworkUrlResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _get_album_url(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(GetArtworkUrlResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env get_track_url
|
||||
func _get_track_url(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h artworkService) GetTrackUrl(ctx context.Context, request *GetArtworkUrlRequest) (*GetArtworkUrlResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _get_track_url(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(GetArtworkUrlResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
//go:build !wasip1
|
||||
|
||||
package artwork
|
||||
|
||||
func NewArtworkService() ArtworkService {
|
||||
panic("not implemented")
|
||||
}
|
||||
@@ -1,425 +0,0 @@
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/artwork/artwork.proto
|
||||
|
||||
package artwork
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
io "io"
|
||||
bits "math/bits"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
func (m *GetArtworkUrlRequest) MarshalVT() (dAtA []byte, err error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
size := m.SizeVT()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *GetArtworkUrlRequest) MarshalToVT(dAtA []byte) (int, error) {
|
||||
size := m.SizeVT()
|
||||
return m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *GetArtworkUrlRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
if m == nil {
|
||||
return 0, nil
|
||||
}
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.unknownFields != nil {
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
if m.Size != 0 {
|
||||
i = encodeVarint(dAtA, i, uint64(m.Size))
|
||||
i--
|
||||
dAtA[i] = 0x10
|
||||
}
|
||||
if len(m.Id) > 0 {
|
||||
i -= len(m.Id)
|
||||
copy(dAtA[i:], m.Id)
|
||||
i = encodeVarint(dAtA, i, uint64(len(m.Id)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *GetArtworkUrlResponse) MarshalVT() (dAtA []byte, err error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
size := m.SizeVT()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *GetArtworkUrlResponse) MarshalToVT(dAtA []byte) (int, error) {
|
||||
size := m.SizeVT()
|
||||
return m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *GetArtworkUrlResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
if m == nil {
|
||||
return 0, nil
|
||||
}
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.unknownFields != nil {
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
if len(m.Url) > 0 {
|
||||
i -= len(m.Url)
|
||||
copy(dAtA[i:], m.Url)
|
||||
i = encodeVarint(dAtA, i, uint64(len(m.Url)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarint(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sov(v)
|
||||
base := offset
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return base
|
||||
}
|
||||
func (m *GetArtworkUrlRequest) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Id)
|
||||
if l > 0 {
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
if m.Size != 0 {
|
||||
n += 1 + sov(uint64(m.Size))
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *GetArtworkUrlResponse) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Url)
|
||||
if l > 0 {
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
|
||||
func sov(x uint64) (n int) {
|
||||
return (bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
func soz(x uint64) (n int) {
|
||||
return sov(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *GetArtworkUrlRequest) UnmarshalVT(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: GetArtworkUrlRequest: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: GetArtworkUrlRequest: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Id = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Size", wireType)
|
||||
}
|
||||
m.Size = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.Size |= int32(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *GetArtworkUrlResponse) UnmarshalVT(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: GetArtworkUrlResponse: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: GetArtworkUrlResponse: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Url", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Url = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func skip(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
depth := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLength
|
||||
}
|
||||
iNdEx += length
|
||||
case 3:
|
||||
depth++
|
||||
case 4:
|
||||
if depth == 0 {
|
||||
return 0, ErrUnexpectedEndOfGroup
|
||||
}
|
||||
depth--
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLength
|
||||
}
|
||||
if depth == 0 {
|
||||
return iNdEx, nil
|
||||
}
|
||||
}
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLength = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflow = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroup = fmt.Errorf("proto: unexpected end of group")
|
||||
)
|
||||
@@ -0,0 +1,230 @@
|
||||
// Code generated by ndpgen. DO NOT EDIT.
|
||||
|
||||
package host
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// ArtworkGetArtistUrlRequest is the request type for Artwork.GetArtistUrl.
|
||||
type ArtworkGetArtistUrlRequest struct {
|
||||
Id string `json:"id"`
|
||||
Size int32 `json:"size"`
|
||||
}
|
||||
|
||||
// ArtworkGetArtistUrlResponse is the response type for Artwork.GetArtistUrl.
|
||||
type ArtworkGetArtistUrlResponse struct {
|
||||
Url string `json:"url,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// ArtworkGetAlbumUrlRequest is the request type for Artwork.GetAlbumUrl.
|
||||
type ArtworkGetAlbumUrlRequest struct {
|
||||
Id string `json:"id"`
|
||||
Size int32 `json:"size"`
|
||||
}
|
||||
|
||||
// ArtworkGetAlbumUrlResponse is the response type for Artwork.GetAlbumUrl.
|
||||
type ArtworkGetAlbumUrlResponse struct {
|
||||
Url string `json:"url,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// ArtworkGetTrackUrlRequest is the request type for Artwork.GetTrackUrl.
|
||||
type ArtworkGetTrackUrlRequest struct {
|
||||
Id string `json:"id"`
|
||||
Size int32 `json:"size"`
|
||||
}
|
||||
|
||||
// ArtworkGetTrackUrlResponse is the response type for Artwork.GetTrackUrl.
|
||||
type ArtworkGetTrackUrlResponse struct {
|
||||
Url string `json:"url,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// ArtworkGetPlaylistUrlRequest is the request type for Artwork.GetPlaylistUrl.
|
||||
type ArtworkGetPlaylistUrlRequest struct {
|
||||
Id string `json:"id"`
|
||||
Size int32 `json:"size"`
|
||||
}
|
||||
|
||||
// ArtworkGetPlaylistUrlResponse is the response type for Artwork.GetPlaylistUrl.
|
||||
type ArtworkGetPlaylistUrlResponse struct {
|
||||
Url string `json:"url,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// RegisterArtworkHostFunctions registers Artwork service host functions.
|
||||
// The returned host functions should be added to the plugin's configuration.
|
||||
func RegisterArtworkHostFunctions(service ArtworkService) []extism.HostFunction {
|
||||
return []extism.HostFunction{
|
||||
newArtworkGetArtistUrlHostFunction(service),
|
||||
newArtworkGetAlbumUrlHostFunction(service),
|
||||
newArtworkGetTrackUrlHostFunction(service),
|
||||
newArtworkGetPlaylistUrlHostFunction(service),
|
||||
}
|
||||
}
|
||||
|
||||
func newArtworkGetArtistUrlHostFunction(service ArtworkService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"artwork_getartisturl",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
artworkWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req ArtworkGetArtistUrlRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
artworkWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
url, svcErr := service.GetArtistUrl(ctx, req.Id, req.Size)
|
||||
if svcErr != nil {
|
||||
artworkWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := ArtworkGetArtistUrlResponse{
|
||||
Url: url,
|
||||
}
|
||||
artworkWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newArtworkGetAlbumUrlHostFunction(service ArtworkService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"artwork_getalbumurl",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
artworkWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req ArtworkGetAlbumUrlRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
artworkWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
url, svcErr := service.GetAlbumUrl(ctx, req.Id, req.Size)
|
||||
if svcErr != nil {
|
||||
artworkWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := ArtworkGetAlbumUrlResponse{
|
||||
Url: url,
|
||||
}
|
||||
artworkWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newArtworkGetTrackUrlHostFunction(service ArtworkService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"artwork_gettrackurl",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
artworkWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req ArtworkGetTrackUrlRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
artworkWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
url, svcErr := service.GetTrackUrl(ctx, req.Id, req.Size)
|
||||
if svcErr != nil {
|
||||
artworkWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := ArtworkGetTrackUrlResponse{
|
||||
Url: url,
|
||||
}
|
||||
artworkWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newArtworkGetPlaylistUrlHostFunction(service ArtworkService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"artwork_getplaylisturl",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
artworkWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req ArtworkGetPlaylistUrlRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
artworkWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
url, svcErr := service.GetPlaylistUrl(ctx, req.Id, req.Size)
|
||||
if svcErr != nil {
|
||||
artworkWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := ArtworkGetPlaylistUrlResponse{
|
||||
Url: url,
|
||||
}
|
||||
artworkWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
// artworkWriteResponse writes a JSON response to plugin memory.
|
||||
func artworkWriteResponse(p *extism.CurrentPlugin, stack []uint64, resp any) {
|
||||
respBytes, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
artworkWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
respPtr, err := p.WriteBytes(respBytes)
|
||||
if err != nil {
|
||||
stack[0] = 0
|
||||
return
|
||||
}
|
||||
stack[0] = respPtr
|
||||
}
|
||||
|
||||
// artworkWriteError writes an error response to plugin memory.
|
||||
func artworkWriteError(p *extism.CurrentPlugin, stack []uint64, err error) {
|
||||
errResp := struct {
|
||||
Error string `json:"error"`
|
||||
}{Error: err.Error()}
|
||||
respBytes, _ := json.Marshal(errResp)
|
||||
respPtr, _ := p.WriteBytes(respBytes)
|
||||
stack[0] = respPtr
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package host
|
||||
|
||||
import "context"
|
||||
|
||||
// CacheService provides in-memory TTL-based caching capabilities for plugins.
|
||||
//
|
||||
// This service allows plugins to store and retrieve typed values (strings, integers,
|
||||
// floats, and byte slices) with configurable time-to-live expiration. Each plugin's
|
||||
// cache keys are automatically namespaced to prevent collisions between plugins.
|
||||
//
|
||||
// The cache is in-memory only and will be lost on server restart. Plugins should
|
||||
// handle cache misses gracefully.
|
||||
//
|
||||
//nd:hostservice name=Cache permission=cache
|
||||
type CacheService interface {
|
||||
// SetString stores a string value in the cache.
|
||||
//
|
||||
// Parameters:
|
||||
// - key: The cache key (will be namespaced with plugin ID)
|
||||
// - value: The string value to store
|
||||
// - ttlSeconds: Time-to-live in seconds (0 uses default of 24 hours)
|
||||
//
|
||||
// Returns an error if the operation fails.
|
||||
//nd:hostfunc
|
||||
SetString(ctx context.Context, key string, value string, ttlSeconds int64) error
|
||||
|
||||
// GetString retrieves a string value from the cache.
|
||||
//
|
||||
// Parameters:
|
||||
// - key: The cache key (will be namespaced with plugin ID)
|
||||
//
|
||||
// Returns the value and whether the key exists. If the key doesn't exist
|
||||
// or the stored value is not a string, exists will be false.
|
||||
//nd:hostfunc
|
||||
GetString(ctx context.Context, key string) (value string, exists bool, err error)
|
||||
|
||||
// SetInt stores an integer value in the cache.
|
||||
//
|
||||
// Parameters:
|
||||
// - key: The cache key (will be namespaced with plugin ID)
|
||||
// - value: The integer value to store
|
||||
// - ttlSeconds: Time-to-live in seconds (0 uses default of 24 hours)
|
||||
//
|
||||
// Returns an error if the operation fails.
|
||||
//nd:hostfunc
|
||||
SetInt(ctx context.Context, key string, value int64, ttlSeconds int64) error
|
||||
|
||||
// GetInt retrieves an integer value from the cache.
|
||||
//
|
||||
// Parameters:
|
||||
// - key: The cache key (will be namespaced with plugin ID)
|
||||
//
|
||||
// Returns the value and whether the key exists. If the key doesn't exist
|
||||
// or the stored value is not an integer, exists will be false.
|
||||
//nd:hostfunc
|
||||
GetInt(ctx context.Context, key string) (value int64, exists bool, err error)
|
||||
|
||||
// SetFloat stores a float value in the cache.
|
||||
//
|
||||
// Parameters:
|
||||
// - key: The cache key (will be namespaced with plugin ID)
|
||||
// - value: The float value to store
|
||||
// - ttlSeconds: Time-to-live in seconds (0 uses default of 24 hours)
|
||||
//
|
||||
// Returns an error if the operation fails.
|
||||
//nd:hostfunc
|
||||
SetFloat(ctx context.Context, key string, value float64, ttlSeconds int64) error
|
||||
|
||||
// GetFloat retrieves a float value from the cache.
|
||||
//
|
||||
// Parameters:
|
||||
// - key: The cache key (will be namespaced with plugin ID)
|
||||
//
|
||||
// Returns the value and whether the key exists. If the key doesn't exist
|
||||
// or the stored value is not a float, exists will be false.
|
||||
//nd:hostfunc
|
||||
GetFloat(ctx context.Context, key string) (value float64, exists bool, err error)
|
||||
|
||||
// SetBytes stores a byte slice in the cache.
|
||||
//
|
||||
// Parameters:
|
||||
// - key: The cache key (will be namespaced with plugin ID)
|
||||
// - value: The byte slice to store
|
||||
// - ttlSeconds: Time-to-live in seconds (0 uses default of 24 hours)
|
||||
//
|
||||
// Returns an error if the operation fails.
|
||||
//nd:hostfunc
|
||||
SetBytes(ctx context.Context, key string, value []byte, ttlSeconds int64) error
|
||||
|
||||
// GetBytes retrieves a byte slice from the cache.
|
||||
//
|
||||
// Parameters:
|
||||
// - key: The cache key (will be namespaced with plugin ID)
|
||||
//
|
||||
// Returns the value and whether the key exists. If the key doesn't exist
|
||||
// or the stored value is not a byte slice, exists will be false.
|
||||
//nd:hostfunc
|
||||
GetBytes(ctx context.Context, key string) (value []byte, exists bool, err error)
|
||||
|
||||
// Has checks if a key exists in the cache.
|
||||
//
|
||||
// Parameters:
|
||||
// - key: The cache key (will be namespaced with plugin ID)
|
||||
//
|
||||
// Returns true if the key exists and has not expired.
|
||||
//nd:hostfunc
|
||||
Has(ctx context.Context, key string) (exists bool, err error)
|
||||
|
||||
// Remove deletes a value from the cache.
|
||||
//
|
||||
// Parameters:
|
||||
// - key: The cache key (will be namespaced with plugin ID)
|
||||
//
|
||||
// Returns an error if the operation fails. Does not return an error if the key doesn't exist.
|
||||
//nd:hostfunc
|
||||
Remove(ctx context.Context, key string) error
|
||||
}
|
||||
Vendored
-420
@@ -1,420 +0,0 @@
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/cache/cache.proto
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
context "context"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// Request to store a string value
|
||||
type SetStringRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` // Cache key
|
||||
Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` // String value to store
|
||||
TtlSeconds int64 `protobuf:"varint,3,opt,name=ttl_seconds,json=ttlSeconds,proto3" json:"ttl_seconds,omitempty"` // TTL in seconds, 0 means use default
|
||||
}
|
||||
|
||||
func (x *SetStringRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *SetStringRequest) GetKey() string {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SetStringRequest) GetValue() string {
|
||||
if x != nil {
|
||||
return x.Value
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SetStringRequest) GetTtlSeconds() int64 {
|
||||
if x != nil {
|
||||
return x.TtlSeconds
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Request to store an integer value
|
||||
type SetIntRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` // Cache key
|
||||
Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` // Integer value to store
|
||||
TtlSeconds int64 `protobuf:"varint,3,opt,name=ttl_seconds,json=ttlSeconds,proto3" json:"ttl_seconds,omitempty"` // TTL in seconds, 0 means use default
|
||||
}
|
||||
|
||||
func (x *SetIntRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *SetIntRequest) GetKey() string {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SetIntRequest) GetValue() int64 {
|
||||
if x != nil {
|
||||
return x.Value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SetIntRequest) GetTtlSeconds() int64 {
|
||||
if x != nil {
|
||||
return x.TtlSeconds
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Request to store a float value
|
||||
type SetFloatRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` // Cache key
|
||||
Value float64 `protobuf:"fixed64,2,opt,name=value,proto3" json:"value,omitempty"` // Float value to store
|
||||
TtlSeconds int64 `protobuf:"varint,3,opt,name=ttl_seconds,json=ttlSeconds,proto3" json:"ttl_seconds,omitempty"` // TTL in seconds, 0 means use default
|
||||
}
|
||||
|
||||
func (x *SetFloatRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *SetFloatRequest) GetKey() string {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SetFloatRequest) GetValue() float64 {
|
||||
if x != nil {
|
||||
return x.Value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SetFloatRequest) GetTtlSeconds() int64 {
|
||||
if x != nil {
|
||||
return x.TtlSeconds
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Request to store a byte slice value
|
||||
type SetBytesRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` // Cache key
|
||||
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` // Byte slice value to store
|
||||
TtlSeconds int64 `protobuf:"varint,3,opt,name=ttl_seconds,json=ttlSeconds,proto3" json:"ttl_seconds,omitempty"` // TTL in seconds, 0 means use default
|
||||
}
|
||||
|
||||
func (x *SetBytesRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *SetBytesRequest) GetKey() string {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SetBytesRequest) GetValue() []byte {
|
||||
if x != nil {
|
||||
return x.Value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SetBytesRequest) GetTtlSeconds() int64 {
|
||||
if x != nil {
|
||||
return x.TtlSeconds
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Response after setting a value
|
||||
type SetResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` // Whether the operation was successful
|
||||
}
|
||||
|
||||
func (x *SetResponse) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *SetResponse) GetSuccess() bool {
|
||||
if x != nil {
|
||||
return x.Success
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Request to get a value
|
||||
type GetRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` // Cache key
|
||||
}
|
||||
|
||||
func (x *GetRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *GetRequest) GetKey() string {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Response containing a string value
|
||||
type GetStringResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Exists bool `protobuf:"varint,1,opt,name=exists,proto3" json:"exists,omitempty"` // Whether the key exists
|
||||
Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` // The string value (if exists is true)
|
||||
}
|
||||
|
||||
func (x *GetStringResponse) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *GetStringResponse) GetExists() bool {
|
||||
if x != nil {
|
||||
return x.Exists
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *GetStringResponse) GetValue() string {
|
||||
if x != nil {
|
||||
return x.Value
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Response containing an integer value
|
||||
type GetIntResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Exists bool `protobuf:"varint,1,opt,name=exists,proto3" json:"exists,omitempty"` // Whether the key exists
|
||||
Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` // The integer value (if exists is true)
|
||||
}
|
||||
|
||||
func (x *GetIntResponse) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *GetIntResponse) GetExists() bool {
|
||||
if x != nil {
|
||||
return x.Exists
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *GetIntResponse) GetValue() int64 {
|
||||
if x != nil {
|
||||
return x.Value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Response containing a float value
|
||||
type GetFloatResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Exists bool `protobuf:"varint,1,opt,name=exists,proto3" json:"exists,omitempty"` // Whether the key exists
|
||||
Value float64 `protobuf:"fixed64,2,opt,name=value,proto3" json:"value,omitempty"` // The float value (if exists is true)
|
||||
}
|
||||
|
||||
func (x *GetFloatResponse) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *GetFloatResponse) GetExists() bool {
|
||||
if x != nil {
|
||||
return x.Exists
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *GetFloatResponse) GetValue() float64 {
|
||||
if x != nil {
|
||||
return x.Value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Response containing a byte slice value
|
||||
type GetBytesResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Exists bool `protobuf:"varint,1,opt,name=exists,proto3" json:"exists,omitempty"` // Whether the key exists
|
||||
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` // The byte slice value (if exists is true)
|
||||
}
|
||||
|
||||
func (x *GetBytesResponse) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *GetBytesResponse) GetExists() bool {
|
||||
if x != nil {
|
||||
return x.Exists
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *GetBytesResponse) GetValue() []byte {
|
||||
if x != nil {
|
||||
return x.Value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Request to remove a value
|
||||
type RemoveRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` // Cache key
|
||||
}
|
||||
|
||||
func (x *RemoveRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *RemoveRequest) GetKey() string {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Response after removing a value
|
||||
type RemoveResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` // Whether the operation was successful
|
||||
}
|
||||
|
||||
func (x *RemoveResponse) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *RemoveResponse) GetSuccess() bool {
|
||||
if x != nil {
|
||||
return x.Success
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Request to check if a key exists
|
||||
type HasRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` // Cache key
|
||||
}
|
||||
|
||||
func (x *HasRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *HasRequest) GetKey() string {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Response indicating if a key exists
|
||||
type HasResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Exists bool `protobuf:"varint,1,opt,name=exists,proto3" json:"exists,omitempty"` // Whether the key exists
|
||||
}
|
||||
|
||||
func (x *HasResponse) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *HasResponse) GetExists() bool {
|
||||
if x != nil {
|
||||
return x.Exists
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// go:plugin type=host version=1
|
||||
type CacheService interface {
|
||||
// Set a string value in the cache
|
||||
SetString(context.Context, *SetStringRequest) (*SetResponse, error)
|
||||
// Get a string value from the cache
|
||||
GetString(context.Context, *GetRequest) (*GetStringResponse, error)
|
||||
// Set an integer value in the cache
|
||||
SetInt(context.Context, *SetIntRequest) (*SetResponse, error)
|
||||
// Get an integer value from the cache
|
||||
GetInt(context.Context, *GetRequest) (*GetIntResponse, error)
|
||||
// Set a float value in the cache
|
||||
SetFloat(context.Context, *SetFloatRequest) (*SetResponse, error)
|
||||
// Get a float value from the cache
|
||||
GetFloat(context.Context, *GetRequest) (*GetFloatResponse, error)
|
||||
// Set a byte slice value in the cache
|
||||
SetBytes(context.Context, *SetBytesRequest) (*SetResponse, error)
|
||||
// Get a byte slice value from the cache
|
||||
GetBytes(context.Context, *GetRequest) (*GetBytesResponse, error)
|
||||
// Remove a value from the cache
|
||||
Remove(context.Context, *RemoveRequest) (*RemoveResponse, error)
|
||||
// Check if a key exists in the cache
|
||||
Has(context.Context, *HasRequest) (*HasResponse, error)
|
||||
}
|
||||
Vendored
-120
@@ -1,120 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package cache;
|
||||
|
||||
option go_package = "github.com/navidrome/navidrome/plugins/host/cache;cache";
|
||||
|
||||
// go:plugin type=host version=1
|
||||
service CacheService {
|
||||
// Set a string value in the cache
|
||||
rpc SetString(SetStringRequest) returns (SetResponse);
|
||||
|
||||
// Get a string value from the cache
|
||||
rpc GetString(GetRequest) returns (GetStringResponse);
|
||||
|
||||
// Set an integer value in the cache
|
||||
rpc SetInt(SetIntRequest) returns (SetResponse);
|
||||
|
||||
// Get an integer value from the cache
|
||||
rpc GetInt(GetRequest) returns (GetIntResponse);
|
||||
|
||||
// Set a float value in the cache
|
||||
rpc SetFloat(SetFloatRequest) returns (SetResponse);
|
||||
|
||||
// Get a float value from the cache
|
||||
rpc GetFloat(GetRequest) returns (GetFloatResponse);
|
||||
|
||||
// Set a byte slice value in the cache
|
||||
rpc SetBytes(SetBytesRequest) returns (SetResponse);
|
||||
|
||||
// Get a byte slice value from the cache
|
||||
rpc GetBytes(GetRequest) returns (GetBytesResponse);
|
||||
|
||||
// Remove a value from the cache
|
||||
rpc Remove(RemoveRequest) returns (RemoveResponse);
|
||||
|
||||
// Check if a key exists in the cache
|
||||
rpc Has(HasRequest) returns (HasResponse);
|
||||
}
|
||||
|
||||
// Request to store a string value
|
||||
message SetStringRequest {
|
||||
string key = 1; // Cache key
|
||||
string value = 2; // String value to store
|
||||
int64 ttl_seconds = 3; // TTL in seconds, 0 means use default
|
||||
}
|
||||
|
||||
// Request to store an integer value
|
||||
message SetIntRequest {
|
||||
string key = 1; // Cache key
|
||||
int64 value = 2; // Integer value to store
|
||||
int64 ttl_seconds = 3; // TTL in seconds, 0 means use default
|
||||
}
|
||||
|
||||
// Request to store a float value
|
||||
message SetFloatRequest {
|
||||
string key = 1; // Cache key
|
||||
double value = 2; // Float value to store
|
||||
int64 ttl_seconds = 3; // TTL in seconds, 0 means use default
|
||||
}
|
||||
|
||||
// Request to store a byte slice value
|
||||
message SetBytesRequest {
|
||||
string key = 1; // Cache key
|
||||
bytes value = 2; // Byte slice value to store
|
||||
int64 ttl_seconds = 3; // TTL in seconds, 0 means use default
|
||||
}
|
||||
|
||||
// Response after setting a value
|
||||
message SetResponse {
|
||||
bool success = 1; // Whether the operation was successful
|
||||
}
|
||||
|
||||
// Request to get a value
|
||||
message GetRequest {
|
||||
string key = 1; // Cache key
|
||||
}
|
||||
|
||||
// Response containing a string value
|
||||
message GetStringResponse {
|
||||
bool exists = 1; // Whether the key exists
|
||||
string value = 2; // The string value (if exists is true)
|
||||
}
|
||||
|
||||
// Response containing an integer value
|
||||
message GetIntResponse {
|
||||
bool exists = 1; // Whether the key exists
|
||||
int64 value = 2; // The integer value (if exists is true)
|
||||
}
|
||||
|
||||
// Response containing a float value
|
||||
message GetFloatResponse {
|
||||
bool exists = 1; // Whether the key exists
|
||||
double value = 2; // The float value (if exists is true)
|
||||
}
|
||||
|
||||
// Response containing a byte slice value
|
||||
message GetBytesResponse {
|
||||
bool exists = 1; // Whether the key exists
|
||||
bytes value = 2; // The byte slice value (if exists is true)
|
||||
}
|
||||
|
||||
// Request to remove a value
|
||||
message RemoveRequest {
|
||||
string key = 1; // Cache key
|
||||
}
|
||||
|
||||
// Response after removing a value
|
||||
message RemoveResponse {
|
||||
bool success = 1; // Whether the operation was successful
|
||||
}
|
||||
|
||||
// Request to check if a key exists
|
||||
message HasRequest {
|
||||
string key = 1; // Cache key
|
||||
}
|
||||
|
||||
// Response indicating if a key exists
|
||||
message HasResponse {
|
||||
bool exists = 1; // Whether the key exists
|
||||
}
|
||||
Vendored
-374
@@ -1,374 +0,0 @@
|
||||
//go:build !wasip1
|
||||
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/cache/cache.proto
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
context "context"
|
||||
wasm "github.com/knqyf263/go-plugin/wasm"
|
||||
wazero "github.com/tetratelabs/wazero"
|
||||
api "github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
|
||||
const (
|
||||
i32 = api.ValueTypeI32
|
||||
i64 = api.ValueTypeI64
|
||||
)
|
||||
|
||||
type _cacheService struct {
|
||||
CacheService
|
||||
}
|
||||
|
||||
// Instantiate a Go-defined module named "env" that exports host functions.
|
||||
func Instantiate(ctx context.Context, r wazero.Runtime, hostFunctions CacheService) error {
|
||||
envBuilder := r.NewHostModuleBuilder("env")
|
||||
h := _cacheService{hostFunctions}
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._SetString), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("set_string")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._GetString), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("get_string")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._SetInt), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("set_int")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._GetInt), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("get_int")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._SetFloat), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("set_float")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._GetFloat), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("get_float")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._SetBytes), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("set_bytes")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._GetBytes), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("get_bytes")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._Remove), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("remove")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._Has), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("has")
|
||||
|
||||
_, err := envBuilder.Instantiate(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// Set a string value in the cache
|
||||
|
||||
func (h _cacheService) _SetString(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(SetStringRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.SetString(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
// Get a string value from the cache
|
||||
|
||||
func (h _cacheService) _GetString(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(GetRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.GetString(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
// Set an integer value in the cache
|
||||
|
||||
func (h _cacheService) _SetInt(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(SetIntRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.SetInt(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
// Get an integer value from the cache
|
||||
|
||||
func (h _cacheService) _GetInt(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(GetRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.GetInt(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
// Set a float value in the cache
|
||||
|
||||
func (h _cacheService) _SetFloat(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(SetFloatRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.SetFloat(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
// Get a float value from the cache
|
||||
|
||||
func (h _cacheService) _GetFloat(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(GetRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.GetFloat(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
// Set a byte slice value in the cache
|
||||
|
||||
func (h _cacheService) _SetBytes(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(SetBytesRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.SetBytes(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
// Get a byte slice value from the cache
|
||||
|
||||
func (h _cacheService) _GetBytes(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(GetRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.GetBytes(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
// Remove a value from the cache
|
||||
|
||||
func (h _cacheService) _Remove(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(RemoveRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.Remove(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
// Check if a key exists in the cache
|
||||
|
||||
func (h _cacheService) _Has(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(HasRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.Has(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
-251
@@ -1,251 +0,0 @@
|
||||
//go:build wasip1
|
||||
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/cache/cache.proto
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
context "context"
|
||||
wasm "github.com/knqyf263/go-plugin/wasm"
|
||||
_ "unsafe"
|
||||
)
|
||||
|
||||
type cacheService struct{}
|
||||
|
||||
func NewCacheService() CacheService {
|
||||
return cacheService{}
|
||||
}
|
||||
|
||||
//go:wasmimport env set_string
|
||||
func _set_string(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h cacheService) SetString(ctx context.Context, request *SetStringRequest) (*SetResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _set_string(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(SetResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env get_string
|
||||
func _get_string(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h cacheService) GetString(ctx context.Context, request *GetRequest) (*GetStringResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _get_string(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(GetStringResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env set_int
|
||||
func _set_int(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h cacheService) SetInt(ctx context.Context, request *SetIntRequest) (*SetResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _set_int(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(SetResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env get_int
|
||||
func _get_int(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h cacheService) GetInt(ctx context.Context, request *GetRequest) (*GetIntResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _get_int(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(GetIntResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env set_float
|
||||
func _set_float(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h cacheService) SetFloat(ctx context.Context, request *SetFloatRequest) (*SetResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _set_float(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(SetResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env get_float
|
||||
func _get_float(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h cacheService) GetFloat(ctx context.Context, request *GetRequest) (*GetFloatResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _get_float(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(GetFloatResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env set_bytes
|
||||
func _set_bytes(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h cacheService) SetBytes(ctx context.Context, request *SetBytesRequest) (*SetResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _set_bytes(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(SetResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env get_bytes
|
||||
func _get_bytes(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h cacheService) GetBytes(ctx context.Context, request *GetRequest) (*GetBytesResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _get_bytes(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(GetBytesResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env remove
|
||||
func _remove(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h cacheService) Remove(ctx context.Context, request *RemoveRequest) (*RemoveResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _remove(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(RemoveResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env has
|
||||
func _has(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h cacheService) Has(ctx context.Context, request *HasRequest) (*HasResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _has(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(HasResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
//go:build !wasip1
|
||||
|
||||
package cache
|
||||
|
||||
func NewCacheService() CacheService {
|
||||
panic("not implemented")
|
||||
}
|
||||
-2352
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,498 @@
|
||||
// Code generated by ndpgen. DO NOT EDIT.
|
||||
|
||||
package host
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// CacheSetStringRequest is the request type for Cache.SetString.
|
||||
type CacheSetStringRequest struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
TtlSeconds int64 `json:"ttlSeconds"`
|
||||
}
|
||||
|
||||
// CacheSetStringResponse is the response type for Cache.SetString.
|
||||
type CacheSetStringResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// CacheGetStringRequest is the request type for Cache.GetString.
|
||||
type CacheGetStringRequest struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// CacheGetStringResponse is the response type for Cache.GetString.
|
||||
type CacheGetStringResponse struct {
|
||||
Value string `json:"value,omitempty"`
|
||||
Exists bool `json:"exists,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// CacheSetIntRequest is the request type for Cache.SetInt.
|
||||
type CacheSetIntRequest struct {
|
||||
Key string `json:"key"`
|
||||
Value int64 `json:"value"`
|
||||
TtlSeconds int64 `json:"ttlSeconds"`
|
||||
}
|
||||
|
||||
// CacheSetIntResponse is the response type for Cache.SetInt.
|
||||
type CacheSetIntResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// CacheGetIntRequest is the request type for Cache.GetInt.
|
||||
type CacheGetIntRequest struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// CacheGetIntResponse is the response type for Cache.GetInt.
|
||||
type CacheGetIntResponse struct {
|
||||
Value int64 `json:"value,omitempty"`
|
||||
Exists bool `json:"exists,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// CacheSetFloatRequest is the request type for Cache.SetFloat.
|
||||
type CacheSetFloatRequest struct {
|
||||
Key string `json:"key"`
|
||||
Value float64 `json:"value"`
|
||||
TtlSeconds int64 `json:"ttlSeconds"`
|
||||
}
|
||||
|
||||
// CacheSetFloatResponse is the response type for Cache.SetFloat.
|
||||
type CacheSetFloatResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// CacheGetFloatRequest is the request type for Cache.GetFloat.
|
||||
type CacheGetFloatRequest struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// CacheGetFloatResponse is the response type for Cache.GetFloat.
|
||||
type CacheGetFloatResponse struct {
|
||||
Value float64 `json:"value,omitempty"`
|
||||
Exists bool `json:"exists,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// CacheSetBytesRequest is the request type for Cache.SetBytes.
|
||||
type CacheSetBytesRequest struct {
|
||||
Key string `json:"key"`
|
||||
Value []byte `json:"value"`
|
||||
TtlSeconds int64 `json:"ttlSeconds"`
|
||||
}
|
||||
|
||||
// CacheSetBytesResponse is the response type for Cache.SetBytes.
|
||||
type CacheSetBytesResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// CacheGetBytesRequest is the request type for Cache.GetBytes.
|
||||
type CacheGetBytesRequest struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// CacheGetBytesResponse is the response type for Cache.GetBytes.
|
||||
type CacheGetBytesResponse struct {
|
||||
Value []byte `json:"value,omitempty"`
|
||||
Exists bool `json:"exists,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// CacheHasRequest is the request type for Cache.Has.
|
||||
type CacheHasRequest struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// CacheHasResponse is the response type for Cache.Has.
|
||||
type CacheHasResponse struct {
|
||||
Exists bool `json:"exists,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// CacheRemoveRequest is the request type for Cache.Remove.
|
||||
type CacheRemoveRequest struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// CacheRemoveResponse is the response type for Cache.Remove.
|
||||
type CacheRemoveResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// RegisterCacheHostFunctions registers Cache service host functions.
|
||||
// The returned host functions should be added to the plugin's configuration.
|
||||
func RegisterCacheHostFunctions(service CacheService) []extism.HostFunction {
|
||||
return []extism.HostFunction{
|
||||
newCacheSetStringHostFunction(service),
|
||||
newCacheGetStringHostFunction(service),
|
||||
newCacheSetIntHostFunction(service),
|
||||
newCacheGetIntHostFunction(service),
|
||||
newCacheSetFloatHostFunction(service),
|
||||
newCacheGetFloatHostFunction(service),
|
||||
newCacheSetBytesHostFunction(service),
|
||||
newCacheGetBytesHostFunction(service),
|
||||
newCacheHasHostFunction(service),
|
||||
newCacheRemoveHostFunction(service),
|
||||
}
|
||||
}
|
||||
|
||||
func newCacheSetStringHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_setstring",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CacheSetStringRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
if svcErr := service.SetString(ctx, req.Key, req.Value, req.TtlSeconds); svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheSetStringResponse{}
|
||||
cacheWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newCacheGetStringHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_getstring",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CacheGetStringRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
value, exists, svcErr := service.GetString(ctx, req.Key)
|
||||
if svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheGetStringResponse{
|
||||
Value: value,
|
||||
Exists: exists,
|
||||
}
|
||||
cacheWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newCacheSetIntHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_setint",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CacheSetIntRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
if svcErr := service.SetInt(ctx, req.Key, req.Value, req.TtlSeconds); svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheSetIntResponse{}
|
||||
cacheWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newCacheGetIntHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_getint",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CacheGetIntRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
value, exists, svcErr := service.GetInt(ctx, req.Key)
|
||||
if svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheGetIntResponse{
|
||||
Value: value,
|
||||
Exists: exists,
|
||||
}
|
||||
cacheWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newCacheSetFloatHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_setfloat",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CacheSetFloatRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
if svcErr := service.SetFloat(ctx, req.Key, req.Value, req.TtlSeconds); svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheSetFloatResponse{}
|
||||
cacheWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newCacheGetFloatHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_getfloat",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CacheGetFloatRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
value, exists, svcErr := service.GetFloat(ctx, req.Key)
|
||||
if svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheGetFloatResponse{
|
||||
Value: value,
|
||||
Exists: exists,
|
||||
}
|
||||
cacheWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newCacheSetBytesHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_setbytes",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CacheSetBytesRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
if svcErr := service.SetBytes(ctx, req.Key, req.Value, req.TtlSeconds); svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheSetBytesResponse{}
|
||||
cacheWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newCacheGetBytesHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_getbytes",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CacheGetBytesRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
value, exists, svcErr := service.GetBytes(ctx, req.Key)
|
||||
if svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheGetBytesResponse{
|
||||
Value: value,
|
||||
Exists: exists,
|
||||
}
|
||||
cacheWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newCacheHasHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_has",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CacheHasRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
exists, svcErr := service.Has(ctx, req.Key)
|
||||
if svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheHasResponse{
|
||||
Exists: exists,
|
||||
}
|
||||
cacheWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newCacheRemoveHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_remove",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CacheRemoveRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
if svcErr := service.Remove(ctx, req.Key); svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheRemoveResponse{}
|
||||
cacheWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
// cacheWriteResponse writes a JSON response to plugin memory.
|
||||
func cacheWriteResponse(p *extism.CurrentPlugin, stack []uint64, resp any) {
|
||||
respBytes, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
respPtr, err := p.WriteBytes(respBytes)
|
||||
if err != nil {
|
||||
stack[0] = 0
|
||||
return
|
||||
}
|
||||
stack[0] = respPtr
|
||||
}
|
||||
|
||||
// cacheWriteError writes an error response to plugin memory.
|
||||
func cacheWriteError(p *extism.CurrentPlugin, stack []uint64, err error) {
|
||||
errResp := struct {
|
||||
Error string `json:"error"`
|
||||
}{Error: err.Error()}
|
||||
respBytes, _ := json.Marshal(errResp)
|
||||
respPtr, _ := p.WriteBytes(respBytes)
|
||||
stack[0] = respPtr
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package host
|
||||
|
||||
import "context"
|
||||
|
||||
// ConfigService provides access to plugin configuration values.
|
||||
//
|
||||
// This service allows plugins to retrieve configuration values and enumerate
|
||||
// available configuration keys. Unlike the built-in pdk.GetConfig(key) which
|
||||
// only retrieves individual values, this service provides methods to list all
|
||||
// available keys, making it useful for plugins that need to discover dynamic
|
||||
// configuration (e.g., user-to-token mappings).
|
||||
//
|
||||
// This service is always available and does not require a permission in the manifest.
|
||||
//
|
||||
//nd:hostservice name=Config
|
||||
type ConfigService interface {
|
||||
// Get retrieves a configuration value as a string.
|
||||
//
|
||||
// Parameters:
|
||||
// - key: The configuration key
|
||||
//
|
||||
// Returns the value and whether the key exists.
|
||||
//nd:hostfunc
|
||||
Get(ctx context.Context, key string) (value string, exists bool)
|
||||
|
||||
// GetInt retrieves a configuration value as an integer.
|
||||
//
|
||||
// Parameters:
|
||||
// - key: The configuration key
|
||||
//
|
||||
// Returns the value and whether the key exists. If the key exists but the
|
||||
// value cannot be parsed as an integer, exists will be false.
|
||||
//nd:hostfunc
|
||||
GetInt(ctx context.Context, key string) (value int64, exists bool)
|
||||
|
||||
// Keys returns configuration keys matching the given prefix.
|
||||
//
|
||||
// Parameters:
|
||||
// - prefix: Key prefix to filter by. If empty, returns all keys.
|
||||
//
|
||||
// Returns a sorted slice of matching configuration keys.
|
||||
//nd:hostfunc
|
||||
Keys(ctx context.Context, prefix string) (keys []string)
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/config/config.proto
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
context "context"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type GetPluginConfigRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *GetPluginConfigRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
type GetPluginConfigResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Config map[string]string `protobuf:"bytes,1,rep,name=config,proto3" json:"config,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
}
|
||||
|
||||
func (x *GetPluginConfigResponse) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *GetPluginConfigResponse) GetConfig() map[string]string {
|
||||
if x != nil {
|
||||
return x.Config
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// go:plugin type=host version=1
|
||||
type ConfigService interface {
|
||||
GetPluginConfig(context.Context, *GetPluginConfigRequest) (*GetPluginConfigResponse, error)
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package config;
|
||||
|
||||
option go_package = "github.com/navidrome/navidrome/plugins/host/config;config";
|
||||
|
||||
// go:plugin type=host version=1
|
||||
service ConfigService {
|
||||
rpc GetPluginConfig(GetPluginConfigRequest) returns (GetPluginConfigResponse);
|
||||
}
|
||||
|
||||
message GetPluginConfigRequest {
|
||||
// No fields needed; plugin name is inferred from context
|
||||
}
|
||||
|
||||
message GetPluginConfigResponse {
|
||||
map<string, string> config = 1;
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
//go:build !wasip1
|
||||
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/config/config.proto
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
context "context"
|
||||
wasm "github.com/knqyf263/go-plugin/wasm"
|
||||
wazero "github.com/tetratelabs/wazero"
|
||||
api "github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
|
||||
const (
|
||||
i32 = api.ValueTypeI32
|
||||
i64 = api.ValueTypeI64
|
||||
)
|
||||
|
||||
type _configService struct {
|
||||
ConfigService
|
||||
}
|
||||
|
||||
// Instantiate a Go-defined module named "env" that exports host functions.
|
||||
func Instantiate(ctx context.Context, r wazero.Runtime, hostFunctions ConfigService) error {
|
||||
envBuilder := r.NewHostModuleBuilder("env")
|
||||
h := _configService{hostFunctions}
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._GetPluginConfig), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("get_plugin_config")
|
||||
|
||||
_, err := envBuilder.Instantiate(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
func (h _configService) _GetPluginConfig(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(GetPluginConfigRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.GetPluginConfig(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
//go:build wasip1
|
||||
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/config/config.proto
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
context "context"
|
||||
wasm "github.com/knqyf263/go-plugin/wasm"
|
||||
_ "unsafe"
|
||||
)
|
||||
|
||||
type configService struct{}
|
||||
|
||||
func NewConfigService() ConfigService {
|
||||
return configService{}
|
||||
}
|
||||
|
||||
//go:wasmimport env get_plugin_config
|
||||
func _get_plugin_config(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h configService) GetPluginConfig(ctx context.Context, request *GetPluginConfigRequest) (*GetPluginConfigResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _get_plugin_config(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(GetPluginConfigResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
//go:build !wasip1
|
||||
|
||||
package config
|
||||
|
||||
func NewConfigService() ConfigService {
|
||||
panic("not implemented")
|
||||
}
|
||||
@@ -1,466 +0,0 @@
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/config/config.proto
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
io "io"
|
||||
bits "math/bits"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
func (m *GetPluginConfigRequest) MarshalVT() (dAtA []byte, err error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
size := m.SizeVT()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *GetPluginConfigRequest) MarshalToVT(dAtA []byte) (int, error) {
|
||||
size := m.SizeVT()
|
||||
return m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *GetPluginConfigRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
if m == nil {
|
||||
return 0, nil
|
||||
}
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.unknownFields != nil {
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *GetPluginConfigResponse) MarshalVT() (dAtA []byte, err error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
size := m.SizeVT()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *GetPluginConfigResponse) MarshalToVT(dAtA []byte) (int, error) {
|
||||
size := m.SizeVT()
|
||||
return m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *GetPluginConfigResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
if m == nil {
|
||||
return 0, nil
|
||||
}
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.unknownFields != nil {
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
if len(m.Config) > 0 {
|
||||
for k := range m.Config {
|
||||
v := m.Config[k]
|
||||
baseI := i
|
||||
i -= len(v)
|
||||
copy(dAtA[i:], v)
|
||||
i = encodeVarint(dAtA, i, uint64(len(v)))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
i -= len(k)
|
||||
copy(dAtA[i:], k)
|
||||
i = encodeVarint(dAtA, i, uint64(len(k)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
i = encodeVarint(dAtA, i, uint64(baseI-i))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarint(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sov(v)
|
||||
base := offset
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return base
|
||||
}
|
||||
func (m *GetPluginConfigRequest) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *GetPluginConfigResponse) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Config) > 0 {
|
||||
for k, v := range m.Config {
|
||||
_ = k
|
||||
_ = v
|
||||
mapEntrySize := 1 + len(k) + sov(uint64(len(k))) + 1 + len(v) + sov(uint64(len(v)))
|
||||
n += mapEntrySize + 1 + sov(uint64(mapEntrySize))
|
||||
}
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
|
||||
func sov(x uint64) (n int) {
|
||||
return (bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
func soz(x uint64) (n int) {
|
||||
return sov(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *GetPluginConfigRequest) UnmarshalVT(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: GetPluginConfigRequest: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: GetPluginConfigRequest: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *GetPluginConfigResponse) UnmarshalVT(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: GetPluginConfigResponse: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: GetPluginConfigResponse: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Config", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.Config == nil {
|
||||
m.Config = make(map[string]string)
|
||||
}
|
||||
var mapkey string
|
||||
var mapvalue string
|
||||
for iNdEx < postIndex {
|
||||
entryPreIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
if fieldNum == 1 {
|
||||
var stringLenmapkey uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLenmapkey |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLenmapkey := int(stringLenmapkey)
|
||||
if intStringLenmapkey < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postStringIndexmapkey := iNdEx + intStringLenmapkey
|
||||
if postStringIndexmapkey < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postStringIndexmapkey > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
mapkey = string(dAtA[iNdEx:postStringIndexmapkey])
|
||||
iNdEx = postStringIndexmapkey
|
||||
} else if fieldNum == 2 {
|
||||
var stringLenmapvalue uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLenmapvalue |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLenmapvalue := int(stringLenmapvalue)
|
||||
if intStringLenmapvalue < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postStringIndexmapvalue := iNdEx + intStringLenmapvalue
|
||||
if postStringIndexmapvalue < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postStringIndexmapvalue > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])
|
||||
iNdEx = postStringIndexmapvalue
|
||||
} else {
|
||||
iNdEx = entryPreIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if (iNdEx + skippy) > postIndex {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
m.Config[mapkey] = mapvalue
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func skip(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
depth := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLength
|
||||
}
|
||||
iNdEx += length
|
||||
case 3:
|
||||
depth++
|
||||
case 4:
|
||||
if depth == 0 {
|
||||
return 0, ErrUnexpectedEndOfGroup
|
||||
}
|
||||
depth--
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLength
|
||||
}
|
||||
if depth == 0 {
|
||||
return iNdEx, nil
|
||||
}
|
||||
}
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLength = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflow = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroup = fmt.Errorf("proto: unexpected end of group")
|
||||
)
|
||||
@@ -0,0 +1,169 @@
|
||||
// Code generated by ndpgen. DO NOT EDIT.
|
||||
|
||||
package host
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// ConfigGetRequest is the request type for Config.Get.
|
||||
type ConfigGetRequest struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// ConfigGetResponse is the response type for Config.Get.
|
||||
type ConfigGetResponse struct {
|
||||
Value string `json:"value,omitempty"`
|
||||
Exists bool `json:"exists,omitempty"`
|
||||
}
|
||||
|
||||
// ConfigGetIntRequest is the request type for Config.GetInt.
|
||||
type ConfigGetIntRequest struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// ConfigGetIntResponse is the response type for Config.GetInt.
|
||||
type ConfigGetIntResponse struct {
|
||||
Value int64 `json:"value,omitempty"`
|
||||
Exists bool `json:"exists,omitempty"`
|
||||
}
|
||||
|
||||
// ConfigKeysRequest is the request type for Config.Keys.
|
||||
type ConfigKeysRequest struct {
|
||||
Prefix string `json:"prefix"`
|
||||
}
|
||||
|
||||
// ConfigKeysResponse is the response type for Config.Keys.
|
||||
type ConfigKeysResponse struct {
|
||||
Keys []string `json:"keys,omitempty"`
|
||||
}
|
||||
|
||||
// RegisterConfigHostFunctions registers Config service host functions.
|
||||
// The returned host functions should be added to the plugin's configuration.
|
||||
func RegisterConfigHostFunctions(service ConfigService) []extism.HostFunction {
|
||||
return []extism.HostFunction{
|
||||
newConfigGetHostFunction(service),
|
||||
newConfigGetIntHostFunction(service),
|
||||
newConfigKeysHostFunction(service),
|
||||
}
|
||||
}
|
||||
|
||||
func newConfigGetHostFunction(service ConfigService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"config_get",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
configWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req ConfigGetRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
configWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
value, exists := service.Get(ctx, req.Key)
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := ConfigGetResponse{
|
||||
Value: value,
|
||||
Exists: exists,
|
||||
}
|
||||
configWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newConfigGetIntHostFunction(service ConfigService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"config_getint",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
configWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req ConfigGetIntRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
configWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
value, exists := service.GetInt(ctx, req.Key)
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := ConfigGetIntResponse{
|
||||
Value: value,
|
||||
Exists: exists,
|
||||
}
|
||||
configWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newConfigKeysHostFunction(service ConfigService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"config_keys",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
configWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req ConfigKeysRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
configWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
keys := service.Keys(ctx, req.Prefix)
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := ConfigKeysResponse{
|
||||
Keys: keys,
|
||||
}
|
||||
configWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
// configWriteResponse writes a JSON response to plugin memory.
|
||||
func configWriteResponse(p *extism.CurrentPlugin, stack []uint64, resp any) {
|
||||
respBytes, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
configWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
respPtr, err := p.WriteBytes(respBytes)
|
||||
if err != nil {
|
||||
stack[0] = 0
|
||||
return
|
||||
}
|
||||
stack[0] = respPtr
|
||||
}
|
||||
|
||||
// configWriteError writes an error response to plugin memory.
|
||||
func configWriteError(p *extism.CurrentPlugin, stack []uint64, err error) {
|
||||
errResp := struct {
|
||||
Error string `json:"error"`
|
||||
}{Error: err.Error()}
|
||||
respBytes, _ := json.Marshal(errResp)
|
||||
respPtr, _ := p.WriteBytes(respBytes)
|
||||
stack[0] = respPtr
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Package host provides host services that can be called by plugins via Extism host functions.
|
||||
//
|
||||
// Host services allow plugins to access Navidrome functionality like the Subsonic API,
|
||||
// scheduler, and other internal services. Services are defined as Go interfaces with
|
||||
// special annotations that enable automatic code generation of Extism host function wrappers.
|
||||
//
|
||||
// # Annotation Format
|
||||
//
|
||||
// Host services use Go doc comment annotations to mark interfaces and methods for code generation:
|
||||
//
|
||||
// // MyService provides some functionality.
|
||||
// //nd:hostservice name=MyService permission=myservice
|
||||
// type MyService interface {
|
||||
// // DoSomething performs an action.
|
||||
// //nd:hostfunc
|
||||
// DoSomething(ctx context.Context, input string) (output string, err error)
|
||||
// }
|
||||
//
|
||||
// Service-level annotations:
|
||||
// - //nd:hostservice - Marks an interface as a host service
|
||||
// - name=<ServiceName> - Service identifier used in generated code
|
||||
// - permission=<key> - Manifest permission key (e.g., "subsonicapi", "scheduler")
|
||||
//
|
||||
// Method-level annotations:
|
||||
// - //nd:hostfunc - Marks a method for host function wrapper generation
|
||||
// - name=<CustomName> - Optional: override the export name
|
||||
//
|
||||
// # Generated Code
|
||||
//
|
||||
// The ndpgen tool reads annotated interfaces and generates Extism host function wrappers
|
||||
// that handle:
|
||||
// - JSON serialization/deserialization of request/response types
|
||||
// - Memory operations (ReadBytes, WriteBytes, Alloc)
|
||||
// - Error handling and propagation
|
||||
// - Service registration functions
|
||||
//
|
||||
// Generated files follow the pattern <servicename>_gen.go and include a header comment
|
||||
// indicating they should not be edited manually.
|
||||
package host
|
||||
@@ -1,117 +0,0 @@
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/http/http.proto
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
context "context"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type HttpRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
|
||||
Headers map[string]string `protobuf:"bytes,2,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
TimeoutMs int32 `protobuf:"varint,3,opt,name=timeout_ms,json=timeoutMs,proto3" json:"timeout_ms,omitempty"`
|
||||
Body []byte `protobuf:"bytes,4,opt,name=body,proto3" json:"body,omitempty"` // Ignored for GET/DELETE/HEAD/OPTIONS
|
||||
}
|
||||
|
||||
func (x *HttpRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *HttpRequest) GetUrl() string {
|
||||
if x != nil {
|
||||
return x.Url
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *HttpRequest) GetHeaders() map[string]string {
|
||||
if x != nil {
|
||||
return x.Headers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *HttpRequest) GetTimeoutMs() int32 {
|
||||
if x != nil {
|
||||
return x.TimeoutMs
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *HttpRequest) GetBody() []byte {
|
||||
if x != nil {
|
||||
return x.Body
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type HttpResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Status int32 `protobuf:"varint,1,opt,name=status,proto3" json:"status,omitempty"`
|
||||
Body []byte `protobuf:"bytes,2,opt,name=body,proto3" json:"body,omitempty"`
|
||||
Headers map[string]string `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
Error string `protobuf:"bytes,4,opt,name=error,proto3" json:"error,omitempty"` // Non-empty if network/protocol error
|
||||
}
|
||||
|
||||
func (x *HttpResponse) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *HttpResponse) GetStatus() int32 {
|
||||
if x != nil {
|
||||
return x.Status
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *HttpResponse) GetBody() []byte {
|
||||
if x != nil {
|
||||
return x.Body
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *HttpResponse) GetHeaders() map[string]string {
|
||||
if x != nil {
|
||||
return x.Headers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *HttpResponse) GetError() string {
|
||||
if x != nil {
|
||||
return x.Error
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// go:plugin type=host version=1
|
||||
type HttpService interface {
|
||||
Get(context.Context, *HttpRequest) (*HttpResponse, error)
|
||||
Post(context.Context, *HttpRequest) (*HttpResponse, error)
|
||||
Put(context.Context, *HttpRequest) (*HttpResponse, error)
|
||||
Delete(context.Context, *HttpRequest) (*HttpResponse, error)
|
||||
Patch(context.Context, *HttpRequest) (*HttpResponse, error)
|
||||
Head(context.Context, *HttpRequest) (*HttpResponse, error)
|
||||
Options(context.Context, *HttpRequest) (*HttpResponse, error)
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package http;
|
||||
|
||||
option go_package = "github.com/navidrome/navidrome/plugins/host/http;http";
|
||||
|
||||
// go:plugin type=host version=1
|
||||
service HttpService {
|
||||
rpc Get(HttpRequest) returns (HttpResponse);
|
||||
rpc Post(HttpRequest) returns (HttpResponse);
|
||||
rpc Put(HttpRequest) returns (HttpResponse);
|
||||
rpc Delete(HttpRequest) returns (HttpResponse);
|
||||
rpc Patch(HttpRequest) returns (HttpResponse);
|
||||
rpc Head(HttpRequest) returns (HttpResponse);
|
||||
rpc Options(HttpRequest) returns (HttpResponse);
|
||||
}
|
||||
|
||||
message HttpRequest {
|
||||
string url = 1;
|
||||
map<string, string> headers = 2;
|
||||
int32 timeout_ms = 3;
|
||||
bytes body = 4; // Ignored for GET/DELETE/HEAD/OPTIONS
|
||||
}
|
||||
|
||||
message HttpResponse {
|
||||
int32 status = 1;
|
||||
bytes body = 2;
|
||||
map<string, string> headers = 3;
|
||||
string error = 4; // Non-empty if network/protocol error
|
||||
}
|
||||
@@ -1,258 +0,0 @@
|
||||
//go:build !wasip1
|
||||
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/http/http.proto
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
context "context"
|
||||
wasm "github.com/knqyf263/go-plugin/wasm"
|
||||
wazero "github.com/tetratelabs/wazero"
|
||||
api "github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
|
||||
const (
|
||||
i32 = api.ValueTypeI32
|
||||
i64 = api.ValueTypeI64
|
||||
)
|
||||
|
||||
type _httpService struct {
|
||||
HttpService
|
||||
}
|
||||
|
||||
// Instantiate a Go-defined module named "env" that exports host functions.
|
||||
func Instantiate(ctx context.Context, r wazero.Runtime, hostFunctions HttpService) error {
|
||||
envBuilder := r.NewHostModuleBuilder("env")
|
||||
h := _httpService{hostFunctions}
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._Get), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("get")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._Post), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("post")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._Put), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("put")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._Delete), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("delete")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._Patch), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("patch")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._Head), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("head")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._Options), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("options")
|
||||
|
||||
_, err := envBuilder.Instantiate(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
func (h _httpService) _Get(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(HttpRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.Get(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
func (h _httpService) _Post(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(HttpRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.Post(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
func (h _httpService) _Put(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(HttpRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.Put(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
func (h _httpService) _Delete(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(HttpRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.Delete(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
func (h _httpService) _Patch(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(HttpRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.Patch(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
func (h _httpService) _Head(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(HttpRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.Head(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
func (h _httpService) _Options(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(HttpRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.Options(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
//go:build wasip1
|
||||
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/http/http.proto
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
context "context"
|
||||
wasm "github.com/knqyf263/go-plugin/wasm"
|
||||
_ "unsafe"
|
||||
)
|
||||
|
||||
type httpService struct{}
|
||||
|
||||
func NewHttpService() HttpService {
|
||||
return httpService{}
|
||||
}
|
||||
|
||||
//go:wasmimport env get
|
||||
func _get(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h httpService) Get(ctx context.Context, request *HttpRequest) (*HttpResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _get(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(HttpResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env post
|
||||
func _post(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h httpService) Post(ctx context.Context, request *HttpRequest) (*HttpResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _post(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(HttpResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env put
|
||||
func _put(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h httpService) Put(ctx context.Context, request *HttpRequest) (*HttpResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _put(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(HttpResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env delete
|
||||
func _delete(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h httpService) Delete(ctx context.Context, request *HttpRequest) (*HttpResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _delete(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(HttpResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env patch
|
||||
func _patch(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h httpService) Patch(ctx context.Context, request *HttpRequest) (*HttpResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _patch(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(HttpResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env head
|
||||
func _head(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h httpService) Head(ctx context.Context, request *HttpRequest) (*HttpResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _head(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(HttpResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env options
|
||||
func _options(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h httpService) Options(ctx context.Context, request *HttpRequest) (*HttpResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _options(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(HttpResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
//go:build !wasip1
|
||||
|
||||
package http
|
||||
|
||||
func NewHttpService() HttpService {
|
||||
panic("not implemented")
|
||||
}
|
||||
@@ -1,850 +0,0 @@
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/http/http.proto
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
io "io"
|
||||
bits "math/bits"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
func (m *HttpRequest) MarshalVT() (dAtA []byte, err error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
size := m.SizeVT()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *HttpRequest) MarshalToVT(dAtA []byte) (int, error) {
|
||||
size := m.SizeVT()
|
||||
return m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *HttpRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
if m == nil {
|
||||
return 0, nil
|
||||
}
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.unknownFields != nil {
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
if len(m.Body) > 0 {
|
||||
i -= len(m.Body)
|
||||
copy(dAtA[i:], m.Body)
|
||||
i = encodeVarint(dAtA, i, uint64(len(m.Body)))
|
||||
i--
|
||||
dAtA[i] = 0x22
|
||||
}
|
||||
if m.TimeoutMs != 0 {
|
||||
i = encodeVarint(dAtA, i, uint64(m.TimeoutMs))
|
||||
i--
|
||||
dAtA[i] = 0x18
|
||||
}
|
||||
if len(m.Headers) > 0 {
|
||||
for k := range m.Headers {
|
||||
v := m.Headers[k]
|
||||
baseI := i
|
||||
i -= len(v)
|
||||
copy(dAtA[i:], v)
|
||||
i = encodeVarint(dAtA, i, uint64(len(v)))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
i -= len(k)
|
||||
copy(dAtA[i:], k)
|
||||
i = encodeVarint(dAtA, i, uint64(len(k)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
i = encodeVarint(dAtA, i, uint64(baseI-i))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
}
|
||||
if len(m.Url) > 0 {
|
||||
i -= len(m.Url)
|
||||
copy(dAtA[i:], m.Url)
|
||||
i = encodeVarint(dAtA, i, uint64(len(m.Url)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *HttpResponse) MarshalVT() (dAtA []byte, err error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
size := m.SizeVT()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *HttpResponse) MarshalToVT(dAtA []byte) (int, error) {
|
||||
size := m.SizeVT()
|
||||
return m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *HttpResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
if m == nil {
|
||||
return 0, nil
|
||||
}
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.unknownFields != nil {
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
if len(m.Error) > 0 {
|
||||
i -= len(m.Error)
|
||||
copy(dAtA[i:], m.Error)
|
||||
i = encodeVarint(dAtA, i, uint64(len(m.Error)))
|
||||
i--
|
||||
dAtA[i] = 0x22
|
||||
}
|
||||
if len(m.Headers) > 0 {
|
||||
for k := range m.Headers {
|
||||
v := m.Headers[k]
|
||||
baseI := i
|
||||
i -= len(v)
|
||||
copy(dAtA[i:], v)
|
||||
i = encodeVarint(dAtA, i, uint64(len(v)))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
i -= len(k)
|
||||
copy(dAtA[i:], k)
|
||||
i = encodeVarint(dAtA, i, uint64(len(k)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
i = encodeVarint(dAtA, i, uint64(baseI-i))
|
||||
i--
|
||||
dAtA[i] = 0x1a
|
||||
}
|
||||
}
|
||||
if len(m.Body) > 0 {
|
||||
i -= len(m.Body)
|
||||
copy(dAtA[i:], m.Body)
|
||||
i = encodeVarint(dAtA, i, uint64(len(m.Body)))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
if m.Status != 0 {
|
||||
i = encodeVarint(dAtA, i, uint64(m.Status))
|
||||
i--
|
||||
dAtA[i] = 0x8
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarint(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sov(v)
|
||||
base := offset
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return base
|
||||
}
|
||||
func (m *HttpRequest) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Url)
|
||||
if l > 0 {
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
if len(m.Headers) > 0 {
|
||||
for k, v := range m.Headers {
|
||||
_ = k
|
||||
_ = v
|
||||
mapEntrySize := 1 + len(k) + sov(uint64(len(k))) + 1 + len(v) + sov(uint64(len(v)))
|
||||
n += mapEntrySize + 1 + sov(uint64(mapEntrySize))
|
||||
}
|
||||
}
|
||||
if m.TimeoutMs != 0 {
|
||||
n += 1 + sov(uint64(m.TimeoutMs))
|
||||
}
|
||||
l = len(m.Body)
|
||||
if l > 0 {
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *HttpResponse) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.Status != 0 {
|
||||
n += 1 + sov(uint64(m.Status))
|
||||
}
|
||||
l = len(m.Body)
|
||||
if l > 0 {
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
if len(m.Headers) > 0 {
|
||||
for k, v := range m.Headers {
|
||||
_ = k
|
||||
_ = v
|
||||
mapEntrySize := 1 + len(k) + sov(uint64(len(k))) + 1 + len(v) + sov(uint64(len(v)))
|
||||
n += mapEntrySize + 1 + sov(uint64(mapEntrySize))
|
||||
}
|
||||
}
|
||||
l = len(m.Error)
|
||||
if l > 0 {
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
|
||||
func sov(x uint64) (n int) {
|
||||
return (bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
func soz(x uint64) (n int) {
|
||||
return sov(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *HttpRequest) UnmarshalVT(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: HttpRequest: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: HttpRequest: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Url", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Url = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Headers", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.Headers == nil {
|
||||
m.Headers = make(map[string]string)
|
||||
}
|
||||
var mapkey string
|
||||
var mapvalue string
|
||||
for iNdEx < postIndex {
|
||||
entryPreIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
if fieldNum == 1 {
|
||||
var stringLenmapkey uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLenmapkey |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLenmapkey := int(stringLenmapkey)
|
||||
if intStringLenmapkey < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postStringIndexmapkey := iNdEx + intStringLenmapkey
|
||||
if postStringIndexmapkey < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postStringIndexmapkey > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
mapkey = string(dAtA[iNdEx:postStringIndexmapkey])
|
||||
iNdEx = postStringIndexmapkey
|
||||
} else if fieldNum == 2 {
|
||||
var stringLenmapvalue uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLenmapvalue |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLenmapvalue := int(stringLenmapvalue)
|
||||
if intStringLenmapvalue < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postStringIndexmapvalue := iNdEx + intStringLenmapvalue
|
||||
if postStringIndexmapvalue < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postStringIndexmapvalue > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])
|
||||
iNdEx = postStringIndexmapvalue
|
||||
} else {
|
||||
iNdEx = entryPreIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if (iNdEx + skippy) > postIndex {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
m.Headers[mapkey] = mapvalue
|
||||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field TimeoutMs", wireType)
|
||||
}
|
||||
m.TimeoutMs = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.TimeoutMs |= int32(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 4:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Body", wireType)
|
||||
}
|
||||
var byteLen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
byteLen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if byteLen < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + byteLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Body = append(m.Body[:0], dAtA[iNdEx:postIndex]...)
|
||||
if m.Body == nil {
|
||||
m.Body = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *HttpResponse) UnmarshalVT(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: HttpResponse: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: HttpResponse: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType)
|
||||
}
|
||||
m.Status = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.Status |= int32(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Body", wireType)
|
||||
}
|
||||
var byteLen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
byteLen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if byteLen < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + byteLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Body = append(m.Body[:0], dAtA[iNdEx:postIndex]...)
|
||||
if m.Body == nil {
|
||||
m.Body = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Headers", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.Headers == nil {
|
||||
m.Headers = make(map[string]string)
|
||||
}
|
||||
var mapkey string
|
||||
var mapvalue string
|
||||
for iNdEx < postIndex {
|
||||
entryPreIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
if fieldNum == 1 {
|
||||
var stringLenmapkey uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLenmapkey |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLenmapkey := int(stringLenmapkey)
|
||||
if intStringLenmapkey < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postStringIndexmapkey := iNdEx + intStringLenmapkey
|
||||
if postStringIndexmapkey < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postStringIndexmapkey > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
mapkey = string(dAtA[iNdEx:postStringIndexmapkey])
|
||||
iNdEx = postStringIndexmapkey
|
||||
} else if fieldNum == 2 {
|
||||
var stringLenmapvalue uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLenmapvalue |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLenmapvalue := int(stringLenmapvalue)
|
||||
if intStringLenmapvalue < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postStringIndexmapvalue := iNdEx + intStringLenmapvalue
|
||||
if postStringIndexmapvalue < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postStringIndexmapvalue > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])
|
||||
iNdEx = postStringIndexmapvalue
|
||||
} else {
|
||||
iNdEx = entryPreIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if (iNdEx + skippy) > postIndex {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
m.Headers[mapkey] = mapvalue
|
||||
iNdEx = postIndex
|
||||
case 4:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Error = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func skip(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
depth := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLength
|
||||
}
|
||||
iNdEx += length
|
||||
case 3:
|
||||
depth++
|
||||
case 4:
|
||||
if depth == 0 {
|
||||
return 0, ErrUnexpectedEndOfGroup
|
||||
}
|
||||
depth--
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLength
|
||||
}
|
||||
if depth == 0 {
|
||||
return iNdEx, nil
|
||||
}
|
||||
}
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLength = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflow = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroup = fmt.Errorf("proto: unexpected end of group")
|
||||
)
|
||||
@@ -0,0 +1,65 @@
|
||||
package host
|
||||
|
||||
import "context"
|
||||
|
||||
// KVStoreService provides persistent key-value storage for plugins.
|
||||
//
|
||||
// Unlike CacheService which is in-memory only, KVStoreService persists data
|
||||
// to disk and survives server restarts. Each plugin has its own isolated
|
||||
// storage with configurable size limits.
|
||||
//
|
||||
// Values are stored as raw bytes, giving plugins full control over
|
||||
// serialization (JSON, protobuf, etc.).
|
||||
//
|
||||
//nd:hostservice name=KVStore permission=kvstore
|
||||
type KVStoreService interface {
|
||||
// Set stores a byte value with the given key.
|
||||
//
|
||||
// Parameters:
|
||||
// - key: The storage key (max 256 bytes, UTF-8)
|
||||
// - value: The byte slice to store
|
||||
//
|
||||
// Returns an error if the storage limit would be exceeded or the operation fails.
|
||||
//nd:hostfunc
|
||||
Set(ctx context.Context, key string, value []byte) error
|
||||
|
||||
// Get retrieves a byte value from storage.
|
||||
//
|
||||
// Parameters:
|
||||
// - key: The storage key
|
||||
//
|
||||
// Returns the value and whether the key exists.
|
||||
//nd:hostfunc
|
||||
Get(ctx context.Context, key string) (value []byte, exists bool, err error)
|
||||
|
||||
// Delete removes a value from storage.
|
||||
//
|
||||
// Parameters:
|
||||
// - key: The storage key
|
||||
//
|
||||
// Returns an error if the operation fails. Does not return an error if the key doesn't exist.
|
||||
//nd:hostfunc
|
||||
Delete(ctx context.Context, key string) error
|
||||
|
||||
// Has checks if a key exists in storage.
|
||||
//
|
||||
// Parameters:
|
||||
// - key: The storage key
|
||||
//
|
||||
// Returns true if the key exists.
|
||||
//nd:hostfunc
|
||||
Has(ctx context.Context, key string) (exists bool, err error)
|
||||
|
||||
// List returns all keys matching the given prefix.
|
||||
//
|
||||
// Parameters:
|
||||
// - prefix: Key prefix to filter by (empty string returns all keys)
|
||||
//
|
||||
// Returns a slice of matching keys.
|
||||
//nd:hostfunc
|
||||
List(ctx context.Context, prefix string) (keys []string, err error)
|
||||
|
||||
// GetStorageUsed returns the total storage used by this plugin in bytes.
|
||||
//nd:hostfunc
|
||||
GetStorageUsed(ctx context.Context) (bytes int64, err error)
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
// Code generated by ndpgen. DO NOT EDIT.
|
||||
|
||||
package host
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// KVStoreSetRequest is the request type for KVStore.Set.
|
||||
type KVStoreSetRequest struct {
|
||||
Key string `json:"key"`
|
||||
Value []byte `json:"value"`
|
||||
}
|
||||
|
||||
// KVStoreSetResponse is the response type for KVStore.Set.
|
||||
type KVStoreSetResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// KVStoreGetRequest is the request type for KVStore.Get.
|
||||
type KVStoreGetRequest struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// KVStoreGetResponse is the response type for KVStore.Get.
|
||||
type KVStoreGetResponse struct {
|
||||
Value []byte `json:"value,omitempty"`
|
||||
Exists bool `json:"exists,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// KVStoreDeleteRequest is the request type for KVStore.Delete.
|
||||
type KVStoreDeleteRequest struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// KVStoreDeleteResponse is the response type for KVStore.Delete.
|
||||
type KVStoreDeleteResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// KVStoreHasRequest is the request type for KVStore.Has.
|
||||
type KVStoreHasRequest struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// KVStoreHasResponse is the response type for KVStore.Has.
|
||||
type KVStoreHasResponse struct {
|
||||
Exists bool `json:"exists,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// KVStoreListRequest is the request type for KVStore.List.
|
||||
type KVStoreListRequest struct {
|
||||
Prefix string `json:"prefix"`
|
||||
}
|
||||
|
||||
// KVStoreListResponse is the response type for KVStore.List.
|
||||
type KVStoreListResponse struct {
|
||||
Keys []string `json:"keys,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// KVStoreGetStorageUsedResponse is the response type for KVStore.GetStorageUsed.
|
||||
type KVStoreGetStorageUsedResponse struct {
|
||||
Bytes int64 `json:"bytes,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// RegisterKVStoreHostFunctions registers KVStore service host functions.
|
||||
// The returned host functions should be added to the plugin's configuration.
|
||||
func RegisterKVStoreHostFunctions(service KVStoreService) []extism.HostFunction {
|
||||
return []extism.HostFunction{
|
||||
newKVStoreSetHostFunction(service),
|
||||
newKVStoreGetHostFunction(service),
|
||||
newKVStoreDeleteHostFunction(service),
|
||||
newKVStoreHasHostFunction(service),
|
||||
newKVStoreListHostFunction(service),
|
||||
newKVStoreGetStorageUsedHostFunction(service),
|
||||
}
|
||||
}
|
||||
|
||||
func newKVStoreSetHostFunction(service KVStoreService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"kvstore_set",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
kvstoreWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req KVStoreSetRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
kvstoreWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
if svcErr := service.Set(ctx, req.Key, req.Value); svcErr != nil {
|
||||
kvstoreWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := KVStoreSetResponse{}
|
||||
kvstoreWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newKVStoreGetHostFunction(service KVStoreService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"kvstore_get",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
kvstoreWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req KVStoreGetRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
kvstoreWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
value, exists, svcErr := service.Get(ctx, req.Key)
|
||||
if svcErr != nil {
|
||||
kvstoreWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := KVStoreGetResponse{
|
||||
Value: value,
|
||||
Exists: exists,
|
||||
}
|
||||
kvstoreWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newKVStoreDeleteHostFunction(service KVStoreService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"kvstore_delete",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
kvstoreWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req KVStoreDeleteRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
kvstoreWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
if svcErr := service.Delete(ctx, req.Key); svcErr != nil {
|
||||
kvstoreWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := KVStoreDeleteResponse{}
|
||||
kvstoreWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newKVStoreHasHostFunction(service KVStoreService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"kvstore_has",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
kvstoreWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req KVStoreHasRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
kvstoreWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
exists, svcErr := service.Has(ctx, req.Key)
|
||||
if svcErr != nil {
|
||||
kvstoreWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := KVStoreHasResponse{
|
||||
Exists: exists,
|
||||
}
|
||||
kvstoreWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newKVStoreListHostFunction(service KVStoreService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"kvstore_list",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
kvstoreWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req KVStoreListRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
kvstoreWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
keys, svcErr := service.List(ctx, req.Prefix)
|
||||
if svcErr != nil {
|
||||
kvstoreWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := KVStoreListResponse{
|
||||
Keys: keys,
|
||||
}
|
||||
kvstoreWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newKVStoreGetStorageUsedHostFunction(service KVStoreService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"kvstore_getstorageused",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
|
||||
// Call the service method
|
||||
bytes, svcErr := service.GetStorageUsed(ctx)
|
||||
if svcErr != nil {
|
||||
kvstoreWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := KVStoreGetStorageUsedResponse{
|
||||
Bytes: bytes,
|
||||
}
|
||||
kvstoreWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
// kvstoreWriteResponse writes a JSON response to plugin memory.
|
||||
func kvstoreWriteResponse(p *extism.CurrentPlugin, stack []uint64, resp any) {
|
||||
respBytes, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
kvstoreWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
respPtr, err := p.WriteBytes(respBytes)
|
||||
if err != nil {
|
||||
stack[0] = 0
|
||||
return
|
||||
}
|
||||
stack[0] = respPtr
|
||||
}
|
||||
|
||||
// kvstoreWriteError writes an error response to plugin memory.
|
||||
func kvstoreWriteError(p *extism.CurrentPlugin, stack []uint64, err error) {
|
||||
errResp := struct {
|
||||
Error string `json:"error"`
|
||||
}{Error: err.Error()}
|
||||
respBytes, _ := json.Marshal(errResp)
|
||||
respPtr, _ := p.WriteBytes(respBytes)
|
||||
stack[0] = respPtr
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package host
|
||||
|
||||
import "context"
|
||||
|
||||
// Library represents a music library with metadata.
|
||||
type Library struct {
|
||||
ID int32 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path,omitempty"`
|
||||
MountPoint string `json:"mountPoint,omitempty"`
|
||||
LastScanAt int64 `json:"lastScanAt"`
|
||||
TotalSongs int32 `json:"totalSongs"`
|
||||
TotalAlbums int32 `json:"totalAlbums"`
|
||||
TotalArtists int32 `json:"totalArtists"`
|
||||
TotalSize int64 `json:"totalSize"`
|
||||
TotalDuration float64 `json:"totalDuration"`
|
||||
}
|
||||
|
||||
// LibraryService provides access to music library metadata for plugins.
|
||||
//
|
||||
// This service allows plugins to query information about configured music libraries,
|
||||
// including statistics and optionally filesystem access to library directories.
|
||||
// Filesystem access is controlled via the `filesystem` permission flag.
|
||||
//
|
||||
//nd:hostservice name=Library permission=library
|
||||
type LibraryService interface {
|
||||
// GetLibrary retrieves metadata for a specific library by ID.
|
||||
//
|
||||
// Parameters:
|
||||
// - id: The library's unique identifier
|
||||
//
|
||||
// Returns the library metadata, or an error if the library is not found.
|
||||
//nd:hostfunc
|
||||
GetLibrary(ctx context.Context, id int32) (*Library, error)
|
||||
|
||||
// GetAllLibraries retrieves metadata for all configured libraries.
|
||||
//
|
||||
// Returns a slice of all libraries with their metadata.
|
||||
//nd:hostfunc
|
||||
GetAllLibraries(ctx context.Context) ([]Library, error)
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
// Code generated by ndpgen. DO NOT EDIT.
|
||||
|
||||
package host
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// LibraryGetLibraryRequest is the request type for Library.GetLibrary.
|
||||
type LibraryGetLibraryRequest struct {
|
||||
Id int32 `json:"id"`
|
||||
}
|
||||
|
||||
// LibraryGetLibraryResponse is the response type for Library.GetLibrary.
|
||||
type LibraryGetLibraryResponse struct {
|
||||
Result *Library `json:"result,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// LibraryGetAllLibrariesResponse is the response type for Library.GetAllLibraries.
|
||||
type LibraryGetAllLibrariesResponse struct {
|
||||
Result []Library `json:"result,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// RegisterLibraryHostFunctions registers Library service host functions.
|
||||
// The returned host functions should be added to the plugin's configuration.
|
||||
func RegisterLibraryHostFunctions(service LibraryService) []extism.HostFunction {
|
||||
return []extism.HostFunction{
|
||||
newLibraryGetLibraryHostFunction(service),
|
||||
newLibraryGetAllLibrariesHostFunction(service),
|
||||
}
|
||||
}
|
||||
|
||||
func newLibraryGetLibraryHostFunction(service LibraryService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"library_getlibrary",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
libraryWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req LibraryGetLibraryRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
libraryWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
result, svcErr := service.GetLibrary(ctx, req.Id)
|
||||
if svcErr != nil {
|
||||
libraryWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := LibraryGetLibraryResponse{
|
||||
Result: result,
|
||||
}
|
||||
libraryWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newLibraryGetAllLibrariesHostFunction(service LibraryService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"library_getalllibraries",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
|
||||
// Call the service method
|
||||
result, svcErr := service.GetAllLibraries(ctx)
|
||||
if svcErr != nil {
|
||||
libraryWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := LibraryGetAllLibrariesResponse{
|
||||
Result: result,
|
||||
}
|
||||
libraryWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
// libraryWriteResponse writes a JSON response to plugin memory.
|
||||
func libraryWriteResponse(p *extism.CurrentPlugin, stack []uint64, resp any) {
|
||||
respBytes, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
libraryWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
respPtr, err := p.WriteBytes(respBytes)
|
||||
if err != nil {
|
||||
stack[0] = 0
|
||||
return
|
||||
}
|
||||
stack[0] = respPtr
|
||||
}
|
||||
|
||||
// libraryWriteError writes an error response to plugin memory.
|
||||
func libraryWriteError(p *extism.CurrentPlugin, stack []uint64, err error) {
|
||||
errResp := struct {
|
||||
Error string `json:"error"`
|
||||
}{Error: err.Error()}
|
||||
respBytes, _ := json.Marshal(errResp)
|
||||
respPtr, _ := p.WriteBytes(respBytes)
|
||||
stack[0] = respPtr
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package host
|
||||
|
||||
import "context"
|
||||
|
||||
// SchedulerService provides task scheduling capabilities for plugins.
|
||||
//
|
||||
// This service allows plugins to schedule both one-time and recurring tasks using
|
||||
// cron expressions. All scheduled tasks can be cancelled using their schedule ID.
|
||||
//
|
||||
//nd:hostservice name=Scheduler permission=scheduler
|
||||
type SchedulerService interface {
|
||||
// ScheduleOneTime schedules a one-time event to be triggered after the specified delay.
|
||||
// Plugins that use this function must also implement the SchedulerCallback capability
|
||||
//
|
||||
// Parameters:
|
||||
// - delaySeconds: Number of seconds to wait before triggering the event
|
||||
// - payload: Data to be passed to the scheduled event handler
|
||||
// - scheduleID: Optional unique identifier for the scheduled job. If empty, one will be generated
|
||||
//
|
||||
// Returns the schedule ID that can be used to cancel the job, or an error if scheduling fails.
|
||||
//nd:hostfunc
|
||||
ScheduleOneTime(ctx context.Context, delaySeconds int32, payload string, scheduleID string) (newScheduleID string, err error)
|
||||
|
||||
// ScheduleRecurring schedules a recurring event using a cron expression.
|
||||
// Plugins that use this function must also implement the SchedulerCallback capability
|
||||
//
|
||||
// Parameters:
|
||||
// - cronExpression: Standard cron format expression (e.g., "0 0 * * *" for daily at midnight)
|
||||
// - payload: Data to be passed to each scheduled event handler invocation
|
||||
// - scheduleID: Optional unique identifier for the scheduled job. If empty, one will be generated
|
||||
//
|
||||
// Returns the schedule ID that can be used to cancel the job, or an error if scheduling fails.
|
||||
//nd:hostfunc
|
||||
ScheduleRecurring(ctx context.Context, cronExpression string, payload string, scheduleID string) (newScheduleID string, err error)
|
||||
|
||||
// CancelSchedule cancels a scheduled job identified by its schedule ID.
|
||||
//
|
||||
// This works for both one-time and recurring schedules. Once cancelled, the job will not trigger
|
||||
// any future events.
|
||||
//
|
||||
// Returns an error if the schedule ID is not found or if cancellation fails.
|
||||
//nd:hostfunc
|
||||
CancelSchedule(ctx context.Context, scheduleID string) error
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/scheduler/scheduler.proto
|
||||
|
||||
package scheduler
|
||||
|
||||
import (
|
||||
context "context"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type ScheduleOneTimeRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
DelaySeconds int32 `protobuf:"varint,1,opt,name=delay_seconds,json=delaySeconds,proto3" json:"delay_seconds,omitempty"` // Delay in seconds
|
||||
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"` // Serialized data to pass to the callback
|
||||
ScheduleId string `protobuf:"bytes,3,opt,name=schedule_id,json=scheduleId,proto3" json:"schedule_id,omitempty"` // Optional custom ID (if not provided, one will be generated)
|
||||
}
|
||||
|
||||
func (x *ScheduleOneTimeRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *ScheduleOneTimeRequest) GetDelaySeconds() int32 {
|
||||
if x != nil {
|
||||
return x.DelaySeconds
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ScheduleOneTimeRequest) GetPayload() []byte {
|
||||
if x != nil {
|
||||
return x.Payload
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ScheduleOneTimeRequest) GetScheduleId() string {
|
||||
if x != nil {
|
||||
return x.ScheduleId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ScheduleRecurringRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
CronExpression string `protobuf:"bytes,1,opt,name=cron_expression,json=cronExpression,proto3" json:"cron_expression,omitempty"` // Cron expression (e.g. "0 0 * * *" for daily at midnight)
|
||||
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"` // Serialized data to pass to the callback
|
||||
ScheduleId string `protobuf:"bytes,3,opt,name=schedule_id,json=scheduleId,proto3" json:"schedule_id,omitempty"` // Optional custom ID (if not provided, one will be generated)
|
||||
}
|
||||
|
||||
func (x *ScheduleRecurringRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *ScheduleRecurringRequest) GetCronExpression() string {
|
||||
if x != nil {
|
||||
return x.CronExpression
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ScheduleRecurringRequest) GetPayload() []byte {
|
||||
if x != nil {
|
||||
return x.Payload
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ScheduleRecurringRequest) GetScheduleId() string {
|
||||
if x != nil {
|
||||
return x.ScheduleId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ScheduleResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
ScheduleId string `protobuf:"bytes,1,opt,name=schedule_id,json=scheduleId,proto3" json:"schedule_id,omitempty"` // ID to reference this scheduled job
|
||||
}
|
||||
|
||||
func (x *ScheduleResponse) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *ScheduleResponse) GetScheduleId() string {
|
||||
if x != nil {
|
||||
return x.ScheduleId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type CancelRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
ScheduleId string `protobuf:"bytes,1,opt,name=schedule_id,json=scheduleId,proto3" json:"schedule_id,omitempty"` // ID of the schedule to cancel
|
||||
}
|
||||
|
||||
func (x *CancelRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *CancelRequest) GetScheduleId() string {
|
||||
if x != nil {
|
||||
return x.ScheduleId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type CancelResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` // Whether cancellation was successful
|
||||
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` // Error message if cancellation failed
|
||||
}
|
||||
|
||||
func (x *CancelResponse) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *CancelResponse) GetSuccess() bool {
|
||||
if x != nil {
|
||||
return x.Success
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *CancelResponse) GetError() string {
|
||||
if x != nil {
|
||||
return x.Error
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type TimeNowRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *TimeNowRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
type TimeNowResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Rfc3339Nano string `protobuf:"bytes,1,opt,name=rfc3339_nano,json=rfc3339Nano,proto3" json:"rfc3339_nano,omitempty"` // Current time in RFC3339Nano format
|
||||
UnixMilli int64 `protobuf:"varint,2,opt,name=unix_milli,json=unixMilli,proto3" json:"unix_milli,omitempty"` // Current time as Unix milliseconds timestamp
|
||||
LocalTimeZone string `protobuf:"bytes,3,opt,name=local_time_zone,json=localTimeZone,proto3" json:"local_time_zone,omitempty"` // Local timezone name (e.g., "America/New_York", "UTC")
|
||||
}
|
||||
|
||||
func (x *TimeNowResponse) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *TimeNowResponse) GetRfc3339Nano() string {
|
||||
if x != nil {
|
||||
return x.Rfc3339Nano
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *TimeNowResponse) GetUnixMilli() int64 {
|
||||
if x != nil {
|
||||
return x.UnixMilli
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *TimeNowResponse) GetLocalTimeZone() string {
|
||||
if x != nil {
|
||||
return x.LocalTimeZone
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// go:plugin type=host version=1
|
||||
type SchedulerService interface {
|
||||
// One-time event scheduling
|
||||
ScheduleOneTime(context.Context, *ScheduleOneTimeRequest) (*ScheduleResponse, error)
|
||||
// Recurring event scheduling
|
||||
ScheduleRecurring(context.Context, *ScheduleRecurringRequest) (*ScheduleResponse, error)
|
||||
// Cancel any scheduled job
|
||||
CancelSchedule(context.Context, *CancelRequest) (*CancelResponse, error)
|
||||
// Get current time in multiple formats
|
||||
TimeNow(context.Context, *TimeNowRequest) (*TimeNowResponse, error)
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package scheduler;
|
||||
|
||||
option go_package = "github.com/navidrome/navidrome/plugins/host/scheduler;scheduler";
|
||||
|
||||
// go:plugin type=host version=1
|
||||
service SchedulerService {
|
||||
// One-time event scheduling
|
||||
rpc ScheduleOneTime(ScheduleOneTimeRequest) returns (ScheduleResponse);
|
||||
|
||||
// Recurring event scheduling
|
||||
rpc ScheduleRecurring(ScheduleRecurringRequest) returns (ScheduleResponse);
|
||||
|
||||
// Cancel any scheduled job
|
||||
rpc CancelSchedule(CancelRequest) returns (CancelResponse);
|
||||
|
||||
// Get current time in multiple formats
|
||||
rpc TimeNow(TimeNowRequest) returns (TimeNowResponse);
|
||||
}
|
||||
|
||||
message ScheduleOneTimeRequest {
|
||||
int32 delay_seconds = 1; // Delay in seconds
|
||||
bytes payload = 2; // Serialized data to pass to the callback
|
||||
string schedule_id = 3; // Optional custom ID (if not provided, one will be generated)
|
||||
}
|
||||
|
||||
message ScheduleRecurringRequest {
|
||||
string cron_expression = 1; // Cron expression (e.g. "0 0 * * *" for daily at midnight)
|
||||
bytes payload = 2; // Serialized data to pass to the callback
|
||||
string schedule_id = 3; // Optional custom ID (if not provided, one will be generated)
|
||||
}
|
||||
|
||||
message ScheduleResponse {
|
||||
string schedule_id = 1; // ID to reference this scheduled job
|
||||
}
|
||||
|
||||
message CancelRequest {
|
||||
string schedule_id = 1; // ID of the schedule to cancel
|
||||
}
|
||||
|
||||
message CancelResponse {
|
||||
bool success = 1; // Whether cancellation was successful
|
||||
string error = 2; // Error message if cancellation failed
|
||||
}
|
||||
|
||||
message TimeNowRequest {
|
||||
// Empty request - no parameters needed
|
||||
}
|
||||
|
||||
message TimeNowResponse {
|
||||
string rfc3339_nano = 1; // Current time in RFC3339Nano format
|
||||
int64 unix_milli = 2; // Current time as Unix milliseconds timestamp
|
||||
string local_time_zone = 3; // Local timezone name (e.g., "America/New_York", "UTC")
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
//go:build !wasip1
|
||||
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/scheduler/scheduler.proto
|
||||
|
||||
package scheduler
|
||||
|
||||
import (
|
||||
context "context"
|
||||
wasm "github.com/knqyf263/go-plugin/wasm"
|
||||
wazero "github.com/tetratelabs/wazero"
|
||||
api "github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
|
||||
const (
|
||||
i32 = api.ValueTypeI32
|
||||
i64 = api.ValueTypeI64
|
||||
)
|
||||
|
||||
type _schedulerService struct {
|
||||
SchedulerService
|
||||
}
|
||||
|
||||
// Instantiate a Go-defined module named "env" that exports host functions.
|
||||
func Instantiate(ctx context.Context, r wazero.Runtime, hostFunctions SchedulerService) error {
|
||||
envBuilder := r.NewHostModuleBuilder("env")
|
||||
h := _schedulerService{hostFunctions}
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._ScheduleOneTime), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("schedule_one_time")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._ScheduleRecurring), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("schedule_recurring")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._CancelSchedule), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("cancel_schedule")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._TimeNow), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("time_now")
|
||||
|
||||
_, err := envBuilder.Instantiate(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// One-time event scheduling
|
||||
|
||||
func (h _schedulerService) _ScheduleOneTime(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(ScheduleOneTimeRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.ScheduleOneTime(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
// Recurring event scheduling
|
||||
|
||||
func (h _schedulerService) _ScheduleRecurring(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(ScheduleRecurringRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.ScheduleRecurring(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
// Cancel any scheduled job
|
||||
|
||||
func (h _schedulerService) _CancelSchedule(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(CancelRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.CancelSchedule(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
// Get current time in multiple formats
|
||||
|
||||
func (h _schedulerService) _TimeNow(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(TimeNowRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.TimeNow(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
//go:build wasip1
|
||||
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/scheduler/scheduler.proto
|
||||
|
||||
package scheduler
|
||||
|
||||
import (
|
||||
context "context"
|
||||
wasm "github.com/knqyf263/go-plugin/wasm"
|
||||
_ "unsafe"
|
||||
)
|
||||
|
||||
type schedulerService struct{}
|
||||
|
||||
func NewSchedulerService() SchedulerService {
|
||||
return schedulerService{}
|
||||
}
|
||||
|
||||
//go:wasmimport env schedule_one_time
|
||||
func _schedule_one_time(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h schedulerService) ScheduleOneTime(ctx context.Context, request *ScheduleOneTimeRequest) (*ScheduleResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _schedule_one_time(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(ScheduleResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env schedule_recurring
|
||||
func _schedule_recurring(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h schedulerService) ScheduleRecurring(ctx context.Context, request *ScheduleRecurringRequest) (*ScheduleResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _schedule_recurring(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(ScheduleResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env cancel_schedule
|
||||
func _cancel_schedule(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h schedulerService) CancelSchedule(ctx context.Context, request *CancelRequest) (*CancelResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _cancel_schedule(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(CancelResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env time_now
|
||||
func _time_now(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h schedulerService) TimeNow(ctx context.Context, request *TimeNowRequest) (*TimeNowResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _time_now(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(TimeNowResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
//go:build !wasip1
|
||||
|
||||
package scheduler
|
||||
|
||||
func NewSchedulerService() SchedulerService {
|
||||
panic("not implemented")
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,180 @@
|
||||
// Code generated by ndpgen. DO NOT EDIT.
|
||||
|
||||
package host
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// SchedulerScheduleOneTimeRequest is the request type for Scheduler.ScheduleOneTime.
|
||||
type SchedulerScheduleOneTimeRequest struct {
|
||||
DelaySeconds int32 `json:"delaySeconds"`
|
||||
Payload string `json:"payload"`
|
||||
ScheduleID string `json:"scheduleId"`
|
||||
}
|
||||
|
||||
// SchedulerScheduleOneTimeResponse is the response type for Scheduler.ScheduleOneTime.
|
||||
type SchedulerScheduleOneTimeResponse struct {
|
||||
NewScheduleID string `json:"newScheduleId,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// SchedulerScheduleRecurringRequest is the request type for Scheduler.ScheduleRecurring.
|
||||
type SchedulerScheduleRecurringRequest struct {
|
||||
CronExpression string `json:"cronExpression"`
|
||||
Payload string `json:"payload"`
|
||||
ScheduleID string `json:"scheduleId"`
|
||||
}
|
||||
|
||||
// SchedulerScheduleRecurringResponse is the response type for Scheduler.ScheduleRecurring.
|
||||
type SchedulerScheduleRecurringResponse struct {
|
||||
NewScheduleID string `json:"newScheduleId,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// SchedulerCancelScheduleRequest is the request type for Scheduler.CancelSchedule.
|
||||
type SchedulerCancelScheduleRequest struct {
|
||||
ScheduleID string `json:"scheduleId"`
|
||||
}
|
||||
|
||||
// SchedulerCancelScheduleResponse is the response type for Scheduler.CancelSchedule.
|
||||
type SchedulerCancelScheduleResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// RegisterSchedulerHostFunctions registers Scheduler service host functions.
|
||||
// The returned host functions should be added to the plugin's configuration.
|
||||
func RegisterSchedulerHostFunctions(service SchedulerService) []extism.HostFunction {
|
||||
return []extism.HostFunction{
|
||||
newSchedulerScheduleOneTimeHostFunction(service),
|
||||
newSchedulerScheduleRecurringHostFunction(service),
|
||||
newSchedulerCancelScheduleHostFunction(service),
|
||||
}
|
||||
}
|
||||
|
||||
func newSchedulerScheduleOneTimeHostFunction(service SchedulerService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"scheduler_scheduleonetime",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
schedulerWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req SchedulerScheduleOneTimeRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
schedulerWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
newscheduleid, svcErr := service.ScheduleOneTime(ctx, req.DelaySeconds, req.Payload, req.ScheduleID)
|
||||
if svcErr != nil {
|
||||
schedulerWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := SchedulerScheduleOneTimeResponse{
|
||||
NewScheduleID: newscheduleid,
|
||||
}
|
||||
schedulerWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newSchedulerScheduleRecurringHostFunction(service SchedulerService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"scheduler_schedulerecurring",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
schedulerWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req SchedulerScheduleRecurringRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
schedulerWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
newscheduleid, svcErr := service.ScheduleRecurring(ctx, req.CronExpression, req.Payload, req.ScheduleID)
|
||||
if svcErr != nil {
|
||||
schedulerWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := SchedulerScheduleRecurringResponse{
|
||||
NewScheduleID: newscheduleid,
|
||||
}
|
||||
schedulerWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newSchedulerCancelScheduleHostFunction(service SchedulerService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"scheduler_cancelschedule",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
schedulerWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req SchedulerCancelScheduleRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
schedulerWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
if svcErr := service.CancelSchedule(ctx, req.ScheduleID); svcErr != nil {
|
||||
schedulerWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := SchedulerCancelScheduleResponse{}
|
||||
schedulerWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
// schedulerWriteResponse writes a JSON response to plugin memory.
|
||||
func schedulerWriteResponse(p *extism.CurrentPlugin, stack []uint64, resp any) {
|
||||
respBytes, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
schedulerWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
respPtr, err := p.WriteBytes(respBytes)
|
||||
if err != nil {
|
||||
stack[0] = 0
|
||||
return
|
||||
}
|
||||
stack[0] = respPtr
|
||||
}
|
||||
|
||||
// schedulerWriteError writes an error response to plugin memory.
|
||||
func schedulerWriteError(p *extism.CurrentPlugin, stack []uint64, err error) {
|
||||
errResp := struct {
|
||||
Error string `json:"error"`
|
||||
}{Error: err.Error()}
|
||||
respBytes, _ := json.Marshal(errResp)
|
||||
respPtr, _ := p.WriteBytes(respBytes)
|
||||
stack[0] = respPtr
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package host
|
||||
|
||||
import "context"
|
||||
|
||||
// SubsonicAPIService provides access to Navidrome's Subsonic API from plugins.
|
||||
//
|
||||
// This service allows plugins to make Subsonic API requests on behalf of the plugin's user,
|
||||
// enabling access to library data, user preferences, and other Subsonic-compatible operations.
|
||||
//
|
||||
//nd:hostservice name=SubsonicAPI permission=subsonicapi
|
||||
type SubsonicAPIService interface {
|
||||
// Call executes a Subsonic API request and returns the JSON response.
|
||||
//
|
||||
// The uri parameter should be the Subsonic API path without the server prefix,
|
||||
// e.g., "getAlbumList2?type=random&size=10". The response is returned as raw JSON.
|
||||
//nd:hostfunc
|
||||
Call(ctx context.Context, uri string) (responseJSON string, err error)
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/subsonicapi/subsonicapi.proto
|
||||
|
||||
package subsonicapi
|
||||
|
||||
import (
|
||||
context "context"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type CallRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
|
||||
}
|
||||
|
||||
func (x *CallRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *CallRequest) GetUrl() string {
|
||||
if x != nil {
|
||||
return x.Url
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type CallResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Json string `protobuf:"bytes,1,opt,name=json,proto3" json:"json,omitempty"`
|
||||
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` // Non-empty if operation failed
|
||||
}
|
||||
|
||||
func (x *CallResponse) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *CallResponse) GetJson() string {
|
||||
if x != nil {
|
||||
return x.Json
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CallResponse) GetError() string {
|
||||
if x != nil {
|
||||
return x.Error
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// go:plugin type=host version=1
|
||||
type SubsonicAPIService interface {
|
||||
Call(context.Context, *CallRequest) (*CallResponse, error)
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package subsonicapi;
|
||||
|
||||
option go_package = "github.com/navidrome/navidrome/plugins/host/subsonicapi;subsonicapi";
|
||||
|
||||
// go:plugin type=host version=1
|
||||
service SubsonicAPIService {
|
||||
rpc Call(CallRequest) returns (CallResponse);
|
||||
}
|
||||
|
||||
message CallRequest {
|
||||
string url = 1;
|
||||
}
|
||||
|
||||
message CallResponse {
|
||||
string json = 1;
|
||||
string error = 2; // Non-empty if operation failed
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
//go:build !wasip1
|
||||
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/subsonicapi/subsonicapi.proto
|
||||
|
||||
package subsonicapi
|
||||
|
||||
import (
|
||||
context "context"
|
||||
wasm "github.com/knqyf263/go-plugin/wasm"
|
||||
wazero "github.com/tetratelabs/wazero"
|
||||
api "github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
|
||||
const (
|
||||
i32 = api.ValueTypeI32
|
||||
i64 = api.ValueTypeI64
|
||||
)
|
||||
|
||||
type _subsonicAPIService struct {
|
||||
SubsonicAPIService
|
||||
}
|
||||
|
||||
// Instantiate a Go-defined module named "env" that exports host functions.
|
||||
func Instantiate(ctx context.Context, r wazero.Runtime, hostFunctions SubsonicAPIService) error {
|
||||
envBuilder := r.NewHostModuleBuilder("env")
|
||||
h := _subsonicAPIService{hostFunctions}
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._Call), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("call")
|
||||
|
||||
_, err := envBuilder.Instantiate(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
func (h _subsonicAPIService) _Call(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(CallRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.Call(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
//go:build wasip1
|
||||
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/subsonicapi/subsonicapi.proto
|
||||
|
||||
package subsonicapi
|
||||
|
||||
import (
|
||||
context "context"
|
||||
wasm "github.com/knqyf263/go-plugin/wasm"
|
||||
_ "unsafe"
|
||||
)
|
||||
|
||||
type subsonicAPIService struct{}
|
||||
|
||||
func NewSubsonicAPIService() SubsonicAPIService {
|
||||
return subsonicAPIService{}
|
||||
}
|
||||
|
||||
//go:wasmimport env call
|
||||
func _call(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h subsonicAPIService) Call(ctx context.Context, request *CallRequest) (*CallResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _call(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(CallResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,441 +0,0 @@
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/subsonicapi/subsonicapi.proto
|
||||
|
||||
package subsonicapi
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
io "io"
|
||||
bits "math/bits"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
func (m *CallRequest) MarshalVT() (dAtA []byte, err error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
size := m.SizeVT()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *CallRequest) MarshalToVT(dAtA []byte) (int, error) {
|
||||
size := m.SizeVT()
|
||||
return m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *CallRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
if m == nil {
|
||||
return 0, nil
|
||||
}
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.unknownFields != nil {
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
if len(m.Url) > 0 {
|
||||
i -= len(m.Url)
|
||||
copy(dAtA[i:], m.Url)
|
||||
i = encodeVarint(dAtA, i, uint64(len(m.Url)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *CallResponse) MarshalVT() (dAtA []byte, err error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
size := m.SizeVT()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *CallResponse) MarshalToVT(dAtA []byte) (int, error) {
|
||||
size := m.SizeVT()
|
||||
return m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *CallResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
if m == nil {
|
||||
return 0, nil
|
||||
}
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.unknownFields != nil {
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
if len(m.Error) > 0 {
|
||||
i -= len(m.Error)
|
||||
copy(dAtA[i:], m.Error)
|
||||
i = encodeVarint(dAtA, i, uint64(len(m.Error)))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
if len(m.Json) > 0 {
|
||||
i -= len(m.Json)
|
||||
copy(dAtA[i:], m.Json)
|
||||
i = encodeVarint(dAtA, i, uint64(len(m.Json)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarint(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sov(v)
|
||||
base := offset
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return base
|
||||
}
|
||||
func (m *CallRequest) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Url)
|
||||
if l > 0 {
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *CallResponse) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Json)
|
||||
if l > 0 {
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
l = len(m.Error)
|
||||
if l > 0 {
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
|
||||
func sov(x uint64) (n int) {
|
||||
return (bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
func soz(x uint64) (n int) {
|
||||
return sov(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *CallRequest) UnmarshalVT(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: CallRequest: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: CallRequest: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Url", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Url = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *CallResponse) UnmarshalVT(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: CallResponse: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: CallResponse: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Json", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Json = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Error = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func skip(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
depth := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLength
|
||||
}
|
||||
iNdEx += length
|
||||
case 3:
|
||||
depth++
|
||||
case 4:
|
||||
if depth == 0 {
|
||||
return 0, ErrUnexpectedEndOfGroup
|
||||
}
|
||||
depth--
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLength
|
||||
}
|
||||
if depth == 0 {
|
||||
return iNdEx, nil
|
||||
}
|
||||
}
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLength = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflow = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroup = fmt.Errorf("proto: unexpected end of group")
|
||||
)
|
||||
@@ -0,0 +1,88 @@
|
||||
// Code generated by ndpgen. DO NOT EDIT.
|
||||
|
||||
package host
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// SubsonicAPICallRequest is the request type for SubsonicAPI.Call.
|
||||
type SubsonicAPICallRequest struct {
|
||||
Uri string `json:"uri"`
|
||||
}
|
||||
|
||||
// SubsonicAPICallResponse is the response type for SubsonicAPI.Call.
|
||||
type SubsonicAPICallResponse struct {
|
||||
ResponseJSON string `json:"responseJson,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// RegisterSubsonicAPIHostFunctions registers SubsonicAPI service host functions.
|
||||
// The returned host functions should be added to the plugin's configuration.
|
||||
func RegisterSubsonicAPIHostFunctions(service SubsonicAPIService) []extism.HostFunction {
|
||||
return []extism.HostFunction{
|
||||
newSubsonicAPICallHostFunction(service),
|
||||
}
|
||||
}
|
||||
|
||||
func newSubsonicAPICallHostFunction(service SubsonicAPIService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"subsonicapi_call",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
subsonicapiWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req SubsonicAPICallRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
subsonicapiWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
responsejson, svcErr := service.Call(ctx, req.Uri)
|
||||
if svcErr != nil {
|
||||
subsonicapiWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := SubsonicAPICallResponse{
|
||||
ResponseJSON: responsejson,
|
||||
}
|
||||
subsonicapiWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
// subsonicapiWriteResponse writes a JSON response to plugin memory.
|
||||
func subsonicapiWriteResponse(p *extism.CurrentPlugin, stack []uint64, resp any) {
|
||||
respBytes, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
subsonicapiWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
respPtr, err := p.WriteBytes(respBytes)
|
||||
if err != nil {
|
||||
stack[0] = 0
|
||||
return
|
||||
}
|
||||
stack[0] = respPtr
|
||||
}
|
||||
|
||||
// subsonicapiWriteError writes an error response to plugin memory.
|
||||
func subsonicapiWriteError(p *extism.CurrentPlugin, stack []uint64, err error) {
|
||||
errResp := struct {
|
||||
Error string `json:"error"`
|
||||
}{Error: err.Error()}
|
||||
respBytes, _ := json.Marshal(errResp)
|
||||
respPtr, _ := p.WriteBytes(respBytes)
|
||||
stack[0] = respPtr
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package host
|
||||
|
||||
import "context"
|
||||
|
||||
// User represents a Navidrome user with minimal information exposed to plugins.
|
||||
// Sensitive fields like password, email, and internal IDs are intentionally excluded.
|
||||
type User struct {
|
||||
UserName string `json:"userName"`
|
||||
Name string `json:"name"`
|
||||
IsAdmin bool `json:"isAdmin"`
|
||||
}
|
||||
|
||||
// UsersService provides access to user information for plugins.
|
||||
//
|
||||
// This service allows plugins to query information about users that the plugin
|
||||
// has been granted access to. Access is controlled by the administrator who
|
||||
// configures which users each plugin can see.
|
||||
//
|
||||
//nd:hostservice name=Users permission=users
|
||||
type UsersService interface {
|
||||
// GetUsers returns all users the plugin has been granted access to.
|
||||
// Only minimal user information (userName, name, isAdmin) is returned.
|
||||
// Sensitive fields like password and email are never exposed.
|
||||
//
|
||||
// Returns a slice of users the plugin can access, or an empty slice if none configured.
|
||||
//nd:hostfunc
|
||||
GetUsers(ctx context.Context) ([]User, error)
|
||||
|
||||
// GetAdmins returns only admin users the plugin has been granted access to.
|
||||
// This is a convenience method that filters GetUsers results to include only admins.
|
||||
//
|
||||
// Returns a slice of admin users the plugin can access, or an empty slice if none.
|
||||
//nd:hostfunc
|
||||
GetAdmins(ctx context.Context) ([]User, error)
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
// Code generated by ndpgen. DO NOT EDIT.
|
||||
|
||||
package host
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// UsersGetUsersResponse is the response type for Users.GetUsers.
|
||||
type UsersGetUsersResponse struct {
|
||||
Result []User `json:"result,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// UsersGetAdminsResponse is the response type for Users.GetAdmins.
|
||||
type UsersGetAdminsResponse struct {
|
||||
Result []User `json:"result,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// RegisterUsersHostFunctions registers Users service host functions.
|
||||
// The returned host functions should be added to the plugin's configuration.
|
||||
func RegisterUsersHostFunctions(service UsersService) []extism.HostFunction {
|
||||
return []extism.HostFunction{
|
||||
newUsersGetUsersHostFunction(service),
|
||||
newUsersGetAdminsHostFunction(service),
|
||||
}
|
||||
}
|
||||
|
||||
func newUsersGetUsersHostFunction(service UsersService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"users_getusers",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
|
||||
// Call the service method
|
||||
result, svcErr := service.GetUsers(ctx)
|
||||
if svcErr != nil {
|
||||
usersWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := UsersGetUsersResponse{
|
||||
Result: result,
|
||||
}
|
||||
usersWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newUsersGetAdminsHostFunction(service UsersService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"users_getadmins",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
|
||||
// Call the service method
|
||||
result, svcErr := service.GetAdmins(ctx)
|
||||
if svcErr != nil {
|
||||
usersWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := UsersGetAdminsResponse{
|
||||
Result: result,
|
||||
}
|
||||
usersWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
// usersWriteResponse writes a JSON response to plugin memory.
|
||||
func usersWriteResponse(p *extism.CurrentPlugin, stack []uint64, resp any) {
|
||||
respBytes, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
usersWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
respPtr, err := p.WriteBytes(respBytes)
|
||||
if err != nil {
|
||||
stack[0] = 0
|
||||
return
|
||||
}
|
||||
stack[0] = respPtr
|
||||
}
|
||||
|
||||
// usersWriteError writes an error response to plugin memory.
|
||||
func usersWriteError(p *extism.CurrentPlugin, stack []uint64, err error) {
|
||||
errResp := struct {
|
||||
Error string `json:"error"`
|
||||
}{Error: err.Error()}
|
||||
respBytes, _ := json.Marshal(errResp)
|
||||
respPtr, _ := p.WriteBytes(respBytes)
|
||||
stack[0] = respPtr
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package host
|
||||
|
||||
import "context"
|
||||
|
||||
// WebSocketService provides WebSocket communication capabilities for plugins.
|
||||
//
|
||||
// This service allows plugins to establish WebSocket connections to external services,
|
||||
// send and receive messages, and manage connection lifecycle. Plugins using this service
|
||||
// must implement the WebSocketCallback capability to receive incoming messages and
|
||||
// connection state changes.
|
||||
//
|
||||
//nd:hostservice name=WebSocket permission=websocket
|
||||
type WebSocketService interface {
|
||||
// Connect establishes a WebSocket connection to the specified URL.
|
||||
//
|
||||
// Plugins that use this function must also implement the WebSocketCallback capability
|
||||
// to receive incoming messages and connection events.
|
||||
//
|
||||
// Parameters:
|
||||
// - url: The WebSocket URL to connect to (ws:// or wss://)
|
||||
// - headers: Optional HTTP headers to include in the handshake request
|
||||
// - connectionID: Optional unique identifier for the connection. If empty, one will be generated
|
||||
//
|
||||
// Returns the connection ID that can be used to send messages or close the connection,
|
||||
// or an error if the connection fails.
|
||||
//nd:hostfunc
|
||||
Connect(ctx context.Context, url string, headers map[string]string, connectionID string) (newConnectionID string, err error)
|
||||
|
||||
// SendText sends a text message over an established WebSocket connection.
|
||||
//
|
||||
// Parameters:
|
||||
// - connectionID: The connection identifier returned by Connect
|
||||
// - message: The text message to send
|
||||
//
|
||||
// Returns an error if the connection is not found or if sending fails.
|
||||
//nd:hostfunc
|
||||
SendText(ctx context.Context, connectionID, message string) error
|
||||
|
||||
// SendBinary sends binary data over an established WebSocket connection.
|
||||
//
|
||||
// Parameters:
|
||||
// - connectionID: The connection identifier returned by Connect
|
||||
// - data: The binary data to send
|
||||
//
|
||||
// Returns an error if the connection is not found or if sending fails.
|
||||
//nd:hostfunc
|
||||
SendBinary(ctx context.Context, connectionID string, data []byte) error
|
||||
|
||||
// CloseConnection gracefully closes a WebSocket connection.
|
||||
//
|
||||
// Parameters:
|
||||
// - connectionID: The connection identifier returned by Connect
|
||||
// - code: WebSocket close status code (e.g., 1000 for normal closure)
|
||||
// - reason: Optional human-readable reason for closing
|
||||
//
|
||||
// Returns an error if the connection is not found or if closing fails.
|
||||
//nd:hostfunc
|
||||
CloseConnection(ctx context.Context, connectionID string, code int32, reason string) error
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/websocket/websocket.proto
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
context "context"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type ConnectRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
|
||||
Headers map[string]string `protobuf:"bytes,2,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
ConnectionId string `protobuf:"bytes,3,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ConnectRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *ConnectRequest) GetUrl() string {
|
||||
if x != nil {
|
||||
return x.Url
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ConnectRequest) GetHeaders() map[string]string {
|
||||
if x != nil {
|
||||
return x.Headers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ConnectRequest) GetConnectionId() string {
|
||||
if x != nil {
|
||||
return x.ConnectionId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ConnectResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
ConnectionId string `protobuf:"bytes,1,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"`
|
||||
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ConnectResponse) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *ConnectResponse) GetConnectionId() string {
|
||||
if x != nil {
|
||||
return x.ConnectionId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ConnectResponse) GetError() string {
|
||||
if x != nil {
|
||||
return x.Error
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type SendTextRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
ConnectionId string `protobuf:"bytes,1,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"`
|
||||
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SendTextRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *SendTextRequest) GetConnectionId() string {
|
||||
if x != nil {
|
||||
return x.ConnectionId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SendTextRequest) GetMessage() string {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type SendTextResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SendTextResponse) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *SendTextResponse) GetError() string {
|
||||
if x != nil {
|
||||
return x.Error
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type SendBinaryRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
ConnectionId string `protobuf:"bytes,1,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"`
|
||||
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SendBinaryRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *SendBinaryRequest) GetConnectionId() string {
|
||||
if x != nil {
|
||||
return x.ConnectionId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SendBinaryRequest) GetData() []byte {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type SendBinaryResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SendBinaryResponse) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *SendBinaryResponse) GetError() string {
|
||||
if x != nil {
|
||||
return x.Error
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type CloseRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
ConnectionId string `protobuf:"bytes,1,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"`
|
||||
Code int32 `protobuf:"varint,2,opt,name=code,proto3" json:"code,omitempty"`
|
||||
Reason string `protobuf:"bytes,3,opt,name=reason,proto3" json:"reason,omitempty"`
|
||||
}
|
||||
|
||||
func (x *CloseRequest) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *CloseRequest) GetConnectionId() string {
|
||||
if x != nil {
|
||||
return x.ConnectionId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CloseRequest) GetCode() int32 {
|
||||
if x != nil {
|
||||
return x.Code
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *CloseRequest) GetReason() string {
|
||||
if x != nil {
|
||||
return x.Reason
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type CloseResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (x *CloseResponse) ProtoReflect() protoreflect.Message {
|
||||
panic(`not implemented`)
|
||||
}
|
||||
|
||||
func (x *CloseResponse) GetError() string {
|
||||
if x != nil {
|
||||
return x.Error
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// go:plugin type=host version=1
|
||||
type WebSocketService interface {
|
||||
// Connect to a WebSocket endpoint
|
||||
Connect(context.Context, *ConnectRequest) (*ConnectResponse, error)
|
||||
// Send a text message
|
||||
SendText(context.Context, *SendTextRequest) (*SendTextResponse, error)
|
||||
// Send binary data
|
||||
SendBinary(context.Context, *SendBinaryRequest) (*SendBinaryResponse, error)
|
||||
// Close a connection
|
||||
Close(context.Context, *CloseRequest) (*CloseResponse, error)
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
syntax = "proto3";
|
||||
package websocket;
|
||||
option go_package = "github.com/navidrome/navidrome/plugins/host/websocket";
|
||||
|
||||
// go:plugin type=host version=1
|
||||
service WebSocketService {
|
||||
// Connect to a WebSocket endpoint
|
||||
rpc Connect(ConnectRequest) returns (ConnectResponse);
|
||||
|
||||
// Send a text message
|
||||
rpc SendText(SendTextRequest) returns (SendTextResponse);
|
||||
|
||||
// Send binary data
|
||||
rpc SendBinary(SendBinaryRequest) returns (SendBinaryResponse);
|
||||
|
||||
// Close a connection
|
||||
rpc Close(CloseRequest) returns (CloseResponse);
|
||||
}
|
||||
|
||||
message ConnectRequest {
|
||||
string url = 1;
|
||||
map<string, string> headers = 2;
|
||||
string connection_id = 3;
|
||||
}
|
||||
|
||||
message ConnectResponse {
|
||||
string connection_id = 1;
|
||||
string error = 2;
|
||||
}
|
||||
|
||||
message SendTextRequest {
|
||||
string connection_id = 1;
|
||||
string message = 2;
|
||||
}
|
||||
|
||||
message SendTextResponse {
|
||||
string error = 1;
|
||||
}
|
||||
|
||||
message SendBinaryRequest {
|
||||
string connection_id = 1;
|
||||
bytes data = 2;
|
||||
}
|
||||
|
||||
message SendBinaryResponse {
|
||||
string error = 1;
|
||||
}
|
||||
|
||||
message CloseRequest {
|
||||
string connection_id = 1;
|
||||
int32 code = 2;
|
||||
string reason = 3;
|
||||
}
|
||||
|
||||
message CloseResponse {
|
||||
string error = 1;
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
//go:build !wasip1
|
||||
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/websocket/websocket.proto
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
context "context"
|
||||
wasm "github.com/knqyf263/go-plugin/wasm"
|
||||
wazero "github.com/tetratelabs/wazero"
|
||||
api "github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
|
||||
const (
|
||||
i32 = api.ValueTypeI32
|
||||
i64 = api.ValueTypeI64
|
||||
)
|
||||
|
||||
type _webSocketService struct {
|
||||
WebSocketService
|
||||
}
|
||||
|
||||
// Instantiate a Go-defined module named "env" that exports host functions.
|
||||
func Instantiate(ctx context.Context, r wazero.Runtime, hostFunctions WebSocketService) error {
|
||||
envBuilder := r.NewHostModuleBuilder("env")
|
||||
h := _webSocketService{hostFunctions}
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._Connect), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("connect")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._SendText), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("send_text")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._SendBinary), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("send_binary")
|
||||
|
||||
envBuilder.NewFunctionBuilder().
|
||||
WithGoModuleFunction(api.GoModuleFunc(h._Close), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||
WithParameterNames("offset", "size").
|
||||
Export("close")
|
||||
|
||||
_, err := envBuilder.Instantiate(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// Connect to a WebSocket endpoint
|
||||
|
||||
func (h _webSocketService) _Connect(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(ConnectRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.Connect(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
// Send a text message
|
||||
|
||||
func (h _webSocketService) _SendText(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(SendTextRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.SendText(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
// Send binary data
|
||||
|
||||
func (h _webSocketService) _SendBinary(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(SendBinaryRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.SendBinary(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
|
||||
// Close a connection
|
||||
|
||||
func (h _webSocketService) _Close(ctx context.Context, m api.Module, stack []uint64) {
|
||||
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
request := new(CloseRequest)
|
||||
err = request.UnmarshalVT(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resp, err := h.Close(ctx, request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf, err = resp.MarshalVT()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||
stack[0] = ptrLen
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
//go:build wasip1
|
||||
|
||||
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go-plugin v0.1.0
|
||||
// protoc v5.29.3
|
||||
// source: host/websocket/websocket.proto
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
context "context"
|
||||
wasm "github.com/knqyf263/go-plugin/wasm"
|
||||
_ "unsafe"
|
||||
)
|
||||
|
||||
type webSocketService struct{}
|
||||
|
||||
func NewWebSocketService() WebSocketService {
|
||||
return webSocketService{}
|
||||
}
|
||||
|
||||
//go:wasmimport env connect
|
||||
func _connect(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h webSocketService) Connect(ctx context.Context, request *ConnectRequest) (*ConnectResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _connect(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(ConnectResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env send_text
|
||||
func _send_text(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h webSocketService) SendText(ctx context.Context, request *SendTextRequest) (*SendTextResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _send_text(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(SendTextResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env send_binary
|
||||
func _send_binary(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h webSocketService) SendBinary(ctx context.Context, request *SendBinaryRequest) (*SendBinaryResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _send_binary(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(SendBinaryResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
//go:wasmimport env close
|
||||
func _close(ptr uint32, size uint32) uint64
|
||||
|
||||
func (h webSocketService) Close(ctx context.Context, request *CloseRequest) (*CloseResponse, error) {
|
||||
buf, err := request.MarshalVT()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, size := wasm.ByteToPtr(buf)
|
||||
ptrSize := _close(ptr, size)
|
||||
wasm.Free(ptr)
|
||||
|
||||
ptr = uint32(ptrSize >> 32)
|
||||
size = uint32(ptrSize)
|
||||
buf = wasm.PtrToByte(ptr, size)
|
||||
|
||||
response := new(CloseResponse)
|
||||
if err = response.UnmarshalVT(buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
//go:build !wasip1
|
||||
|
||||
package websocket
|
||||
|
||||
func NewWebSocketService() WebSocketService {
|
||||
panic("not implemented")
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,220 @@
|
||||
// Code generated by ndpgen. DO NOT EDIT.
|
||||
|
||||
package host
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// WebSocketConnectRequest is the request type for WebSocket.Connect.
|
||||
type WebSocketConnectRequest struct {
|
||||
Url string `json:"url"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
ConnectionID string `json:"connectionId"`
|
||||
}
|
||||
|
||||
// WebSocketConnectResponse is the response type for WebSocket.Connect.
|
||||
type WebSocketConnectResponse struct {
|
||||
NewConnectionID string `json:"newConnectionId,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// WebSocketSendTextRequest is the request type for WebSocket.SendText.
|
||||
type WebSocketSendTextRequest struct {
|
||||
ConnectionID string `json:"connectionId"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// WebSocketSendTextResponse is the response type for WebSocket.SendText.
|
||||
type WebSocketSendTextResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// WebSocketSendBinaryRequest is the request type for WebSocket.SendBinary.
|
||||
type WebSocketSendBinaryRequest struct {
|
||||
ConnectionID string `json:"connectionId"`
|
||||
Data []byte `json:"data"`
|
||||
}
|
||||
|
||||
// WebSocketSendBinaryResponse is the response type for WebSocket.SendBinary.
|
||||
type WebSocketSendBinaryResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// WebSocketCloseConnectionRequest is the request type for WebSocket.CloseConnection.
|
||||
type WebSocketCloseConnectionRequest struct {
|
||||
ConnectionID string `json:"connectionId"`
|
||||
Code int32 `json:"code"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
// WebSocketCloseConnectionResponse is the response type for WebSocket.CloseConnection.
|
||||
type WebSocketCloseConnectionResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// RegisterWebSocketHostFunctions registers WebSocket service host functions.
|
||||
// The returned host functions should be added to the plugin's configuration.
|
||||
func RegisterWebSocketHostFunctions(service WebSocketService) []extism.HostFunction {
|
||||
return []extism.HostFunction{
|
||||
newWebSocketConnectHostFunction(service),
|
||||
newWebSocketSendTextHostFunction(service),
|
||||
newWebSocketSendBinaryHostFunction(service),
|
||||
newWebSocketCloseConnectionHostFunction(service),
|
||||
}
|
||||
}
|
||||
|
||||
func newWebSocketConnectHostFunction(service WebSocketService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"websocket_connect",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
websocketWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req WebSocketConnectRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
websocketWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
newconnectionid, svcErr := service.Connect(ctx, req.Url, req.Headers, req.ConnectionID)
|
||||
if svcErr != nil {
|
||||
websocketWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := WebSocketConnectResponse{
|
||||
NewConnectionID: newconnectionid,
|
||||
}
|
||||
websocketWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newWebSocketSendTextHostFunction(service WebSocketService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"websocket_sendtext",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
websocketWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req WebSocketSendTextRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
websocketWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
if svcErr := service.SendText(ctx, req.ConnectionID, req.Message); svcErr != nil {
|
||||
websocketWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := WebSocketSendTextResponse{}
|
||||
websocketWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newWebSocketSendBinaryHostFunction(service WebSocketService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"websocket_sendbinary",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
websocketWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req WebSocketSendBinaryRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
websocketWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
if svcErr := service.SendBinary(ctx, req.ConnectionID, req.Data); svcErr != nil {
|
||||
websocketWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := WebSocketSendBinaryResponse{}
|
||||
websocketWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
func newWebSocketCloseConnectionHostFunction(service WebSocketService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"websocket_closeconnection",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
websocketWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req WebSocketCloseConnectionRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
websocketWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
if svcErr := service.CloseConnection(ctx, req.ConnectionID, req.Code, req.Reason); svcErr != nil {
|
||||
websocketWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := WebSocketCloseConnectionResponse{}
|
||||
websocketWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
// websocketWriteResponse writes a JSON response to plugin memory.
|
||||
func websocketWriteResponse(p *extism.CurrentPlugin, stack []uint64, resp any) {
|
||||
respBytes, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
websocketWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
respPtr, err := p.WriteBytes(respBytes)
|
||||
if err != nil {
|
||||
stack[0] = 0
|
||||
return
|
||||
}
|
||||
stack[0] = respPtr
|
||||
}
|
||||
|
||||
// websocketWriteError writes an error response to plugin memory.
|
||||
func websocketWriteError(p *extism.CurrentPlugin, stack []uint64, err error) {
|
||||
errResp := struct {
|
||||
Error string `json:"error"`
|
||||
}{Error: err.Error()}
|
||||
respBytes, _ := json.Marshal(errResp)
|
||||
respPtr, _ := p.WriteBytes(respBytes)
|
||||
stack[0] = respPtr
|
||||
}
|
||||
Reference in New Issue
Block a user