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>
This commit is contained in:
Deluan 2025-12-29 22:17:02 -05:00
parent ebba3a2c46
commit 6fa9ef0dfe
37 changed files with 5635 additions and 68 deletions

View File

@ -79,7 +79,8 @@ type TestService interface {
outputStr := string(output)
Expect(outputStr).To(ContainSubstring("Input directory:"))
Expect(outputStr).To(ContainSubstring("Output directory:"))
Expect(outputStr).To(ContainSubstring("Base output directory:"))
Expect(outputStr).To(ContainSubstring("Go output directory:"))
Expect(outputStr).To(ContainSubstring("Found 1 host service(s)"))
Expect(outputStr).To(ContainSubstring("Generated"))
})
@ -93,7 +94,7 @@ type TestService interface {
Expect(filepath.Join(outputDir, "nd_host_test.go")).ToNot(BeAnExistingFile())
})
It("infers package name from output directory", func() {
It("uses default package name 'host'", func() {
customOutput, err := os.MkdirTemp("", "mypkg")
Expect(err).ToNot(HaveOccurred())
defer os.RemoveAll(customOutput)
@ -102,9 +103,10 @@ type TestService interface {
_, err = cmd.CombinedOutput()
Expect(err).ToNot(HaveOccurred())
content, err := os.ReadFile(filepath.Join(customOutput, "nd_host_test.go"))
// Go code goes to $output/go/host/
content, err := os.ReadFile(filepath.Join(customOutput, "go", "host", "nd_host_test.go"))
Expect(err).ToNot(HaveOccurred())
Expect(string(content)).To(ContainSubstring("package mypkg"))
Expect(string(content)).To(ContainSubstring("package host"))
})
It("returns error for invalid input directory", func() {
@ -151,8 +153,10 @@ type ServiceB interface {
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
Expect(string(output)).To(ContainSubstring("Found 2 host service(s)"))
Expect(filepath.Join(outputDir, "nd_host_servicea.go")).To(BeAnExistingFile())
Expect(filepath.Join(outputDir, "nd_host_serviceb.go")).To(BeAnExistingFile())
// Go code goes to $output/go/host/
goHostDir := filepath.Join(outputDir, "go", "host")
Expect(filepath.Join(goHostDir, "nd_host_servicea.go")).To(BeAnExistingFile())
Expect(filepath.Join(goHostDir, "nd_host_serviceb.go")).To(BeAnExistingFile())
})
It("generates Go client code by default", func() {
@ -160,13 +164,14 @@ type ServiceB interface {
output, err := cmd.CombinedOutput()
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
// Client code in output directory
Expect(filepath.Join(outputDir, "nd_host_test.go")).To(BeAnExistingFile())
// Go client code goes to $output/go/host/
goHostDir := filepath.Join(outputDir, "go", "host")
Expect(filepath.Join(goHostDir, "nd_host_test.go")).To(BeAnExistingFile())
// Stub file also generated
Expect(filepath.Join(outputDir, "nd_host_test_stub.go")).To(BeAnExistingFile())
Expect(filepath.Join(goHostDir, "nd_host_test_stub.go")).To(BeAnExistingFile())
// doc.go and go.mod also generated
Expect(filepath.Join(outputDir, "doc.go")).To(BeAnExistingFile())
Expect(filepath.Join(outputDir, "go.mod")).To(BeAnExistingFile())
Expect(filepath.Join(goHostDir, "doc.go")).To(BeAnExistingFile())
Expect(filepath.Join(goHostDir, "go.mod")).To(BeAnExistingFile())
})
})
@ -185,13 +190,14 @@ type ServiceB interface {
output, err := cmd.CombinedOutput()
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
// Verify Go client code
entries, err := os.ReadDir(outputDir)
// Verify Go client code (now in $output/go/host/)
goHostDir := filepath.Join(outputDir, "go", "host")
entries, err := os.ReadDir(goHostDir)
Expect(err).ToNot(HaveOccurred())
var goClientFiles []string
for _, e := range entries {
if e.Name() != "python" && e.Name() != "rust" && !e.IsDir() &&
if !e.IsDir() &&
!strings.HasSuffix(e.Name(), "_stub.go") &&
e.Name() != "doc.go" && e.Name() != "go.mod" {
goClientFiles = append(goClientFiles, e.Name())
@ -199,7 +205,7 @@ type ServiceB interface {
}
Expect(goClientFiles).To(HaveLen(1), "Expected exactly one Go client file, got: %v", goClientFiles)
goClientActual, err := os.ReadFile(filepath.Join(outputDir, goClientFiles[0]))
goClientActual, err := os.ReadFile(filepath.Join(goHostDir, goClientFiles[0]))
Expect(err).ToNot(HaveOccurred())
formattedGoClientActual, err := format.Source(goClientActual)
@ -212,20 +218,20 @@ type ServiceB interface {
Expect(string(formattedGoClientActual)).To(Equal(string(formattedGoClientExpected)), "Go client code mismatch")
// Verify Python client code
pythonDir := filepath.Join(outputDir, "python")
pyClientEntries, err := os.ReadDir(pythonDir)
// Verify Python client code (now in $output/python/host/)
pythonHostDir := filepath.Join(outputDir, "python", "host")
pyClientEntries, err := os.ReadDir(pythonHostDir)
Expect(err).ToNot(HaveOccurred())
Expect(pyClientEntries).To(HaveLen(1), "Expected exactly one Python client file")
pyClientActual, err := os.ReadFile(filepath.Join(pythonDir, pyClientEntries[0].Name()))
pyClientActual, err := os.ReadFile(filepath.Join(pythonHostDir, pyClientEntries[0].Name()))
Expect(err).ToNot(HaveOccurred())
Expect(string(pyClientActual)).To(Equal(pyClientExpected), "Python client code mismatch")
// Verify Rust client code
rustDir := filepath.Join(outputDir, "rust")
rsClientEntries, err := os.ReadDir(rustDir)
// Verify Rust client code (now in $output/rust/host/)
rustHostDir := filepath.Join(outputDir, "rust", "host")
rsClientEntries, err := os.ReadDir(rustHostDir)
Expect(err).ToNot(HaveOccurred())
Expect(rsClientEntries).To(HaveLen(2), "Expected Rust client file and lib.rs")
@ -239,7 +245,7 @@ type ServiceB interface {
}
Expect(rsClientName).ToNot(BeEmpty(), "Expected to find Rust client file")
rsClientActual, err := os.ReadFile(filepath.Join(rustDir, rsClientName))
rsClientActual, err := os.ReadFile(filepath.Join(rustHostDir, rsClientName))
Expect(err).ToNot(HaveOccurred())
Expect(string(rsClientActual)).To(Equal(rsClientExpected), "Rust client code mismatch")
@ -286,8 +292,11 @@ type ServiceB interface {
output, err := cmd.CombinedOutput()
Expect(err).ToNot(HaveOccurred(), "Generation failed: %s", output)
// Go code goes to $output/go/host/
goHostDir := filepath.Join(outputDir, "go", "host")
// Read generated client code
entries, err := os.ReadDir(outputDir)
entries, err := os.ReadDir(goHostDir)
Expect(err).ToNot(HaveOccurred())
// Find the client file
@ -301,7 +310,7 @@ type ServiceB interface {
}
Expect(clientFileName).ToNot(BeEmpty(), "Expected to find Go client file")
content, err := os.ReadFile(filepath.Join(outputDir, clientFileName))
content, err := os.ReadFile(filepath.Join(goHostDir, clientFileName))
Expect(err).ToNot(HaveOccurred())
// Verify key expected content
@ -334,7 +343,7 @@ go 1.24
require github.com/navidrome/navidrome/plugins/pdk/go/host v0.0.0
replace github.com/navidrome/navidrome/plugins/pdk/go/host => %s
`, outputDir)
`, goHostDir)
Expect(os.WriteFile(filepath.Join(pluginDir, "go.mod"), []byte(goMod), 0600)).To(Succeed())
// Add a simple main function that imports and uses the ndpdk package
@ -351,7 +360,7 @@ var _ = ndpdk.ComprehensiveNoParams
// Tidy dependencies for the generated go library
goTidyLibCmd := exec.Command("go", "mod", "tidy")
goTidyLibCmd.Dir = outputDir
goTidyLibCmd.Dir = goHostDir
goTidyLibOutput, err := goTidyLibCmd.CombinedOutput()
Expect(err).ToNot(HaveOccurred(), "go mod tidy (library) failed: %s", goTidyLibOutput)
@ -389,11 +398,11 @@ type TestService interface {
output, err := cmd.CombinedOutput()
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
// Verify Python client code exists
pythonDir := filepath.Join(outputDir, "python")
Expect(pythonDir).To(BeADirectory())
// Verify Python client code exists in $output/python/host/
pythonHostDir := filepath.Join(outputDir, "python", "host")
Expect(pythonHostDir).To(BeADirectory())
pythonFile := filepath.Join(pythonDir, "nd_host_test.py")
pythonFile := filepath.Join(pythonHostDir, "nd_host_test.py")
Expect(pythonFile).To(BeAnExistingFile())
content, err := os.ReadFile(pythonFile)
@ -423,12 +432,14 @@ type TestService interface {
output, err := cmd.CombinedOutput()
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
// Verify both Go and Python client code exist
Expect(filepath.Join(outputDir, "nd_host_test.go")).To(BeAnExistingFile())
// Verify Go client code exists in $output/go/host/
goHostDir := filepath.Join(outputDir, "go", "host")
Expect(filepath.Join(goHostDir, "nd_host_test.go")).To(BeAnExistingFile())
pythonDir := filepath.Join(outputDir, "python")
Expect(pythonDir).To(BeADirectory())
Expect(filepath.Join(pythonDir, "nd_host_test.py")).To(BeAnExistingFile())
// Verify Python client code exists in $output/python/host/
pythonHostDir := filepath.Join(outputDir, "python", "host")
Expect(pythonHostDir).To(BeADirectory())
Expect(filepath.Join(pythonHostDir, "nd_host_test.py")).To(BeAnExistingFile())
})
It("generates Python code with dataclass for multi-value returns", func() {
@ -448,7 +459,7 @@ type CacheService interface {
output, err := cmd.CombinedOutput()
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
content, err := os.ReadFile(filepath.Join(outputDir, "python", "nd_host_cache.py"))
content, err := os.ReadFile(filepath.Join(outputDir, "python", "host", "nd_host_cache.py"))
Expect(err).ToNot(HaveOccurred())
contentStr := string(content)
@ -476,7 +487,7 @@ type TestService interface {
output, err := cmd.CombinedOutput()
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
content, err := os.ReadFile(filepath.Join(outputDir, "python", "nd_host_test.py"))
content, err := os.ReadFile(filepath.Join(outputDir, "python", "host", "nd_host_test.py"))
Expect(err).ToNot(HaveOccurred())
contentStr := string(content)

View File

@ -5,13 +5,18 @@
//
// Usage:
//
// ndpgen -input=./plugins/host -output=./plugins/pdk/go/host
// ndpgen -input=./plugins/host -output=./plugins/pdk
//
// This generates code into language-specific subdirectories:
// - Go: $output/go/host/
// - Python: $output/python/host/
// - Rust: $output/rust/host/
//
// Flags:
//
// -input Input directory containing Go source files with annotated interfaces
// -output Output directory for generated files (default: same as input)
// -package Output package name (default: inferred from output directory)
// -output Output directory base for generated files (default: same as input)
// -package Output package name for Go (default: host)
// -host-only Generate only host function wrappers (default: true, capability support TBD)
// -go Generate Go client wrappers (default: true when not using -python/-rust)
// -python Generate Python client wrappers (default: false)
@ -34,7 +39,10 @@ import (
// config holds the parsed command-line configuration.
type config struct {
inputDir string
outputDir string
outputDir string // Base output directory (e.g., plugins/pdk)
goOutputDir string // Go output: $outputDir/go/host
pythonOutputDir string // Python output: $outputDir/python/host
rustOutputDir string // Rust output: $outputDir/rust/host
pkgName string
hostOnly bool
generateGoClient bool
@ -70,8 +78,8 @@ func main() {
func parseConfig() (*config, error) {
var (
inputDir = flag.String("input", ".", "Input directory containing Go source files")
outputDir = flag.String("output", "", "Output directory for generated files (default: same as input)")
pkgName = flag.String("package", "", "Output package name (default: inferred from output directory)")
outputDir = flag.String("output", "", "Base output directory for generated files (default: same as input)")
pkgName = flag.String("package", "host", "Output package name for Go (default: host)")
hostOnly = flag.Bool("host-only", true, "Generate only host function wrappers (capability support TBD)")
goClient = flag.Bool("go", false, "Generate Go client wrappers")
pyClient = flag.Bool("python", false, "Generate Python client wrappers")
@ -94,9 +102,10 @@ func parseConfig() (*config, error) {
return nil, fmt.Errorf("resolving output path: %w", err)
}
if *pkgName == "" {
*pkgName = filepath.Base(absOutput)
}
// Set output directories for each language: $output/$lang/host/
absGoOutput := filepath.Join(absOutput, "go", "host")
absPythonOutput := filepath.Join(absOutput, "python", "host")
absRustOutput := filepath.Join(absOutput, "rust", "host")
// Determine what to generate
// Default: generate Go clients if no language flag is specified
@ -105,6 +114,9 @@ func parseConfig() (*config, error) {
return &config{
inputDir: absInput,
outputDir: absOutput,
goOutputDir: absGoOutput,
pythonOutputDir: absPythonOutput,
rustOutputDir: absRustOutput,
pkgName: *pkgName,
hostOnly: *hostOnly,
generateGoClient: *goClient || !anyLangFlag,
@ -119,7 +131,16 @@ func parseConfig() (*config, error) {
func parseServices(cfg *config) ([]internal.Service, error) {
if cfg.verbose {
fmt.Printf("Input directory: %s\n", cfg.inputDir)
fmt.Printf("Output directory: %s\n", cfg.outputDir)
fmt.Printf("Base output directory: %s\n", cfg.outputDir)
if cfg.generateGoClient {
fmt.Printf("Go output directory: %s\n", cfg.goOutputDir)
}
if cfg.generatePyClient {
fmt.Printf("Python output directory: %s\n", cfg.pythonOutputDir)
}
if cfg.generateRsClient {
fmt.Printf("Rust output directory: %s\n", cfg.rustOutputDir)
}
fmt.Printf("Package name: %s\n", cfg.pkgName)
fmt.Printf("Host-only mode: %v\n", cfg.hostOnly)
fmt.Printf("Generate Go client code: %v\n", cfg.generateGoClient)
@ -153,33 +174,33 @@ func parseServices(cfg *config) ([]internal.Service, error) {
func generateAllCode(cfg *config, services []internal.Service) error {
for _, svc := range services {
if cfg.generateGoClient {
if err := generateGoClientCode(svc, cfg.outputDir, cfg.pkgName, cfg.dryRun, cfg.verbose); err != nil {
if err := generateGoClientCode(svc, cfg.goOutputDir, cfg.pkgName, cfg.dryRun, cfg.verbose); err != nil {
return fmt.Errorf("generating Go client code for %s: %w", svc.Name, err)
}
}
if cfg.generatePyClient {
if err := generatePythonClientCode(svc, cfg.outputDir, cfg.dryRun, cfg.verbose); err != nil {
if err := generatePythonClientCode(svc, cfg.pythonOutputDir, cfg.dryRun, cfg.verbose); err != nil {
return fmt.Errorf("generating Python client code for %s: %w", svc.Name, err)
}
}
if cfg.generateRsClient {
if err := generateRustClientCode(svc, cfg.outputDir, cfg.dryRun, cfg.verbose); err != nil {
if err := generateRustClientCode(svc, cfg.rustOutputDir, cfg.dryRun, cfg.verbose); err != nil {
return fmt.Errorf("generating Rust client code for %s: %w", svc.Name, err)
}
}
}
if cfg.generateRsClient && len(services) > 0 {
if err := generateRustLibFile(services, cfg.outputDir, cfg.dryRun, cfg.verbose); err != nil {
if err := generateRustLibFile(services, cfg.rustOutputDir, cfg.dryRun, cfg.verbose); err != nil {
return fmt.Errorf("generating Rust lib.rs: %w", err)
}
}
if cfg.generateGoClient && len(services) > 0 {
if err := generateGoDocFile(services, cfg.outputDir, cfg.pkgName, cfg.dryRun, cfg.verbose); err != nil {
if err := generateGoDocFile(services, cfg.goOutputDir, cfg.pkgName, cfg.dryRun, cfg.verbose); err != nil {
return fmt.Errorf("generating Go doc.go: %w", err)
}
if err := generateGoModFile(cfg.outputDir, cfg.dryRun, cfg.verbose); err != nil {
if err := generateGoModFile(cfg.goOutputDir, cfg.dryRun, cfg.verbose); err != nil {
return fmt.Errorf("generating Go go.mod: %w", err)
}
}
@ -265,17 +286,16 @@ func generatePythonClientCode(svc internal.Service, outputDir string, dryRun, ve
return fmt.Errorf("generating code: %w", err)
}
// Python code goes in python/ subdirectory
clientDir := filepath.Join(outputDir, "python")
clientFile := filepath.Join(clientDir, "nd_host_"+strings.ToLower(svc.Name)+".py")
// Python code goes directly in the output directory
clientFile := filepath.Join(outputDir, "nd_host_"+strings.ToLower(svc.Name)+".py")
if dryRun {
fmt.Printf("=== %s ===\n%s\n", clientFile, code)
return nil
}
// Create python/ subdirectory if needed
if err := os.MkdirAll(clientDir, 0755); err != nil {
// Create output directory if needed
if err := os.MkdirAll(outputDir, 0755); err != nil {
return fmt.Errorf("creating python client directory: %w", err)
}
@ -296,17 +316,16 @@ func generateRustClientCode(svc internal.Service, outputDir string, dryRun, verb
return fmt.Errorf("generating code: %w", err)
}
// Rust code goes in rust/ subdirectory
clientDir := filepath.Join(outputDir, "rust")
clientFile := filepath.Join(clientDir, "nd_host_"+strings.ToLower(svc.Name)+".rs")
// Rust code goes directly in the output directory
clientFile := filepath.Join(outputDir, "nd_host_"+strings.ToLower(svc.Name)+".rs")
if dryRun {
fmt.Printf("=== %s ===\n%s\n", clientFile, code)
return nil
}
// Create rust/ subdirectory if needed
if err := os.MkdirAll(clientDir, 0755); err != nil {
// Create output directory if needed
if err := os.MkdirAll(outputDir, 0755); err != nil {
return fmt.Errorf("creating rust client directory: %w", err)
}
@ -327,16 +346,16 @@ func generateRustLibFile(services []internal.Service, outputDir string, dryRun,
return fmt.Errorf("generating lib.rs: %w", err)
}
clientDir := filepath.Join(outputDir, "rust")
libFile := filepath.Join(clientDir, "lib.rs")
// lib.rs goes directly in the output directory
libFile := filepath.Join(outputDir, "lib.rs")
if dryRun {
fmt.Printf("=== %s ===\n%s\n", libFile, code)
return nil
}
// Create rust/ subdirectory if needed
if err := os.MkdirAll(clientDir, 0755); err != nil {
// Create output directory if needed
if err := os.MkdirAll(outputDir, 0755); err != nil {
return fmt.Errorf("creating rust client directory: %w", err)
}

View File

@ -0,0 +1,54 @@
// Code generated by ndpgen. DO NOT EDIT.
/*
Package host provides Navidrome Plugin Development Kit wrappers for Go/TinyGo plugins.
This package is auto-generated by the ndpgen tool and should not be edited manually.
# Usage
Add this module as a dependency in your plugin's go.mod:
require github.com/navidrome/navidrome/plugins/pdk/go/host v0.0.0
Then import the package in your plugin code:
import host "github.com/navidrome/navidrome/plugins/pdk/go/host"
func myPluginFunction() error {
// Use the cache service
_, err := host.CacheSetString("my_key", "my_value", 3600)
if err != nil {
return err
}
// Schedule a recurring task
_, err = host.SchedulerScheduleRecurring("@every 5m", "payload", "task_id")
if err != nil {
return err
}
return nil
}
# Available Services
The following host services are available:
- Artwork: provides artwork URL generation capabilities for plugins.
- Cache: provides in-memory TTL-based caching capabilities for plugins.
- KVStore: provides persistent key-value storage for plugins.
- Library: provides access to music library metadata for plugins.
- Scheduler: provides task scheduling capabilities for plugins.
- SubsonicAPI: provides access to Navidrome's Subsonic API from plugins.
- WebSocket: provides WebSocket communication capabilities for plugins.
# Building Plugins
Go plugins must be compiled to WebAssembly using TinyGo:
tinygo build -o plugin.wasm -target=wasip1 -buildmode=c-shared .
See the examples directory for complete plugin implementations.
*/
package host

View File

@ -0,0 +1,5 @@
module github.com/navidrome/navidrome/plugins/pdk/go/host
go 1.24
require github.com/extism/go-pdk v1.1.3

View File

@ -0,0 +1,251 @@
// Code generated by ndpgen. DO NOT EDIT.
//
// This file contains client wrappers for the Artwork host service.
// It is intended for use in Navidrome plugins built with TinyGo.
//
//go:build wasip1
package host
import (
"encoding/json"
"errors"
"github.com/extism/go-pdk"
)
// artwork_getartisturl is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user artwork_getartisturl
func artwork_getartisturl(uint64) uint64
// artwork_getalbumurl is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user artwork_getalbumurl
func artwork_getalbumurl(uint64) uint64
// artwork_gettrackurl is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user artwork_gettrackurl
func artwork_gettrackurl(uint64) uint64
// artwork_getplaylisturl is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user artwork_getplaylisturl
func artwork_getplaylisturl(uint64) uint64
// 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"`
}
// ArtworkGetArtistUrl calls the artwork_getartisturl host function.
// 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.
func ArtworkGetArtistUrl(id string, size int32) (*ArtworkGetArtistUrlResponse, error) {
// Marshal request to JSON
req := ArtworkGetArtistUrlRequest{
Id: id,
Size: size,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := artwork_getartisturl(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response ArtworkGetArtistUrlResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// ArtworkGetAlbumUrl calls the artwork_getalbumurl host function.
// 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.
func ArtworkGetAlbumUrl(id string, size int32) (*ArtworkGetAlbumUrlResponse, error) {
// Marshal request to JSON
req := ArtworkGetAlbumUrlRequest{
Id: id,
Size: size,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := artwork_getalbumurl(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response ArtworkGetAlbumUrlResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// ArtworkGetTrackUrl calls the artwork_gettrackurl host function.
// 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.
func ArtworkGetTrackUrl(id string, size int32) (*ArtworkGetTrackUrlResponse, error) {
// Marshal request to JSON
req := ArtworkGetTrackUrlRequest{
Id: id,
Size: size,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := artwork_gettrackurl(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response ArtworkGetTrackUrlResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// ArtworkGetPlaylistUrl calls the artwork_getplaylisturl host function.
// 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.
func ArtworkGetPlaylistUrl(id string, size int32) (*ArtworkGetPlaylistUrlResponse, error) {
// Marshal request to JSON
req := ArtworkGetPlaylistUrlRequest{
Id: id,
Size: size,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := artwork_getplaylisturl(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response ArtworkGetPlaylistUrlResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}

View File

@ -0,0 +1,105 @@
// Code generated by ndpgen. DO NOT EDIT.
//
// This file contains stub implementations for non-WASM builds.
// These stubs allow IDE support and compilation on non-WASM platforms.
// They panic at runtime since host functions are only available in WASM plugins.
//
//go:build !wasip1
package host
// 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"`
}
// ArtworkGetArtistUrl is a stub that panics on non-WASM platforms.
// 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.
func ArtworkGetArtistUrl(id string, size int32) (*ArtworkGetArtistUrlResponse, error) {
panic("host: ArtworkGetArtistUrl is only available in WASM plugins")
}
// ArtworkGetAlbumUrl is a stub that panics on non-WASM platforms.
// 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.
func ArtworkGetAlbumUrl(id string, size int32) (*ArtworkGetAlbumUrlResponse, error) {
panic("host: ArtworkGetAlbumUrl is only available in WASM plugins")
}
// ArtworkGetTrackUrl is a stub that panics on non-WASM platforms.
// 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.
func ArtworkGetTrackUrl(id string, size int32) (*ArtworkGetTrackUrlResponse, error) {
panic("host: ArtworkGetTrackUrl is only available in WASM plugins")
}
// ArtworkGetPlaylistUrl is a stub that panics on non-WASM platforms.
// 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.
func ArtworkGetPlaylistUrl(id string, size int32) (*ArtworkGetPlaylistUrlResponse, error) {
panic("host: ArtworkGetPlaylistUrl is only available in WASM plugins")
}

View File

@ -0,0 +1,602 @@
// Code generated by ndpgen. DO NOT EDIT.
//
// This file contains client wrappers for the Cache host service.
// It is intended for use in Navidrome plugins built with TinyGo.
//
//go:build wasip1
package host
import (
"encoding/json"
"errors"
"github.com/extism/go-pdk"
)
// cache_setstring is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user cache_setstring
func cache_setstring(uint64) uint64
// cache_getstring is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user cache_getstring
func cache_getstring(uint64) uint64
// cache_setint is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user cache_setint
func cache_setint(uint64) uint64
// cache_getint is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user cache_getint
func cache_getint(uint64) uint64
// cache_setfloat is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user cache_setfloat
func cache_setfloat(uint64) uint64
// cache_getfloat is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user cache_getfloat
func cache_getfloat(uint64) uint64
// cache_setbytes is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user cache_setbytes
func cache_setbytes(uint64) uint64
// cache_getbytes is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user cache_getbytes
func cache_getbytes(uint64) uint64
// cache_has is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user cache_has
func cache_has(uint64) uint64
// cache_remove is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user cache_remove
func cache_remove(uint64) uint64
// 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"`
}
// CacheSetString calls the cache_setstring host function.
// 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.
func CacheSetString(key string, value string, ttlSeconds int64) (*CacheSetStringResponse, error) {
// Marshal request to JSON
req := CacheSetStringRequest{
Key: key,
Value: value,
TtlSeconds: ttlSeconds,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := cache_setstring(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response CacheSetStringResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// CacheGetString calls the cache_getstring host function.
// 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.
func CacheGetString(key string) (*CacheGetStringResponse, error) {
// Marshal request to JSON
req := CacheGetStringRequest{
Key: key,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := cache_getstring(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response CacheGetStringResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// CacheSetInt calls the cache_setint host function.
// 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.
func CacheSetInt(key string, value int64, ttlSeconds int64) (*CacheSetIntResponse, error) {
// Marshal request to JSON
req := CacheSetIntRequest{
Key: key,
Value: value,
TtlSeconds: ttlSeconds,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := cache_setint(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response CacheSetIntResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// CacheGetInt calls the cache_getint host function.
// 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.
func CacheGetInt(key string) (*CacheGetIntResponse, error) {
// Marshal request to JSON
req := CacheGetIntRequest{
Key: key,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := cache_getint(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response CacheGetIntResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// CacheSetFloat calls the cache_setfloat host function.
// 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.
func CacheSetFloat(key string, value float64, ttlSeconds int64) (*CacheSetFloatResponse, error) {
// Marshal request to JSON
req := CacheSetFloatRequest{
Key: key,
Value: value,
TtlSeconds: ttlSeconds,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := cache_setfloat(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response CacheSetFloatResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// CacheGetFloat calls the cache_getfloat host function.
// 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.
func CacheGetFloat(key string) (*CacheGetFloatResponse, error) {
// Marshal request to JSON
req := CacheGetFloatRequest{
Key: key,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := cache_getfloat(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response CacheGetFloatResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// CacheSetBytes calls the cache_setbytes host function.
// 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.
func CacheSetBytes(key string, value []byte, ttlSeconds int64) (*CacheSetBytesResponse, error) {
// Marshal request to JSON
req := CacheSetBytesRequest{
Key: key,
Value: value,
TtlSeconds: ttlSeconds,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := cache_setbytes(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response CacheSetBytesResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// CacheGetBytes calls the cache_getbytes host function.
// 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.
func CacheGetBytes(key string) (*CacheGetBytesResponse, error) {
// Marshal request to JSON
req := CacheGetBytesRequest{
Key: key,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := cache_getbytes(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response CacheGetBytesResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// CacheHas calls the cache_has host function.
// 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.
func CacheHas(key string) (*CacheHasResponse, error) {
// Marshal request to JSON
req := CacheHasRequest{
Key: key,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := cache_has(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response CacheHasResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// CacheRemove calls the cache_remove host function.
// 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.
func CacheRemove(key string) (*CacheRemoveResponse, error) {
// Marshal request to JSON
req := CacheRemoveRequest{
Key: key,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := cache_remove(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response CacheRemoveResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}

View File

@ -0,0 +1,248 @@
// Code generated by ndpgen. DO NOT EDIT.
//
// This file contains stub implementations for non-WASM builds.
// These stubs allow IDE support and compilation on non-WASM platforms.
// They panic at runtime since host functions are only available in WASM plugins.
//
//go:build !wasip1
package host
// 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"`
}
// CacheSetString is a stub that panics on non-WASM platforms.
// 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.
func CacheSetString(key string, value string, ttlSeconds int64) (*CacheSetStringResponse, error) {
panic("host: CacheSetString is only available in WASM plugins")
}
// CacheGetString is a stub that panics on non-WASM platforms.
// 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.
func CacheGetString(key string) (*CacheGetStringResponse, error) {
panic("host: CacheGetString is only available in WASM plugins")
}
// CacheSetInt is a stub that panics on non-WASM platforms.
// 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.
func CacheSetInt(key string, value int64, ttlSeconds int64) (*CacheSetIntResponse, error) {
panic("host: CacheSetInt is only available in WASM plugins")
}
// CacheGetInt is a stub that panics on non-WASM platforms.
// 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.
func CacheGetInt(key string) (*CacheGetIntResponse, error) {
panic("host: CacheGetInt is only available in WASM plugins")
}
// CacheSetFloat is a stub that panics on non-WASM platforms.
// 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.
func CacheSetFloat(key string, value float64, ttlSeconds int64) (*CacheSetFloatResponse, error) {
panic("host: CacheSetFloat is only available in WASM plugins")
}
// CacheGetFloat is a stub that panics on non-WASM platforms.
// 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.
func CacheGetFloat(key string) (*CacheGetFloatResponse, error) {
panic("host: CacheGetFloat is only available in WASM plugins")
}
// CacheSetBytes is a stub that panics on non-WASM platforms.
// 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.
func CacheSetBytes(key string, value []byte, ttlSeconds int64) (*CacheSetBytesResponse, error) {
panic("host: CacheSetBytes is only available in WASM plugins")
}
// CacheGetBytes is a stub that panics on non-WASM platforms.
// 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.
func CacheGetBytes(key string) (*CacheGetBytesResponse, error) {
panic("host: CacheGetBytes is only available in WASM plugins")
}
// CacheHas is a stub that panics on non-WASM platforms.
// 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.
func CacheHas(key string) (*CacheHasResponse, error) {
panic("host: CacheHas is only available in WASM plugins")
}
// CacheRemove is a stub that panics on non-WASM platforms.
// 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.
func CacheRemove(key string) (*CacheRemoveResponse, error) {
panic("host: CacheRemove is only available in WASM plugins")
}

View File

@ -0,0 +1,336 @@
// Code generated by ndpgen. DO NOT EDIT.
//
// This file contains client wrappers for the KVStore host service.
// It is intended for use in Navidrome plugins built with TinyGo.
//
//go:build wasip1
package host
import (
"encoding/json"
"errors"
"github.com/extism/go-pdk"
)
// kvstore_set is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user kvstore_set
func kvstore_set(uint64) uint64
// kvstore_get is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user kvstore_get
func kvstore_get(uint64) uint64
// kvstore_delete is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user kvstore_delete
func kvstore_delete(uint64) uint64
// kvstore_has is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user kvstore_has
func kvstore_has(uint64) uint64
// kvstore_list is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user kvstore_list
func kvstore_list(uint64) uint64
// kvstore_getstorageused is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user kvstore_getstorageused
func kvstore_getstorageused(uint64) uint64
// 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"`
}
// KVStoreSet calls the kvstore_set host function.
// 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.
func KVStoreSet(key string, value []byte) (*KVStoreSetResponse, error) {
// Marshal request to JSON
req := KVStoreSetRequest{
Key: key,
Value: value,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := kvstore_set(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response KVStoreSetResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// KVStoreGet calls the kvstore_get host function.
// Get retrieves a byte value from storage.
//
// Parameters:
// - key: The storage key
//
// Returns the value and whether the key exists.
func KVStoreGet(key string) (*KVStoreGetResponse, error) {
// Marshal request to JSON
req := KVStoreGetRequest{
Key: key,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := kvstore_get(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response KVStoreGetResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// KVStoreDelete calls the kvstore_delete host function.
// 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.
func KVStoreDelete(key string) (*KVStoreDeleteResponse, error) {
// Marshal request to JSON
req := KVStoreDeleteRequest{
Key: key,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := kvstore_delete(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response KVStoreDeleteResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// KVStoreHas calls the kvstore_has host function.
// Has checks if a key exists in storage.
//
// Parameters:
// - key: The storage key
//
// Returns true if the key exists.
func KVStoreHas(key string) (*KVStoreHasResponse, error) {
// Marshal request to JSON
req := KVStoreHasRequest{
Key: key,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := kvstore_has(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response KVStoreHasResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// KVStoreList calls the kvstore_list host function.
// 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.
func KVStoreList(prefix string) (*KVStoreListResponse, error) {
// Marshal request to JSON
req := KVStoreListRequest{
Prefix: prefix,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := kvstore_list(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response KVStoreListResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// KVStoreGetStorageUsed calls the kvstore_getstorageused host function.
// GetStorageUsed returns the total storage used by this plugin in bytes.
func KVStoreGetStorageUsed() (*KVStoreGetStorageUsedResponse, error) {
// No parameters - allocate empty JSON object
reqMem := pdk.AllocateBytes([]byte("{}"))
defer reqMem.Free()
// Call the host function
responsePtr := kvstore_getstorageused(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response KVStoreGetStorageUsedResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}

View File

@ -0,0 +1,132 @@
// Code generated by ndpgen. DO NOT EDIT.
//
// This file contains stub implementations for non-WASM builds.
// These stubs allow IDE support and compilation on non-WASM platforms.
// They panic at runtime since host functions are only available in WASM plugins.
//
//go:build !wasip1
package host
// 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"`
}
// KVStoreSet is a stub that panics on non-WASM platforms.
// 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.
func KVStoreSet(key string, value []byte) (*KVStoreSetResponse, error) {
panic("host: KVStoreSet is only available in WASM plugins")
}
// KVStoreGet is a stub that panics on non-WASM platforms.
// Get retrieves a byte value from storage.
//
// Parameters:
// - key: The storage key
//
// Returns the value and whether the key exists.
func KVStoreGet(key string) (*KVStoreGetResponse, error) {
panic("host: KVStoreGet is only available in WASM plugins")
}
// KVStoreDelete is a stub that panics on non-WASM platforms.
// 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.
func KVStoreDelete(key string) (*KVStoreDeleteResponse, error) {
panic("host: KVStoreDelete is only available in WASM plugins")
}
// KVStoreHas is a stub that panics on non-WASM platforms.
// Has checks if a key exists in storage.
//
// Parameters:
// - key: The storage key
//
// Returns true if the key exists.
func KVStoreHas(key string) (*KVStoreHasResponse, error) {
panic("host: KVStoreHas is only available in WASM plugins")
}
// KVStoreList is a stub that panics on non-WASM platforms.
// 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.
func KVStoreList(prefix string) (*KVStoreListResponse, error) {
panic("host: KVStoreList is only available in WASM plugins")
}
// KVStoreGetStorageUsed is a stub that panics on non-WASM platforms.
// GetStorageUsed returns the total storage used by this plugin in bytes.
func KVStoreGetStorageUsed() (*KVStoreGetStorageUsedResponse, error) {
panic("host: KVStoreGetStorageUsed is only available in WASM plugins")
}

View File

@ -0,0 +1,127 @@
// Code generated by ndpgen. DO NOT EDIT.
//
// This file contains client wrappers for the Library host service.
// It is intended for use in Navidrome plugins built with TinyGo.
//
//go:build wasip1
package host
import (
"encoding/json"
"errors"
"github.com/extism/go-pdk"
)
// Library represents the Library data structure.
// Library represents a music library with metadata.
type Library struct {
ID int32 `json:"id"`
Name string `json:"name"`
Path string `json:"path"`
MountPoint string `json:"mountPoint"`
LastScanAt int64 `json:"lastScanAt"`
TotalSongs int32 `json:"totalSongs"`
TotalAlbums int32 `json:"totalAlbums"`
TotalArtists int32 `json:"totalArtists"`
TotalSize int64 `json:"totalSize"`
TotalDuration float64 `json:"totalDuration"`
}
// library_getlibrary is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user library_getlibrary
func library_getlibrary(uint64) uint64
// library_getalllibraries is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user library_getalllibraries
func library_getalllibraries(uint64) uint64
// 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"`
}
// LibraryGetLibrary calls the library_getlibrary host function.
// 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.
func LibraryGetLibrary(id int32) (*LibraryGetLibraryResponse, error) {
// Marshal request to JSON
req := LibraryGetLibraryRequest{
Id: id,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := library_getlibrary(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response LibraryGetLibraryResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// LibraryGetAllLibraries calls the library_getalllibraries host function.
// GetAllLibraries retrieves metadata for all configured libraries.
//
// Returns a slice of all libraries with their metadata.
func LibraryGetAllLibraries() (*LibraryGetAllLibrariesResponse, error) {
// No parameters - allocate empty JSON object
reqMem := pdk.AllocateBytes([]byte("{}"))
defer reqMem.Free()
// Call the host function
responsePtr := library_getalllibraries(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response LibraryGetAllLibrariesResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}

View File

@ -0,0 +1,60 @@
// Code generated by ndpgen. DO NOT EDIT.
//
// This file contains stub implementations for non-WASM builds.
// These stubs allow IDE support and compilation on non-WASM platforms.
// They panic at runtime since host functions are only available in WASM plugins.
//
//go:build !wasip1
package host
// Library represents the Library data structure.
// Library represents a music library with metadata.
type Library struct {
ID int32 `json:"id"`
Name string `json:"name"`
Path string `json:"path"`
MountPoint string `json:"mountPoint"`
LastScanAt int64 `json:"lastScanAt"`
TotalSongs int32 `json:"totalSongs"`
TotalAlbums int32 `json:"totalAlbums"`
TotalArtists int32 `json:"totalArtists"`
TotalSize int64 `json:"totalSize"`
TotalDuration float64 `json:"totalDuration"`
}
// 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"`
}
// LibraryGetLibrary is a stub that panics on non-WASM platforms.
// 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.
func LibraryGetLibrary(id int32) (*LibraryGetLibraryResponse, error) {
panic("host: LibraryGetLibrary is only available in WASM plugins")
}
// LibraryGetAllLibraries is a stub that panics on non-WASM platforms.
// GetAllLibraries retrieves metadata for all configured libraries.
//
// Returns a slice of all libraries with their metadata.
func LibraryGetAllLibraries() (*LibraryGetAllLibrariesResponse, error) {
panic("host: LibraryGetAllLibraries is only available in WASM plugins")
}

View File

@ -0,0 +1,196 @@
// Code generated by ndpgen. DO NOT EDIT.
//
// This file contains client wrappers for the Scheduler host service.
// It is intended for use in Navidrome plugins built with TinyGo.
//
//go:build wasip1
package host
import (
"encoding/json"
"errors"
"github.com/extism/go-pdk"
)
// scheduler_scheduleonetime is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user scheduler_scheduleonetime
func scheduler_scheduleonetime(uint64) uint64
// scheduler_schedulerecurring is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user scheduler_schedulerecurring
func scheduler_schedulerecurring(uint64) uint64
// scheduler_cancelschedule is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user scheduler_cancelschedule
func scheduler_cancelschedule(uint64) uint64
// 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"`
}
// SchedulerScheduleOneTime calls the scheduler_scheduleonetime host function.
// 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.
func SchedulerScheduleOneTime(delaySeconds int32, payload string, scheduleID string) (*SchedulerScheduleOneTimeResponse, error) {
// Marshal request to JSON
req := SchedulerScheduleOneTimeRequest{
DelaySeconds: delaySeconds,
Payload: payload,
ScheduleID: scheduleID,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := scheduler_scheduleonetime(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response SchedulerScheduleOneTimeResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// SchedulerScheduleRecurring calls the scheduler_schedulerecurring host function.
// 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.
func SchedulerScheduleRecurring(cronExpression string, payload string, scheduleID string) (*SchedulerScheduleRecurringResponse, error) {
// Marshal request to JSON
req := SchedulerScheduleRecurringRequest{
CronExpression: cronExpression,
Payload: payload,
ScheduleID: scheduleID,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := scheduler_schedulerecurring(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response SchedulerScheduleRecurringResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// SchedulerCancelSchedule calls the scheduler_cancelschedule host function.
// 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.
func SchedulerCancelSchedule(scheduleID string) (*SchedulerCancelScheduleResponse, error) {
// Marshal request to JSON
req := SchedulerCancelScheduleRequest{
ScheduleID: scheduleID,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := scheduler_cancelschedule(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response SchedulerCancelScheduleResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}

View File

@ -0,0 +1,84 @@
// Code generated by ndpgen. DO NOT EDIT.
//
// This file contains stub implementations for non-WASM builds.
// These stubs allow IDE support and compilation on non-WASM platforms.
// They panic at runtime since host functions are only available in WASM plugins.
//
//go:build !wasip1
package host
// 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"`
}
// SchedulerScheduleOneTime is a stub that panics on non-WASM platforms.
// 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.
func SchedulerScheduleOneTime(delaySeconds int32, payload string, scheduleID string) (*SchedulerScheduleOneTimeResponse, error) {
panic("host: SchedulerScheduleOneTime is only available in WASM plugins")
}
// SchedulerScheduleRecurring is a stub that panics on non-WASM platforms.
// 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.
func SchedulerScheduleRecurring(cronExpression string, payload string, scheduleID string) (*SchedulerScheduleRecurringResponse, error) {
panic("host: SchedulerScheduleRecurring is only available in WASM plugins")
}
// SchedulerCancelSchedule is a stub that panics on non-WASM platforms.
// 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.
func SchedulerCancelSchedule(scheduleID string) (*SchedulerCancelScheduleResponse, error) {
panic("host: SchedulerCancelSchedule is only available in WASM plugins")
}

View File

@ -0,0 +1,69 @@
// Code generated by ndpgen. DO NOT EDIT.
//
// This file contains client wrappers for the SubsonicAPI host service.
// It is intended for use in Navidrome plugins built with TinyGo.
//
//go:build wasip1
package host
import (
"encoding/json"
"errors"
"github.com/extism/go-pdk"
)
// subsonicapi_call is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user subsonicapi_call
func subsonicapi_call(uint64) uint64
// 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"`
}
// SubsonicAPICall calls the subsonicapi_call host function.
// 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.
func SubsonicAPICall(uri string) (*SubsonicAPICallResponse, error) {
// Marshal request to JSON
req := SubsonicAPICallRequest{
Uri: uri,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := subsonicapi_call(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response SubsonicAPICallResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}

View File

@ -0,0 +1,29 @@
// Code generated by ndpgen. DO NOT EDIT.
//
// This file contains stub implementations for non-WASM builds.
// These stubs allow IDE support and compilation on non-WASM platforms.
// They panic at runtime since host functions are only available in WASM plugins.
//
//go:build !wasip1
package host
// 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"`
}
// SubsonicAPICall is a stub that panics on non-WASM platforms.
// 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.
func SubsonicAPICall(uri string) (*SubsonicAPICallResponse, error) {
panic("host: SubsonicAPICall is only available in WASM plugins")
}

View File

@ -0,0 +1,258 @@
// Code generated by ndpgen. DO NOT EDIT.
//
// This file contains client wrappers for the WebSocket host service.
// It is intended for use in Navidrome plugins built with TinyGo.
//
//go:build wasip1
package host
import (
"encoding/json"
"errors"
"github.com/extism/go-pdk"
)
// websocket_connect is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user websocket_connect
func websocket_connect(uint64) uint64
// websocket_sendtext is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user websocket_sendtext
func websocket_sendtext(uint64) uint64
// websocket_sendbinary is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user websocket_sendbinary
func websocket_sendbinary(uint64) uint64
// websocket_closeconnection is the host function provided by Navidrome.
//
//go:wasmimport extism:host/user websocket_closeconnection
func websocket_closeconnection(uint64) uint64
// 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"`
}
// WebSocketConnect calls the websocket_connect host function.
// 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.
func WebSocketConnect(url string, headers map[string]string, connectionID string) (*WebSocketConnectResponse, error) {
// Marshal request to JSON
req := WebSocketConnectRequest{
Url: url,
Headers: headers,
ConnectionID: connectionID,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := websocket_connect(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response WebSocketConnectResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// WebSocketSendText calls the websocket_sendtext host function.
// 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.
func WebSocketSendText(connectionID string, message string) (*WebSocketSendTextResponse, error) {
// Marshal request to JSON
req := WebSocketSendTextRequest{
ConnectionID: connectionID,
Message: message,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := websocket_sendtext(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response WebSocketSendTextResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// WebSocketSendBinary calls the websocket_sendbinary host function.
// 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.
func WebSocketSendBinary(connectionID string, data []byte) (*WebSocketSendBinaryResponse, error) {
// Marshal request to JSON
req := WebSocketSendBinaryRequest{
ConnectionID: connectionID,
Data: data,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := websocket_sendbinary(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response WebSocketSendBinaryResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}
// WebSocketCloseConnection calls the websocket_closeconnection host function.
// 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.
func WebSocketCloseConnection(connectionID string, code int32, reason string) (*WebSocketCloseConnectionResponse, error) {
// Marshal request to JSON
req := WebSocketCloseConnectionRequest{
ConnectionID: connectionID,
Code: code,
Reason: reason,
}
reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}
reqMem := pdk.AllocateBytes(reqBytes)
defer reqMem.Free()
// Call the host function
responsePtr := websocket_closeconnection(reqMem.Offset())
// Read the response from memory
responseMem := pdk.FindMemory(responsePtr)
responseBytes := responseMem.ReadBytes()
// Parse the response
var response WebSocketCloseConnectionResponse
if err := json.Unmarshal(responseBytes, &response); err != nil {
return nil, err
}
// Convert Error field to Go error
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response, nil
}

View File

@ -0,0 +1,110 @@
// Code generated by ndpgen. DO NOT EDIT.
//
// This file contains stub implementations for non-WASM builds.
// These stubs allow IDE support and compilation on non-WASM platforms.
// They panic at runtime since host functions are only available in WASM plugins.
//
//go:build !wasip1
package host
// 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"`
}
// WebSocketConnect is a stub that panics on non-WASM platforms.
// 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.
func WebSocketConnect(url string, headers map[string]string, connectionID string) (*WebSocketConnectResponse, error) {
panic("host: WebSocketConnect is only available in WASM plugins")
}
// WebSocketSendText is a stub that panics on non-WASM platforms.
// 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.
func WebSocketSendText(connectionID string, message string) (*WebSocketSendTextResponse, error) {
panic("host: WebSocketSendText is only available in WASM plugins")
}
// WebSocketSendBinary is a stub that panics on non-WASM platforms.
// 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.
func WebSocketSendBinary(connectionID string, data []byte) (*WebSocketSendBinaryResponse, error) {
panic("host: WebSocketSendBinary is only available in WASM plugins")
}
// WebSocketCloseConnection is a stub that panics on non-WASM platforms.
// 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.
func WebSocketCloseConnection(connectionID string, code int32, reason string) (*WebSocketCloseConnectionResponse, error) {
panic("host: WebSocketCloseConnection is only available in WASM plugins")
}

View File

@ -0,0 +1,183 @@
# Code generated by hostgen. DO NOT EDIT.
#
# This file contains client wrappers for the Artwork host service.
# It is intended for use in Navidrome plugins built with extism-py.
#
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
# The @extism.import_fn decorators are only detected when defined in the plugin's
# main __init__.py file. Copy the needed functions from this file into your plugin.
from dataclasses import dataclass
from typing import Any
import extism
import json
class HostFunctionError(Exception):
"""Raised when a host function returns an error."""
pass
@extism.import_fn("extism:host/user", "artwork_getartisturl")
def _artwork_getartisturl(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "artwork_getalbumurl")
def _artwork_getalbumurl(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "artwork_gettrackurl")
def _artwork_gettrackurl(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "artwork_getplaylisturl")
def _artwork_getplaylisturl(offset: int) -> int:
"""Raw host function - do not call directly."""
...
def artwork_get_artist_url(id: str, size: int) -> str:
"""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.
Args:
id: str parameter.
size: int parameter.
Returns:
str: The result value.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"id": id,
"size": size,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _artwork_getartisturl(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return response.get("url", "")
def artwork_get_album_url(id: str, size: int) -> str:
"""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.
Args:
id: str parameter.
size: int parameter.
Returns:
str: The result value.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"id": id,
"size": size,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _artwork_getalbumurl(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return response.get("url", "")
def artwork_get_track_url(id: str, size: int) -> str:
"""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.
Args:
id: str parameter.
size: int parameter.
Returns:
str: The result value.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"id": id,
"size": size,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _artwork_gettrackurl(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return response.get("url", "")
def artwork_get_playlist_url(id: str, size: int) -> str:
"""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.
Args:
id: str parameter.
size: int parameter.
Returns:
str: The result value.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"id": id,
"size": size,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _artwork_getplaylisturl(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return response.get("url", "")

View File

@ -0,0 +1,447 @@
# Code generated by hostgen. DO NOT EDIT.
#
# This file contains client wrappers for the Cache host service.
# It is intended for use in Navidrome plugins built with extism-py.
#
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
# The @extism.import_fn decorators are only detected when defined in the plugin's
# main __init__.py file. Copy the needed functions from this file into your plugin.
from dataclasses import dataclass
from typing import Any
import extism
import json
class HostFunctionError(Exception):
"""Raised when a host function returns an error."""
pass
@extism.import_fn("extism:host/user", "cache_setstring")
def _cache_setstring(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "cache_getstring")
def _cache_getstring(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "cache_setint")
def _cache_setint(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "cache_getint")
def _cache_getint(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "cache_setfloat")
def _cache_setfloat(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "cache_getfloat")
def _cache_getfloat(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "cache_setbytes")
def _cache_setbytes(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "cache_getbytes")
def _cache_getbytes(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "cache_has")
def _cache_has(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "cache_remove")
def _cache_remove(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@dataclass
class CacheGetStringResult:
"""Result type for cache_get_string."""
value: str
exists: bool
@dataclass
class CacheGetIntResult:
"""Result type for cache_get_int."""
value: int
exists: bool
@dataclass
class CacheGetFloatResult:
"""Result type for cache_get_float."""
value: float
exists: bool
@dataclass
class CacheGetBytesResult:
"""Result type for cache_get_bytes."""
value: bytes
exists: bool
def cache_set_string(key: str, value: str, ttl_seconds: int) -> None:
"""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.
Args:
key: str parameter.
value: str parameter.
ttl_seconds: int parameter.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"key": key,
"value": value,
"ttlSeconds": ttl_seconds,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _cache_setstring(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
def cache_get_string(key: str) -> CacheGetStringResult:
"""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.
Args:
key: str parameter.
Returns:
CacheGetStringResult containing value, exists,.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"key": key,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _cache_getstring(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return CacheGetStringResult(
value=response.get("value", ""),
exists=response.get("exists", False),
)
def cache_set_int(key: str, value: int, ttl_seconds: int) -> None:
"""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.
Args:
key: str parameter.
value: int parameter.
ttl_seconds: int parameter.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"key": key,
"value": value,
"ttlSeconds": ttl_seconds,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _cache_setint(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
def cache_get_int(key: str) -> CacheGetIntResult:
"""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.
Args:
key: str parameter.
Returns:
CacheGetIntResult containing value, exists,.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"key": key,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _cache_getint(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return CacheGetIntResult(
value=response.get("value", 0),
exists=response.get("exists", False),
)
def cache_set_float(key: str, value: float, ttl_seconds: int) -> None:
"""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.
Args:
key: str parameter.
value: float parameter.
ttl_seconds: int parameter.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"key": key,
"value": value,
"ttlSeconds": ttl_seconds,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _cache_setfloat(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
def cache_get_float(key: str) -> CacheGetFloatResult:
"""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.
Args:
key: str parameter.
Returns:
CacheGetFloatResult containing value, exists,.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"key": key,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _cache_getfloat(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return CacheGetFloatResult(
value=response.get("value", 0.0),
exists=response.get("exists", False),
)
def cache_set_bytes(key: str, value: bytes, ttl_seconds: int) -> None:
"""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.
Args:
key: str parameter.
value: bytes parameter.
ttl_seconds: int parameter.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"key": key,
"value": value,
"ttlSeconds": ttl_seconds,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _cache_setbytes(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
def cache_get_bytes(key: str) -> CacheGetBytesResult:
"""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.
Args:
key: str parameter.
Returns:
CacheGetBytesResult containing value, exists,.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"key": key,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _cache_getbytes(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return CacheGetBytesResult(
value=response.get("value", b""),
exists=response.get("exists", False),
)
def cache_has(key: str) -> bool:
"""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.
Args:
key: str parameter.
Returns:
bool: The result value.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"key": key,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _cache_has(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return response.get("exists", False)
def cache_remove(key: str) -> None:
"""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.
Args:
key: str parameter.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"key": key,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _cache_remove(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])

View File

@ -0,0 +1,241 @@
# Code generated by hostgen. DO NOT EDIT.
#
# This file contains client wrappers for the KVStore host service.
# It is intended for use in Navidrome plugins built with extism-py.
#
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
# The @extism.import_fn decorators are only detected when defined in the plugin's
# main __init__.py file. Copy the needed functions from this file into your plugin.
from dataclasses import dataclass
from typing import Any
import extism
import json
class HostFunctionError(Exception):
"""Raised when a host function returns an error."""
pass
@extism.import_fn("extism:host/user", "kvstore_set")
def _kvstore_set(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "kvstore_get")
def _kvstore_get(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "kvstore_delete")
def _kvstore_delete(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "kvstore_has")
def _kvstore_has(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "kvstore_list")
def _kvstore_list(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "kvstore_getstorageused")
def _kvstore_getstorageused(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@dataclass
class KVStoreGetResult:
"""Result type for kvstore_get."""
value: bytes
exists: bool
def kvstore_set(key: str, value: bytes) -> None:
"""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.
Args:
key: str parameter.
value: bytes parameter.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"key": key,
"value": value,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _kvstore_set(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
def kvstore_get(key: str) -> KVStoreGetResult:
"""Get retrieves a byte value from storage.
Parameters:
- key: The storage key
Returns the value and whether the key exists.
Args:
key: str parameter.
Returns:
KVStoreGetResult containing value, exists,.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"key": key,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _kvstore_get(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return KVStoreGetResult(
value=response.get("value", b""),
exists=response.get("exists", False),
)
def kvstore_delete(key: str) -> None:
"""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.
Args:
key: str parameter.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"key": key,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _kvstore_delete(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
def kvstore_has(key: str) -> bool:
"""Has checks if a key exists in storage.
Parameters:
- key: The storage key
Returns true if the key exists.
Args:
key: str parameter.
Returns:
bool: The result value.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"key": key,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _kvstore_has(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return response.get("exists", False)
def kvstore_list(prefix: str) -> Any:
"""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.
Args:
prefix: str parameter.
Returns:
Any: The result value.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"prefix": prefix,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _kvstore_list(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return response.get("keys", None)
def kvstore_get_storage_used() -> int:
"""GetStorageUsed returns the total storage used by this plugin in bytes.
Returns:
int: The result value.
Raises:
HostFunctionError: If the host function returns an error.
"""
request_bytes = b"{}"
request_mem = extism.memory.alloc(request_bytes)
response_offset = _kvstore_getstorageused(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return response.get("bytes", 0)

View File

@ -0,0 +1,86 @@
# Code generated by hostgen. DO NOT EDIT.
#
# This file contains client wrappers for the Library host service.
# It is intended for use in Navidrome plugins built with extism-py.
#
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
# The @extism.import_fn decorators are only detected when defined in the plugin's
# main __init__.py file. Copy the needed functions from this file into your plugin.
from dataclasses import dataclass
from typing import Any
import extism
import json
class HostFunctionError(Exception):
"""Raised when a host function returns an error."""
pass
@extism.import_fn("extism:host/user", "library_getlibrary")
def _library_getlibrary(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "library_getalllibraries")
def _library_getalllibraries(offset: int) -> int:
"""Raw host function - do not call directly."""
...
def library_get_library(id: int) -> Any:
"""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.
Args:
id: int parameter.
Returns:
Any: The result value.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"id": id,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _library_getlibrary(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return response.get("result", None)
def library_get_all_libraries() -> Any:
"""GetAllLibraries retrieves metadata for all configured libraries.
Returns a slice of all libraries with their metadata.
Returns:
Any: The result value.
Raises:
HostFunctionError: If the host function returns an error.
"""
request_bytes = b"{}"
request_mem = extism.memory.alloc(request_bytes)
response_offset = _library_getalllibraries(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return response.get("result", None)

View File

@ -0,0 +1,143 @@
# Code generated by hostgen. DO NOT EDIT.
#
# This file contains client wrappers for the Scheduler host service.
# It is intended for use in Navidrome plugins built with extism-py.
#
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
# The @extism.import_fn decorators are only detected when defined in the plugin's
# main __init__.py file. Copy the needed functions from this file into your plugin.
from dataclasses import dataclass
from typing import Any
import extism
import json
class HostFunctionError(Exception):
"""Raised when a host function returns an error."""
pass
@extism.import_fn("extism:host/user", "scheduler_scheduleonetime")
def _scheduler_scheduleonetime(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "scheduler_schedulerecurring")
def _scheduler_schedulerecurring(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "scheduler_cancelschedule")
def _scheduler_cancelschedule(offset: int) -> int:
"""Raw host function - do not call directly."""
...
def scheduler_schedule_one_time(delay_seconds: int, payload: str, schedule_id: str) -> str:
"""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.
Args:
delay_seconds: int parameter.
payload: str parameter.
schedule_id: str parameter.
Returns:
str: The result value.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"delaySeconds": delay_seconds,
"payload": payload,
"scheduleId": schedule_id,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _scheduler_scheduleonetime(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return response.get("newScheduleId", "")
def scheduler_schedule_recurring(cron_expression: str, payload: str, schedule_id: str) -> str:
"""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.
Args:
cron_expression: str parameter.
payload: str parameter.
schedule_id: str parameter.
Returns:
str: The result value.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"cronExpression": cron_expression,
"payload": payload,
"scheduleId": schedule_id,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _scheduler_schedulerecurring(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return response.get("newScheduleId", "")
def scheduler_cancel_schedule(schedule_id: str) -> None:
"""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.
Args:
schedule_id: str parameter.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"scheduleId": schedule_id,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _scheduler_cancelschedule(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])

View File

@ -0,0 +1,55 @@
# Code generated by hostgen. DO NOT EDIT.
#
# This file contains client wrappers for the SubsonicAPI host service.
# It is intended for use in Navidrome plugins built with extism-py.
#
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
# The @extism.import_fn decorators are only detected when defined in the plugin's
# main __init__.py file. Copy the needed functions from this file into your plugin.
from dataclasses import dataclass
from typing import Any
import extism
import json
class HostFunctionError(Exception):
"""Raised when a host function returns an error."""
pass
@extism.import_fn("extism:host/user", "subsonicapi_call")
def _subsonicapi_call(offset: int) -> int:
"""Raw host function - do not call directly."""
...
def subsonicapi_call(uri: str) -> str:
"""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.
Args:
uri: str parameter.
Returns:
str: The result value.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"uri": uri,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _subsonicapi_call(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return response.get("responseJson", "")

View File

@ -0,0 +1,181 @@
# Code generated by hostgen. DO NOT EDIT.
#
# This file contains client wrappers for the WebSocket host service.
# It is intended for use in Navidrome plugins built with extism-py.
#
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
# The @extism.import_fn decorators are only detected when defined in the plugin's
# main __init__.py file. Copy the needed functions from this file into your plugin.
from dataclasses import dataclass
from typing import Any
import extism
import json
class HostFunctionError(Exception):
"""Raised when a host function returns an error."""
pass
@extism.import_fn("extism:host/user", "websocket_connect")
def _websocket_connect(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "websocket_sendtext")
def _websocket_sendtext(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "websocket_sendbinary")
def _websocket_sendbinary(offset: int) -> int:
"""Raw host function - do not call directly."""
...
@extism.import_fn("extism:host/user", "websocket_closeconnection")
def _websocket_closeconnection(offset: int) -> int:
"""Raw host function - do not call directly."""
...
def websocket_connect(url: str, headers: Any, connection_id: str) -> str:
"""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.
Args:
url: str parameter.
headers: Any parameter.
connection_id: str parameter.
Returns:
str: The result value.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"url": url,
"headers": headers,
"connectionId": connection_id,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _websocket_connect(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
return response.get("newConnectionId", "")
def websocket_send_text(connection_id: str, message: str) -> None:
"""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.
Args:
connection_id: str parameter.
message: str parameter.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"connectionId": connection_id,
"message": message,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _websocket_sendtext(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
def websocket_send_binary(connection_id: str, data: bytes) -> None:
"""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.
Args:
connection_id: str parameter.
data: bytes parameter.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"connectionId": connection_id,
"data": data,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _websocket_sendbinary(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])
def websocket_close_connection(connection_id: str, code: int, reason: str) -> None:
"""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.
Args:
connection_id: str parameter.
code: int parameter.
reason: str parameter.
Raises:
HostFunctionError: If the host function returns an error.
"""
request = {
"connectionId": connection_id,
"code": code,
"reason": reason,
}
request_bytes = json.dumps(request).encode("utf-8")
request_mem = extism.memory.alloc(request_bytes)
response_offset = _websocket_closeconnection(request_mem.offset)
response_mem = extism.memory.find(response_offset)
response = json.loads(extism.memory.string(response_mem))
if response.get("error"):
raise HostFunctionError(response["error"])

View File

@ -0,0 +1,65 @@
// Code generated by hostgen. DO NOT EDIT.
//
//! Navidrome Host Function Wrappers for Rust Plugins
//!
//! This crate provides idiomatic Rust wrappers for all Navidrome host services.
//! It is auto-generated by the hostgen tool and should not be edited manually.
//!
//! # Usage
//!
//! Add this crate as a dependency in your plugin's Cargo.toml:
//!
//! ```toml
//! [dependencies]
//! nd-host = { path = "../../host/rust" }
//! ```
//!
//! Then import the services you need:
//!
//! ```ignore
//! use nd_host::{cache, scheduler};
//!
//! fn my_plugin_function() -> Result<(), extism_pdk::Error> {
//! // Use the cache service
//! cache::set_string("my_key", "my_value", 3600)?;
//!
//! // Schedule a recurring task
//! scheduler::schedule_recurring("@every 5m", "payload", "task_id")?;
//!
//! Ok(())
//! }
//! ```
//!
//! # Available Services
//!
//! - [`artwork`] - provides artwork URL generation capabilities for plugins.
//! - [`cache`] - provides in-memory TTL-based caching capabilities for plugins.
//! - [`kvstore`] - provides persistent key-value storage for plugins.
//! - [`library`] - provides access to music library metadata for plugins.
//! - [`scheduler`] - provides task scheduling capabilities for plugins.
//! - [`subsonicapi`] - provides access to Navidrome's Subsonic API from plugins.
//! - [`websocket`] - provides WebSocket communication capabilities for plugins.
#[path = "nd_host_artwork.rs"]
pub mod artwork;
#[path = "nd_host_cache.rs"]
pub mod cache;
#[path = "nd_host_kvstore.rs"]
pub mod kvstore;
#[path = "nd_host_library.rs"]
pub mod library;
#[path = "nd_host_scheduler.rs"]
pub mod scheduler;
#[path = "nd_host_subsonicapi.rs"]
pub mod subsonicapi;
#[path = "nd_host_websocket.rs"]
pub mod websocket;
// Re-export commonly used types from extism-pdk for convenience
pub use extism_pdk::Error;

View File

@ -0,0 +1,207 @@
// Code generated by hostgen. DO NOT EDIT.
//
// This file contains client wrappers for the Artwork host service.
// It is intended for use in Navidrome plugins built with extism-pdk.
use extism_pdk::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct ArtworkGetArtistUrlRequest {
id: String,
size: i32,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ArtworkGetArtistUrlResponse {
#[serde(default)]
url: String,
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct ArtworkGetAlbumUrlRequest {
id: String,
size: i32,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ArtworkGetAlbumUrlResponse {
#[serde(default)]
url: String,
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct ArtworkGetTrackUrlRequest {
id: String,
size: i32,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ArtworkGetTrackUrlResponse {
#[serde(default)]
url: String,
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct ArtworkGetPlaylistUrlRequest {
id: String,
size: i32,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ArtworkGetPlaylistUrlResponse {
#[serde(default)]
url: String,
#[serde(default)]
error: Option<String>,
}
#[host_fn]
extern "ExtismHost" {
fn artwork_getartisturl(input: Json<ArtworkGetArtistUrlRequest>) -> Json<ArtworkGetArtistUrlResponse>;
fn artwork_getalbumurl(input: Json<ArtworkGetAlbumUrlRequest>) -> Json<ArtworkGetAlbumUrlResponse>;
fn artwork_gettrackurl(input: Json<ArtworkGetTrackUrlRequest>) -> Json<ArtworkGetTrackUrlResponse>;
fn artwork_getplaylisturl(input: Json<ArtworkGetPlaylistUrlRequest>) -> Json<ArtworkGetPlaylistUrlResponse>;
}
/// 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.
///
/// # Arguments
/// * `id` - String parameter.
/// * `size` - i32 parameter.
///
/// # Returns
/// The url value.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn get_artist_url(id: &str, size: i32) -> Result<String, Error> {
let response = unsafe {
artwork_getartisturl(Json(ArtworkGetArtistUrlRequest {
id: id.to_owned(),
size: size,
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(response.0.url)
}
/// 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.
///
/// # Arguments
/// * `id` - String parameter.
/// * `size` - i32 parameter.
///
/// # Returns
/// The url value.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn get_album_url(id: &str, size: i32) -> Result<String, Error> {
let response = unsafe {
artwork_getalbumurl(Json(ArtworkGetAlbumUrlRequest {
id: id.to_owned(),
size: size,
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(response.0.url)
}
/// 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.
///
/// # Arguments
/// * `id` - String parameter.
/// * `size` - i32 parameter.
///
/// # Returns
/// The url value.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn get_track_url(id: &str, size: i32) -> Result<String, Error> {
let response = unsafe {
artwork_gettrackurl(Json(ArtworkGetTrackUrlRequest {
id: id.to_owned(),
size: size,
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(response.0.url)
}
/// 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.
///
/// # Arguments
/// * `id` - String parameter.
/// * `size` - i32 parameter.
///
/// # Returns
/// The url value.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn get_playlist_url(id: &str, size: i32) -> Result<String, Error> {
let response = unsafe {
artwork_getplaylisturl(Json(ArtworkGetPlaylistUrlRequest {
id: id.to_owned(),
size: size,
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(response.0.url)
}

View File

@ -0,0 +1,480 @@
// Code generated by hostgen. DO NOT EDIT.
//
// This file contains client wrappers for the Cache host service.
// It is intended for use in Navidrome plugins built with extism-pdk.
use extism_pdk::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct CacheSetStringRequest {
key: String,
value: String,
ttl_seconds: i64,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct CacheSetStringResponse {
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct CacheGetStringRequest {
key: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct CacheGetStringResponse {
#[serde(default)]
value: String,
#[serde(default)]
exists: bool,
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct CacheSetIntRequest {
key: String,
value: i64,
ttl_seconds: i64,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct CacheSetIntResponse {
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct CacheGetIntRequest {
key: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct CacheGetIntResponse {
#[serde(default)]
value: i64,
#[serde(default)]
exists: bool,
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct CacheSetFloatRequest {
key: String,
value: f64,
ttl_seconds: i64,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct CacheSetFloatResponse {
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct CacheGetFloatRequest {
key: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct CacheGetFloatResponse {
#[serde(default)]
value: f64,
#[serde(default)]
exists: bool,
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct CacheSetBytesRequest {
key: String,
value: Vec<u8>,
ttl_seconds: i64,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct CacheSetBytesResponse {
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct CacheGetBytesRequest {
key: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct CacheGetBytesResponse {
#[serde(default)]
value: Vec<u8>,
#[serde(default)]
exists: bool,
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct CacheHasRequest {
key: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct CacheHasResponse {
#[serde(default)]
exists: bool,
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct CacheRemoveRequest {
key: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct CacheRemoveResponse {
#[serde(default)]
error: Option<String>,
}
#[host_fn]
extern "ExtismHost" {
fn cache_setstring(input: Json<CacheSetStringRequest>) -> Json<CacheSetStringResponse>;
fn cache_getstring(input: Json<CacheGetStringRequest>) -> Json<CacheGetStringResponse>;
fn cache_setint(input: Json<CacheSetIntRequest>) -> Json<CacheSetIntResponse>;
fn cache_getint(input: Json<CacheGetIntRequest>) -> Json<CacheGetIntResponse>;
fn cache_setfloat(input: Json<CacheSetFloatRequest>) -> Json<CacheSetFloatResponse>;
fn cache_getfloat(input: Json<CacheGetFloatRequest>) -> Json<CacheGetFloatResponse>;
fn cache_setbytes(input: Json<CacheSetBytesRequest>) -> Json<CacheSetBytesResponse>;
fn cache_getbytes(input: Json<CacheGetBytesRequest>) -> Json<CacheGetBytesResponse>;
fn cache_has(input: Json<CacheHasRequest>) -> Json<CacheHasResponse>;
fn cache_remove(input: Json<CacheRemoveRequest>) -> Json<CacheRemoveResponse>;
}
/// 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.
///
/// # Arguments
/// * `key` - String parameter.
/// * `value` - String parameter.
/// * `ttl_seconds` - i64 parameter.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn set_string(key: &str, value: &str, ttl_seconds: i64) -> Result<(), Error> {
let response = unsafe {
cache_setstring(Json(CacheSetStringRequest {
key: key.to_owned(),
value: value.to_owned(),
ttl_seconds: ttl_seconds,
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(())
}
/// 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.
///
/// # Arguments
/// * `key` - String parameter.
///
/// # Returns
/// A tuple of (value, exists).
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn get_string(key: &str) -> Result<(String, bool), Error> {
let response = unsafe {
cache_getstring(Json(CacheGetStringRequest {
key: key.to_owned(),
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok((response.0.value, response.0.exists))
}
/// 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.
///
/// # Arguments
/// * `key` - String parameter.
/// * `value` - i64 parameter.
/// * `ttl_seconds` - i64 parameter.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn set_int(key: &str, value: i64, ttl_seconds: i64) -> Result<(), Error> {
let response = unsafe {
cache_setint(Json(CacheSetIntRequest {
key: key.to_owned(),
value: value,
ttl_seconds: ttl_seconds,
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(())
}
/// 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.
///
/// # Arguments
/// * `key` - String parameter.
///
/// # Returns
/// A tuple of (value, exists).
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn get_int(key: &str) -> Result<(i64, bool), Error> {
let response = unsafe {
cache_getint(Json(CacheGetIntRequest {
key: key.to_owned(),
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok((response.0.value, response.0.exists))
}
/// 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.
///
/// # Arguments
/// * `key` - String parameter.
/// * `value` - f64 parameter.
/// * `ttl_seconds` - i64 parameter.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn set_float(key: &str, value: f64, ttl_seconds: i64) -> Result<(), Error> {
let response = unsafe {
cache_setfloat(Json(CacheSetFloatRequest {
key: key.to_owned(),
value: value,
ttl_seconds: ttl_seconds,
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(())
}
/// 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.
///
/// # Arguments
/// * `key` - String parameter.
///
/// # Returns
/// A tuple of (value, exists).
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn get_float(key: &str) -> Result<(f64, bool), Error> {
let response = unsafe {
cache_getfloat(Json(CacheGetFloatRequest {
key: key.to_owned(),
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok((response.0.value, response.0.exists))
}
/// 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.
///
/// # Arguments
/// * `key` - String parameter.
/// * `value` - Vec<u8> parameter.
/// * `ttl_seconds` - i64 parameter.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn set_bytes(key: &str, value: Vec<u8>, ttl_seconds: i64) -> Result<(), Error> {
let response = unsafe {
cache_setbytes(Json(CacheSetBytesRequest {
key: key.to_owned(),
value: value,
ttl_seconds: ttl_seconds,
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(())
}
/// 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.
///
/// # Arguments
/// * `key` - String parameter.
///
/// # Returns
/// A tuple of (value, exists).
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn get_bytes(key: &str) -> Result<(Vec<u8>, bool), Error> {
let response = unsafe {
cache_getbytes(Json(CacheGetBytesRequest {
key: key.to_owned(),
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok((response.0.value, response.0.exists))
}
/// 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.
///
/// # Arguments
/// * `key` - String parameter.
///
/// # Returns
/// The exists value.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn has(key: &str) -> Result<bool, Error> {
let response = unsafe {
cache_has(Json(CacheHasRequest {
key: key.to_owned(),
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(response.0.exists)
}
/// 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.
///
/// # Arguments
/// * `key` - String parameter.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn remove(key: &str) -> Result<(), Error> {
let response = unsafe {
cache_remove(Json(CacheRemoveRequest {
key: key.to_owned(),
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(())
}

View File

@ -0,0 +1,261 @@
// Code generated by hostgen. DO NOT EDIT.
//
// This file contains client wrappers for the KVStore host service.
// It is intended for use in Navidrome plugins built with extism-pdk.
use extism_pdk::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct KVStoreSetRequest {
key: String,
value: Vec<u8>,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct KVStoreSetResponse {
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct KVStoreGetRequest {
key: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct KVStoreGetResponse {
#[serde(default)]
value: Vec<u8>,
#[serde(default)]
exists: bool,
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct KVStoreDeleteRequest {
key: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct KVStoreDeleteResponse {
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct KVStoreHasRequest {
key: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct KVStoreHasResponse {
#[serde(default)]
exists: bool,
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct KVStoreListRequest {
prefix: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct KVStoreListResponse {
#[serde(default)]
keys: Vec<String>,
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct KVStoreGetStorageUsedResponse {
#[serde(default)]
bytes: i64,
#[serde(default)]
error: Option<String>,
}
#[host_fn]
extern "ExtismHost" {
fn kvstore_set(input: Json<KVStoreSetRequest>) -> Json<KVStoreSetResponse>;
fn kvstore_get(input: Json<KVStoreGetRequest>) -> Json<KVStoreGetResponse>;
fn kvstore_delete(input: Json<KVStoreDeleteRequest>) -> Json<KVStoreDeleteResponse>;
fn kvstore_has(input: Json<KVStoreHasRequest>) -> Json<KVStoreHasResponse>;
fn kvstore_list(input: Json<KVStoreListRequest>) -> Json<KVStoreListResponse>;
fn kvstore_getstorageused(input: Json<serde_json::Value>) -> Json<KVStoreGetStorageUsedResponse>;
}
/// 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.
///
/// # Arguments
/// * `key` - String parameter.
/// * `value` - Vec<u8> parameter.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn set(key: &str, value: Vec<u8>) -> Result<(), Error> {
let response = unsafe {
kvstore_set(Json(KVStoreSetRequest {
key: key.to_owned(),
value: value,
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(())
}
/// Get retrieves a byte value from storage.
///
/// Parameters:
/// - key: The storage key
///
/// Returns the value and whether the key exists.
///
/// # Arguments
/// * `key` - String parameter.
///
/// # Returns
/// A tuple of (value, exists).
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn get(key: &str) -> Result<(Vec<u8>, bool), Error> {
let response = unsafe {
kvstore_get(Json(KVStoreGetRequest {
key: key.to_owned(),
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok((response.0.value, response.0.exists))
}
/// 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.
///
/// # Arguments
/// * `key` - String parameter.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn delete(key: &str) -> Result<(), Error> {
let response = unsafe {
kvstore_delete(Json(KVStoreDeleteRequest {
key: key.to_owned(),
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(())
}
/// Has checks if a key exists in storage.
///
/// Parameters:
/// - key: The storage key
///
/// Returns true if the key exists.
///
/// # Arguments
/// * `key` - String parameter.
///
/// # Returns
/// The exists value.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn has(key: &str) -> Result<bool, Error> {
let response = unsafe {
kvstore_has(Json(KVStoreHasRequest {
key: key.to_owned(),
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(response.0.exists)
}
/// 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.
///
/// # Arguments
/// * `prefix` - String parameter.
///
/// # Returns
/// The keys value.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn list(prefix: &str) -> Result<Vec<String>, Error> {
let response = unsafe {
kvstore_list(Json(KVStoreListRequest {
prefix: prefix.to_owned(),
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(response.0.keys)
}
/// GetStorageUsed returns the total storage used by this plugin in bytes.
///
/// # Returns
/// The bytes value.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn get_storage_used() -> Result<i64, Error> {
let response = unsafe {
kvstore_getstorageused(Json(serde_json::json!({})))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(response.0.bytes)
}

View File

@ -0,0 +1,105 @@
// Code generated by hostgen. DO NOT EDIT.
//
// This file contains client wrappers for the Library host service.
// It is intended for use in Navidrome plugins built with extism-pdk.
use extism_pdk::*;
use serde::{Deserialize, Serialize};
/// Library represents a music library with metadata.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Library {
pub id: i32,
pub name: String,
#[serde(default)]
pub path: String,
#[serde(default)]
pub mount_point: String,
pub last_scan_at: i64,
pub total_songs: i32,
pub total_albums: i32,
pub total_artists: i32,
pub total_size: i64,
pub total_duration: f64,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct LibraryGetLibraryRequest {
id: i32,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct LibraryGetLibraryResponse {
#[serde(default)]
result: Option<Library>,
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct LibraryGetAllLibrariesResponse {
#[serde(default)]
result: Vec<Library>,
#[serde(default)]
error: Option<String>,
}
#[host_fn]
extern "ExtismHost" {
fn library_getlibrary(input: Json<LibraryGetLibraryRequest>) -> Json<LibraryGetLibraryResponse>;
fn library_getalllibraries(input: Json<serde_json::Value>) -> Json<LibraryGetAllLibrariesResponse>;
}
/// 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.
///
/// # Arguments
/// * `id` - i32 parameter.
///
/// # Returns
/// The result value.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn get_library(id: i32) -> Result<Option<Library>, Error> {
let response = unsafe {
library_getlibrary(Json(LibraryGetLibraryRequest {
id: id,
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(response.0.result)
}
/// GetAllLibraries retrieves metadata for all configured libraries.
///
/// Returns a slice of all libraries with their metadata.
///
/// # Returns
/// The result value.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn get_all_libraries() -> Result<Vec<Library>, Error> {
let response = unsafe {
library_getalllibraries(Json(serde_json::json!({})))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(response.0.result)
}

View File

@ -0,0 +1,159 @@
// Code generated by hostgen. DO NOT EDIT.
//
// This file contains client wrappers for the Scheduler host service.
// It is intended for use in Navidrome plugins built with extism-pdk.
use extism_pdk::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct SchedulerScheduleOneTimeRequest {
delay_seconds: i32,
payload: String,
schedule_id: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct SchedulerScheduleOneTimeResponse {
#[serde(default)]
new_schedule_id: String,
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct SchedulerScheduleRecurringRequest {
cron_expression: String,
payload: String,
schedule_id: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct SchedulerScheduleRecurringResponse {
#[serde(default)]
new_schedule_id: String,
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct SchedulerCancelScheduleRequest {
schedule_id: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct SchedulerCancelScheduleResponse {
#[serde(default)]
error: Option<String>,
}
#[host_fn]
extern "ExtismHost" {
fn scheduler_scheduleonetime(input: Json<SchedulerScheduleOneTimeRequest>) -> Json<SchedulerScheduleOneTimeResponse>;
fn scheduler_schedulerecurring(input: Json<SchedulerScheduleRecurringRequest>) -> Json<SchedulerScheduleRecurringResponse>;
fn scheduler_cancelschedule(input: Json<SchedulerCancelScheduleRequest>) -> Json<SchedulerCancelScheduleResponse>;
}
/// 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.
///
/// # Arguments
/// * `delay_seconds` - i32 parameter.
/// * `payload` - String parameter.
/// * `schedule_id` - String parameter.
///
/// # Returns
/// The new_schedule_id value.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn schedule_one_time(delay_seconds: i32, payload: &str, schedule_id: &str) -> Result<String, Error> {
let response = unsafe {
scheduler_scheduleonetime(Json(SchedulerScheduleOneTimeRequest {
delay_seconds: delay_seconds,
payload: payload.to_owned(),
schedule_id: schedule_id.to_owned(),
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(response.0.new_schedule_id)
}
/// 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.
///
/// # Arguments
/// * `cron_expression` - String parameter.
/// * `payload` - String parameter.
/// * `schedule_id` - String parameter.
///
/// # Returns
/// The new_schedule_id value.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn schedule_recurring(cron_expression: &str, payload: &str, schedule_id: &str) -> Result<String, Error> {
let response = unsafe {
scheduler_schedulerecurring(Json(SchedulerScheduleRecurringRequest {
cron_expression: cron_expression.to_owned(),
payload: payload.to_owned(),
schedule_id: schedule_id.to_owned(),
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(response.0.new_schedule_id)
}
/// 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.
///
/// # Arguments
/// * `schedule_id` - String parameter.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn cancel_schedule(schedule_id: &str) -> Result<(), Error> {
let response = unsafe {
scheduler_cancelschedule(Json(SchedulerCancelScheduleRequest {
schedule_id: schedule_id.to_owned(),
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(())
}

View File

@ -0,0 +1,54 @@
// Code generated by hostgen. DO NOT EDIT.
//
// This file contains client wrappers for the SubsonicAPI host service.
// It is intended for use in Navidrome plugins built with extism-pdk.
use extism_pdk::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct SubsonicAPICallRequest {
uri: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct SubsonicAPICallResponse {
#[serde(default)]
response_json: String,
#[serde(default)]
error: Option<String>,
}
#[host_fn]
extern "ExtismHost" {
fn subsonicapi_call(input: Json<SubsonicAPICallRequest>) -> Json<SubsonicAPICallResponse>;
}
/// 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.
///
/// # Arguments
/// * `uri` - String parameter.
///
/// # Returns
/// The response_json value.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn call(uri: &str) -> Result<String, Error> {
let response = unsafe {
subsonicapi_call(Json(SubsonicAPICallRequest {
uri: uri.to_owned(),
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(response.0.response_json)
}

View File

@ -0,0 +1,204 @@
// Code generated by hostgen. DO NOT EDIT.
//
// This file contains client wrappers for the WebSocket host service.
// It is intended for use in Navidrome plugins built with extism-pdk.
use extism_pdk::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct WebSocketConnectRequest {
url: String,
headers: std::collections::HashMap<String, String>,
connection_id: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct WebSocketConnectResponse {
#[serde(default)]
new_connection_id: String,
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct WebSocketSendTextRequest {
connection_id: String,
message: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct WebSocketSendTextResponse {
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct WebSocketSendBinaryRequest {
connection_id: String,
data: Vec<u8>,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct WebSocketSendBinaryResponse {
#[serde(default)]
error: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct WebSocketCloseConnectionRequest {
connection_id: String,
code: i32,
reason: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
struct WebSocketCloseConnectionResponse {
#[serde(default)]
error: Option<String>,
}
#[host_fn]
extern "ExtismHost" {
fn websocket_connect(input: Json<WebSocketConnectRequest>) -> Json<WebSocketConnectResponse>;
fn websocket_sendtext(input: Json<WebSocketSendTextRequest>) -> Json<WebSocketSendTextResponse>;
fn websocket_sendbinary(input: Json<WebSocketSendBinaryRequest>) -> Json<WebSocketSendBinaryResponse>;
fn websocket_closeconnection(input: Json<WebSocketCloseConnectionRequest>) -> Json<WebSocketCloseConnectionResponse>;
}
/// 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.
///
/// # Arguments
/// * `url` - String parameter.
/// * `headers` - std::collections::HashMap<String, String> parameter.
/// * `connection_id` - String parameter.
///
/// # Returns
/// The new_connection_id value.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn connect(url: &str, headers: std::collections::HashMap<String, String>, connection_id: &str) -> Result<String, Error> {
let response = unsafe {
websocket_connect(Json(WebSocketConnectRequest {
url: url.to_owned(),
headers: headers,
connection_id: connection_id.to_owned(),
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(response.0.new_connection_id)
}
/// 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.
///
/// # Arguments
/// * `connection_id` - String parameter.
/// * `message` - String parameter.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn send_text(connection_id: &str, message: &str) -> Result<(), Error> {
let response = unsafe {
websocket_sendtext(Json(WebSocketSendTextRequest {
connection_id: connection_id.to_owned(),
message: message.to_owned(),
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(())
}
/// 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.
///
/// # Arguments
/// * `connection_id` - String parameter.
/// * `data` - Vec<u8> parameter.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn send_binary(connection_id: &str, data: Vec<u8>) -> Result<(), Error> {
let response = unsafe {
websocket_sendbinary(Json(WebSocketSendBinaryRequest {
connection_id: connection_id.to_owned(),
data: data,
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(())
}
/// 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.
///
/// # Arguments
/// * `connection_id` - String parameter.
/// * `code` - i32 parameter.
/// * `reason` - String parameter.
///
/// # Errors
/// Returns an error if the host function call fails.
pub fn close_connection(connection_id: &str, code: i32, reason: &str) -> Result<(), Error> {
let response = unsafe {
websocket_closeconnection(Json(WebSocketCloseConnectionRequest {
connection_id: connection_id.to_owned(),
code: code,
reason: reason.to_owned(),
}))?
};
if let Some(err) = response.0.error {
return Err(Error::msg(err));
}
Ok(())
}