mirror of
https://github.com/navidrome/navidrome.git
synced 2026-05-03 06:51:16 +00:00
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:
parent
ebba3a2c46
commit
6fa9ef0dfe
@ -79,7 +79,8 @@ type TestService interface {
|
|||||||
|
|
||||||
outputStr := string(output)
|
outputStr := string(output)
|
||||||
Expect(outputStr).To(ContainSubstring("Input directory:"))
|
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("Found 1 host service(s)"))
|
||||||
Expect(outputStr).To(ContainSubstring("Generated"))
|
Expect(outputStr).To(ContainSubstring("Generated"))
|
||||||
})
|
})
|
||||||
@ -93,7 +94,7 @@ type TestService interface {
|
|||||||
Expect(filepath.Join(outputDir, "nd_host_test.go")).ToNot(BeAnExistingFile())
|
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")
|
customOutput, err := os.MkdirTemp("", "mypkg")
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
defer os.RemoveAll(customOutput)
|
defer os.RemoveAll(customOutput)
|
||||||
@ -102,9 +103,10 @@ type TestService interface {
|
|||||||
_, err = cmd.CombinedOutput()
|
_, err = cmd.CombinedOutput()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
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(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() {
|
It("returns error for invalid input directory", func() {
|
||||||
@ -151,8 +153,10 @@ type ServiceB interface {
|
|||||||
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
|
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
|
||||||
Expect(string(output)).To(ContainSubstring("Found 2 host service(s)"))
|
Expect(string(output)).To(ContainSubstring("Found 2 host service(s)"))
|
||||||
|
|
||||||
Expect(filepath.Join(outputDir, "nd_host_servicea.go")).To(BeAnExistingFile())
|
// Go code goes to $output/go/host/
|
||||||
Expect(filepath.Join(outputDir, "nd_host_serviceb.go")).To(BeAnExistingFile())
|
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() {
|
It("generates Go client code by default", func() {
|
||||||
@ -160,13 +164,14 @@ type ServiceB interface {
|
|||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
|
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
|
||||||
|
|
||||||
// Client code in output directory
|
// Go client code goes to $output/go/host/
|
||||||
Expect(filepath.Join(outputDir, "nd_host_test.go")).To(BeAnExistingFile())
|
goHostDir := filepath.Join(outputDir, "go", "host")
|
||||||
|
Expect(filepath.Join(goHostDir, "nd_host_test.go")).To(BeAnExistingFile())
|
||||||
// Stub file also generated
|
// 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
|
// doc.go and go.mod also generated
|
||||||
Expect(filepath.Join(outputDir, "doc.go")).To(BeAnExistingFile())
|
Expect(filepath.Join(goHostDir, "doc.go")).To(BeAnExistingFile())
|
||||||
Expect(filepath.Join(outputDir, "go.mod")).To(BeAnExistingFile())
|
Expect(filepath.Join(goHostDir, "go.mod")).To(BeAnExistingFile())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -185,13 +190,14 @@ type ServiceB interface {
|
|||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
|
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
|
||||||
|
|
||||||
// Verify Go client code
|
// Verify Go client code (now in $output/go/host/)
|
||||||
entries, err := os.ReadDir(outputDir)
|
goHostDir := filepath.Join(outputDir, "go", "host")
|
||||||
|
entries, err := os.ReadDir(goHostDir)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
var goClientFiles []string
|
var goClientFiles []string
|
||||||
for _, e := range entries {
|
for _, e := range entries {
|
||||||
if e.Name() != "python" && e.Name() != "rust" && !e.IsDir() &&
|
if !e.IsDir() &&
|
||||||
!strings.HasSuffix(e.Name(), "_stub.go") &&
|
!strings.HasSuffix(e.Name(), "_stub.go") &&
|
||||||
e.Name() != "doc.go" && e.Name() != "go.mod" {
|
e.Name() != "doc.go" && e.Name() != "go.mod" {
|
||||||
goClientFiles = append(goClientFiles, e.Name())
|
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)
|
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())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
formattedGoClientActual, err := format.Source(goClientActual)
|
formattedGoClientActual, err := format.Source(goClientActual)
|
||||||
@ -212,20 +218,20 @@ type ServiceB interface {
|
|||||||
|
|
||||||
Expect(string(formattedGoClientActual)).To(Equal(string(formattedGoClientExpected)), "Go client code mismatch")
|
Expect(string(formattedGoClientActual)).To(Equal(string(formattedGoClientExpected)), "Go client code mismatch")
|
||||||
|
|
||||||
// Verify Python client code
|
// Verify Python client code (now in $output/python/host/)
|
||||||
pythonDir := filepath.Join(outputDir, "python")
|
pythonHostDir := filepath.Join(outputDir, "python", "host")
|
||||||
pyClientEntries, err := os.ReadDir(pythonDir)
|
pyClientEntries, err := os.ReadDir(pythonHostDir)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(pyClientEntries).To(HaveLen(1), "Expected exactly one Python client file")
|
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(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
Expect(string(pyClientActual)).To(Equal(pyClientExpected), "Python client code mismatch")
|
Expect(string(pyClientActual)).To(Equal(pyClientExpected), "Python client code mismatch")
|
||||||
|
|
||||||
// Verify Rust client code
|
// Verify Rust client code (now in $output/rust/host/)
|
||||||
rustDir := filepath.Join(outputDir, "rust")
|
rustHostDir := filepath.Join(outputDir, "rust", "host")
|
||||||
rsClientEntries, err := os.ReadDir(rustDir)
|
rsClientEntries, err := os.ReadDir(rustHostDir)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(rsClientEntries).To(HaveLen(2), "Expected Rust client file and lib.rs")
|
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")
|
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(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
Expect(string(rsClientActual)).To(Equal(rsClientExpected), "Rust client code mismatch")
|
Expect(string(rsClientActual)).To(Equal(rsClientExpected), "Rust client code mismatch")
|
||||||
@ -286,8 +292,11 @@ type ServiceB interface {
|
|||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
Expect(err).ToNot(HaveOccurred(), "Generation failed: %s", output)
|
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
|
// Read generated client code
|
||||||
entries, err := os.ReadDir(outputDir)
|
entries, err := os.ReadDir(goHostDir)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
// Find the client file
|
// Find the client file
|
||||||
@ -301,7 +310,7 @@ type ServiceB interface {
|
|||||||
}
|
}
|
||||||
Expect(clientFileName).ToNot(BeEmpty(), "Expected to find Go client file")
|
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())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
// Verify key expected content
|
// Verify key expected content
|
||||||
@ -334,7 +343,7 @@ go 1.24
|
|||||||
require github.com/navidrome/navidrome/plugins/pdk/go/host v0.0.0
|
require github.com/navidrome/navidrome/plugins/pdk/go/host v0.0.0
|
||||||
|
|
||||||
replace github.com/navidrome/navidrome/plugins/pdk/go/host => %s
|
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())
|
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
|
// 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
|
// Tidy dependencies for the generated go library
|
||||||
goTidyLibCmd := exec.Command("go", "mod", "tidy")
|
goTidyLibCmd := exec.Command("go", "mod", "tidy")
|
||||||
goTidyLibCmd.Dir = outputDir
|
goTidyLibCmd.Dir = goHostDir
|
||||||
goTidyLibOutput, err := goTidyLibCmd.CombinedOutput()
|
goTidyLibOutput, err := goTidyLibCmd.CombinedOutput()
|
||||||
Expect(err).ToNot(HaveOccurred(), "go mod tidy (library) failed: %s", goTidyLibOutput)
|
Expect(err).ToNot(HaveOccurred(), "go mod tidy (library) failed: %s", goTidyLibOutput)
|
||||||
|
|
||||||
@ -389,11 +398,11 @@ type TestService interface {
|
|||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
|
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
|
||||||
|
|
||||||
// Verify Python client code exists
|
// Verify Python client code exists in $output/python/host/
|
||||||
pythonDir := filepath.Join(outputDir, "python")
|
pythonHostDir := filepath.Join(outputDir, "python", "host")
|
||||||
Expect(pythonDir).To(BeADirectory())
|
Expect(pythonHostDir).To(BeADirectory())
|
||||||
|
|
||||||
pythonFile := filepath.Join(pythonDir, "nd_host_test.py")
|
pythonFile := filepath.Join(pythonHostDir, "nd_host_test.py")
|
||||||
Expect(pythonFile).To(BeAnExistingFile())
|
Expect(pythonFile).To(BeAnExistingFile())
|
||||||
|
|
||||||
content, err := os.ReadFile(pythonFile)
|
content, err := os.ReadFile(pythonFile)
|
||||||
@ -423,12 +432,14 @@ type TestService interface {
|
|||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
|
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
|
||||||
|
|
||||||
// Verify both Go and Python client code exist
|
// Verify Go client code exists in $output/go/host/
|
||||||
Expect(filepath.Join(outputDir, "nd_host_test.go")).To(BeAnExistingFile())
|
goHostDir := filepath.Join(outputDir, "go", "host")
|
||||||
|
Expect(filepath.Join(goHostDir, "nd_host_test.go")).To(BeAnExistingFile())
|
||||||
|
|
||||||
pythonDir := filepath.Join(outputDir, "python")
|
// Verify Python client code exists in $output/python/host/
|
||||||
Expect(pythonDir).To(BeADirectory())
|
pythonHostDir := filepath.Join(outputDir, "python", "host")
|
||||||
Expect(filepath.Join(pythonDir, "nd_host_test.py")).To(BeAnExistingFile())
|
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() {
|
It("generates Python code with dataclass for multi-value returns", func() {
|
||||||
@ -448,7 +459,7 @@ type CacheService interface {
|
|||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
|
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())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
contentStr := string(content)
|
contentStr := string(content)
|
||||||
@ -476,7 +487,7 @@ type TestService interface {
|
|||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
Expect(err).ToNot(HaveOccurred(), "Command failed: %s", output)
|
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())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
contentStr := string(content)
|
contentStr := string(content)
|
||||||
|
|||||||
@ -5,13 +5,18 @@
|
|||||||
//
|
//
|
||||||
// Usage:
|
// 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:
|
// Flags:
|
||||||
//
|
//
|
||||||
// -input Input directory containing Go source files with annotated interfaces
|
// -input Input directory containing Go source files with annotated interfaces
|
||||||
// -output Output directory for generated files (default: same as input)
|
// -output Output directory base for generated files (default: same as input)
|
||||||
// -package Output package name (default: inferred from output directory)
|
// -package Output package name for Go (default: host)
|
||||||
// -host-only Generate only host function wrappers (default: true, capability support TBD)
|
// -host-only Generate only host function wrappers (default: true, capability support TBD)
|
||||||
// -go Generate Go client wrappers (default: true when not using -python/-rust)
|
// -go Generate Go client wrappers (default: true when not using -python/-rust)
|
||||||
// -python Generate Python client wrappers (default: false)
|
// -python Generate Python client wrappers (default: false)
|
||||||
@ -34,7 +39,10 @@ import (
|
|||||||
// config holds the parsed command-line configuration.
|
// config holds the parsed command-line configuration.
|
||||||
type config struct {
|
type config struct {
|
||||||
inputDir string
|
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
|
pkgName string
|
||||||
hostOnly bool
|
hostOnly bool
|
||||||
generateGoClient bool
|
generateGoClient bool
|
||||||
@ -70,8 +78,8 @@ func main() {
|
|||||||
func parseConfig() (*config, error) {
|
func parseConfig() (*config, error) {
|
||||||
var (
|
var (
|
||||||
inputDir = flag.String("input", ".", "Input directory containing Go source files")
|
inputDir = flag.String("input", ".", "Input directory containing Go source files")
|
||||||
outputDir = flag.String("output", "", "Output directory for generated files (default: same as input)")
|
outputDir = flag.String("output", "", "Base output directory for generated files (default: same as input)")
|
||||||
pkgName = flag.String("package", "", "Output package name (default: inferred from output directory)")
|
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)")
|
hostOnly = flag.Bool("host-only", true, "Generate only host function wrappers (capability support TBD)")
|
||||||
goClient = flag.Bool("go", false, "Generate Go client wrappers")
|
goClient = flag.Bool("go", false, "Generate Go client wrappers")
|
||||||
pyClient = flag.Bool("python", false, "Generate Python 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)
|
return nil, fmt.Errorf("resolving output path: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if *pkgName == "" {
|
// Set output directories for each language: $output/$lang/host/
|
||||||
*pkgName = filepath.Base(absOutput)
|
absGoOutput := filepath.Join(absOutput, "go", "host")
|
||||||
}
|
absPythonOutput := filepath.Join(absOutput, "python", "host")
|
||||||
|
absRustOutput := filepath.Join(absOutput, "rust", "host")
|
||||||
|
|
||||||
// Determine what to generate
|
// Determine what to generate
|
||||||
// Default: generate Go clients if no language flag is specified
|
// Default: generate Go clients if no language flag is specified
|
||||||
@ -105,6 +114,9 @@ func parseConfig() (*config, error) {
|
|||||||
return &config{
|
return &config{
|
||||||
inputDir: absInput,
|
inputDir: absInput,
|
||||||
outputDir: absOutput,
|
outputDir: absOutput,
|
||||||
|
goOutputDir: absGoOutput,
|
||||||
|
pythonOutputDir: absPythonOutput,
|
||||||
|
rustOutputDir: absRustOutput,
|
||||||
pkgName: *pkgName,
|
pkgName: *pkgName,
|
||||||
hostOnly: *hostOnly,
|
hostOnly: *hostOnly,
|
||||||
generateGoClient: *goClient || !anyLangFlag,
|
generateGoClient: *goClient || !anyLangFlag,
|
||||||
@ -119,7 +131,16 @@ func parseConfig() (*config, error) {
|
|||||||
func parseServices(cfg *config) ([]internal.Service, error) {
|
func parseServices(cfg *config) ([]internal.Service, error) {
|
||||||
if cfg.verbose {
|
if cfg.verbose {
|
||||||
fmt.Printf("Input directory: %s\n", cfg.inputDir)
|
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("Package name: %s\n", cfg.pkgName)
|
||||||
fmt.Printf("Host-only mode: %v\n", cfg.hostOnly)
|
fmt.Printf("Host-only mode: %v\n", cfg.hostOnly)
|
||||||
fmt.Printf("Generate Go client code: %v\n", cfg.generateGoClient)
|
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 {
|
func generateAllCode(cfg *config, services []internal.Service) error {
|
||||||
for _, svc := range services {
|
for _, svc := range services {
|
||||||
if cfg.generateGoClient {
|
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)
|
return fmt.Errorf("generating Go client code for %s: %w", svc.Name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if cfg.generatePyClient {
|
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)
|
return fmt.Errorf("generating Python client code for %s: %w", svc.Name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if cfg.generateRsClient {
|
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)
|
return fmt.Errorf("generating Rust client code for %s: %w", svc.Name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.generateRsClient && len(services) > 0 {
|
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)
|
return fmt.Errorf("generating Rust lib.rs: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.generateGoClient && len(services) > 0 {
|
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)
|
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)
|
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)
|
return fmt.Errorf("generating code: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Python code goes in python/ subdirectory
|
// Python code goes directly in the output directory
|
||||||
clientDir := filepath.Join(outputDir, "python")
|
clientFile := filepath.Join(outputDir, "nd_host_"+strings.ToLower(svc.Name)+".py")
|
||||||
clientFile := filepath.Join(clientDir, "nd_host_"+strings.ToLower(svc.Name)+".py")
|
|
||||||
|
|
||||||
if dryRun {
|
if dryRun {
|
||||||
fmt.Printf("=== %s ===\n%s\n", clientFile, code)
|
fmt.Printf("=== %s ===\n%s\n", clientFile, code)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create python/ subdirectory if needed
|
// Create output directory if needed
|
||||||
if err := os.MkdirAll(clientDir, 0755); err != nil {
|
if err := os.MkdirAll(outputDir, 0755); err != nil {
|
||||||
return fmt.Errorf("creating python client directory: %w", err)
|
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)
|
return fmt.Errorf("generating code: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rust code goes in rust/ subdirectory
|
// Rust code goes directly in the output directory
|
||||||
clientDir := filepath.Join(outputDir, "rust")
|
clientFile := filepath.Join(outputDir, "nd_host_"+strings.ToLower(svc.Name)+".rs")
|
||||||
clientFile := filepath.Join(clientDir, "nd_host_"+strings.ToLower(svc.Name)+".rs")
|
|
||||||
|
|
||||||
if dryRun {
|
if dryRun {
|
||||||
fmt.Printf("=== %s ===\n%s\n", clientFile, code)
|
fmt.Printf("=== %s ===\n%s\n", clientFile, code)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create rust/ subdirectory if needed
|
// Create output directory if needed
|
||||||
if err := os.MkdirAll(clientDir, 0755); err != nil {
|
if err := os.MkdirAll(outputDir, 0755); err != nil {
|
||||||
return fmt.Errorf("creating rust client directory: %w", err)
|
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)
|
return fmt.Errorf("generating lib.rs: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
clientDir := filepath.Join(outputDir, "rust")
|
// lib.rs goes directly in the output directory
|
||||||
libFile := filepath.Join(clientDir, "lib.rs")
|
libFile := filepath.Join(outputDir, "lib.rs")
|
||||||
|
|
||||||
if dryRun {
|
if dryRun {
|
||||||
fmt.Printf("=== %s ===\n%s\n", libFile, code)
|
fmt.Printf("=== %s ===\n%s\n", libFile, code)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create rust/ subdirectory if needed
|
// Create output directory if needed
|
||||||
if err := os.MkdirAll(clientDir, 0755); err != nil {
|
if err := os.MkdirAll(outputDir, 0755); err != nil {
|
||||||
return fmt.Errorf("creating rust client directory: %w", err)
|
return fmt.Errorf("creating rust client directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
54
plugins/pdk/go/host/doc.go
Normal file
54
plugins/pdk/go/host/doc.go
Normal 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
|
||||||
5
plugins/pdk/go/host/go.mod
Normal file
5
plugins/pdk/go/host/go.mod
Normal 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
|
||||||
251
plugins/pdk/go/host/nd_host_artwork.go
Normal file
251
plugins/pdk/go/host/nd_host_artwork.go
Normal 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
|
||||||
|
}
|
||||||
105
plugins/pdk/go/host/nd_host_artwork_stub.go
Normal file
105
plugins/pdk/go/host/nd_host_artwork_stub.go
Normal 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")
|
||||||
|
}
|
||||||
602
plugins/pdk/go/host/nd_host_cache.go
Normal file
602
plugins/pdk/go/host/nd_host_cache.go
Normal 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
|
||||||
|
}
|
||||||
248
plugins/pdk/go/host/nd_host_cache_stub.go
Normal file
248
plugins/pdk/go/host/nd_host_cache_stub.go
Normal 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")
|
||||||
|
}
|
||||||
336
plugins/pdk/go/host/nd_host_kvstore.go
Normal file
336
plugins/pdk/go/host/nd_host_kvstore.go
Normal 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
|
||||||
|
}
|
||||||
132
plugins/pdk/go/host/nd_host_kvstore_stub.go
Normal file
132
plugins/pdk/go/host/nd_host_kvstore_stub.go
Normal 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")
|
||||||
|
}
|
||||||
127
plugins/pdk/go/host/nd_host_library.go
Normal file
127
plugins/pdk/go/host/nd_host_library.go
Normal 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
|
||||||
|
}
|
||||||
60
plugins/pdk/go/host/nd_host_library_stub.go
Normal file
60
plugins/pdk/go/host/nd_host_library_stub.go
Normal 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")
|
||||||
|
}
|
||||||
196
plugins/pdk/go/host/nd_host_scheduler.go
Normal file
196
plugins/pdk/go/host/nd_host_scheduler.go
Normal 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
|
||||||
|
}
|
||||||
84
plugins/pdk/go/host/nd_host_scheduler_stub.go
Normal file
84
plugins/pdk/go/host/nd_host_scheduler_stub.go
Normal 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")
|
||||||
|
}
|
||||||
69
plugins/pdk/go/host/nd_host_subsonicapi.go
Normal file
69
plugins/pdk/go/host/nd_host_subsonicapi.go
Normal 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
|
||||||
|
}
|
||||||
29
plugins/pdk/go/host/nd_host_subsonicapi_stub.go
Normal file
29
plugins/pdk/go/host/nd_host_subsonicapi_stub.go
Normal 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")
|
||||||
|
}
|
||||||
258
plugins/pdk/go/host/nd_host_websocket.go
Normal file
258
plugins/pdk/go/host/nd_host_websocket.go
Normal 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
|
||||||
|
}
|
||||||
110
plugins/pdk/go/host/nd_host_websocket_stub.go
Normal file
110
plugins/pdk/go/host/nd_host_websocket_stub.go
Normal 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")
|
||||||
|
}
|
||||||
183
plugins/pdk/python/host/nd_host_artwork.py
Normal file
183
plugins/pdk/python/host/nd_host_artwork.py
Normal 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", "")
|
||||||
447
plugins/pdk/python/host/nd_host_cache.py
Normal file
447
plugins/pdk/python/host/nd_host_cache.py
Normal 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"])
|
||||||
|
|
||||||
241
plugins/pdk/python/host/nd_host_kvstore.py
Normal file
241
plugins/pdk/python/host/nd_host_kvstore.py
Normal 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)
|
||||||
86
plugins/pdk/python/host/nd_host_library.py
Normal file
86
plugins/pdk/python/host/nd_host_library.py
Normal 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)
|
||||||
143
plugins/pdk/python/host/nd_host_scheduler.py
Normal file
143
plugins/pdk/python/host/nd_host_scheduler.py
Normal 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"])
|
||||||
|
|
||||||
55
plugins/pdk/python/host/nd_host_subsonicapi.py
Normal file
55
plugins/pdk/python/host/nd_host_subsonicapi.py
Normal 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", "")
|
||||||
181
plugins/pdk/python/host/nd_host_websocket.py
Normal file
181
plugins/pdk/python/host/nd_host_websocket.py
Normal 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"])
|
||||||
|
|
||||||
65
plugins/pdk/rust/host/lib.rs
Normal file
65
plugins/pdk/rust/host/lib.rs
Normal 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;
|
||||||
207
plugins/pdk/rust/host/nd_host_artwork.rs
Normal file
207
plugins/pdk/rust/host/nd_host_artwork.rs
Normal 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)
|
||||||
|
}
|
||||||
480
plugins/pdk/rust/host/nd_host_cache.rs
Normal file
480
plugins/pdk/rust/host/nd_host_cache.rs
Normal 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(())
|
||||||
|
}
|
||||||
261
plugins/pdk/rust/host/nd_host_kvstore.rs
Normal file
261
plugins/pdk/rust/host/nd_host_kvstore.rs
Normal 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)
|
||||||
|
}
|
||||||
105
plugins/pdk/rust/host/nd_host_library.rs
Normal file
105
plugins/pdk/rust/host/nd_host_library.rs
Normal 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)
|
||||||
|
}
|
||||||
159
plugins/pdk/rust/host/nd_host_scheduler.rs
Normal file
159
plugins/pdk/rust/host/nd_host_scheduler.rs
Normal 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(())
|
||||||
|
}
|
||||||
54
plugins/pdk/rust/host/nd_host_subsonicapi.rs
Normal file
54
plugins/pdk/rust/host/nd_host_subsonicapi.rs
Normal 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)
|
||||||
|
}
|
||||||
204
plugins/pdk/rust/host/nd_host_websocket.rs
Normal file
204
plugins/pdk/rust/host/nd_host_websocket.rs
Normal 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(())
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user