mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-31 07:30:32 +00:00
refactor: host function wrappers to use structured request and response types
- Updated the host function signatures in `nd_host_artwork.go`, `nd_host_scheduler.go`, `nd_host_subsonicapi.go`, and `nd_host_websocket.go` to accept a single parameter for JSON requests. - Introduced structured request and response types for various cache operations in `nd_host_cache.go`. - Modified cache functions to marshal requests to JSON and unmarshal responses, improving error handling and code clarity. - Removed redundant memory allocation for string parameters in favor of JSON marshaling. - Enhanced error handling in WebSocket and cache operations to return structured error responses.
This commit is contained in:
parent
b9fceac12c
commit
cab656dbe5
@ -14,45 +14,23 @@ var templatesFS embed.FS
|
||||
// hostFuncMap returns the template functions for host code generation.
|
||||
func hostFuncMap(svc Service) template.FuncMap {
|
||||
return template.FuncMap{
|
||||
"lower": strings.ToLower,
|
||||
"title": strings.Title,
|
||||
"exportName": func(m Method) string { return m.FunctionName(svc.ExportPrefix()) },
|
||||
"requestType": func(m Method) string { return m.RequestTypeName(svc.Name) },
|
||||
"responseType": func(m Method) string { return m.ResponseTypeName(svc.Name) },
|
||||
"valueType": GoTypeToValueType,
|
||||
"isSimple": IsSimpleType,
|
||||
"isString": IsStringType,
|
||||
"isBytes": IsBytesType,
|
||||
"needsJSON": NeedsJSON,
|
||||
"needsRequestType": func(m Method) bool { return m.NeedsRequestType() },
|
||||
"needsRespType": func(m Method) bool { return m.NeedsResponseType() },
|
||||
"isErrorOnly": func(m Method) bool { return m.IsErrorOnly() },
|
||||
"hasErrFromRead": hasErrorFromRead,
|
||||
"readParam": generateReadParam,
|
||||
"writeReturn": generateWriteReturn,
|
||||
"encodeReturn": generateEncodeReturn,
|
||||
"lower": strings.ToLower,
|
||||
"title": strings.Title,
|
||||
"exportName": func(m Method) string { return m.FunctionName(svc.ExportPrefix()) },
|
||||
"requestType": func(m Method) string { return m.RequestTypeName(svc.Name) },
|
||||
"responseType": func(m Method) string { return m.ResponseTypeName(svc.Name) },
|
||||
}
|
||||
}
|
||||
|
||||
// clientFuncMap returns the template functions for client code generation.
|
||||
func clientFuncMap(svc Service) template.FuncMap {
|
||||
return template.FuncMap{
|
||||
"lower": strings.ToLower,
|
||||
"title": strings.Title,
|
||||
"exportName": func(m Method) string { return m.FunctionName(svc.ExportPrefix()) },
|
||||
"responseType": func(m Method) string { return m.ResponseTypeName(svc.Name) },
|
||||
"isSimple": IsSimpleType,
|
||||
"isString": IsStringType,
|
||||
"isBytes": IsBytesType,
|
||||
"needsJSON": NeedsJSON,
|
||||
"needsRespType": func(m Method) bool { return m.NeedsResponseType() },
|
||||
"isErrorOnly": func(m Method) bool { return m.IsErrorOnly() },
|
||||
"wasmParamType": wasmParamType,
|
||||
"wasmReturnType": wasmReturnType,
|
||||
"wrapperReturnType": func(m Method, svcName string) string { return wrapperReturnType(m, svcName) },
|
||||
"clientCallArg": clientCallArg,
|
||||
"decodeResult": decodeResult,
|
||||
"formatDoc": formatDoc,
|
||||
"lower": strings.ToLower,
|
||||
"title": strings.Title,
|
||||
"exportName": func(m Method) string { return m.FunctionName(svc.ExportPrefix()) },
|
||||
"requestType": func(m Method) string { return m.RequestTypeName(svc.Name) },
|
||||
"responseType": func(m Method) string { return m.ResponseTypeName(svc.Name) },
|
||||
"formatDoc": formatDoc,
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,11 +47,8 @@ func GenerateHost(svc Service, pkgName string) ([]byte, error) {
|
||||
}
|
||||
|
||||
data := templateData{
|
||||
Package: pkgName,
|
||||
Service: svc,
|
||||
NeedsJSON: serviceNeedsJSON(svc),
|
||||
NeedsWriteHelper: serviceNeedsWriteHelper(svc),
|
||||
NeedsErrorHelper: serviceNeedsErrorHelper(svc),
|
||||
Package: pkgName,
|
||||
Service: svc,
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
@ -97,9 +72,7 @@ func GenerateClientGo(svc Service) ([]byte, error) {
|
||||
}
|
||||
|
||||
data := templateData{
|
||||
Service: svc,
|
||||
NeedsJSON: serviceClientNeedsJSON(svc),
|
||||
NeedsErrors: serviceClientNeedsErrors(svc),
|
||||
Service: svc,
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
@ -111,269 +84,8 @@ func GenerateClientGo(svc Service) ([]byte, error) {
|
||||
}
|
||||
|
||||
type templateData struct {
|
||||
Package string
|
||||
Service Service
|
||||
NeedsJSON bool
|
||||
NeedsErrors bool // Client: needs "errors" import
|
||||
NeedsWriteHelper bool
|
||||
NeedsErrorHelper bool
|
||||
}
|
||||
|
||||
// serviceNeedsJSON returns true if any method needs JSON encoding.
|
||||
func serviceNeedsJSON(svc Service) bool {
|
||||
for _, m := range svc.Methods {
|
||||
for _, p := range m.Params {
|
||||
if NeedsJSON(p.Type) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for _, r := range m.Returns {
|
||||
if NeedsJSON(r.Type) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// Error responses are also JSON
|
||||
if m.HasError && m.NeedsResponseType() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// serviceNeedsWriteHelper returns true if any method needs the write helper.
|
||||
func serviceNeedsWriteHelper(svc Service) bool {
|
||||
for _, m := range svc.Methods {
|
||||
if m.NeedsResponseType() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// serviceClientNeedsJSON returns true if any method needs JSON encoding in client code.
|
||||
// This is true if any method has a response type (complex returns) or if any param/return needs JSON.
|
||||
func serviceClientNeedsJSON(svc Service) bool {
|
||||
for _, m := range svc.Methods {
|
||||
// Response types use JSON for serialization
|
||||
if m.NeedsResponseType() {
|
||||
return true
|
||||
}
|
||||
// Parameters that need JSON marshaling
|
||||
for _, p := range m.Params {
|
||||
if NeedsJSON(p.Type) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// serviceClientNeedsErrors returns true if any method needs the errors package in client code.
|
||||
// This is only true for error-only methods (methods that return just error).
|
||||
func serviceClientNeedsErrors(svc Service) bool {
|
||||
for _, m := range svc.Methods {
|
||||
if m.IsErrorOnly() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// serviceNeedsErrorHelper returns true if any method needs error handling with JSON.
|
||||
func serviceNeedsErrorHelper(svc Service) bool {
|
||||
for _, m := range svc.Methods {
|
||||
if m.HasError && m.NeedsResponseType() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// hasErrorFromRead returns true if reading params declares an err variable.
|
||||
// This happens when using needsRequestType (JSON) or when any param is a PTR type.
|
||||
func hasErrorFromRead(m Method) bool {
|
||||
if m.NeedsRequestType() {
|
||||
return true
|
||||
}
|
||||
for _, p := range m.Params {
|
||||
if IsStringType(p.Type) || IsBytesType(p.Type) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// generateReadParam generates code to read a parameter from the stack.
|
||||
func generateReadParam(p Param, stackIndex int) string {
|
||||
switch {
|
||||
case IsSimpleType(p.Type):
|
||||
return generateReadSimple(p, stackIndex)
|
||||
case IsStringType(p.Type):
|
||||
return fmt.Sprintf(`%s, err := p.ReadString(stack[%d])
|
||||
if err != nil {
|
||||
return
|
||||
}`, p.Name, stackIndex)
|
||||
case IsBytesType(p.Type):
|
||||
return fmt.Sprintf(`%s, err := p.ReadBytes(stack[%d])
|
||||
if err != nil {
|
||||
return
|
||||
}`, p.Name, stackIndex)
|
||||
default:
|
||||
// Complex type - JSON
|
||||
return fmt.Sprintf(`%sBytes, err := p.ReadBytes(stack[%d])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var %s %s
|
||||
if err := json.Unmarshal(%sBytes, &%s); err != nil {
|
||||
return
|
||||
}`, p.Name, stackIndex, p.Name, p.Type, p.Name, p.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// generateReadSimple generates code to read a simple type from the stack.
|
||||
func generateReadSimple(p Param, stackIndex int) string {
|
||||
switch p.Type {
|
||||
case "int32":
|
||||
return fmt.Sprintf(`%s := extism.DecodeI32(stack[%d])`, p.Name, stackIndex)
|
||||
case "uint32":
|
||||
return fmt.Sprintf(`%s := extism.DecodeU32(stack[%d])`, p.Name, stackIndex)
|
||||
case "int64":
|
||||
return fmt.Sprintf(`%s := int64(stack[%d])`, p.Name, stackIndex)
|
||||
case "uint64":
|
||||
return fmt.Sprintf(`%s := stack[%d]`, p.Name, stackIndex)
|
||||
case "float32":
|
||||
return fmt.Sprintf(`%s := extism.DecodeF32(stack[%d])`, p.Name, stackIndex)
|
||||
case "float64":
|
||||
return fmt.Sprintf(`%s := extism.DecodeF64(stack[%d])`, p.Name, stackIndex)
|
||||
case "bool":
|
||||
return fmt.Sprintf(`%s := extism.DecodeI32(stack[%d]) != 0`, p.Name, stackIndex)
|
||||
default:
|
||||
return fmt.Sprintf(`// FIXME: unsupported type: %s`, p.Type)
|
||||
}
|
||||
}
|
||||
|
||||
// generateWriteReturn generates code to write a return value to the stack.
|
||||
func generateWriteReturn(p Param, stackIndex int, varName string) string {
|
||||
switch {
|
||||
case IsSimpleType(p.Type):
|
||||
return fmt.Sprintf(`stack[%d] = %s`, stackIndex, generateEncodeReturn(p, varName))
|
||||
case IsStringType(p.Type):
|
||||
return fmt.Sprintf(`if ptr, err := p.WriteString(%s); err == nil {
|
||||
stack[%d] = ptr
|
||||
}`, varName, stackIndex)
|
||||
case IsBytesType(p.Type):
|
||||
return fmt.Sprintf(`if ptr, err := p.WriteBytes(%s); err == nil {
|
||||
stack[%d] = ptr
|
||||
}`, varName, stackIndex)
|
||||
default:
|
||||
// Complex type - JSON
|
||||
return fmt.Sprintf(`if bytes, err := json.Marshal(%s); err == nil {
|
||||
if ptr, err := p.WriteBytes(bytes); err == nil {
|
||||
stack[%d] = ptr
|
||||
}
|
||||
}`, varName, stackIndex)
|
||||
}
|
||||
}
|
||||
|
||||
// generateEncodeReturn generates the encoding expression for a simple return.
|
||||
func generateEncodeReturn(p Param, varName string) string {
|
||||
switch p.Type {
|
||||
case "int32":
|
||||
return fmt.Sprintf("extism.EncodeI32(%s)", varName)
|
||||
case "uint32":
|
||||
return fmt.Sprintf("extism.EncodeU32(%s)", varName)
|
||||
case "int64":
|
||||
return fmt.Sprintf("uint64(%s)", varName)
|
||||
case "uint64":
|
||||
return varName
|
||||
case "float32":
|
||||
return fmt.Sprintf("extism.EncodeF32(%s)", varName)
|
||||
case "float64":
|
||||
return fmt.Sprintf("extism.EncodeF64(%s)", varName)
|
||||
case "bool":
|
||||
return fmt.Sprintf("func() uint64 { if %s { return 1 }; return 0 }()", varName)
|
||||
default:
|
||||
return "0"
|
||||
}
|
||||
}
|
||||
|
||||
// Client-side helper functions for template
|
||||
|
||||
// wasmParamType returns the WASM parameter type for a Go parameter.
|
||||
func wasmParamType(p Param) string {
|
||||
if IsSimpleType(p.Type) {
|
||||
return p.Type
|
||||
}
|
||||
// All pointer types (string, []byte, complex) use uint64 offset
|
||||
return "uint64"
|
||||
}
|
||||
|
||||
// wasmReturnType returns the WASM return type declaration for a method.
|
||||
func wasmReturnType(m Method) string {
|
||||
// Methods with JSON responses or error-only return uint64 (pointer)
|
||||
if m.NeedsResponseType() || m.IsErrorOnly() {
|
||||
return "uint64"
|
||||
}
|
||||
// Simple return types
|
||||
if len(m.Returns) == 1 && IsSimpleType(m.Returns[0].Type) {
|
||||
return m.Returns[0].Type
|
||||
}
|
||||
// No returns or multiple returns - use uint64 for pointer
|
||||
if len(m.Returns) == 0 {
|
||||
return ""
|
||||
}
|
||||
return "uint64"
|
||||
}
|
||||
|
||||
// wrapperReturnType returns the Go return type for the wrapper function.
|
||||
func wrapperReturnType(m Method, svcName string) string {
|
||||
if m.NeedsResponseType() {
|
||||
return fmt.Sprintf("(*%s%sResponse, error)", svcName, m.Name)
|
||||
}
|
||||
if m.IsErrorOnly() {
|
||||
return "error"
|
||||
}
|
||||
if len(m.Returns) == 1 {
|
||||
return m.Returns[0].Type
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// clientCallArg returns the argument expression for calling the host function.
|
||||
func clientCallArg(p Param) string {
|
||||
if IsSimpleType(p.Type) {
|
||||
return p.Name
|
||||
}
|
||||
// Pointer types use .Offset()
|
||||
return p.Name + "Mem.Offset()"
|
||||
}
|
||||
|
||||
// decodeResult generates code to decode a simple return value.
|
||||
func decodeResult(p Param, varName string) string {
|
||||
switch p.Type {
|
||||
case "int32":
|
||||
return fmt.Sprintf("int32(%s)", varName)
|
||||
case "uint32":
|
||||
return fmt.Sprintf("uint32(%s)", varName)
|
||||
case "int64":
|
||||
return fmt.Sprintf("int64(%s)", varName)
|
||||
case "uint64":
|
||||
return varName
|
||||
case "float32":
|
||||
return fmt.Sprintf("math.Float32frombits(uint32(%s))", varName)
|
||||
case "float64":
|
||||
return fmt.Sprintf("math.Float64frombits(%s)", varName)
|
||||
case "bool":
|
||||
return fmt.Sprintf("%s != 0", varName)
|
||||
case "string":
|
||||
// pdk.FindMemory returns a value type, ReadBytes has pointer receiver
|
||||
return fmt.Sprintf("func() string { m := pdk.FindMemory(%s); return string(m.ReadBytes()) }()", varName)
|
||||
case "[]byte":
|
||||
return fmt.Sprintf("func() []byte { m := pdk.FindMemory(%s); return m.ReadBytes() }()", varName)
|
||||
default:
|
||||
return varName
|
||||
}
|
||||
Package string
|
||||
Service Service
|
||||
}
|
||||
|
||||
// formatDoc formats a documentation string for Go comments.
|
||||
|
||||
@ -11,7 +11,7 @@ import (
|
||||
var _ = Describe("Generator", func() {
|
||||
Describe("GenerateHost", func() {
|
||||
It("should generate valid Go code for a simple service with strings", func() {
|
||||
// String params/returns don't need JSON - they use direct memory read/write
|
||||
// All methods use JSON request/response types
|
||||
svc := Service{
|
||||
Name: "SubsonicAPI",
|
||||
Permission: "subsonicapi",
|
||||
@ -41,10 +41,11 @@ var _ = Describe("Generator", func() {
|
||||
// Check for package declaration
|
||||
Expect(codeStr).To(ContainSubstring("package host"))
|
||||
|
||||
// String params don't need request type - read directly from memory
|
||||
Expect(codeStr).NotTo(ContainSubstring("type SubsonicAPICallRequest struct"))
|
||||
// All methods now use request type for JSON protocol
|
||||
Expect(codeStr).To(ContainSubstring("type SubsonicAPICallRequest struct"))
|
||||
Expect(codeStr).To(ContainSubstring(`Uri string `))
|
||||
|
||||
// String return with error needs response type for error handling
|
||||
// Response type with error handling
|
||||
Expect(codeStr).To(ContainSubstring("type SubsonicAPICallResponse struct"))
|
||||
Expect(codeStr).To(ContainSubstring(`Response string `))
|
||||
Expect(codeStr).To(ContainSubstring(`Error string `))
|
||||
@ -55,8 +56,8 @@ var _ = Describe("Generator", func() {
|
||||
// Check for host function name
|
||||
Expect(codeStr).To(ContainSubstring(`"subsonicapi_call"`))
|
||||
|
||||
// Check for direct string read (not JSON unmarshal)
|
||||
Expect(codeStr).To(ContainSubstring("p.ReadString(stack[0])"))
|
||||
// Check for JSON unmarshal (all methods use JSON now)
|
||||
Expect(codeStr).To(ContainSubstring("json.Unmarshal"))
|
||||
})
|
||||
|
||||
It("should generate code for methods without parameters", func() {
|
||||
@ -80,8 +81,10 @@ var _ = Describe("Generator", func() {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
codeStr := string(code)
|
||||
// Should not have request type for methods without params
|
||||
// Methods without params don't need a request type - no params to serialize
|
||||
Expect(codeStr).NotTo(ContainSubstring("type TestNoParamsRequest struct"))
|
||||
// But still uses PTR input/output for consistency
|
||||
Expect(codeStr).To(MatchRegexp(`\[\]extism\.ValueType\{extism\.ValueTypePTR\},\s*\[\]extism\.ValueType\{extism\.ValueTypePTR\}`))
|
||||
})
|
||||
|
||||
It("should generate code for methods without return values", func() {
|
||||
@ -144,8 +147,8 @@ var _ = Describe("Generator", func() {
|
||||
Expect(codeStr).To(ContainSubstring("scheduler_cancelschedule"))
|
||||
})
|
||||
|
||||
It("should handle multiple simple parameters without JSON", func() {
|
||||
// All simple params (string, int32, bool) can be passed on stack directly
|
||||
It("should handle multiple simple parameters with JSON", func() {
|
||||
// All params use JSON - single PTR input
|
||||
svc := Service{
|
||||
Name: "Test",
|
||||
Permission: "test",
|
||||
@ -171,14 +174,12 @@ var _ = Describe("Generator", func() {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
codeStr := string(code)
|
||||
// No request type for simple params - they're read directly from stack
|
||||
Expect(codeStr).NotTo(ContainSubstring("type TestMultiParamRequest struct"))
|
||||
// Check for direct stack reads
|
||||
Expect(codeStr).To(ContainSubstring("p.ReadString(stack[0])"))
|
||||
Expect(codeStr).To(ContainSubstring("extism.DecodeI32(stack[1])"))
|
||||
Expect(codeStr).To(ContainSubstring("extism.DecodeI32(stack[2])"))
|
||||
// Check that input ValueType slice has correct entries (3 params: PTR for string, I32 for int32, I32 for bool)
|
||||
Expect(codeStr).To(ContainSubstring("extism.ValueTypePTR, extism.ValueTypeI32, extism.ValueTypeI32"))
|
||||
// All methods use request type with JSON protocol
|
||||
Expect(codeStr).To(ContainSubstring("type TestMultiParamRequest struct"))
|
||||
// Check for JSON unmarshal (all methods use JSON now)
|
||||
Expect(codeStr).To(ContainSubstring("json.Unmarshal"))
|
||||
// Check that input/output ValueType both use PTR (JSON)
|
||||
Expect(codeStr).To(MatchRegexp(`\[\]extism\.ValueType\{extism\.ValueTypePTR\},\s*\[\]extism\.ValueType\{extism\.ValueTypePTR\}`))
|
||||
})
|
||||
|
||||
It("should use single PTR for mixed simple and complex params", func() {
|
||||
@ -263,8 +264,8 @@ var _ = Describe("Generator", func() {
|
||||
Expect(codeStr).To(ContainSubstring(`extism "github.com/extism/go-sdk"`))
|
||||
})
|
||||
|
||||
It("should not include json import when not needed", func() {
|
||||
// Service with only simple types doesn't need JSON import
|
||||
It("should always include json import for JSON protocol", func() {
|
||||
// All services use JSON protocol, so json import is always needed
|
||||
svc := Service{
|
||||
Name: "Test",
|
||||
Permission: "test",
|
||||
@ -283,7 +284,7 @@ var _ = Describe("Generator", func() {
|
||||
|
||||
codeStr := string(code)
|
||||
Expect(codeStr).To(ContainSubstring(`"context"`))
|
||||
Expect(codeStr).NotTo(ContainSubstring(`"encoding/json"`))
|
||||
Expect(codeStr).To(ContainSubstring(`"encoding/json"`))
|
||||
Expect(codeStr).To(ContainSubstring(`extism "github.com/extism/go-sdk"`))
|
||||
})
|
||||
})
|
||||
|
||||
@ -8,12 +8,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
{{- if .NeedsJSON}}
|
||||
"encoding/json"
|
||||
{{- end}}
|
||||
{{- if .NeedsErrors}}
|
||||
"errors"
|
||||
{{- end}}
|
||||
|
||||
"github.com/extism/go-pdk"
|
||||
)
|
||||
@ -24,12 +19,20 @@ import (
|
||||
// {{exportName .}} is the host function provided by Navidrome.
|
||||
//
|
||||
//go:wasmimport extism:host/user {{exportName .}}
|
||||
func {{exportName .}}({{range $i, $p := .Params}}{{if $i}}, {{end}}{{wasmParamType $p}}{{end}}) {{wasmReturnType .}}
|
||||
func {{exportName .}}(uint64) uint64
|
||||
{{- end}}
|
||||
|
||||
{{- /* Generate response types for methods that need them */ -}}
|
||||
{{- /* Generate request/response types for all methods */ -}}
|
||||
{{range .Service.Methods}}
|
||||
{{- if needsRespType .}}
|
||||
{{- if .HasParams}}
|
||||
|
||||
// {{requestType .}} is the request type for {{$.Service.Name}}.{{.Name}}.
|
||||
type {{requestType .}} struct {
|
||||
{{- range .Params}}
|
||||
{{title .Name}} {{.Type}} `json:"{{.JSONName}}"`
|
||||
{{- end}}
|
||||
}
|
||||
{{- end}}
|
||||
|
||||
// {{responseType .}} is the response type for {{$.Service.Name}}.{{.Name}}.
|
||||
type {{responseType .}} struct {
|
||||
@ -39,7 +42,6 @@ type {{responseType .}} struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
|
||||
{{- /* Generate wrapper functions */ -}}
|
||||
{{range .Service.Methods}}
|
||||
@ -48,28 +50,28 @@ type {{responseType .}} struct {
|
||||
{{- if .Doc}}
|
||||
{{formatDoc .Doc}}
|
||||
{{- end}}
|
||||
func {{$.Service.Name}}{{.Name}}({{range $i, $p := .Params}}{{if $i}}, {{end}}{{$p.Name}} {{$p.Type}}{{end}}) {{wrapperReturnType . $.Service.Name}} {
|
||||
{{- if needsRespType .}}
|
||||
{{- /* Complex response - use JSON */}}
|
||||
func {{$.Service.Name}}{{.Name}}({{range $i, $p := .Params}}{{if $i}}, {{end}}{{$p.Name}} {{$p.Type}}{{end}}) (*{{responseType .}}, error) {
|
||||
{{- if .HasParams}}
|
||||
// Marshal request to JSON
|
||||
req := {{requestType .}}{
|
||||
{{- range .Params}}
|
||||
{{- if isString .Type}}
|
||||
{{.Name}}Mem := pdk.AllocateString({{.Name}})
|
||||
defer {{.Name}}Mem.Free()
|
||||
{{- else if isBytes .Type}}
|
||||
{{.Name}}Mem := pdk.AllocateBytes({{.Name}})
|
||||
defer {{.Name}}Mem.Free()
|
||||
{{- else if needsJSON .Type}}
|
||||
{{.Name}}Bytes, err := json.Marshal({{.Name}})
|
||||
{{title .Name}}: {{.Name}},
|
||||
{{- end}}
|
||||
}
|
||||
reqBytes, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
{{.Name}}Mem := pdk.AllocateBytes({{.Name}}Bytes)
|
||||
defer {{.Name}}Mem.Free()
|
||||
{{- end}}
|
||||
reqMem := pdk.AllocateBytes(reqBytes)
|
||||
defer reqMem.Free()
|
||||
{{- else}}
|
||||
// No parameters - allocate empty JSON object
|
||||
reqMem := pdk.AllocateBytes([]byte("{}"))
|
||||
defer reqMem.Free()
|
||||
{{- end}}
|
||||
|
||||
// Call the host function
|
||||
responsePtr := {{exportName .}}({{range $i, $p := .Params}}{{if $i}}, {{end}}{{clientCallArg $p}}{{end}})
|
||||
responsePtr := {{exportName .}}(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -82,56 +84,5 @@ func {{$.Service.Name}}{{.Name}}({{range $i, $p := .Params}}{{if $i}}, {{end}}{{
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
{{- else if isErrorOnly .}}
|
||||
{{- /* Error-only response - string result */}}
|
||||
{{- range .Params}}
|
||||
{{- if isString .Type}}
|
||||
{{.Name}}Mem := pdk.AllocateString({{.Name}})
|
||||
defer {{.Name}}Mem.Free()
|
||||
{{- else if isBytes .Type}}
|
||||
{{.Name}}Mem := pdk.AllocateBytes({{.Name}})
|
||||
defer {{.Name}}Mem.Free()
|
||||
{{- else if needsJSON .Type}}
|
||||
{{.Name}}Bytes, err := json.Marshal({{.Name}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
{{.Name}}Mem := pdk.AllocateBytes({{.Name}}Bytes)
|
||||
defer {{.Name}}Mem.Free()
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
|
||||
// Call the host function
|
||||
responsePtr := {{exportName .}}({{range $i, $p := .Params}}{{if $i}}, {{end}}{{clientCallArg $p}}{{end}})
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
}
|
||||
|
||||
return nil
|
||||
{{- else}}
|
||||
{{- /* Simple return types - direct stack values */}}
|
||||
{{- range .Params}}
|
||||
{{- if isString .Type}}
|
||||
{{.Name}}Mem := pdk.AllocateString({{.Name}})
|
||||
defer {{.Name}}Mem.Free()
|
||||
{{- else if isBytes .Type}}
|
||||
{{.Name}}Mem := pdk.AllocateBytes({{.Name}})
|
||||
defer {{.Name}}Mem.Free()
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
|
||||
// Call the host function
|
||||
{{- if .HasReturns}}
|
||||
result := {{exportName .}}({{range $i, $p := .Params}}{{if $i}}, {{end}}{{clientCallArg $p}}{{end}})
|
||||
return {{decodeResult (index .Returns 0) "result"}}
|
||||
{{- else}}
|
||||
{{exportName .}}({{range $i, $p := .Params}}{{if $i}}, {{end}}{{clientCallArg $p}}{{end}})
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
}
|
||||
{{- end}}
|
||||
|
||||
@ -4,16 +4,14 @@ package {{.Package}}
|
||||
|
||||
import (
|
||||
"context"
|
||||
{{- if .NeedsJSON}}
|
||||
"encoding/json"
|
||||
{{- end}}
|
||||
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
{{- /* Generate request/response types only when needed */ -}}
|
||||
{{- /* Generate request/response types for all methods */ -}}
|
||||
{{range .Service.Methods}}
|
||||
{{- if needsRequestType .}}
|
||||
{{- if .HasParams}}
|
||||
|
||||
// {{requestType .}} is the request type for {{$.Service.Name}}.{{.Name}}.
|
||||
type {{requestType .}} struct {
|
||||
@ -22,7 +20,6 @@ type {{requestType .}} struct {
|
||||
{{- end}}
|
||||
}
|
||||
{{- end}}
|
||||
{{- if needsRespType .}}
|
||||
|
||||
// {{responseType .}} is the response type for {{$.Service.Name}}.{{.Name}}.
|
||||
type {{responseType .}} struct {
|
||||
@ -31,7 +28,6 @@ type {{responseType .}} struct {
|
||||
{{- end}}
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
{{- end}}
|
||||
{{end}}
|
||||
|
||||
// Register{{.Service.Name}}HostFunctions registers {{.Service.Name}} service host functions.
|
||||
@ -50,7 +46,6 @@ func new{{$.Service.Name}}{{.Name}}HostFunction(service {{$.Service.Interface}})
|
||||
"{{exportName .}}",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
{{- if .HasParams}}
|
||||
{{- if needsRequestType .}}
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
@ -62,47 +57,28 @@ func new{{$.Service.Name}}{{.Name}}HostFunction(service {{$.Service.Interface}})
|
||||
{{$.Service.Name | lower}}WriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
{{- else}}
|
||||
// Read parameters from stack
|
||||
{{- range $i, $p := .Params}}
|
||||
{{readParam $p $i}}
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
|
||||
// Call the service method
|
||||
{{- $m := .}}
|
||||
{{- if .HasReturns}}
|
||||
{{- if .HasError}}
|
||||
{{range $i, $r := .Returns}}{{if $i}}, {{end}}{{lower $r.Name}}{{end}}, err := service.{{.Name}}(ctx{{range .Params}}, {{if needsRequestType $m}}req.{{title .Name}}{{else}}{{.Name}}{{end}}{{end}})
|
||||
{{- else}}
|
||||
{{range $i, $r := .Returns}}{{if $i}}, {{end}}{{lower $r.Name}}{{end}} := service.{{.Name}}(ctx{{range .Params}}, {{if needsRequestType $m}}req.{{title .Name}}{{else}}{{.Name}}{{end}}{{end}})
|
||||
{{- end}}
|
||||
{{- else if .HasError}}
|
||||
err {{if hasErrFromRead .}}={{else}}:={{end}} service.{{.Name}}(ctx{{range .Params}}, {{if needsRequestType $m}}req.{{title .Name}}{{else}}{{.Name}}{{end}}{{end}})
|
||||
{{- else}}
|
||||
service.{{.Name}}(ctx{{range .Params}}, {{if needsRequestType $m}}req.{{title .Name}}{{else}}{{.Name}}{{end}}{{end}})
|
||||
{{- end}}
|
||||
{{- if .HasError}}
|
||||
if err != nil {
|
||||
{{- if isErrorOnly .}}
|
||||
// Write error string to plugin memory
|
||||
if ptr, err := p.WriteString(err.Error()); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
{{- else if needsRespType .}}
|
||||
{{$.Service.Name | lower}}WriteError(p, stack, err)
|
||||
{{- end}}
|
||||
{{range $i, $r := .Returns}}{{if $i}}, {{end}}{{lower $r.Name}}{{end}}, svcErr := service.{{.Name}}(ctx{{range .Params}}, req.{{title .Name}}{{end}})
|
||||
if svcErr != nil {
|
||||
{{$.Service.Name | lower}}WriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
{{- else}}
|
||||
{{range $i, $r := .Returns}}{{if $i}}, {{end}}{{lower $r.Name}}{{end}} := service.{{.Name}}(ctx{{range .Params}}, req.{{title .Name}}{{end}})
|
||||
{{- end}}
|
||||
{{- else if .HasError}}
|
||||
if svcErr := service.{{.Name}}(ctx{{range .Params}}, req.{{title .Name}}{{end}}); svcErr != nil {
|
||||
{{$.Service.Name | lower}}WriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
{{- else}}
|
||||
service.{{.Name}}(ctx{{range .Params}}, req.{{title .Name}}{{end}})
|
||||
{{- end}}
|
||||
|
||||
{{- if isErrorOnly .}}
|
||||
// Write empty string to indicate success
|
||||
if ptr, err := p.WriteString(""); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
{{- else if needsRespType .}}
|
||||
// Write JSON response to plugin memory
|
||||
resp := {{responseType .}}{
|
||||
{{- range .Returns}}
|
||||
@ -110,27 +86,12 @@ func new{{$.Service.Name}}{{.Name}}HostFunction(service {{$.Service.Interface}})
|
||||
{{- end}}
|
||||
}
|
||||
{{$.Service.Name | lower}}WriteResponse(p, stack, resp)
|
||||
{{- else if .HasReturns}}
|
||||
// Write return values to stack
|
||||
{{- range $i, $r := .Returns}}
|
||||
{{writeReturn $r $i (lower $r.Name)}}
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
},
|
||||
{{- if needsRequestType $m}}
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
{{- else}}
|
||||
[]extism.ValueType{ {{- range $i, $p := .Params}}{{if $i}}, {{end}}{{valueType $p.Type}}{{end}}{{if not .HasParams}}{{end}} },
|
||||
{{- end}}
|
||||
{{- if or (needsRespType .) (isErrorOnly .)}}
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
{{- else}}
|
||||
[]extism.ValueType{ {{- range $i, $r := .Returns}}{{if $i}}, {{end}}{{valueType $r.Type}}{{end}}{{if not .HasReturns}}{{end}} },
|
||||
{{- end}}
|
||||
)
|
||||
}
|
||||
{{end}}
|
||||
{{- if .NeedsWriteHelper}}
|
||||
|
||||
// {{.Service.Name | lower}}WriteResponse writes a JSON response to plugin memory.
|
||||
func {{.Service.Name | lower}}WriteResponse(p *extism.CurrentPlugin, stack []uint64, resp any) {
|
||||
@ -146,8 +107,6 @@ func {{.Service.Name | lower}}WriteResponse(p *extism.CurrentPlugin, stack []uin
|
||||
}
|
||||
stack[0] = respPtr
|
||||
}
|
||||
{{- end}}
|
||||
{{- if .NeedsErrorHelper}}
|
||||
|
||||
// {{.Service.Name | lower}}WriteError writes an error response to plugin memory.
|
||||
func {{.Service.Name | lower}}WriteError(p *extism.CurrentPlugin, stack []uint64, err error) {
|
||||
@ -158,4 +117,3 @@ func {{.Service.Name | lower}}WriteError(p *extism.CurrentPlugin, stack []uint64
|
||||
respPtr, _ := p.WriteBytes(respBytes)
|
||||
stack[0] = respPtr
|
||||
}
|
||||
{{- end}}
|
||||
|
||||
@ -77,128 +77,6 @@ func NewParam(name, typ string) Param {
|
||||
}
|
||||
}
|
||||
|
||||
// IsSimple returns true if the type can be passed directly on the WASM stack
|
||||
// without JSON serialization (primitive numeric types).
|
||||
func (p Param) IsSimple() bool {
|
||||
return IsSimpleType(p.Type)
|
||||
}
|
||||
|
||||
// IsPTR returns true if the type should be passed via memory pointer
|
||||
// (strings, bytes, and complex types that need JSON serialization).
|
||||
func (p Param) IsPTR() bool {
|
||||
return !p.IsSimple()
|
||||
}
|
||||
|
||||
// ValueType returns the Extism ValueType constant name for this parameter.
|
||||
func (p Param) ValueType() string {
|
||||
return GoTypeToValueType(p.Type)
|
||||
}
|
||||
|
||||
// IsSimpleType returns true if a Go type can be passed directly on WASM stack.
|
||||
func IsSimpleType(typ string) bool {
|
||||
switch typ {
|
||||
case "int32", "uint32", "int64", "uint64", "float32", "float64", "bool":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// IsStringType returns true if the type is a string.
|
||||
func IsStringType(typ string) bool {
|
||||
return typ == "string"
|
||||
}
|
||||
|
||||
// IsBytesType returns true if the type is []byte.
|
||||
func IsBytesType(typ string) bool {
|
||||
return typ == "[]byte"
|
||||
}
|
||||
|
||||
// NeedsJSON returns true if the type requires JSON serialization.
|
||||
func NeedsJSON(typ string) bool {
|
||||
if IsSimpleType(typ) || IsStringType(typ) || IsBytesType(typ) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// GoTypeToValueType returns the Extism ValueType constant for a Go type.
|
||||
func GoTypeToValueType(typ string) string {
|
||||
switch typ {
|
||||
case "int32", "uint32":
|
||||
return "extism.ValueTypeI32"
|
||||
case "int64", "uint64":
|
||||
return "extism.ValueTypeI64"
|
||||
case "float32":
|
||||
return "extism.ValueTypeF32"
|
||||
case "float64":
|
||||
return "extism.ValueTypeF64"
|
||||
case "bool":
|
||||
return "extism.ValueTypeI32" // bool as i32
|
||||
default:
|
||||
// strings, []byte, structs, maps, slices all use PTR (i64)
|
||||
return "extism.ValueTypePTR"
|
||||
}
|
||||
}
|
||||
|
||||
// AllParamsSimple returns true if all params can be passed on the stack.
|
||||
func (m Method) AllParamsSimple() bool {
|
||||
for _, p := range m.Params {
|
||||
if !p.IsSimple() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// AllReturnsSimple returns true if all returns can be passed on the stack.
|
||||
func (m Method) AllReturnsSimple() bool {
|
||||
for _, r := range m.Returns {
|
||||
if !r.IsSimple() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// NeedsRequestType returns true if a request struct is needed.
|
||||
// Only needed when we have complex params that require JSON.
|
||||
func (m Method) NeedsRequestType() bool {
|
||||
if !m.HasParams() {
|
||||
return false
|
||||
}
|
||||
for _, p := range m.Params {
|
||||
if NeedsJSON(p.Type) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NeedsResponseType returns true if a response struct is needed.
|
||||
// Needed when we have complex returns that require JSON (but not for error-only methods).
|
||||
func (m Method) NeedsResponseType() bool {
|
||||
// Error-only methods return a simple string, not JSON
|
||||
if m.IsErrorOnly() {
|
||||
return false
|
||||
}
|
||||
// If there's an error with other returns, we need a response type
|
||||
if m.HasError && m.HasReturns() {
|
||||
return true
|
||||
}
|
||||
for _, r := range m.Returns {
|
||||
if NeedsJSON(r.Type) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsErrorOnly returns true if the method only returns an error (no other return values).
|
||||
func (m Method) IsErrorOnly() bool {
|
||||
return m.HasError && !m.HasReturns()
|
||||
}
|
||||
|
||||
// toJSONName converts a Go identifier to camelCase JSON field name.
|
||||
func toJSONName(name string) string {
|
||||
if name == "" {
|
||||
|
||||
@ -18,6 +18,11 @@ import (
|
||||
//go:wasmimport extism:host/user codec_encode
|
||||
func codec_encode(uint64) uint64
|
||||
|
||||
// CodecEncodeRequest is the request type for Codec.Encode.
|
||||
type CodecEncodeRequest struct {
|
||||
Data []byte `json:"data"`
|
||||
}
|
||||
|
||||
// CodecEncodeResponse is the response type for Codec.Encode.
|
||||
type CodecEncodeResponse struct {
|
||||
Result []byte `json:"result,omitempty"`
|
||||
@ -26,11 +31,19 @@ type CodecEncodeResponse struct {
|
||||
|
||||
// CodecEncode calls the codec_encode host function.
|
||||
func CodecEncode(data []byte) (*CodecEncodeResponse, error) {
|
||||
dataMem := pdk.AllocateBytes(data)
|
||||
defer dataMem.Free()
|
||||
// Marshal request to JSON
|
||||
req := CodecEncodeRequest{
|
||||
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 := codec_encode(dataMem.Offset())
|
||||
responsePtr := codec_encode(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
|
||||
28
plugins/cmd/hostgen/testdata/codec_expected.go
vendored
28
plugins/cmd/hostgen/testdata/codec_expected.go
vendored
@ -9,6 +9,11 @@ import (
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// CodecEncodeRequest is the request type for Codec.Encode.
|
||||
type CodecEncodeRequest struct {
|
||||
Data []byte `json:"data"`
|
||||
}
|
||||
|
||||
// CodecEncodeResponse is the response type for Codec.Encode.
|
||||
type CodecEncodeResponse struct {
|
||||
Result []byte `json:"result,omitempty"`
|
||||
@ -27,18 +32,25 @@ func newCodecEncodeHostFunction(service CodecService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"codec_encode",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
data, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
result, err := service.Encode(ctx, data)
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
codecWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CodecEncodeRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
codecWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
result, svcErr := service.Encode(ctx, req.Data)
|
||||
if svcErr != nil {
|
||||
codecWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CodecEncodeResponse{
|
||||
Result: result,
|
||||
|
||||
@ -8,20 +8,52 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/extism/go-pdk"
|
||||
)
|
||||
|
||||
// counter_count is the host function provided by Navidrome.
|
||||
//
|
||||
//go:wasmimport extism:host/user counter_count
|
||||
func counter_count(uint64) int32
|
||||
func counter_count(uint64) uint64
|
||||
|
||||
// CounterCountRequest is the request type for Counter.Count.
|
||||
type CounterCountRequest struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// CounterCountResponse is the response type for Counter.Count.
|
||||
type CounterCountResponse struct {
|
||||
Value int32 `json:"value,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// CounterCount calls the counter_count host function.
|
||||
func CounterCount(name string) int32 {
|
||||
nameMem := pdk.AllocateString(name)
|
||||
defer nameMem.Free()
|
||||
func CounterCount(name string) (*CounterCountResponse, error) {
|
||||
// Marshal request to JSON
|
||||
req := CounterCountRequest{
|
||||
Name: name,
|
||||
}
|
||||
reqBytes, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reqMem := pdk.AllocateBytes(reqBytes)
|
||||
defer reqMem.Free()
|
||||
|
||||
// Call the host function
|
||||
result := counter_count(nameMem.Offset())
|
||||
return int32(result)
|
||||
responsePtr := counter_count(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
// Parse the response
|
||||
var response CounterCountResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
59
plugins/cmd/hostgen/testdata/counter_expected.go
vendored
59
plugins/cmd/hostgen/testdata/counter_expected.go
vendored
@ -4,10 +4,22 @@ package testpkg
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// CounterCountRequest is the request type for Counter.Count.
|
||||
type CounterCountRequest struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// CounterCountResponse is the response type for Counter.Count.
|
||||
type CounterCountResponse struct {
|
||||
Value int32 `json:"value,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// RegisterCounterHostFunctions registers Counter service host functions.
|
||||
// The returned host functions should be added to the plugin's configuration.
|
||||
func RegisterCounterHostFunctions(service CounterService) []extism.HostFunction {
|
||||
@ -20,18 +32,53 @@ func newCounterCountHostFunction(service CounterService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"counter_count",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
name, err := p.ReadString(stack[0])
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
counterWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CounterCountRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
counterWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
value := service.Count(ctx, name)
|
||||
// Write return values to stack
|
||||
stack[0] = extism.EncodeI32(value)
|
||||
value := service.Count(ctx, req.Name)
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CounterCountResponse{
|
||||
Value: value,
|
||||
}
|
||||
counterWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypeI32},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
// counterWriteResponse writes a JSON response to plugin memory.
|
||||
func counterWriteResponse(p *extism.CurrentPlugin, stack []uint64, resp any) {
|
||||
respBytes, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
counterWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
respPtr, err := p.WriteBytes(respBytes)
|
||||
if err != nil {
|
||||
stack[0] = 0
|
||||
return
|
||||
}
|
||||
stack[0] = respPtr
|
||||
}
|
||||
|
||||
// counterWriteError writes an error response to plugin memory.
|
||||
func counterWriteError(p *extism.CurrentPlugin, stack []uint64, err error) {
|
||||
errResp := struct {
|
||||
Error string `json:"error"`
|
||||
}{Error: err.Error()}
|
||||
respBytes, _ := json.Marshal(errResp)
|
||||
respPtr, _ := p.WriteBytes(respBytes)
|
||||
stack[0] = respPtr
|
||||
}
|
||||
|
||||
@ -18,6 +18,11 @@ import (
|
||||
//go:wasmimport extism:host/user echo_echo
|
||||
func echo_echo(uint64) uint64
|
||||
|
||||
// EchoEchoRequest is the request type for Echo.Echo.
|
||||
type EchoEchoRequest struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// EchoEchoResponse is the response type for Echo.Echo.
|
||||
type EchoEchoResponse struct {
|
||||
Reply string `json:"reply,omitempty"`
|
||||
@ -26,11 +31,19 @@ type EchoEchoResponse struct {
|
||||
|
||||
// EchoEcho calls the echo_echo host function.
|
||||
func EchoEcho(message string) (*EchoEchoResponse, error) {
|
||||
messageMem := pdk.AllocateString(message)
|
||||
defer messageMem.Free()
|
||||
// Marshal request to JSON
|
||||
req := EchoEchoRequest{
|
||||
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 := echo_echo(messageMem.Offset())
|
||||
responsePtr := echo_echo(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
|
||||
28
plugins/cmd/hostgen/testdata/echo_expected.go
vendored
28
plugins/cmd/hostgen/testdata/echo_expected.go
vendored
@ -9,6 +9,11 @@ import (
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// EchoEchoRequest is the request type for Echo.Echo.
|
||||
type EchoEchoRequest struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// EchoEchoResponse is the response type for Echo.Echo.
|
||||
type EchoEchoResponse struct {
|
||||
Reply string `json:"reply,omitempty"`
|
||||
@ -27,18 +32,25 @@ func newEchoEchoHostFunction(service EchoService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"echo_echo",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
message, err := p.ReadString(stack[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
reply, err := service.Echo(ctx, message)
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
echoWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req EchoEchoRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
echoWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
reply, svcErr := service.Echo(ctx, req.Message)
|
||||
if svcErr != nil {
|
||||
echoWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := EchoEchoResponse{
|
||||
Reply: reply,
|
||||
|
||||
@ -16,7 +16,13 @@ import (
|
||||
// list_items is the host function provided by Navidrome.
|
||||
//
|
||||
//go:wasmimport extism:host/user list_items
|
||||
func list_items(uint64, uint64) uint64
|
||||
func list_items(uint64) uint64
|
||||
|
||||
// ListItemsRequest is the request type for List.Items.
|
||||
type ListItemsRequest struct {
|
||||
Name string `json:"name"`
|
||||
Filter Filter `json:"filter"`
|
||||
}
|
||||
|
||||
// ListItemsResponse is the response type for List.Items.
|
||||
type ListItemsResponse struct {
|
||||
@ -26,17 +32,20 @@ type ListItemsResponse struct {
|
||||
|
||||
// ListItems calls the list_items host function.
|
||||
func ListItems(name string, filter Filter) (*ListItemsResponse, error) {
|
||||
nameMem := pdk.AllocateString(name)
|
||||
defer nameMem.Free()
|
||||
filterBytes, err := json.Marshal(filter)
|
||||
// Marshal request to JSON
|
||||
req := ListItemsRequest{
|
||||
Name: name,
|
||||
Filter: filter,
|
||||
}
|
||||
reqBytes, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filterMem := pdk.AllocateBytes(filterBytes)
|
||||
defer filterMem.Free()
|
||||
reqMem := pdk.AllocateBytes(reqBytes)
|
||||
defer reqMem.Free()
|
||||
|
||||
// Call the host function
|
||||
responsePtr := list_items(nameMem.Offset(), filterMem.Offset())
|
||||
responsePtr := list_items(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
|
||||
@ -46,11 +46,12 @@ func newListItemsHostFunction(service ListService) extism.HostFunction {
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
count, err := service.Items(ctx, req.Name, req.Filter)
|
||||
if err != nil {
|
||||
listWriteError(p, stack, err)
|
||||
count, svcErr := service.Items(ctx, req.Name, req.Filter)
|
||||
if svcErr != nil {
|
||||
listWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := ListItemsResponse{
|
||||
Count: count,
|
||||
|
||||
@ -16,7 +16,13 @@ import (
|
||||
// math_add is the host function provided by Navidrome.
|
||||
//
|
||||
//go:wasmimport extism:host/user math_add
|
||||
func math_add(int32, int32) uint64
|
||||
func math_add(uint64) uint64
|
||||
|
||||
// MathAddRequest is the request type for Math.Add.
|
||||
type MathAddRequest struct {
|
||||
A int32 `json:"a"`
|
||||
B int32 `json:"b"`
|
||||
}
|
||||
|
||||
// MathAddResponse is the response type for Math.Add.
|
||||
type MathAddResponse struct {
|
||||
@ -26,9 +32,20 @@ type MathAddResponse struct {
|
||||
|
||||
// MathAdd calls the math_add host function.
|
||||
func MathAdd(a int32, b int32) (*MathAddResponse, error) {
|
||||
// Marshal request to JSON
|
||||
req := MathAddRequest{
|
||||
A: a,
|
||||
B: b,
|
||||
}
|
||||
reqBytes, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reqMem := pdk.AllocateBytes(reqBytes)
|
||||
defer reqMem.Free()
|
||||
|
||||
// Call the host function
|
||||
responsePtr := math_add(a, b)
|
||||
responsePtr := math_add(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
|
||||
29
plugins/cmd/hostgen/testdata/math_expected.go
vendored
29
plugins/cmd/hostgen/testdata/math_expected.go
vendored
@ -9,6 +9,12 @@ import (
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// MathAddRequest is the request type for Math.Add.
|
||||
type MathAddRequest struct {
|
||||
A int32 `json:"a"`
|
||||
B int32 `json:"b"`
|
||||
}
|
||||
|
||||
// MathAddResponse is the response type for Math.Add.
|
||||
type MathAddResponse struct {
|
||||
Result int32 `json:"result,omitempty"`
|
||||
@ -27,23 +33,32 @@ func newMathAddHostFunction(service MathService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"math_add",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
a := extism.DecodeI32(stack[0])
|
||||
b := extism.DecodeI32(stack[1])
|
||||
|
||||
// Call the service method
|
||||
result, err := service.Add(ctx, a, b)
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
mathWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req MathAddRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
mathWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
result, svcErr := service.Add(ctx, req.A, req.B)
|
||||
if svcErr != nil {
|
||||
mathWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := MathAddResponse{
|
||||
Result: result,
|
||||
}
|
||||
mathWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypeI32, extism.ValueTypeI32},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
@ -9,7 +9,6 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/extism/go-pdk"
|
||||
)
|
||||
@ -24,19 +23,42 @@ func meta_get(uint64) uint64
|
||||
//go:wasmimport extism:host/user meta_set
|
||||
func meta_set(uint64) uint64
|
||||
|
||||
// MetaGetRequest is the request type for Meta.Get.
|
||||
type MetaGetRequest struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// MetaGetResponse is the response type for Meta.Get.
|
||||
type MetaGetResponse struct {
|
||||
Value any `json:"value,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// MetaSetRequest is the request type for Meta.Set.
|
||||
type MetaSetRequest struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
// MetaSetResponse is the response type for Meta.Set.
|
||||
type MetaSetResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// MetaGet calls the meta_get host function.
|
||||
func MetaGet(key string) (*MetaGetResponse, error) {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
// Marshal request to JSON
|
||||
req := MetaGetRequest{
|
||||
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 := meta_get(keyMem.Offset())
|
||||
responsePtr := meta_get(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -52,24 +74,30 @@ func MetaGet(key string) (*MetaGetResponse, error) {
|
||||
}
|
||||
|
||||
// MetaSet calls the meta_set host function.
|
||||
func MetaSet(data map[string]any) error {
|
||||
dataBytes, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
func MetaSet(data map[string]any) (*MetaSetResponse, error) {
|
||||
// Marshal request to JSON
|
||||
req := MetaSetRequest{
|
||||
Data: data,
|
||||
}
|
||||
dataMem := pdk.AllocateBytes(dataBytes)
|
||||
defer dataMem.Free()
|
||||
reqBytes, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reqMem := pdk.AllocateBytes(reqBytes)
|
||||
defer reqMem.Free()
|
||||
|
||||
// Call the host function
|
||||
responsePtr := meta_set(dataMem.Offset())
|
||||
responsePtr := meta_set(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response MetaSetResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
49
plugins/cmd/hostgen/testdata/meta_expected.go
vendored
49
plugins/cmd/hostgen/testdata/meta_expected.go
vendored
@ -9,6 +9,11 @@ import (
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// MetaGetRequest is the request type for Meta.Get.
|
||||
type MetaGetRequest struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// MetaGetResponse is the response type for Meta.Get.
|
||||
type MetaGetResponse struct {
|
||||
Value any `json:"value,omitempty"`
|
||||
@ -20,6 +25,11 @@ type MetaSetRequest struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
// MetaSetResponse is the response type for Meta.Set.
|
||||
type MetaSetResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// RegisterMetaHostFunctions registers Meta service host functions.
|
||||
// The returned host functions should be added to the plugin's configuration.
|
||||
func RegisterMetaHostFunctions(service MetaService) []extism.HostFunction {
|
||||
@ -33,18 +43,25 @@ func newMetaGetHostFunction(service MetaService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"meta_get",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
key, err := p.ReadString(stack[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
value, err := service.Get(ctx, key)
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
metaWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req MetaGetRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
metaWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
value, svcErr := service.Get(ctx, req.Key)
|
||||
if svcErr != nil {
|
||||
metaWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := MetaGetResponse{
|
||||
Value: value,
|
||||
@ -73,18 +90,14 @@ func newMetaSetHostFunction(service MetaService) extism.HostFunction {
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
err = service.Set(ctx, req.Data)
|
||||
if err != nil {
|
||||
// Write error string to plugin memory
|
||||
if ptr, err := p.WriteString(err.Error()); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
if svcErr := service.Set(ctx, req.Data); svcErr != nil {
|
||||
metaWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
// Write empty string to indicate success
|
||||
if ptr, err := p.WriteString(""); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := MetaSetResponse{}
|
||||
metaWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/extism/go-pdk"
|
||||
)
|
||||
@ -16,21 +16,31 @@ import (
|
||||
// ping_ping is the host function provided by Navidrome.
|
||||
//
|
||||
//go:wasmimport extism:host/user ping_ping
|
||||
func ping_ping() uint64
|
||||
func ping_ping(uint64) uint64
|
||||
|
||||
// PingPingResponse is the response type for Ping.Ping.
|
||||
type PingPingResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// PingPing calls the ping_ping host function.
|
||||
func PingPing() error {
|
||||
func PingPing() (*PingPingResponse, error) {
|
||||
// No parameters - allocate empty JSON object
|
||||
reqMem := pdk.AllocateBytes([]byte("{}"))
|
||||
defer reqMem.Free()
|
||||
|
||||
// Call the host function
|
||||
responsePtr := ping_ping()
|
||||
responsePtr := ping_ping(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response PingPingResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
49
plugins/cmd/hostgen/testdata/ping_expected.go
vendored
49
plugins/cmd/hostgen/testdata/ping_expected.go
vendored
@ -4,10 +4,16 @@ package testpkg
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// PingPingResponse is the response type for Ping.Ping.
|
||||
type PingPingResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// RegisterPingHostFunctions registers Ping service host functions.
|
||||
// The returned host functions should be added to the plugin's configuration.
|
||||
func RegisterPingHostFunctions(service PingService) []extism.HostFunction {
|
||||
@ -22,20 +28,41 @@ func newPingPingHostFunction(service PingService) extism.HostFunction {
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
|
||||
// Call the service method
|
||||
err := service.Ping(ctx)
|
||||
if err != nil {
|
||||
// Write error string to plugin memory
|
||||
if ptr, err := p.WriteString(err.Error()); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
if svcErr := service.Ping(ctx); svcErr != nil {
|
||||
pingWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
// Write empty string to indicate success
|
||||
if ptr, err := p.WriteString(""); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := PingPingResponse{}
|
||||
pingWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
// pingWriteResponse writes a JSON response to plugin memory.
|
||||
func pingWriteResponse(p *extism.CurrentPlugin, stack []uint64, resp any) {
|
||||
respBytes, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
pingWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
respPtr, err := p.WriteBytes(respBytes)
|
||||
if err != nil {
|
||||
stack[0] = 0
|
||||
return
|
||||
}
|
||||
stack[0] = respPtr
|
||||
}
|
||||
|
||||
// pingWriteError writes an error response to plugin memory.
|
||||
func pingWriteError(p *extism.CurrentPlugin, stack []uint64, err error) {
|
||||
errResp := struct {
|
||||
Error string `json:"error"`
|
||||
}{Error: err.Error()}
|
||||
respBytes, _ := json.Marshal(errResp)
|
||||
respPtr, _ := p.WriteBytes(respBytes)
|
||||
stack[0] = respPtr
|
||||
}
|
||||
|
||||
@ -18,6 +18,11 @@ import (
|
||||
//go:wasmimport extism:host/user search_find
|
||||
func search_find(uint64) uint64
|
||||
|
||||
// SearchFindRequest is the request type for Search.Find.
|
||||
type SearchFindRequest struct {
|
||||
Query string `json:"query"`
|
||||
}
|
||||
|
||||
// SearchFindResponse is the response type for Search.Find.
|
||||
type SearchFindResponse struct {
|
||||
Results []Result `json:"results,omitempty"`
|
||||
@ -27,11 +32,19 @@ type SearchFindResponse struct {
|
||||
|
||||
// SearchFind calls the search_find host function.
|
||||
func SearchFind(query string) (*SearchFindResponse, error) {
|
||||
queryMem := pdk.AllocateString(query)
|
||||
defer queryMem.Free()
|
||||
// Marshal request to JSON
|
||||
req := SearchFindRequest{
|
||||
Query: query,
|
||||
}
|
||||
reqBytes, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reqMem := pdk.AllocateBytes(reqBytes)
|
||||
defer reqMem.Free()
|
||||
|
||||
// Call the host function
|
||||
responsePtr := search_find(queryMem.Offset())
|
||||
responsePtr := search_find(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
|
||||
28
plugins/cmd/hostgen/testdata/search_expected.go
vendored
28
plugins/cmd/hostgen/testdata/search_expected.go
vendored
@ -9,6 +9,11 @@ import (
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// SearchFindRequest is the request type for Search.Find.
|
||||
type SearchFindRequest struct {
|
||||
Query string `json:"query"`
|
||||
}
|
||||
|
||||
// SearchFindResponse is the response type for Search.Find.
|
||||
type SearchFindResponse struct {
|
||||
Results []Result `json:"results,omitempty"`
|
||||
@ -28,18 +33,25 @@ func newSearchFindHostFunction(service SearchService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"search_find",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
query, err := p.ReadString(stack[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
results, total, err := service.Find(ctx, query)
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
searchWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req SearchFindRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
searchWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
results, total, svcErr := service.Find(ctx, req.Query)
|
||||
if svcErr != nil {
|
||||
searchWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := SearchFindResponse{
|
||||
Results: results,
|
||||
|
||||
@ -18,6 +18,11 @@ import (
|
||||
//go:wasmimport extism:host/user store_save
|
||||
func store_save(uint64) uint64
|
||||
|
||||
// StoreSaveRequest is the request type for Store.Save.
|
||||
type StoreSaveRequest struct {
|
||||
Item Item `json:"item"`
|
||||
}
|
||||
|
||||
// StoreSaveResponse is the response type for Store.Save.
|
||||
type StoreSaveResponse struct {
|
||||
Id string `json:"id,omitempty"`
|
||||
@ -26,15 +31,19 @@ type StoreSaveResponse struct {
|
||||
|
||||
// StoreSave calls the store_save host function.
|
||||
func StoreSave(item Item) (*StoreSaveResponse, error) {
|
||||
itemBytes, err := json.Marshal(item)
|
||||
// Marshal request to JSON
|
||||
req := StoreSaveRequest{
|
||||
Item: item,
|
||||
}
|
||||
reqBytes, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
itemMem := pdk.AllocateBytes(itemBytes)
|
||||
defer itemMem.Free()
|
||||
reqMem := pdk.AllocateBytes(reqBytes)
|
||||
defer reqMem.Free()
|
||||
|
||||
// Call the host function
|
||||
responsePtr := store_save(itemMem.Offset())
|
||||
responsePtr := store_save(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
|
||||
@ -45,11 +45,12 @@ func newStoreSaveHostFunction(service StoreService) extism.HostFunction {
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
id, err := service.Save(ctx, req.Item)
|
||||
if err != nil {
|
||||
storeWriteError(p, stack, err)
|
||||
id, svcErr := service.Save(ctx, req.Item)
|
||||
if svcErr != nil {
|
||||
storeWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := StoreSaveResponse{
|
||||
Id: id,
|
||||
|
||||
@ -16,7 +16,13 @@ import (
|
||||
// users_get is the host function provided by Navidrome.
|
||||
//
|
||||
//go:wasmimport extism:host/user users_get
|
||||
func users_get(uint64, uint64) uint64
|
||||
func users_get(uint64) uint64
|
||||
|
||||
// UsersGetRequest is the request type for Users.Get.
|
||||
type UsersGetRequest struct {
|
||||
Id *string `json:"id"`
|
||||
Filter *User `json:"filter"`
|
||||
}
|
||||
|
||||
// UsersGetResponse is the response type for Users.Get.
|
||||
type UsersGetResponse struct {
|
||||
@ -26,21 +32,20 @@ type UsersGetResponse struct {
|
||||
|
||||
// UsersGet calls the users_get host function.
|
||||
func UsersGet(id *string, filter *User) (*UsersGetResponse, error) {
|
||||
idBytes, err := json.Marshal(id)
|
||||
// Marshal request to JSON
|
||||
req := UsersGetRequest{
|
||||
Id: id,
|
||||
Filter: filter,
|
||||
}
|
||||
reqBytes, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idMem := pdk.AllocateBytes(idBytes)
|
||||
defer idMem.Free()
|
||||
filterBytes, err := json.Marshal(filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filterMem := pdk.AllocateBytes(filterBytes)
|
||||
defer filterMem.Free()
|
||||
reqMem := pdk.AllocateBytes(reqBytes)
|
||||
defer reqMem.Free()
|
||||
|
||||
// Call the host function
|
||||
responsePtr := users_get(idMem.Offset(), filterMem.Offset())
|
||||
responsePtr := users_get(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
|
||||
@ -46,11 +46,12 @@ func newUsersGetHostFunction(service UsersService) extism.HostFunction {
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
result, err := service.Get(ctx, req.Id, req.Filter)
|
||||
if err != nil {
|
||||
usersWriteError(p, stack, err)
|
||||
result, svcErr := service.Get(ctx, req.Id, req.Filter)
|
||||
if svcErr != nil {
|
||||
usersWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := UsersGetResponse{
|
||||
Result: result,
|
||||
|
||||
@ -176,11 +176,14 @@ func parseTickerSymbols(tickerConfig string) []string {
|
||||
// connectAndSubscribe connects to Coinbase WebSocket and subscribes to tickers
|
||||
func connectAndSubscribe(tickers []string) error {
|
||||
// Connect to WebSocket using host function
|
||||
connID, err := WebSocketConnect(coinbaseWSEndpoint, nil, connectionID)
|
||||
resp, err := WebSocketConnect(coinbaseWSEndpoint, nil, connectionID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("WebSocket connection error: %v", err)
|
||||
}
|
||||
pdk.Log(pdk.LogInfo, fmt.Sprintf("Connected to Coinbase WebSocket API (connection: %s)", connID))
|
||||
if resp.Error != "" {
|
||||
return fmt.Errorf("WebSocket connection error: %s", resp.Error)
|
||||
}
|
||||
pdk.Log(pdk.LogInfo, fmt.Sprintf("Connected to Coinbase WebSocket API (connection: %s)", resp.NewConnectionID))
|
||||
|
||||
// Subscribe to ticker channel
|
||||
subscription := CoinbaseSubscription{
|
||||
@ -195,10 +198,13 @@ func connectAndSubscribe(tickers []string) error {
|
||||
}
|
||||
|
||||
// Send subscription message
|
||||
err = WebSocketSendText(connectionID, string(subscriptionJSON))
|
||||
sendResp, err := WebSocketSendText(connectionID, string(subscriptionJSON))
|
||||
if err != nil {
|
||||
return fmt.Errorf("WebSocket send error: %v", err)
|
||||
}
|
||||
if sendResp.Error != "" {
|
||||
return fmt.Errorf("WebSocket send error: %s", sendResp.Error)
|
||||
}
|
||||
|
||||
pdk.Log(pdk.LogInfo, "Subscription message sent to Coinbase WebSocket API")
|
||||
return nil
|
||||
@ -266,9 +272,11 @@ func NdWebsocketOnClose(input OnCloseInput) (OnCloseOutput, error) {
|
||||
pdk.Log(pdk.LogInfo, "Scheduling reconnection attempt in 5 seconds...")
|
||||
|
||||
// Schedule a one-time reconnection attempt
|
||||
_, err := SchedulerScheduleOneTime(5, "reconnect", reconnectScheduleID)
|
||||
resp, err := SchedulerScheduleOneTime(5, "reconnect", reconnectScheduleID)
|
||||
if err != nil {
|
||||
pdk.Log(pdk.LogError, fmt.Sprintf("Failed to schedule reconnection: %v", err))
|
||||
} else if resp.Error != "" {
|
||||
pdk.Log(pdk.LogError, fmt.Sprintf("Failed to schedule reconnection: %s", resp.Error))
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,9 +325,11 @@ func ndSchedulerCallback() int32 {
|
||||
pdk.Log(pdk.LogError, fmt.Sprintf("Reconnection failed: %v - will retry in 10 seconds", err))
|
||||
|
||||
// Schedule another attempt
|
||||
_, err = SchedulerScheduleOneTime(10, "reconnect", reconnectScheduleID)
|
||||
resp, err := SchedulerScheduleOneTime(10, "reconnect", reconnectScheduleID)
|
||||
if err != nil {
|
||||
pdk.Log(pdk.LogError, fmt.Sprintf("Failed to schedule retry: %v", err))
|
||||
} else if resp.Error != "" {
|
||||
pdk.Log(pdk.LogError, fmt.Sprintf("Failed to schedule retry: %s", resp.Error))
|
||||
}
|
||||
} else {
|
||||
pdk.Log(pdk.LogInfo, "Successfully reconnected!")
|
||||
|
||||
@ -1,188 +0,0 @@
|
||||
// Host function wrappers for Navidrome plugin services.
|
||||
// These allow the plugin to call host functions provided by Navidrome.
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
pdk "github.com/extism/go-pdk"
|
||||
)
|
||||
|
||||
// WebSocket host functions
|
||||
|
||||
//go:wasmimport extism:host/user websocket_connect
|
||||
func websocket_connect(uint64) uint64
|
||||
|
||||
//go:wasmimport extism:host/user websocket_sendtext
|
||||
func websocket_sendtext(connectionID uint64, message uint64) uint64
|
||||
|
||||
//go:wasmimport extism:host/user websocket_closeconnection
|
||||
func websocket_closeconnection(connectionID uint64, code int32, reason uint64) uint64
|
||||
|
||||
// WebSocketConnectRequest is the request type for WebSocket.Connect
|
||||
type WebSocketConnectRequest struct {
|
||||
Url string `json:"url"`
|
||||
Headers map[string]string `json:"headers,omitempty"`
|
||||
ConnectionID string `json:"connectionID,omitempty"`
|
||||
}
|
||||
|
||||
// WebSocketConnectResponse is the response type for WebSocket.Connect
|
||||
type WebSocketConnectResponse struct {
|
||||
NewConnectionID string `json:"newConnectionID,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// WebSocketConnect establishes a WebSocket connection to the specified URL.
|
||||
func WebSocketConnect(url string, headers map[string]string, connectionID string) (string, error) {
|
||||
req := WebSocketConnectRequest{
|
||||
Url: url,
|
||||
Headers: headers,
|
||||
ConnectionID: connectionID,
|
||||
}
|
||||
reqBytes, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
reqMem := pdk.AllocateBytes(reqBytes)
|
||||
defer reqMem.Free()
|
||||
|
||||
responsePtr := websocket_connect(reqMem.Offset())
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
var resp WebSocketConnectResponse
|
||||
if err := json.Unmarshal(responseBytes, &resp); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if resp.Error != "" {
|
||||
return "", errors.New(resp.Error)
|
||||
}
|
||||
|
||||
return resp.NewConnectionID, nil
|
||||
}
|
||||
|
||||
// WebSocketSendText sends a text message over an established WebSocket connection.
|
||||
func WebSocketSendText(connectionID, message string) error {
|
||||
connMem := pdk.AllocateString(connectionID)
|
||||
defer connMem.Free()
|
||||
msgMem := pdk.AllocateString(message)
|
||||
defer msgMem.Free()
|
||||
|
||||
responsePtr := websocket_sendtext(connMem.Offset(), msgMem.Offset())
|
||||
if responsePtr != 0 {
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WebSocketCloseConnection gracefully closes a WebSocket connection.
|
||||
func WebSocketCloseConnection(connectionID string, code int32, reason string) error {
|
||||
connMem := pdk.AllocateString(connectionID)
|
||||
defer connMem.Free()
|
||||
reasonMem := pdk.AllocateString(reason)
|
||||
defer reasonMem.Free()
|
||||
|
||||
responsePtr := websocket_closeconnection(connMem.Offset(), code, reasonMem.Offset())
|
||||
if responsePtr != 0 {
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Scheduler host functions
|
||||
|
||||
//go:wasmimport extism:host/user scheduler_scheduleonetime
|
||||
func scheduler_scheduleonetime(delaySeconds int32, payload uint64, scheduleID uint64) uint64
|
||||
|
||||
//go:wasmimport extism:host/user scheduler_schedulerecurring
|
||||
func scheduler_schedulerecurring(cronExpression uint64, payload uint64, scheduleID uint64) uint64
|
||||
|
||||
//go:wasmimport extism:host/user scheduler_cancelschedule
|
||||
func scheduler_cancelschedule(scheduleID uint64) uint64
|
||||
|
||||
// SchedulerScheduleOneTimeResponse is the response type for Scheduler.ScheduleOneTime
|
||||
type SchedulerScheduleOneTimeResponse struct {
|
||||
NewScheduleID string `json:"newScheduleID,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// SchedulerScheduleRecurringResponse is the response type for Scheduler.ScheduleRecurring
|
||||
type SchedulerScheduleRecurringResponse struct {
|
||||
NewScheduleID string `json:"newScheduleID,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// SchedulerScheduleOneTime schedules a one-time task to run after delaySeconds.
|
||||
func SchedulerScheduleOneTime(delaySeconds int32, payload, scheduleID string) (string, error) {
|
||||
payloadMem := pdk.AllocateString(payload)
|
||||
defer payloadMem.Free()
|
||||
scheduleIDMem := pdk.AllocateString(scheduleID)
|
||||
defer scheduleIDMem.Free()
|
||||
|
||||
responsePtr := scheduler_scheduleonetime(delaySeconds, payloadMem.Offset(), scheduleIDMem.Offset())
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
var resp SchedulerScheduleOneTimeResponse
|
||||
if err := json.Unmarshal(responseBytes, &resp); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if resp.Error != "" {
|
||||
return "", errors.New(resp.Error)
|
||||
}
|
||||
|
||||
return resp.NewScheduleID, nil
|
||||
}
|
||||
|
||||
// SchedulerScheduleRecurring schedules a recurring task using a cron expression.
|
||||
func SchedulerScheduleRecurring(cronExpression, payload, scheduleID string) (string, error) {
|
||||
cronMem := pdk.AllocateString(cronExpression)
|
||||
defer cronMem.Free()
|
||||
payloadMem := pdk.AllocateString(payload)
|
||||
defer payloadMem.Free()
|
||||
scheduleIDMem := pdk.AllocateString(scheduleID)
|
||||
defer scheduleIDMem.Free()
|
||||
|
||||
responsePtr := scheduler_schedulerecurring(cronMem.Offset(), payloadMem.Offset(), scheduleIDMem.Offset())
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
var resp SchedulerScheduleRecurringResponse
|
||||
if err := json.Unmarshal(responseBytes, &resp); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if resp.Error != "" {
|
||||
return "", errors.New(resp.Error)
|
||||
}
|
||||
|
||||
return resp.NewScheduleID, nil
|
||||
}
|
||||
|
||||
// SchedulerCancelSchedule cancels a scheduled task.
|
||||
func SchedulerCancelSchedule(scheduleID string) error {
|
||||
scheduleIDMem := pdk.AllocateString(scheduleID)
|
||||
defer scheduleIDMem.Free()
|
||||
|
||||
responsePtr := scheduler_cancelschedule(scheduleIDMem.Offset())
|
||||
if responsePtr != 0 {
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
180
plugins/examples/crypto-ticker/nd_host_scheduler.go
Normal file
180
plugins/examples/crypto-ticker/nd_host_scheduler.go
Normal file
@ -0,0 +1,180 @@
|
||||
// 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 TinyGo.
|
||||
//
|
||||
//go:build wasip1
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
}
|
||||
237
plugins/examples/crypto-ticker/nd_host_websocket.go
Normal file
237
plugins/examples/crypto-ticker/nd_host_websocket.go
Normal file
@ -0,0 +1,237 @@
|
||||
// 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 TinyGo.
|
||||
//
|
||||
//go:build wasip1
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
}
|
||||
@ -181,7 +181,7 @@ func NdScrobblerNowPlaying(input NowPlayingInput) (ScrobblerOutput, error) {
|
||||
}
|
||||
|
||||
// Cancel any existing completion schedule
|
||||
_ = SchedulerCancelSchedule(fmt.Sprintf("%s-clear", input.Username))
|
||||
_, _ = SchedulerCancelSchedule(fmt.Sprintf("%s-clear", input.Username))
|
||||
|
||||
// Calculate timestamps
|
||||
now := time.Now().Unix()
|
||||
|
||||
@ -16,22 +16,28 @@ import (
|
||||
// artwork_getartisturl is the host function provided by Navidrome.
|
||||
//
|
||||
//go:wasmimport extism:host/user artwork_getartisturl
|
||||
func artwork_getartisturl(uint64, int32) uint64
|
||||
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, int32) uint64
|
||||
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, int32) uint64
|
||||
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, int32) uint64
|
||||
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 {
|
||||
@ -39,18 +45,36 @@ type ArtworkGetArtistUrlResponse struct {
|
||||
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"`
|
||||
@ -66,11 +90,20 @@ type ArtworkGetPlaylistUrlResponse struct {
|
||||
//
|
||||
// Returns the public URL for the artwork, or an error if generation fails.
|
||||
func ArtworkGetArtistUrl(id string, size int32) (*ArtworkGetArtistUrlResponse, error) {
|
||||
idMem := pdk.AllocateString(id)
|
||||
defer idMem.Free()
|
||||
// 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(idMem.Offset(), size)
|
||||
responsePtr := artwork_getartisturl(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -94,11 +127,20 @@ func ArtworkGetArtistUrl(id string, size int32) (*ArtworkGetArtistUrlResponse, e
|
||||
//
|
||||
// Returns the public URL for the artwork, or an error if generation fails.
|
||||
func ArtworkGetAlbumUrl(id string, size int32) (*ArtworkGetAlbumUrlResponse, error) {
|
||||
idMem := pdk.AllocateString(id)
|
||||
defer idMem.Free()
|
||||
// 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(idMem.Offset(), size)
|
||||
responsePtr := artwork_getalbumurl(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -122,11 +164,20 @@ func ArtworkGetAlbumUrl(id string, size int32) (*ArtworkGetAlbumUrlResponse, err
|
||||
//
|
||||
// Returns the public URL for the artwork, or an error if generation fails.
|
||||
func ArtworkGetTrackUrl(id string, size int32) (*ArtworkGetTrackUrlResponse, error) {
|
||||
idMem := pdk.AllocateString(id)
|
||||
defer idMem.Free()
|
||||
// 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(idMem.Offset(), size)
|
||||
responsePtr := artwork_gettrackurl(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -150,11 +201,20 @@ func ArtworkGetTrackUrl(id string, size int32) (*ArtworkGetTrackUrlResponse, err
|
||||
//
|
||||
// Returns the public URL for the artwork, or an error if generation fails.
|
||||
func ArtworkGetPlaylistUrl(id string, size int32) (*ArtworkGetPlaylistUrlResponse, error) {
|
||||
idMem := pdk.AllocateString(id)
|
||||
defer idMem.Free()
|
||||
// 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(idMem.Offset(), size)
|
||||
responsePtr := artwork_getplaylisturl(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
|
||||
@ -9,7 +9,6 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/extism/go-pdk"
|
||||
)
|
||||
@ -17,7 +16,7 @@ import (
|
||||
// cache_setstring is the host function provided by Navidrome.
|
||||
//
|
||||
//go:wasmimport extism:host/user cache_setstring
|
||||
func cache_setstring(uint64, uint64, int64) uint64
|
||||
func cache_setstring(uint64) uint64
|
||||
|
||||
// cache_getstring is the host function provided by Navidrome.
|
||||
//
|
||||
@ -27,7 +26,7 @@ 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, int64, int64) uint64
|
||||
func cache_setint(uint64) uint64
|
||||
|
||||
// cache_getint is the host function provided by Navidrome.
|
||||
//
|
||||
@ -37,7 +36,7 @@ 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, float64, int64) uint64
|
||||
func cache_setfloat(uint64) uint64
|
||||
|
||||
// cache_getfloat is the host function provided by Navidrome.
|
||||
//
|
||||
@ -47,7 +46,7 @@ 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, int64) uint64
|
||||
func cache_setbytes(uint64) uint64
|
||||
|
||||
// cache_getbytes is the host function provided by Navidrome.
|
||||
//
|
||||
@ -64,6 +63,23 @@ func cache_has(uint64) uint64
|
||||
//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"`
|
||||
@ -71,6 +87,23 @@ type CacheGetStringResponse struct {
|
||||
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"`
|
||||
@ -78,6 +111,23 @@ type CacheGetIntResponse struct {
|
||||
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"`
|
||||
@ -85,6 +135,23 @@ type CacheGetFloatResponse struct {
|
||||
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"`
|
||||
@ -92,12 +159,27 @@ type CacheGetBytesResponse struct {
|
||||
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.
|
||||
//
|
||||
@ -107,24 +189,34 @@ type CacheHasResponse struct {
|
||||
// - 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) error {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
valueMem := pdk.AllocateString(value)
|
||||
defer valueMem.Free()
|
||||
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(keyMem.Offset(), valueMem.Offset(), ttlSeconds)
|
||||
responsePtr := cache_setstring(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response CacheSetStringResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// CacheGetString calls the cache_getstring host function.
|
||||
@ -136,11 +228,19 @@ func CacheSetString(key string, value string, ttlSeconds int64) error {
|
||||
// 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) {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
// 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(keyMem.Offset())
|
||||
responsePtr := cache_getstring(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -164,22 +264,34 @@ func CacheGetString(key string) (*CacheGetStringResponse, error) {
|
||||
// - 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) error {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
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(keyMem.Offset(), value, ttlSeconds)
|
||||
responsePtr := cache_setint(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response CacheSetIntResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// CacheGetInt calls the cache_getint host function.
|
||||
@ -191,11 +303,19 @@ func CacheSetInt(key string, value int64, ttlSeconds int64) error {
|
||||
// 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) {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
// 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(keyMem.Offset())
|
||||
responsePtr := cache_getint(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -219,22 +339,34 @@ func CacheGetInt(key string) (*CacheGetIntResponse, error) {
|
||||
// - 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) error {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
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(keyMem.Offset(), value, ttlSeconds)
|
||||
responsePtr := cache_setfloat(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response CacheSetFloatResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// CacheGetFloat calls the cache_getfloat host function.
|
||||
@ -246,11 +378,19 @@ func CacheSetFloat(key string, value float64, ttlSeconds int64) error {
|
||||
// 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) {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
// 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(keyMem.Offset())
|
||||
responsePtr := cache_getfloat(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -274,24 +414,34 @@ func CacheGetFloat(key string) (*CacheGetFloatResponse, error) {
|
||||
// - 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) error {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
valueMem := pdk.AllocateBytes(value)
|
||||
defer valueMem.Free()
|
||||
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(keyMem.Offset(), valueMem.Offset(), ttlSeconds)
|
||||
responsePtr := cache_setbytes(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response CacheSetBytesResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// CacheGetBytes calls the cache_getbytes host function.
|
||||
@ -303,11 +453,19 @@ func CacheSetBytes(key string, value []byte, ttlSeconds int64) error {
|
||||
// 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) {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
// 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(keyMem.Offset())
|
||||
responsePtr := cache_getbytes(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -330,11 +488,19 @@ func CacheGetBytes(key string) (*CacheGetBytesResponse, error) {
|
||||
//
|
||||
// Returns true if the key exists and has not expired.
|
||||
func CacheHas(key string) (*CacheHasResponse, error) {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
// 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(keyMem.Offset())
|
||||
responsePtr := cache_has(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -356,20 +522,30 @@ func CacheHas(key string) (*CacheHasResponse, error) {
|
||||
// - 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) error {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
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(keyMem.Offset())
|
||||
responsePtr := cache_remove(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response CacheRemoveResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
@ -9,7 +9,6 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/extism/go-pdk"
|
||||
)
|
||||
@ -17,30 +16,54 @@ import (
|
||||
// scheduler_scheduleonetime is the host function provided by Navidrome.
|
||||
//
|
||||
//go:wasmimport extism:host/user scheduler_scheduleonetime
|
||||
func scheduler_scheduleonetime(int32, uint64, uint64) uint64
|
||||
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, uint64) uint64
|
||||
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
|
||||
@ -52,13 +75,21 @@ type SchedulerScheduleRecurringResponse struct {
|
||||
//
|
||||
// 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) {
|
||||
payloadMem := pdk.AllocateString(payload)
|
||||
defer payloadMem.Free()
|
||||
scheduleIDMem := pdk.AllocateString(scheduleID)
|
||||
defer scheduleIDMem.Free()
|
||||
// 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(delaySeconds, payloadMem.Offset(), scheduleIDMem.Offset())
|
||||
responsePtr := scheduler_scheduleonetime(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -84,15 +115,21 @@ func SchedulerScheduleOneTime(delaySeconds int32, payload string, scheduleID str
|
||||
//
|
||||
// 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) {
|
||||
cronExpressionMem := pdk.AllocateString(cronExpression)
|
||||
defer cronExpressionMem.Free()
|
||||
payloadMem := pdk.AllocateString(payload)
|
||||
defer payloadMem.Free()
|
||||
scheduleIDMem := pdk.AllocateString(scheduleID)
|
||||
defer scheduleIDMem.Free()
|
||||
// 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(cronExpressionMem.Offset(), payloadMem.Offset(), scheduleIDMem.Offset())
|
||||
responsePtr := scheduler_schedulerecurring(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -114,20 +151,30 @@ func SchedulerScheduleRecurring(cronExpression string, payload string, scheduleI
|
||||
// any future events.
|
||||
//
|
||||
// Returns an error if the schedule ID is not found or if cancellation fails.
|
||||
func SchedulerCancelSchedule(scheduleID string) error {
|
||||
scheduleIDMem := pdk.AllocateString(scheduleID)
|
||||
defer scheduleIDMem.Free()
|
||||
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(scheduleIDMem.Offset())
|
||||
responsePtr := scheduler_cancelschedule(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response SchedulerCancelScheduleResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
@ -9,13 +9,11 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/extism/go-pdk"
|
||||
)
|
||||
|
||||
// websocket_connect is the host function provided by Navidrome.
|
||||
// Takes a single JSON request pointer containing url, headers, and connectionID.
|
||||
//
|
||||
//go:wasmimport extism:host/user websocket_connect
|
||||
func websocket_connect(uint64) uint64
|
||||
@ -23,17 +21,17 @@ 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) uint64
|
||||
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) uint64
|
||||
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, int32, uint64) uint64
|
||||
func websocket_closeconnection(uint64) uint64
|
||||
|
||||
// WebSocketConnectRequest is the request type for WebSocket.Connect.
|
||||
type WebSocketConnectRequest struct {
|
||||
@ -48,6 +46,40 @@ type WebSocketConnectResponse struct {
|
||||
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.
|
||||
//
|
||||
@ -62,7 +94,7 @@ type WebSocketConnectResponse struct {
|
||||
// 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) {
|
||||
// Create JSON request with all parameters
|
||||
// Marshal request to JSON
|
||||
req := WebSocketConnectRequest{
|
||||
Url: url,
|
||||
Headers: headers,
|
||||
@ -75,7 +107,7 @@ func WebSocketConnect(url string, headers map[string]string, connectionID string
|
||||
reqMem := pdk.AllocateBytes(reqBytes)
|
||||
defer reqMem.Free()
|
||||
|
||||
// Call the host function with single JSON request
|
||||
// Call the host function
|
||||
responsePtr := websocket_connect(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
@ -99,24 +131,33 @@ func WebSocketConnect(url string, headers map[string]string, connectionID string
|
||||
// - 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) error {
|
||||
connectionIDMem := pdk.AllocateString(connectionID)
|
||||
defer connectionIDMem.Free()
|
||||
messageMem := pdk.AllocateString(message)
|
||||
defer messageMem.Free()
|
||||
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(connectionIDMem.Offset(), messageMem.Offset())
|
||||
responsePtr := websocket_sendtext(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response WebSocketSendTextResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// WebSocketSendBinary calls the websocket_sendbinary host function.
|
||||
@ -127,24 +168,33 @@ func WebSocketSendText(connectionID string, message string) error {
|
||||
// - 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) error {
|
||||
connectionIDMem := pdk.AllocateString(connectionID)
|
||||
defer connectionIDMem.Free()
|
||||
dataMem := pdk.AllocateBytes(data)
|
||||
defer dataMem.Free()
|
||||
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(connectionIDMem.Offset(), dataMem.Offset())
|
||||
responsePtr := websocket_sendbinary(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response WebSocketSendBinaryResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// WebSocketCloseConnection calls the websocket_closeconnection host function.
|
||||
@ -156,22 +206,32 @@ func WebSocketSendBinary(connectionID string, data []byte) error {
|
||||
// - 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) error {
|
||||
connectionIDMem := pdk.AllocateString(connectionID)
|
||||
defer connectionIDMem.Free()
|
||||
reasonMem := pdk.AllocateString(reason)
|
||||
defer reasonMem.Free()
|
||||
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(connectionIDMem.Offset(), code, reasonMem.Offset())
|
||||
responsePtr := websocket_closeconnection(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response WebSocketCloseConnectionResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ func processImage(imageURL, clientID, token string, isDefaultImage bool) (string
|
||||
ttl = 48 * 60 * 60 // 48 hours for default image
|
||||
}
|
||||
|
||||
_ = CacheSetString(cacheKey, processedImage, ttl)
|
||||
_, _ = CacheSetString(cacheKey, processedImage, ttl)
|
||||
pdk.Log(pdk.LogDebug, fmt.Sprintf("Cached processed image URL for %s (TTL: %ds)", imageURL, ttl))
|
||||
|
||||
return processedImage, nil
|
||||
@ -183,9 +183,13 @@ func sendMessage(username string, opCode int, payload any) error {
|
||||
return fmt.Errorf("failed to marshal message: %w", err)
|
||||
}
|
||||
|
||||
if err := WebSocketSendText(username, string(b)); err != nil {
|
||||
resp, err := WebSocketSendText(username, string(b))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send message: %w", err)
|
||||
}
|
||||
if resp.Error != "" {
|
||||
return fmt.Errorf("failed to send message: %s", resp.Error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -220,17 +224,21 @@ func cleanupFailedConnection(username string) {
|
||||
pdk.Log(pdk.LogInfo, fmt.Sprintf("Cleaning up failed connection for user %s", username))
|
||||
|
||||
// Cancel the heartbeat schedule
|
||||
if err := SchedulerCancelSchedule(username); err != nil {
|
||||
if resp, err := SchedulerCancelSchedule(username); err != nil {
|
||||
pdk.Log(pdk.LogWarn, fmt.Sprintf("Failed to cancel heartbeat schedule for user %s: %v", username, err))
|
||||
} else if resp.Error != "" {
|
||||
pdk.Log(pdk.LogWarn, fmt.Sprintf("Failed to cancel heartbeat schedule for user %s: %s", username, resp.Error))
|
||||
}
|
||||
|
||||
// Close the WebSocket connection
|
||||
if err := WebSocketCloseConnection(username, 1000, "Connection lost"); err != nil {
|
||||
if resp, err := WebSocketCloseConnection(username, 1000, "Connection lost"); err != nil {
|
||||
pdk.Log(pdk.LogWarn, fmt.Sprintf("Failed to close WebSocket connection for user %s: %v", username, err))
|
||||
} else if resp.Error != "" {
|
||||
pdk.Log(pdk.LogWarn, fmt.Sprintf("Failed to close WebSocket connection for user %s: %s", username, resp.Error))
|
||||
}
|
||||
|
||||
// Clean up cache entries
|
||||
_ = CacheRemove(fmt.Sprintf("discord.seq.%s", username))
|
||||
_, _ = CacheRemove(fmt.Sprintf("discord.seq.%s", username))
|
||||
|
||||
pdk.Log(pdk.LogInfo, fmt.Sprintf("Cleaned up connection for user %s", username))
|
||||
}
|
||||
@ -297,12 +305,16 @@ func connect(username, token string) error {
|
||||
|
||||
// disconnect closes the Discord connection for a user.
|
||||
func disconnect(username string) error {
|
||||
if err := SchedulerCancelSchedule(username); err != nil {
|
||||
if resp, err := SchedulerCancelSchedule(username); err != nil {
|
||||
return fmt.Errorf("failed to cancel schedule: %w", err)
|
||||
} else if resp.Error != "" {
|
||||
return fmt.Errorf("failed to cancel schedule: %s", resp.Error)
|
||||
}
|
||||
|
||||
if err := WebSocketCloseConnection(username, 1000, "Navidrome disconnect"); err != nil {
|
||||
if resp, err := WebSocketCloseConnection(username, 1000, "Navidrome disconnect"); err != nil {
|
||||
return fmt.Errorf("failed to close WebSocket connection: %w", err)
|
||||
} else if resp.Error != "" {
|
||||
return fmt.Errorf("failed to close WebSocket connection: %s", resp.Error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -325,8 +337,10 @@ func handleWebSocketMessage(connectionID, message string) error {
|
||||
if v := msg["s"]; v != nil {
|
||||
seq := int64(v.(float64))
|
||||
pdk.Log(pdk.LogTrace, fmt.Sprintf("Received sequence number for connection '%s': %d", connectionID, seq))
|
||||
if err := CacheSetInt(fmt.Sprintf("discord.seq.%s", connectionID), seq, int64(heartbeatInterval*2)); err != nil {
|
||||
if resp, err := CacheSetInt(fmt.Sprintf("discord.seq.%s", connectionID), seq, int64(heartbeatInterval*2)); err != nil {
|
||||
return fmt.Errorf("failed to store sequence number for user %s: %w", connectionID, err)
|
||||
} else if resp.Error != "" {
|
||||
return fmt.Errorf("failed to store sequence number for user %s: %s", connectionID, resp.Error)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@ -9,24 +9,48 @@ import (
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// ArtworkGetArtistUrlRequest is the request type for Artwork.GetArtistUrl.
|
||||
type ArtworkGetArtistUrlRequest struct {
|
||||
Id string `json:"id"`
|
||||
Size int32 `json:"size"`
|
||||
}
|
||||
|
||||
// ArtworkGetArtistUrlResponse is the response type for Artwork.GetArtistUrl.
|
||||
type ArtworkGetArtistUrlResponse struct {
|
||||
Url string `json:"url,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// ArtworkGetAlbumUrlRequest is the request type for Artwork.GetAlbumUrl.
|
||||
type ArtworkGetAlbumUrlRequest struct {
|
||||
Id string `json:"id"`
|
||||
Size int32 `json:"size"`
|
||||
}
|
||||
|
||||
// ArtworkGetAlbumUrlResponse is the response type for Artwork.GetAlbumUrl.
|
||||
type ArtworkGetAlbumUrlResponse struct {
|
||||
Url string `json:"url,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// ArtworkGetTrackUrlRequest is the request type for Artwork.GetTrackUrl.
|
||||
type ArtworkGetTrackUrlRequest struct {
|
||||
Id string `json:"id"`
|
||||
Size int32 `json:"size"`
|
||||
}
|
||||
|
||||
// ArtworkGetTrackUrlResponse is the response type for Artwork.GetTrackUrl.
|
||||
type ArtworkGetTrackUrlResponse struct {
|
||||
Url string `json:"url,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// ArtworkGetPlaylistUrlRequest is the request type for Artwork.GetPlaylistUrl.
|
||||
type ArtworkGetPlaylistUrlRequest struct {
|
||||
Id string `json:"id"`
|
||||
Size int32 `json:"size"`
|
||||
}
|
||||
|
||||
// ArtworkGetPlaylistUrlResponse is the response type for Artwork.GetPlaylistUrl.
|
||||
type ArtworkGetPlaylistUrlResponse struct {
|
||||
Url string `json:"url,omitempty"`
|
||||
@ -48,26 +72,32 @@ func newArtworkGetArtistUrlHostFunction(service ArtworkService) extism.HostFunct
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"artwork_getartisturl",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
id, err := p.ReadString(stack[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
size := extism.DecodeI32(stack[1])
|
||||
|
||||
// Call the service method
|
||||
url, err := service.GetArtistUrl(ctx, id, size)
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
artworkWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req ArtworkGetArtistUrlRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
artworkWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
url, svcErr := service.GetArtistUrl(ctx, req.Id, req.Size)
|
||||
if svcErr != nil {
|
||||
artworkWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := ArtworkGetArtistUrlResponse{
|
||||
Url: url,
|
||||
}
|
||||
artworkWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR, extism.ValueTypeI32},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
@ -76,26 +106,32 @@ func newArtworkGetAlbumUrlHostFunction(service ArtworkService) extism.HostFuncti
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"artwork_getalbumurl",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
id, err := p.ReadString(stack[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
size := extism.DecodeI32(stack[1])
|
||||
|
||||
// Call the service method
|
||||
url, err := service.GetAlbumUrl(ctx, id, size)
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
artworkWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req ArtworkGetAlbumUrlRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
artworkWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
url, svcErr := service.GetAlbumUrl(ctx, req.Id, req.Size)
|
||||
if svcErr != nil {
|
||||
artworkWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := ArtworkGetAlbumUrlResponse{
|
||||
Url: url,
|
||||
}
|
||||
artworkWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR, extism.ValueTypeI32},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
@ -104,26 +140,32 @@ func newArtworkGetTrackUrlHostFunction(service ArtworkService) extism.HostFuncti
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"artwork_gettrackurl",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
id, err := p.ReadString(stack[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
size := extism.DecodeI32(stack[1])
|
||||
|
||||
// Call the service method
|
||||
url, err := service.GetTrackUrl(ctx, id, size)
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
artworkWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req ArtworkGetTrackUrlRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
artworkWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
url, svcErr := service.GetTrackUrl(ctx, req.Id, req.Size)
|
||||
if svcErr != nil {
|
||||
artworkWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := ArtworkGetTrackUrlResponse{
|
||||
Url: url,
|
||||
}
|
||||
artworkWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR, extism.ValueTypeI32},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
@ -132,26 +174,32 @@ func newArtworkGetPlaylistUrlHostFunction(service ArtworkService) extism.HostFun
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"artwork_getplaylisturl",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
id, err := p.ReadString(stack[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
size := extism.DecodeI32(stack[1])
|
||||
|
||||
// Call the service method
|
||||
url, err := service.GetPlaylistUrl(ctx, id, size)
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
artworkWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req ArtworkGetPlaylistUrlRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
artworkWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
url, svcErr := service.GetPlaylistUrl(ctx, req.Id, req.Size)
|
||||
if svcErr != nil {
|
||||
artworkWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := ArtworkGetPlaylistUrlResponse{
|
||||
Url: url,
|
||||
}
|
||||
artworkWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR, extism.ValueTypeI32},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
@ -9,6 +9,23 @@ import (
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// CacheSetStringRequest is the request type for Cache.SetString.
|
||||
type CacheSetStringRequest struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
TtlSeconds int64 `json:"ttlSeconds"`
|
||||
}
|
||||
|
||||
// CacheSetStringResponse is the response type for Cache.SetString.
|
||||
type CacheSetStringResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// CacheGetStringRequest is the request type for Cache.GetString.
|
||||
type CacheGetStringRequest struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// CacheGetStringResponse is the response type for Cache.GetString.
|
||||
type CacheGetStringResponse struct {
|
||||
Value string `json:"value,omitempty"`
|
||||
@ -16,6 +33,23 @@ type CacheGetStringResponse struct {
|
||||
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"`
|
||||
@ -23,6 +57,23 @@ type CacheGetIntResponse struct {
|
||||
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"`
|
||||
@ -30,6 +81,23 @@ type CacheGetFloatResponse struct {
|
||||
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"`
|
||||
@ -37,12 +105,27 @@ type CacheGetBytesResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// CacheHasRequest is the request type for Cache.Has.
|
||||
type CacheHasRequest struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// CacheHasResponse is the response type for Cache.Has.
|
||||
type CacheHasResponse struct {
|
||||
Exists bool `json:"exists,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// CacheRemoveRequest is the request type for Cache.Remove.
|
||||
type CacheRemoveRequest struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// CacheRemoveResponse is the response type for Cache.Remove.
|
||||
type CacheRemoveResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// RegisterCacheHostFunctions registers Cache service host functions.
|
||||
// The returned host functions should be added to the plugin's configuration.
|
||||
func RegisterCacheHostFunctions(service CacheService) []extism.HostFunction {
|
||||
@ -64,32 +147,29 @@ func newCacheSetStringHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_setstring",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
key, err := p.ReadString(stack[0])
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
value, err := p.ReadString(stack[1])
|
||||
if err != nil {
|
||||
var req CacheSetStringRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
ttlSeconds := int64(stack[2])
|
||||
|
||||
// Call the service method
|
||||
err = service.SetString(ctx, key, value, ttlSeconds)
|
||||
if err != nil {
|
||||
// Write error string to plugin memory
|
||||
if ptr, err := p.WriteString(err.Error()); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
if svcErr := service.SetString(ctx, req.Key, req.Value, req.TtlSeconds); svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
// Write empty string to indicate success
|
||||
if ptr, err := p.WriteString(""); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheSetStringResponse{}
|
||||
cacheWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR, extism.ValueTypePTR, extism.ValueTypeI64},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
@ -98,18 +178,25 @@ func newCacheGetStringHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_getstring",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
key, err := p.ReadString(stack[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
value, exists, err := service.GetString(ctx, key)
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CacheGetStringRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
value, exists, svcErr := service.GetString(ctx, req.Key)
|
||||
if svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheGetStringResponse{
|
||||
Value: value,
|
||||
@ -126,29 +213,29 @@ func newCacheSetIntHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_setint",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
key, err := p.ReadString(stack[0])
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CacheSetIntRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
value := int64(stack[1])
|
||||
ttlSeconds := int64(stack[2])
|
||||
|
||||
// Call the service method
|
||||
err = service.SetInt(ctx, key, value, ttlSeconds)
|
||||
if err != nil {
|
||||
// Write error string to plugin memory
|
||||
if ptr, err := p.WriteString(err.Error()); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
if svcErr := service.SetInt(ctx, req.Key, req.Value, req.TtlSeconds); svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
// Write empty string to indicate success
|
||||
if ptr, err := p.WriteString(""); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheSetIntResponse{}
|
||||
cacheWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR, extism.ValueTypeI64, extism.ValueTypeI64},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
@ -157,18 +244,25 @@ func newCacheGetIntHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_getint",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
key, err := p.ReadString(stack[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
value, exists, err := service.GetInt(ctx, key)
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CacheGetIntRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
value, exists, svcErr := service.GetInt(ctx, req.Key)
|
||||
if svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheGetIntResponse{
|
||||
Value: value,
|
||||
@ -185,29 +279,29 @@ func newCacheSetFloatHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_setfloat",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
key, err := p.ReadString(stack[0])
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CacheSetFloatRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
value := extism.DecodeF64(stack[1])
|
||||
ttlSeconds := int64(stack[2])
|
||||
|
||||
// Call the service method
|
||||
err = service.SetFloat(ctx, key, value, ttlSeconds)
|
||||
if err != nil {
|
||||
// Write error string to plugin memory
|
||||
if ptr, err := p.WriteString(err.Error()); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
if svcErr := service.SetFloat(ctx, req.Key, req.Value, req.TtlSeconds); svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
// Write empty string to indicate success
|
||||
if ptr, err := p.WriteString(""); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheSetFloatResponse{}
|
||||
cacheWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR, extism.ValueTypeF64, extism.ValueTypeI64},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
@ -216,18 +310,25 @@ func newCacheGetFloatHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_getfloat",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
key, err := p.ReadString(stack[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
value, exists, err := service.GetFloat(ctx, key)
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CacheGetFloatRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
value, exists, svcErr := service.GetFloat(ctx, req.Key)
|
||||
if svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheGetFloatResponse{
|
||||
Value: value,
|
||||
@ -244,32 +345,29 @@ func newCacheSetBytesHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_setbytes",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
key, err := p.ReadString(stack[0])
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
value, err := p.ReadBytes(stack[1])
|
||||
if err != nil {
|
||||
var req CacheSetBytesRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
ttlSeconds := int64(stack[2])
|
||||
|
||||
// Call the service method
|
||||
err = service.SetBytes(ctx, key, value, ttlSeconds)
|
||||
if err != nil {
|
||||
// Write error string to plugin memory
|
||||
if ptr, err := p.WriteString(err.Error()); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
if svcErr := service.SetBytes(ctx, req.Key, req.Value, req.TtlSeconds); svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
// Write empty string to indicate success
|
||||
if ptr, err := p.WriteString(""); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheSetBytesResponse{}
|
||||
cacheWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR, extism.ValueTypePTR, extism.ValueTypeI64},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
@ -278,18 +376,25 @@ func newCacheGetBytesHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_getbytes",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
key, err := p.ReadString(stack[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
value, exists, err := service.GetBytes(ctx, key)
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CacheGetBytesRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
value, exists, svcErr := service.GetBytes(ctx, req.Key)
|
||||
if svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheGetBytesResponse{
|
||||
Value: value,
|
||||
@ -306,18 +411,25 @@ func newCacheHasHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_has",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
key, err := p.ReadString(stack[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
exists, err := service.Has(ctx, key)
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CacheHasRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
exists, svcErr := service.Has(ctx, req.Key)
|
||||
if svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheHasResponse{
|
||||
Exists: exists,
|
||||
@ -333,25 +445,27 @@ func newCacheRemoveHostFunction(service CacheService) extism.HostFunction {
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"cache_remove",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
key, err := p.ReadString(stack[0])
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req CacheRemoveRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
cacheWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
err = service.Remove(ctx, key)
|
||||
if err != nil {
|
||||
// Write error string to plugin memory
|
||||
if ptr, err := p.WriteString(err.Error()); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
if svcErr := service.Remove(ctx, req.Key); svcErr != nil {
|
||||
cacheWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
// Write empty string to indicate success
|
||||
if ptr, err := p.WriteString(""); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := CacheRemoveResponse{}
|
||||
cacheWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
|
||||
@ -16,22 +16,28 @@ import (
|
||||
// artwork_getartisturl is the host function provided by Navidrome.
|
||||
//
|
||||
//go:wasmimport extism:host/user artwork_getartisturl
|
||||
func artwork_getartisturl(uint64, int32) uint64
|
||||
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, int32) uint64
|
||||
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, int32) uint64
|
||||
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, int32) uint64
|
||||
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 {
|
||||
@ -39,18 +45,36 @@ type ArtworkGetArtistUrlResponse struct {
|
||||
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"`
|
||||
@ -66,11 +90,20 @@ type ArtworkGetPlaylistUrlResponse struct {
|
||||
//
|
||||
// Returns the public URL for the artwork, or an error if generation fails.
|
||||
func ArtworkGetArtistUrl(id string, size int32) (*ArtworkGetArtistUrlResponse, error) {
|
||||
idMem := pdk.AllocateString(id)
|
||||
defer idMem.Free()
|
||||
// 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(idMem.Offset(), size)
|
||||
responsePtr := artwork_getartisturl(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -94,11 +127,20 @@ func ArtworkGetArtistUrl(id string, size int32) (*ArtworkGetArtistUrlResponse, e
|
||||
//
|
||||
// Returns the public URL for the artwork, or an error if generation fails.
|
||||
func ArtworkGetAlbumUrl(id string, size int32) (*ArtworkGetAlbumUrlResponse, error) {
|
||||
idMem := pdk.AllocateString(id)
|
||||
defer idMem.Free()
|
||||
// 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(idMem.Offset(), size)
|
||||
responsePtr := artwork_getalbumurl(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -122,11 +164,20 @@ func ArtworkGetAlbumUrl(id string, size int32) (*ArtworkGetAlbumUrlResponse, err
|
||||
//
|
||||
// Returns the public URL for the artwork, or an error if generation fails.
|
||||
func ArtworkGetTrackUrl(id string, size int32) (*ArtworkGetTrackUrlResponse, error) {
|
||||
idMem := pdk.AllocateString(id)
|
||||
defer idMem.Free()
|
||||
// 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(idMem.Offset(), size)
|
||||
responsePtr := artwork_gettrackurl(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -150,11 +201,20 @@ func ArtworkGetTrackUrl(id string, size int32) (*ArtworkGetTrackUrlResponse, err
|
||||
//
|
||||
// Returns the public URL for the artwork, or an error if generation fails.
|
||||
func ArtworkGetPlaylistUrl(id string, size int32) (*ArtworkGetPlaylistUrlResponse, error) {
|
||||
idMem := pdk.AllocateString(id)
|
||||
defer idMem.Free()
|
||||
// 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(idMem.Offset(), size)
|
||||
responsePtr := artwork_getplaylisturl(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
|
||||
@ -9,7 +9,6 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/extism/go-pdk"
|
||||
)
|
||||
@ -17,7 +16,7 @@ import (
|
||||
// cache_setstring is the host function provided by Navidrome.
|
||||
//
|
||||
//go:wasmimport extism:host/user cache_setstring
|
||||
func cache_setstring(uint64, uint64, int64) uint64
|
||||
func cache_setstring(uint64) uint64
|
||||
|
||||
// cache_getstring is the host function provided by Navidrome.
|
||||
//
|
||||
@ -27,7 +26,7 @@ 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, int64, int64) uint64
|
||||
func cache_setint(uint64) uint64
|
||||
|
||||
// cache_getint is the host function provided by Navidrome.
|
||||
//
|
||||
@ -37,7 +36,7 @@ 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, float64, int64) uint64
|
||||
func cache_setfloat(uint64) uint64
|
||||
|
||||
// cache_getfloat is the host function provided by Navidrome.
|
||||
//
|
||||
@ -47,7 +46,7 @@ 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, int64) uint64
|
||||
func cache_setbytes(uint64) uint64
|
||||
|
||||
// cache_getbytes is the host function provided by Navidrome.
|
||||
//
|
||||
@ -64,6 +63,23 @@ func cache_has(uint64) uint64
|
||||
//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"`
|
||||
@ -71,6 +87,23 @@ type CacheGetStringResponse struct {
|
||||
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"`
|
||||
@ -78,6 +111,23 @@ type CacheGetIntResponse struct {
|
||||
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"`
|
||||
@ -85,6 +135,23 @@ type CacheGetFloatResponse struct {
|
||||
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"`
|
||||
@ -92,12 +159,27 @@ type CacheGetBytesResponse struct {
|
||||
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.
|
||||
//
|
||||
@ -107,24 +189,34 @@ type CacheHasResponse struct {
|
||||
// - 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) error {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
valueMem := pdk.AllocateString(value)
|
||||
defer valueMem.Free()
|
||||
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(keyMem.Offset(), valueMem.Offset(), ttlSeconds)
|
||||
responsePtr := cache_setstring(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response CacheSetStringResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// CacheGetString calls the cache_getstring host function.
|
||||
@ -136,11 +228,19 @@ func CacheSetString(key string, value string, ttlSeconds int64) error {
|
||||
// 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) {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
// 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(keyMem.Offset())
|
||||
responsePtr := cache_getstring(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -164,22 +264,34 @@ func CacheGetString(key string) (*CacheGetStringResponse, error) {
|
||||
// - 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) error {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
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(keyMem.Offset(), value, ttlSeconds)
|
||||
responsePtr := cache_setint(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response CacheSetIntResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// CacheGetInt calls the cache_getint host function.
|
||||
@ -191,11 +303,19 @@ func CacheSetInt(key string, value int64, ttlSeconds int64) error {
|
||||
// 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) {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
// 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(keyMem.Offset())
|
||||
responsePtr := cache_getint(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -219,22 +339,34 @@ func CacheGetInt(key string) (*CacheGetIntResponse, error) {
|
||||
// - 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) error {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
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(keyMem.Offset(), value, ttlSeconds)
|
||||
responsePtr := cache_setfloat(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response CacheSetFloatResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// CacheGetFloat calls the cache_getfloat host function.
|
||||
@ -246,11 +378,19 @@ func CacheSetFloat(key string, value float64, ttlSeconds int64) error {
|
||||
// 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) {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
// 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(keyMem.Offset())
|
||||
responsePtr := cache_getfloat(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -274,24 +414,34 @@ func CacheGetFloat(key string) (*CacheGetFloatResponse, error) {
|
||||
// - 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) error {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
valueMem := pdk.AllocateBytes(value)
|
||||
defer valueMem.Free()
|
||||
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(keyMem.Offset(), valueMem.Offset(), ttlSeconds)
|
||||
responsePtr := cache_setbytes(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response CacheSetBytesResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// CacheGetBytes calls the cache_getbytes host function.
|
||||
@ -303,11 +453,19 @@ func CacheSetBytes(key string, value []byte, ttlSeconds int64) error {
|
||||
// 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) {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
// 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(keyMem.Offset())
|
||||
responsePtr := cache_getbytes(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -330,11 +488,19 @@ func CacheGetBytes(key string) (*CacheGetBytesResponse, error) {
|
||||
//
|
||||
// Returns true if the key exists and has not expired.
|
||||
func CacheHas(key string) (*CacheHasResponse, error) {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
// 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(keyMem.Offset())
|
||||
responsePtr := cache_has(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -356,20 +522,30 @@ func CacheHas(key string) (*CacheHasResponse, error) {
|
||||
// - 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) error {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
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(keyMem.Offset())
|
||||
responsePtr := cache_remove(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response CacheRemoveResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
@ -9,7 +9,6 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/extism/go-pdk"
|
||||
)
|
||||
@ -17,30 +16,54 @@ import (
|
||||
// scheduler_scheduleonetime is the host function provided by Navidrome.
|
||||
//
|
||||
//go:wasmimport extism:host/user scheduler_scheduleonetime
|
||||
func scheduler_scheduleonetime(int32, uint64, uint64) uint64
|
||||
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, uint64) uint64
|
||||
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
|
||||
@ -52,13 +75,21 @@ type SchedulerScheduleRecurringResponse struct {
|
||||
//
|
||||
// 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) {
|
||||
payloadMem := pdk.AllocateString(payload)
|
||||
defer payloadMem.Free()
|
||||
scheduleIDMem := pdk.AllocateString(scheduleID)
|
||||
defer scheduleIDMem.Free()
|
||||
// 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(delaySeconds, payloadMem.Offset(), scheduleIDMem.Offset())
|
||||
responsePtr := scheduler_scheduleonetime(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -84,15 +115,21 @@ func SchedulerScheduleOneTime(delaySeconds int32, payload string, scheduleID str
|
||||
//
|
||||
// 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) {
|
||||
cronExpressionMem := pdk.AllocateString(cronExpression)
|
||||
defer cronExpressionMem.Free()
|
||||
payloadMem := pdk.AllocateString(payload)
|
||||
defer payloadMem.Free()
|
||||
scheduleIDMem := pdk.AllocateString(scheduleID)
|
||||
defer scheduleIDMem.Free()
|
||||
// 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(cronExpressionMem.Offset(), payloadMem.Offset(), scheduleIDMem.Offset())
|
||||
responsePtr := scheduler_schedulerecurring(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -114,20 +151,30 @@ func SchedulerScheduleRecurring(cronExpression string, payload string, scheduleI
|
||||
// any future events.
|
||||
//
|
||||
// Returns an error if the schedule ID is not found or if cancellation fails.
|
||||
func SchedulerCancelSchedule(scheduleID string) error {
|
||||
scheduleIDMem := pdk.AllocateString(scheduleID)
|
||||
defer scheduleIDMem.Free()
|
||||
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(scheduleIDMem.Offset())
|
||||
responsePtr := scheduler_cancelschedule(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response SchedulerCancelScheduleResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
@ -18,6 +18,11 @@ import (
|
||||
//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"`
|
||||
@ -30,11 +35,19 @@ type SubsonicAPICallResponse struct {
|
||||
// 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) {
|
||||
uriMem := pdk.AllocateString(uri)
|
||||
defer uriMem.Free()
|
||||
// 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(uriMem.Offset())
|
||||
responsePtr := subsonicapi_call(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
|
||||
@ -9,13 +9,11 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/extism/go-pdk"
|
||||
)
|
||||
|
||||
// websocket_connect is the host function provided by Navidrome.
|
||||
// Takes a single JSON request pointer containing url, headers, and connectionID.
|
||||
//
|
||||
//go:wasmimport extism:host/user websocket_connect
|
||||
func websocket_connect(uint64) uint64
|
||||
@ -23,17 +21,17 @@ 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) uint64
|
||||
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) uint64
|
||||
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, int32, uint64) uint64
|
||||
func websocket_closeconnection(uint64) uint64
|
||||
|
||||
// WebSocketConnectRequest is the request type for WebSocket.Connect.
|
||||
type WebSocketConnectRequest struct {
|
||||
@ -48,6 +46,40 @@ type WebSocketConnectResponse struct {
|
||||
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.
|
||||
//
|
||||
@ -62,7 +94,7 @@ type WebSocketConnectResponse struct {
|
||||
// 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) {
|
||||
// Create JSON request with all parameters
|
||||
// Marshal request to JSON
|
||||
req := WebSocketConnectRequest{
|
||||
Url: url,
|
||||
Headers: headers,
|
||||
@ -75,7 +107,7 @@ func WebSocketConnect(url string, headers map[string]string, connectionID string
|
||||
reqMem := pdk.AllocateBytes(reqBytes)
|
||||
defer reqMem.Free()
|
||||
|
||||
// Call the host function with single JSON request
|
||||
// Call the host function
|
||||
responsePtr := websocket_connect(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
@ -99,24 +131,33 @@ func WebSocketConnect(url string, headers map[string]string, connectionID string
|
||||
// - 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) error {
|
||||
connectionIDMem := pdk.AllocateString(connectionID)
|
||||
defer connectionIDMem.Free()
|
||||
messageMem := pdk.AllocateString(message)
|
||||
defer messageMem.Free()
|
||||
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(connectionIDMem.Offset(), messageMem.Offset())
|
||||
responsePtr := websocket_sendtext(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response WebSocketSendTextResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// WebSocketSendBinary calls the websocket_sendbinary host function.
|
||||
@ -127,24 +168,33 @@ func WebSocketSendText(connectionID string, message string) error {
|
||||
// - 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) error {
|
||||
connectionIDMem := pdk.AllocateString(connectionID)
|
||||
defer connectionIDMem.Free()
|
||||
dataMem := pdk.AllocateBytes(data)
|
||||
defer dataMem.Free()
|
||||
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(connectionIDMem.Offset(), dataMem.Offset())
|
||||
responsePtr := websocket_sendbinary(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response WebSocketSendBinaryResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// WebSocketCloseConnection calls the websocket_closeconnection host function.
|
||||
@ -156,22 +206,32 @@ func WebSocketSendBinary(connectionID string, data []byte) error {
|
||||
// - 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) error {
|
||||
connectionIDMem := pdk.AllocateString(connectionID)
|
||||
defer connectionIDMem.Free()
|
||||
reasonMem := pdk.AllocateString(reason)
|
||||
defer reasonMem.Free()
|
||||
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(connectionIDMem.Offset(), code, reasonMem.Offset())
|
||||
responsePtr := websocket_closeconnection(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response WebSocketCloseConnectionResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
@ -9,18 +9,42 @@ import (
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// SchedulerScheduleOneTimeRequest is the request type for Scheduler.ScheduleOneTime.
|
||||
type SchedulerScheduleOneTimeRequest struct {
|
||||
DelaySeconds int32 `json:"delaySeconds"`
|
||||
Payload string `json:"payload"`
|
||||
ScheduleID string `json:"scheduleID"`
|
||||
}
|
||||
|
||||
// SchedulerScheduleOneTimeResponse is the response type for Scheduler.ScheduleOneTime.
|
||||
type SchedulerScheduleOneTimeResponse struct {
|
||||
NewScheduleID string `json:"newScheduleID,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// SchedulerScheduleRecurringRequest is the request type for Scheduler.ScheduleRecurring.
|
||||
type SchedulerScheduleRecurringRequest struct {
|
||||
CronExpression string `json:"cronExpression"`
|
||||
Payload string `json:"payload"`
|
||||
ScheduleID string `json:"scheduleID"`
|
||||
}
|
||||
|
||||
// SchedulerScheduleRecurringResponse is the response type for Scheduler.ScheduleRecurring.
|
||||
type SchedulerScheduleRecurringResponse struct {
|
||||
NewScheduleID string `json:"newScheduleID,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// SchedulerCancelScheduleRequest is the request type for Scheduler.CancelSchedule.
|
||||
type SchedulerCancelScheduleRequest struct {
|
||||
ScheduleID string `json:"scheduleID"`
|
||||
}
|
||||
|
||||
// SchedulerCancelScheduleResponse is the response type for Scheduler.CancelSchedule.
|
||||
type SchedulerCancelScheduleResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// RegisterSchedulerHostFunctions registers Scheduler service host functions.
|
||||
// The returned host functions should be added to the plugin's configuration.
|
||||
func RegisterSchedulerHostFunctions(service SchedulerService) []extism.HostFunction {
|
||||
@ -35,30 +59,32 @@ func newSchedulerScheduleOneTimeHostFunction(service SchedulerService) extism.Ho
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"scheduler_scheduleonetime",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
delaySeconds := extism.DecodeI32(stack[0])
|
||||
payload, err := p.ReadString(stack[1])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
scheduleID, err := p.ReadString(stack[2])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
newscheduleid, err := service.ScheduleOneTime(ctx, delaySeconds, payload, scheduleID)
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
schedulerWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req SchedulerScheduleOneTimeRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
schedulerWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
newscheduleid, svcErr := service.ScheduleOneTime(ctx, req.DelaySeconds, req.Payload, req.ScheduleID)
|
||||
if svcErr != nil {
|
||||
schedulerWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := SchedulerScheduleOneTimeResponse{
|
||||
NewScheduleID: newscheduleid,
|
||||
}
|
||||
schedulerWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypeI32, extism.ValueTypePTR, extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
@ -67,33 +93,32 @@ func newSchedulerScheduleRecurringHostFunction(service SchedulerService) extism.
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"scheduler_schedulerecurring",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
cronExpression, err := p.ReadString(stack[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
payload, err := p.ReadString(stack[1])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
scheduleID, err := p.ReadString(stack[2])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
newscheduleid, err := service.ScheduleRecurring(ctx, cronExpression, payload, scheduleID)
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
schedulerWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req SchedulerScheduleRecurringRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
schedulerWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
newscheduleid, svcErr := service.ScheduleRecurring(ctx, req.CronExpression, req.Payload, req.ScheduleID)
|
||||
if svcErr != nil {
|
||||
schedulerWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := SchedulerScheduleRecurringResponse{
|
||||
NewScheduleID: newscheduleid,
|
||||
}
|
||||
schedulerWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR, extism.ValueTypePTR, extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
@ -102,25 +127,27 @@ func newSchedulerCancelScheduleHostFunction(service SchedulerService) extism.Hos
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"scheduler_cancelschedule",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
scheduleID, err := p.ReadString(stack[0])
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
schedulerWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req SchedulerCancelScheduleRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
schedulerWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
err = service.CancelSchedule(ctx, scheduleID)
|
||||
if err != nil {
|
||||
// Write error string to plugin memory
|
||||
if ptr, err := p.WriteString(err.Error()); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
if svcErr := service.CancelSchedule(ctx, req.ScheduleID); svcErr != nil {
|
||||
schedulerWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
// Write empty string to indicate success
|
||||
if ptr, err := p.WriteString(""); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := SchedulerCancelScheduleResponse{}
|
||||
schedulerWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
|
||||
@ -9,6 +9,11 @@ import (
|
||||
extism "github.com/extism/go-sdk"
|
||||
)
|
||||
|
||||
// SubsonicAPICallRequest is the request type for SubsonicAPI.Call.
|
||||
type SubsonicAPICallRequest struct {
|
||||
Uri string `json:"uri"`
|
||||
}
|
||||
|
||||
// SubsonicAPICallResponse is the response type for SubsonicAPI.Call.
|
||||
type SubsonicAPICallResponse struct {
|
||||
ResponseJSON string `json:"responseJSON,omitempty"`
|
||||
@ -27,18 +32,25 @@ func newSubsonicAPICallHostFunction(service SubsonicAPIService) extism.HostFunct
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"subsonicapi_call",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
uri, err := p.ReadString(stack[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
responsejson, err := service.Call(ctx, uri)
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
subsonicapiWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
var req SubsonicAPICallRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
subsonicapiWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
responsejson, svcErr := service.Call(ctx, req.Uri)
|
||||
if svcErr != nil {
|
||||
subsonicapiWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := SubsonicAPICallResponse{
|
||||
ResponseJSON: responsejson,
|
||||
|
||||
@ -22,6 +22,40 @@ type WebSocketConnectResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// WebSocketSendTextRequest is the request type for WebSocket.SendText.
|
||||
type WebSocketSendTextRequest struct {
|
||||
ConnectionID string `json:"connectionID"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// WebSocketSendTextResponse is the response type for WebSocket.SendText.
|
||||
type WebSocketSendTextResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// WebSocketSendBinaryRequest is the request type for WebSocket.SendBinary.
|
||||
type WebSocketSendBinaryRequest struct {
|
||||
ConnectionID string `json:"connectionID"`
|
||||
Data []byte `json:"data"`
|
||||
}
|
||||
|
||||
// WebSocketSendBinaryResponse is the response type for WebSocket.SendBinary.
|
||||
type WebSocketSendBinaryResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// WebSocketCloseConnectionRequest is the request type for WebSocket.CloseConnection.
|
||||
type WebSocketCloseConnectionRequest struct {
|
||||
ConnectionID string `json:"connectionID"`
|
||||
Code int32 `json:"code"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
// WebSocketCloseConnectionResponse is the response type for WebSocket.CloseConnection.
|
||||
type WebSocketCloseConnectionResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// RegisterWebSocketHostFunctions registers WebSocket service host functions.
|
||||
// The returned host functions should be added to the plugin's configuration.
|
||||
func RegisterWebSocketHostFunctions(service WebSocketService) []extism.HostFunction {
|
||||
@ -50,11 +84,12 @@ func newWebSocketConnectHostFunction(service WebSocketService) extism.HostFuncti
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
newconnectionid, err := service.Connect(ctx, req.Url, req.Headers, req.ConnectionID)
|
||||
if err != nil {
|
||||
websocketWriteError(p, stack, err)
|
||||
newconnectionid, svcErr := service.Connect(ctx, req.Url, req.Headers, req.ConnectionID)
|
||||
if svcErr != nil {
|
||||
websocketWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := WebSocketConnectResponse{
|
||||
NewConnectionID: newconnectionid,
|
||||
@ -70,31 +105,29 @@ func newWebSocketSendTextHostFunction(service WebSocketService) extism.HostFunct
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"websocket_sendtext",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
connectionID, err := p.ReadString(stack[0])
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
websocketWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
message, err := p.ReadString(stack[1])
|
||||
if err != nil {
|
||||
var req WebSocketSendTextRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
websocketWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
err = service.SendText(ctx, connectionID, message)
|
||||
if err != nil {
|
||||
// Write error string to plugin memory
|
||||
if ptr, err := p.WriteString(err.Error()); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
if svcErr := service.SendText(ctx, req.ConnectionID, req.Message); svcErr != nil {
|
||||
websocketWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
// Write empty string to indicate success
|
||||
if ptr, err := p.WriteString(""); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := WebSocketSendTextResponse{}
|
||||
websocketWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR, extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
@ -103,31 +136,29 @@ func newWebSocketSendBinaryHostFunction(service WebSocketService) extism.HostFun
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"websocket_sendbinary",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
connectionID, err := p.ReadString(stack[0])
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
websocketWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
data, err := p.ReadBytes(stack[1])
|
||||
if err != nil {
|
||||
var req WebSocketSendBinaryRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
websocketWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
err = service.SendBinary(ctx, connectionID, data)
|
||||
if err != nil {
|
||||
// Write error string to plugin memory
|
||||
if ptr, err := p.WriteString(err.Error()); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
if svcErr := service.SendBinary(ctx, req.ConnectionID, req.Data); svcErr != nil {
|
||||
websocketWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
// Write empty string to indicate success
|
||||
if ptr, err := p.WriteString(""); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := WebSocketSendBinaryResponse{}
|
||||
websocketWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR, extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
@ -136,32 +167,29 @@ func newWebSocketCloseConnectionHostFunction(service WebSocketService) extism.Ho
|
||||
return extism.NewHostFunctionWithStack(
|
||||
"websocket_closeconnection",
|
||||
func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {
|
||||
// Read parameters from stack
|
||||
connectionID, err := p.ReadString(stack[0])
|
||||
// Read JSON request from plugin memory
|
||||
reqBytes, err := p.ReadBytes(stack[0])
|
||||
if err != nil {
|
||||
websocketWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
code := extism.DecodeI32(stack[1])
|
||||
reason, err := p.ReadString(stack[2])
|
||||
if err != nil {
|
||||
var req WebSocketCloseConnectionRequest
|
||||
if err := json.Unmarshal(reqBytes, &req); err != nil {
|
||||
websocketWriteError(p, stack, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the service method
|
||||
err = service.CloseConnection(ctx, connectionID, code, reason)
|
||||
if err != nil {
|
||||
// Write error string to plugin memory
|
||||
if ptr, err := p.WriteString(err.Error()); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
if svcErr := service.CloseConnection(ctx, req.ConnectionID, req.Code, req.Reason); svcErr != nil {
|
||||
websocketWriteError(p, stack, svcErr)
|
||||
return
|
||||
}
|
||||
// Write empty string to indicate success
|
||||
if ptr, err := p.WriteString(""); err == nil {
|
||||
stack[0] = ptr
|
||||
}
|
||||
|
||||
// Write JSON response to plugin memory
|
||||
resp := WebSocketCloseConnectionResponse{}
|
||||
websocketWriteResponse(p, stack, resp)
|
||||
},
|
||||
[]extism.ValueType{extism.ValueTypePTR, extism.ValueTypeI32, extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
[]extism.ValueType{extism.ValueTypePTR},
|
||||
)
|
||||
}
|
||||
|
||||
92
plugins/testdata/fake-artwork/nd_host_artwork.go
vendored
92
plugins/testdata/fake-artwork/nd_host_artwork.go
vendored
@ -16,22 +16,28 @@ import (
|
||||
// artwork_getartisturl is the host function provided by Navidrome.
|
||||
//
|
||||
//go:wasmimport extism:host/user artwork_getartisturl
|
||||
func artwork_getartisturl(uint64, int32) uint64
|
||||
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, int32) uint64
|
||||
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, int32) uint64
|
||||
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, int32) uint64
|
||||
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 {
|
||||
@ -39,18 +45,36 @@ type ArtworkGetArtistUrlResponse struct {
|
||||
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"`
|
||||
@ -66,11 +90,20 @@ type ArtworkGetPlaylistUrlResponse struct {
|
||||
//
|
||||
// Returns the public URL for the artwork, or an error if generation fails.
|
||||
func ArtworkGetArtistUrl(id string, size int32) (*ArtworkGetArtistUrlResponse, error) {
|
||||
idMem := pdk.AllocateString(id)
|
||||
defer idMem.Free()
|
||||
// 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(idMem.Offset(), size)
|
||||
responsePtr := artwork_getartisturl(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -94,11 +127,20 @@ func ArtworkGetArtistUrl(id string, size int32) (*ArtworkGetArtistUrlResponse, e
|
||||
//
|
||||
// Returns the public URL for the artwork, or an error if generation fails.
|
||||
func ArtworkGetAlbumUrl(id string, size int32) (*ArtworkGetAlbumUrlResponse, error) {
|
||||
idMem := pdk.AllocateString(id)
|
||||
defer idMem.Free()
|
||||
// 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(idMem.Offset(), size)
|
||||
responsePtr := artwork_getalbumurl(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -122,11 +164,20 @@ func ArtworkGetAlbumUrl(id string, size int32) (*ArtworkGetAlbumUrlResponse, err
|
||||
//
|
||||
// Returns the public URL for the artwork, or an error if generation fails.
|
||||
func ArtworkGetTrackUrl(id string, size int32) (*ArtworkGetTrackUrlResponse, error) {
|
||||
idMem := pdk.AllocateString(id)
|
||||
defer idMem.Free()
|
||||
// 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(idMem.Offset(), size)
|
||||
responsePtr := artwork_gettrackurl(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -150,11 +201,20 @@ func ArtworkGetTrackUrl(id string, size int32) (*ArtworkGetTrackUrlResponse, err
|
||||
//
|
||||
// Returns the public URL for the artwork, or an error if generation fails.
|
||||
func ArtworkGetPlaylistUrl(id string, size int32) (*ArtworkGetPlaylistUrlResponse, error) {
|
||||
idMem := pdk.AllocateString(id)
|
||||
defer idMem.Free()
|
||||
// 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(idMem.Offset(), size)
|
||||
responsePtr := artwork_getplaylisturl(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
|
||||
@ -9,7 +9,6 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/extism/go-pdk"
|
||||
)
|
||||
@ -17,30 +16,54 @@ import (
|
||||
// scheduler_scheduleonetime is the host function provided by Navidrome.
|
||||
//
|
||||
//go:wasmimport extism:host/user scheduler_scheduleonetime
|
||||
func scheduler_scheduleonetime(int32, uint64, uint64) uint64
|
||||
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, uint64) uint64
|
||||
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
|
||||
@ -52,13 +75,21 @@ type SchedulerScheduleRecurringResponse struct {
|
||||
//
|
||||
// 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) {
|
||||
payloadMem := pdk.AllocateString(payload)
|
||||
defer payloadMem.Free()
|
||||
scheduleIDMem := pdk.AllocateString(scheduleID)
|
||||
defer scheduleIDMem.Free()
|
||||
// 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(delaySeconds, payloadMem.Offset(), scheduleIDMem.Offset())
|
||||
responsePtr := scheduler_scheduleonetime(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -84,15 +115,21 @@ func SchedulerScheduleOneTime(delaySeconds int32, payload string, scheduleID str
|
||||
//
|
||||
// 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) {
|
||||
cronExpressionMem := pdk.AllocateString(cronExpression)
|
||||
defer cronExpressionMem.Free()
|
||||
payloadMem := pdk.AllocateString(payload)
|
||||
defer payloadMem.Free()
|
||||
scheduleIDMem := pdk.AllocateString(scheduleID)
|
||||
defer scheduleIDMem.Free()
|
||||
// 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(cronExpressionMem.Offset(), payloadMem.Offset(), scheduleIDMem.Offset())
|
||||
responsePtr := scheduler_schedulerecurring(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -114,20 +151,30 @@ func SchedulerScheduleRecurring(cronExpression string, payload string, scheduleI
|
||||
// any future events.
|
||||
//
|
||||
// Returns an error if the schedule ID is not found or if cancellation fails.
|
||||
func SchedulerCancelSchedule(scheduleID string) error {
|
||||
scheduleIDMem := pdk.AllocateString(scheduleID)
|
||||
defer scheduleIDMem.Free()
|
||||
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(scheduleIDMem.Offset())
|
||||
responsePtr := scheduler_cancelschedule(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response SchedulerCancelScheduleResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
//
|
||||
// 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 main
|
||||
|
||||
@ -16,6 +18,11 @@ import (
|
||||
//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"`
|
||||
@ -28,11 +35,19 @@ type SubsonicAPICallResponse struct {
|
||||
// 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) {
|
||||
uriMem := pdk.AllocateString(uri)
|
||||
defer uriMem.Free()
|
||||
// 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(uriMem.Offset())
|
||||
responsePtr := subsonicapi_call(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
|
||||
57
plugins/testdata/fake-websocket/main.go
vendored
57
plugins/testdata/fake-websocket/main.go
vendored
@ -4,7 +4,6 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
pdk "github.com/extism/go-pdk"
|
||||
)
|
||||
@ -82,20 +81,28 @@ func ndWebSocketOnTextMessage() int32 {
|
||||
|
||||
switch input.Message {
|
||||
case "echo":
|
||||
err := webSocketSendText(input.ConnectionID, "echo:"+input.Message)
|
||||
resp, err := WebSocketSendText(input.ConnectionID, "echo:"+input.Message)
|
||||
if err != nil {
|
||||
errStr := err.Error()
|
||||
pdk.OutputJSON(OnTextMessageOutput{Error: &errStr})
|
||||
return 0
|
||||
}
|
||||
if resp.Error != "" {
|
||||
pdk.OutputJSON(OnTextMessageOutput{Error: &resp.Error})
|
||||
return 0
|
||||
}
|
||||
|
||||
case "close":
|
||||
err := webSocketCloseConnection(input.ConnectionID)
|
||||
resp, err := WebSocketCloseConnection(input.ConnectionID, 1000, "closed by plugin")
|
||||
if err != nil {
|
||||
errStr := err.Error()
|
||||
pdk.OutputJSON(OnTextMessageOutput{Error: &errStr})
|
||||
return 0
|
||||
}
|
||||
if resp.Error != "" {
|
||||
pdk.OutputJSON(OnTextMessageOutput{Error: &resp.Error})
|
||||
return 0
|
||||
}
|
||||
|
||||
case "fail":
|
||||
errStr := "intentional test failure"
|
||||
@ -205,48 +212,4 @@ func storeReceivedMessage(msg string) {
|
||||
pdk.SetVar("_received_messages", []byte(msg))
|
||||
}
|
||||
|
||||
// Host function declarations for WebSocket operations
|
||||
//
|
||||
//go:wasmimport extism:host/user websocket_sendtext
|
||||
func websocket_sendtext(connectionID uint64, message uint64) uint64
|
||||
|
||||
//go:wasmimport extism:host/user websocket_closeconnection
|
||||
func websocket_closeconnection(connectionID uint64, code int32, reason uint64) uint64
|
||||
|
||||
// webSocketSendText sends a text message to the specified connection.
|
||||
func webSocketSendText(connectionID, message string) error {
|
||||
connMem := pdk.AllocateString(connectionID)
|
||||
defer connMem.Free()
|
||||
msgMem := pdk.AllocateString(message)
|
||||
defer msgMem.Free()
|
||||
|
||||
responsePtr := websocket_sendtext(connMem.Offset(), msgMem.Offset())
|
||||
if responsePtr != 0 {
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// webSocketCloseConnection closes the specified WebSocket connection.
|
||||
func webSocketCloseConnection(connectionID string) error {
|
||||
connMem := pdk.AllocateString(connectionID)
|
||||
defer connMem.Free()
|
||||
reasonMem := pdk.AllocateString("closed by plugin")
|
||||
defer reasonMem.Free()
|
||||
|
||||
responsePtr := websocket_closeconnection(connMem.Offset(), 1000, reasonMem.Offset())
|
||||
if responsePtr != 0 {
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {}
|
||||
|
||||
237
plugins/testdata/fake-websocket/nd_host_websocket.go
vendored
Normal file
237
plugins/testdata/fake-websocket/nd_host_websocket.go
vendored
Normal file
@ -0,0 +1,237 @@
|
||||
// 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 TinyGo.
|
||||
//
|
||||
//go:build wasip1
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
}
|
||||
30
plugins/testdata/fake_cache_plugin/main.go
vendored
30
plugins/testdata/fake_cache_plugin/main.go
vendored
@ -81,12 +81,16 @@ func ndTestCache() int32 {
|
||||
|
||||
switch input.Operation {
|
||||
case "set_string":
|
||||
err := CacheSetString(input.Key, input.StringVal, input.TTLSeconds)
|
||||
resp, err := CacheSetString(input.Key, input.StringVal, input.TTLSeconds)
|
||||
if err != nil {
|
||||
errStr := err.Error()
|
||||
pdk.OutputJSON(TestCacheOutput{Error: &errStr})
|
||||
return 0
|
||||
}
|
||||
if resp.Error != "" {
|
||||
pdk.OutputJSON(TestCacheOutput{Error: &resp.Error})
|
||||
return 0
|
||||
}
|
||||
pdk.OutputJSON(TestCacheOutput{})
|
||||
return 0
|
||||
|
||||
@ -105,12 +109,16 @@ func ndTestCache() int32 {
|
||||
return 0
|
||||
|
||||
case "set_int":
|
||||
err := CacheSetInt(input.Key, input.IntVal, input.TTLSeconds)
|
||||
resp, err := CacheSetInt(input.Key, input.IntVal, input.TTLSeconds)
|
||||
if err != nil {
|
||||
errStr := err.Error()
|
||||
pdk.OutputJSON(TestCacheOutput{Error: &errStr})
|
||||
return 0
|
||||
}
|
||||
if resp.Error != "" {
|
||||
pdk.OutputJSON(TestCacheOutput{Error: &resp.Error})
|
||||
return 0
|
||||
}
|
||||
pdk.OutputJSON(TestCacheOutput{})
|
||||
return 0
|
||||
|
||||
@ -129,12 +137,16 @@ func ndTestCache() int32 {
|
||||
return 0
|
||||
|
||||
case "set_float":
|
||||
err := CacheSetFloat(input.Key, input.FloatVal, input.TTLSeconds)
|
||||
resp, err := CacheSetFloat(input.Key, input.FloatVal, input.TTLSeconds)
|
||||
if err != nil {
|
||||
errStr := err.Error()
|
||||
pdk.OutputJSON(TestCacheOutput{Error: &errStr})
|
||||
return 0
|
||||
}
|
||||
if resp.Error != "" {
|
||||
pdk.OutputJSON(TestCacheOutput{Error: &resp.Error})
|
||||
return 0
|
||||
}
|
||||
pdk.OutputJSON(TestCacheOutput{})
|
||||
return 0
|
||||
|
||||
@ -153,12 +165,16 @@ func ndTestCache() int32 {
|
||||
return 0
|
||||
|
||||
case "set_bytes":
|
||||
err := CacheSetBytes(input.Key, input.BytesVal, input.TTLSeconds)
|
||||
resp, err := CacheSetBytes(input.Key, input.BytesVal, input.TTLSeconds)
|
||||
if err != nil {
|
||||
errStr := err.Error()
|
||||
pdk.OutputJSON(TestCacheOutput{Error: &errStr})
|
||||
return 0
|
||||
}
|
||||
if resp.Error != "" {
|
||||
pdk.OutputJSON(TestCacheOutput{Error: &resp.Error})
|
||||
return 0
|
||||
}
|
||||
pdk.OutputJSON(TestCacheOutput{})
|
||||
return 0
|
||||
|
||||
@ -191,12 +207,16 @@ func ndTestCache() int32 {
|
||||
return 0
|
||||
|
||||
case "remove":
|
||||
err := CacheRemove(input.Key)
|
||||
resp, err := CacheRemove(input.Key)
|
||||
if err != nil {
|
||||
errStr := err.Error()
|
||||
pdk.OutputJSON(TestCacheOutput{Error: &errStr})
|
||||
return 0
|
||||
}
|
||||
if resp.Error != "" {
|
||||
pdk.OutputJSON(TestCacheOutput{Error: &resp.Error})
|
||||
return 0
|
||||
}
|
||||
pdk.OutputJSON(TestCacheOutput{})
|
||||
return 0
|
||||
|
||||
|
||||
304
plugins/testdata/fake_cache_plugin/nd_host_cache.go
vendored
304
plugins/testdata/fake_cache_plugin/nd_host_cache.go
vendored
@ -9,7 +9,6 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/extism/go-pdk"
|
||||
)
|
||||
@ -17,7 +16,7 @@ import (
|
||||
// cache_setstring is the host function provided by Navidrome.
|
||||
//
|
||||
//go:wasmimport extism:host/user cache_setstring
|
||||
func cache_setstring(uint64, uint64, int64) uint64
|
||||
func cache_setstring(uint64) uint64
|
||||
|
||||
// cache_getstring is the host function provided by Navidrome.
|
||||
//
|
||||
@ -27,7 +26,7 @@ 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, int64, int64) uint64
|
||||
func cache_setint(uint64) uint64
|
||||
|
||||
// cache_getint is the host function provided by Navidrome.
|
||||
//
|
||||
@ -37,7 +36,7 @@ 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, float64, int64) uint64
|
||||
func cache_setfloat(uint64) uint64
|
||||
|
||||
// cache_getfloat is the host function provided by Navidrome.
|
||||
//
|
||||
@ -47,7 +46,7 @@ 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, int64) uint64
|
||||
func cache_setbytes(uint64) uint64
|
||||
|
||||
// cache_getbytes is the host function provided by Navidrome.
|
||||
//
|
||||
@ -64,6 +63,23 @@ func cache_has(uint64) uint64
|
||||
//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"`
|
||||
@ -71,6 +87,23 @@ type CacheGetStringResponse struct {
|
||||
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"`
|
||||
@ -78,6 +111,23 @@ type CacheGetIntResponse struct {
|
||||
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"`
|
||||
@ -85,6 +135,23 @@ type CacheGetFloatResponse struct {
|
||||
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"`
|
||||
@ -92,12 +159,27 @@ type CacheGetBytesResponse struct {
|
||||
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.
|
||||
//
|
||||
@ -107,24 +189,34 @@ type CacheHasResponse struct {
|
||||
// - 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) error {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
valueMem := pdk.AllocateString(value)
|
||||
defer valueMem.Free()
|
||||
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(keyMem.Offset(), valueMem.Offset(), ttlSeconds)
|
||||
responsePtr := cache_setstring(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response CacheSetStringResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// CacheGetString calls the cache_getstring host function.
|
||||
@ -136,11 +228,19 @@ func CacheSetString(key string, value string, ttlSeconds int64) error {
|
||||
// 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) {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
// 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(keyMem.Offset())
|
||||
responsePtr := cache_getstring(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -164,22 +264,34 @@ func CacheGetString(key string) (*CacheGetStringResponse, error) {
|
||||
// - 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) error {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
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(keyMem.Offset(), value, ttlSeconds)
|
||||
responsePtr := cache_setint(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response CacheSetIntResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// CacheGetInt calls the cache_getint host function.
|
||||
@ -191,11 +303,19 @@ func CacheSetInt(key string, value int64, ttlSeconds int64) error {
|
||||
// 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) {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
// 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(keyMem.Offset())
|
||||
responsePtr := cache_getint(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -219,22 +339,34 @@ func CacheGetInt(key string) (*CacheGetIntResponse, error) {
|
||||
// - 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) error {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
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(keyMem.Offset(), value, ttlSeconds)
|
||||
responsePtr := cache_setfloat(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response CacheSetFloatResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// CacheGetFloat calls the cache_getfloat host function.
|
||||
@ -246,11 +378,19 @@ func CacheSetFloat(key string, value float64, ttlSeconds int64) error {
|
||||
// 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) {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
// 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(keyMem.Offset())
|
||||
responsePtr := cache_getfloat(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -274,24 +414,34 @@ func CacheGetFloat(key string) (*CacheGetFloatResponse, error) {
|
||||
// - 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) error {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
valueMem := pdk.AllocateBytes(value)
|
||||
defer valueMem.Free()
|
||||
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(keyMem.Offset(), valueMem.Offset(), ttlSeconds)
|
||||
responsePtr := cache_setbytes(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response CacheSetBytesResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// CacheGetBytes calls the cache_getbytes host function.
|
||||
@ -303,11 +453,19 @@ func CacheSetBytes(key string, value []byte, ttlSeconds int64) error {
|
||||
// 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) {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
// 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(keyMem.Offset())
|
||||
responsePtr := cache_getbytes(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -330,11 +488,19 @@ func CacheGetBytes(key string) (*CacheGetBytesResponse, error) {
|
||||
//
|
||||
// Returns true if the key exists and has not expired.
|
||||
func CacheHas(key string) (*CacheHasResponse, error) {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
// 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(keyMem.Offset())
|
||||
responsePtr := cache_has(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
@ -356,20 +522,30 @@ func CacheHas(key string) (*CacheHasResponse, error) {
|
||||
// - 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) error {
|
||||
keyMem := pdk.AllocateString(key)
|
||||
defer keyMem.Free()
|
||||
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(keyMem.Offset())
|
||||
responsePtr := cache_remove(reqMem.Offset())
|
||||
|
||||
// Read the response from memory
|
||||
responseMem := pdk.FindMemory(responsePtr)
|
||||
errStr := string(responseMem.ReadBytes())
|
||||
responseBytes := responseMem.ReadBytes()
|
||||
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
// Parse the response
|
||||
var response CacheRemoveResponse
|
||||
if err := json.Unmarshal(responseBytes, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user