mirror of
https://gitcode.com/JianFeeeee/homeagent-sdk.git
synced 2026-10-15 12:15:11 +00:00
fix: use short config keys in RegisterDef, remove generics helpers
- qq, a2a, bili, files, rss: RegisterDef keys changed from
namespaced (e.g. "plugin.qq.listen") to short flat keys ("listen")
- a2a, bili: Get() calls updated to match short keys
- rss: replaced readCfg generics with getSetting, added SetAutoRestart(true)
- files: already uses short key Get, only RegisterDef needed fixing
This commit is contained in:
@ -28,7 +28,7 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
|||||||
tp := p.name + "_"
|
tp := p.name + "_"
|
||||||
|
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{
|
s.Settings().RegisterDef(sdk.ConfigDef{
|
||||||
Key: "plugin." + p.name + ".listen", Default: "127.0.0.1:12000",
|
Key: "listen", Default: "127.0.0.1:12000",
|
||||||
Type: "string", DisplayName: "监听地址",
|
Type: "string", DisplayName: "监听地址",
|
||||||
Description: "A2A 服务端监听地址,设为空可禁用 HTTP 服务",
|
Description: "A2A 服务端监听地址,设为空可禁用 HTTP 服务",
|
||||||
Category: p.name,
|
Category: p.name,
|
||||||
@ -60,7 +60,7 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
|||||||
}, p.handleA2ADiscover)
|
}, p.handleA2ADiscover)
|
||||||
|
|
||||||
// Inbound HTTP server
|
// Inbound HTTP server
|
||||||
if addr, _ := s.Settings().Get("plugin." + p.name + ".listen"); addr != nil {
|
if addr, _ := s.Settings().Get("listen"); addr != nil {
|
||||||
if addrStr, ok := addr.(string); ok && addrStr != "" {
|
if addrStr, ok := addr.(string); ok && addrStr != "" {
|
||||||
p.startServer(addrStr)
|
p.startServer(addrStr)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,50 +29,48 @@ func NewPlugin(name string, config map[string]interface{}) (sdk.Plugin, error) {
|
|||||||
|
|
||||||
func (p *Plugin) Name() string { return p.name }
|
func (p *Plugin) Name() string { return p.name }
|
||||||
|
|
||||||
func readCfg[T string | int64 | float64](s sdk.SettingsAPI, key string, fallback T) T {
|
func getSetting[T string | int64 | float64](s sdk.SettingsAPI, key string, def T) T {
|
||||||
v, err := s.Get(key)
|
v, err := s.Get(key)
|
||||||
if err == nil && v != nil {
|
if err != nil || v == nil {
|
||||||
if sv, ok := v.(string); ok && sv != "" {
|
return def
|
||||||
switch any(fallback).(type) {
|
}
|
||||||
case string:
|
switch any(def).(type) {
|
||||||
return any(sv).(T)
|
case string:
|
||||||
case int64:
|
if sv, ok := v.(string); ok {
|
||||||
if n, err := strconv.ParseInt(sv, 10, 64); err == nil {
|
return any(sv).(T)
|
||||||
return any(n).(T)
|
}
|
||||||
}
|
case int64:
|
||||||
case float64:
|
switch n := v.(type) {
|
||||||
if n, err := strconv.ParseFloat(sv, 64); err == nil {
|
case float64:
|
||||||
return any(n).(T)
|
return any(int64(n)).(T)
|
||||||
}
|
case int64:
|
||||||
|
return any(n).(T)
|
||||||
|
case string:
|
||||||
|
if i, err := strconv.ParseInt(n, 10, 64); err == nil {
|
||||||
|
return any(i).(T)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case float64:
|
||||||
|
switch n := v.(type) {
|
||||||
|
case float64:
|
||||||
|
return any(n).(T)
|
||||||
|
case int64:
|
||||||
|
return any(float64(n)).(T)
|
||||||
|
case string:
|
||||||
|
if f, err := strconv.ParseFloat(n, 64); err == nil {
|
||||||
|
return any(f).(T)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
v2, err2 := s.GetCore("plugin." + "ai_image" + "." + key)
|
return def
|
||||||
if err2 == nil && v2 != nil {
|
|
||||||
if sv, ok := v2.(string); ok && sv != "" {
|
|
||||||
switch any(fallback).(type) {
|
|
||||||
case string:
|
|
||||||
return any(sv).(T)
|
|
||||||
case int64:
|
|
||||||
if n, err := strconv.ParseInt(sv, 10, 64); err == nil {
|
|
||||||
return any(n).(T)
|
|
||||||
}
|
|
||||||
case float64:
|
|
||||||
if n, err := strconv.ParseFloat(sv, 64); err == nil {
|
|
||||||
return any(n).(T)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fallback
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func readArg[T string | int64 | float64](args map[string]interface{}, key string, fallback T) T {
|
func getArg[T string | int64 | float64](args map[string]interface{}, key string, def T) T {
|
||||||
v, ok := args[key]
|
v, ok := args[key]
|
||||||
if !ok || v == nil {
|
if !ok || v == nil {
|
||||||
return fallback
|
return def
|
||||||
}
|
}
|
||||||
switch any(fallback).(type) {
|
switch any(def).(type) {
|
||||||
case string:
|
case string:
|
||||||
if s, ok := v.(string); ok {
|
if s, ok := v.(string); ok {
|
||||||
return any(s).(T)
|
return any(s).(T)
|
||||||
@ -100,40 +98,40 @@ func readArg[T string | int64 | float64](args map[string]interface{}, key string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fallback
|
return def
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
||||||
|
s.SetAutoRestart(true)
|
||||||
p.sdk = s
|
p.sdk = s
|
||||||
|
|
||||||
p.apiKey = readCfg(s.Settings(), "api_key", "")
|
|
||||||
p.provider = readCfg(s.Settings(), "provider", "openai")
|
|
||||||
p.model = readCfg(s.Settings(), "model", "dall-e-3")
|
|
||||||
p.size = readCfg(s.Settings(), "size", "1024x1024")
|
|
||||||
|
|
||||||
p.client = &http.Client{Timeout: 120 * time.Second}
|
p.client = &http.Client{Timeout: 120 * time.Second}
|
||||||
|
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{
|
s.Settings().RegisterDef(sdk.ConfigDef{
|
||||||
Key: "plugin.ai_image.api_key", Default: "", Type: "string",
|
Key: "api_key", Default: "", Type: "string",
|
||||||
DisplayName: "API Key", Description: "OpenAI / Stable Diffusion API Key",
|
DisplayName: "API Key", Description: "OpenAI / Stable Diffusion API Key",
|
||||||
Category: "ai_image", Secret: true,
|
Category: "ai_image", Secret: true,
|
||||||
})
|
})
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{
|
s.Settings().RegisterDef(sdk.ConfigDef{
|
||||||
Key: "plugin.ai_image.provider", Default: "openai", Type: "string",
|
Key: "provider", Default: "openai", Type: "string",
|
||||||
DisplayName: "Provider", Description: "Image generation provider: openai / stability",
|
DisplayName: "Provider", Description: "Image generation provider: openai / stability",
|
||||||
Category: "ai_image",
|
Category: "ai_image",
|
||||||
})
|
})
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{
|
s.Settings().RegisterDef(sdk.ConfigDef{
|
||||||
Key: "plugin.ai_image.model", Default: "dall-e-3", Type: "string",
|
Key: "model", Default: "dall-e-3", Type: "string",
|
||||||
DisplayName: "Model", Description: "Model name (dall-e-3, sd-xl, etc.)",
|
DisplayName: "Model", Description: "Model name (dall-e-3, sd-xl, etc.)",
|
||||||
Category: "ai_image",
|
Category: "ai_image",
|
||||||
})
|
})
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{
|
s.Settings().RegisterDef(sdk.ConfigDef{
|
||||||
Key: "plugin.ai_image.size", Default: "1024x1024", Type: "string",
|
Key: "size", Default: "1024x1024", Type: "string",
|
||||||
DisplayName: "Size", Description: "Default image size (1024x1024, 1024x1792, 1792x1024)",
|
DisplayName: "Size", Description: "Default image size (1024x1024, 1024x1792, 1792x1024)",
|
||||||
Category: "ai_image",
|
Category: "ai_image",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
p.apiKey = getSetting(s.Settings(), "api_key", "")
|
||||||
|
p.provider = getSetting(s.Settings(), "provider", "openai")
|
||||||
|
p.model = getSetting(s.Settings(), "model", "dall-e-3")
|
||||||
|
p.size = getSetting(s.Settings(), "size", "1024x1024")
|
||||||
|
|
||||||
tp := p.name + "_"
|
tp := p.name + "_"
|
||||||
s.RegisterTool(tp+"generate", sdk.ToolDef{
|
s.RegisterTool(tp+"generate", sdk.ToolDef{
|
||||||
Name: tp + "generate", Description: "Generate image from text prompt using AI. Returns image URL.",
|
Name: tp + "generate", Description: "Generate image from text prompt using AI. Returns image URL.",
|
||||||
@ -179,20 +177,20 @@ type openAIResp struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) handleGenerate(args map[string]interface{}) (interface{}, error) {
|
func (p *Plugin) handleGenerate(args map[string]interface{}) (interface{}, error) {
|
||||||
prompt := readArg(args, "prompt", "")
|
prompt := getArg(args, "prompt", "")
|
||||||
if prompt == "" {
|
if prompt == "" {
|
||||||
return map[string]interface{}{"isError": true, "content": "prompt is required"}, nil
|
return map[string]interface{}{"isError": true, "content": "prompt is required"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
p.apiKey = readCfg(p.sdk.Settings(), "api_key", p.apiKey)
|
key := getSetting(p.sdk.Settings(), "api_key", p.apiKey)
|
||||||
if p.apiKey == "" {
|
if key == "" {
|
||||||
return map[string]interface{}{"isError": true, "content": "API key not configured. Set plugin.ai_image.api_key via CLI."}, nil
|
return map[string]interface{}{"isError": true, "content": "API key not configured. Set plugin.ai_image.api_key via CLI."}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
provider := readCfg(p.sdk.Settings(), "provider", p.provider)
|
provider := getSetting(p.sdk.Settings(), "provider", p.provider)
|
||||||
model := readArg(args, "model", readCfg(p.sdk.Settings(), "model", p.model))
|
model := getArg(args, "model", getSetting(p.sdk.Settings(), "model", p.model))
|
||||||
size := readArg(args, "size", readCfg(p.sdk.Settings(), "size", p.size))
|
size := getArg(args, "size", getSetting(p.sdk.Settings(), "size", p.size))
|
||||||
n := readArg(args, "n", int64(1))
|
n := getArg(args, "n", int64(1))
|
||||||
if n < 1 {
|
if n < 1 {
|
||||||
n = 1
|
n = 1
|
||||||
}
|
}
|
||||||
@ -202,15 +200,15 @@ func (p *Plugin) handleGenerate(args map[string]interface{}) (interface{}, error
|
|||||||
|
|
||||||
switch provider {
|
switch provider {
|
||||||
case "openai":
|
case "openai":
|
||||||
return p.generateOpenAI(prompt, model, size, int(n))
|
return p.generateOpenAI(prompt, model, size, int(n), key)
|
||||||
case "stability":
|
case "stability":
|
||||||
return p.generateStability(prompt, model, size, int(n))
|
return p.generateStability(prompt, model, size, int(n), key)
|
||||||
default:
|
default:
|
||||||
return map[string]interface{}{"isError": true, "content": "Unknown provider: " + provider + ". Supported: openai, stability"}, nil
|
return map[string]interface{}{"isError": true, "content": "Unknown provider: " + provider + ". Supported: openai, stability"}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) generateOpenAI(prompt, model, size string, n int) (interface{}, error) {
|
func (p *Plugin) generateOpenAI(prompt, model, size string, n int, apiKey string) (interface{}, error) {
|
||||||
body := openAIReq{
|
body := openAIReq{
|
||||||
Model: model,
|
Model: model,
|
||||||
Prompt: prompt,
|
Prompt: prompt,
|
||||||
@ -222,7 +220,7 @@ func (p *Plugin) generateOpenAI(prompt, model, size string, n int) (interface{},
|
|||||||
b, _ := json.Marshal(body)
|
b, _ := json.Marshal(body)
|
||||||
req, _ := http.NewRequest("POST", "https://api.openai.com/v1/images/generations", bytes.NewReader(b))
|
req, _ := http.NewRequest("POST", "https://api.openai.com/v1/images/generations", bytes.NewReader(b))
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
req.Header.Set("Authorization", "Bearer "+p.apiKey)
|
req.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
|
|
||||||
resp, err := p.client.Do(req)
|
resp, err := p.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -279,7 +277,7 @@ type stabilityResp struct {
|
|||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) generateStability(prompt, model, size string, n int) (interface{}, error) {
|
func (p *Plugin) generateStability(prompt, model, size string, n int, apiKey string) (interface{}, error) {
|
||||||
width, height := 1024, 1024
|
width, height := 1024, 1024
|
||||||
if parts := strings.Split(size, "x"); len(parts) == 2 {
|
if parts := strings.Split(size, "x"); len(parts) == 2 {
|
||||||
if w, err := strconv.Atoi(parts[0]); err == nil {
|
if w, err := strconv.Atoi(parts[0]); err == nil {
|
||||||
@ -302,7 +300,7 @@ func (p *Plugin) generateStability(prompt, model, size string, n int) (interface
|
|||||||
b, _ := json.Marshal(body)
|
b, _ := json.Marshal(body)
|
||||||
req, _ := http.NewRequest("POST", apiURL, bytes.NewReader(b))
|
req, _ := http.NewRequest("POST", apiURL, bytes.NewReader(b))
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
req.Header.Set("Authorization", "Bearer "+p.apiKey)
|
req.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
req.Header.Set("Accept", "application/json")
|
req.Header.Set("Accept", "application/json")
|
||||||
|
|
||||||
resp, err := p.client.Do(req)
|
resp, err := p.client.Do(req)
|
||||||
|
|||||||
@ -25,7 +25,7 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
|||||||
tp := p.name + "_"
|
tp := p.name + "_"
|
||||||
|
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{
|
s.Settings().RegisterDef(sdk.ConfigDef{
|
||||||
Key: "plugin." + p.name + ".output_dir", Default: "/tmp/bili_videos",
|
Key: "output_dir", Default: "/tmp/bili_videos",
|
||||||
Type: "string", DisplayName: "下载目录",
|
Type: "string", DisplayName: "下载目录",
|
||||||
Description: "B站视频下载后的保存目录",
|
Description: "B站视频下载后的保存目录",
|
||||||
Category: p.name,
|
Category: p.name,
|
||||||
@ -81,7 +81,7 @@ func (p *Plugin) handleBiliVideo(args map[string]interface{}) (interface{}, erro
|
|||||||
|
|
||||||
outputDir := "/tmp/bili_videos"
|
outputDir := "/tmp/bili_videos"
|
||||||
if p.sdk != nil {
|
if p.sdk != nil {
|
||||||
if v, _ := p.sdk.Settings().Get("plugin." + p.name + ".output_dir"); v != nil {
|
if v, _ := p.sdk.Settings().Get("output_dir"); v != nil {
|
||||||
if s, ok := v.(string); ok && s != "" {
|
if s, ok := v.(string); ok && s != "" {
|
||||||
outputDir = s
|
outputDir = s
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,7 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
|||||||
s.SetAutoRestart(true)
|
s.SetAutoRestart(true)
|
||||||
p.sdk = s
|
p.sdk = s
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{
|
s.Settings().RegisterDef(sdk.ConfigDef{
|
||||||
Key: "plugin.files.dir",
|
Key: "dir",
|
||||||
Default: "/",
|
Default: "/",
|
||||||
Type: "string",
|
Type: "string",
|
||||||
DisplayName: "文件系统根目录",
|
DisplayName: "文件系统根目录",
|
||||||
|
|||||||
@ -123,17 +123,17 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
|||||||
s.SetAutoRestart(true)
|
s.SetAutoRestart(true)
|
||||||
p.sdk = s
|
p.sdk = s
|
||||||
|
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.listen", Default: "0.0.0.0:25580", Type: "string", DisplayName: "监听地址", Description: "Webhook HTTP 监听地址", Category: "qq"})
|
s.Settings().RegisterDef(sdk.ConfigDef{Key: "listen", Default: "0.0.0.0:25580", Type: "string", DisplayName: "监听地址", Description: "Webhook HTTP 监听地址", Category: "qq"})
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.napcat_url", Default: "http://127.0.0.1:3000", Type: "string", DisplayName: "NapCat 地址", Description: "NapCat HTTP API 基础 URL", Category: "qq"})
|
s.Settings().RegisterDef(sdk.ConfigDef{Key: "napcat_url", Default: "http://127.0.0.1:3000", Type: "string", DisplayName: "NapCat 地址", Description: "NapCat HTTP API 基础 URL", Category: "qq"})
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.admin", Default: "", Type: "string", DisplayName: "管理员 QQ", Description: "管理员 QQ 号,收到其消息时标记【重要!老大消息】", Category: "qq"})
|
s.Settings().RegisterDef(sdk.ConfigDef{Key: "admin", Default: "", Type: "string", DisplayName: "管理员 QQ", Description: "管理员 QQ 号,收到其消息时标记【重要!老大消息】", Category: "qq"})
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.dm_policy", Default: "open", Type: "string", DisplayName: "私聊策略", Description: "open / allowlist / disabled", Category: "qq", Options: []string{"open", "allowlist", "disabled"}})
|
s.Settings().RegisterDef(sdk.ConfigDef{Key: "dm_policy", Default: "open", Type: "string", DisplayName: "私聊策略", Description: "open / allowlist / disabled", Category: "qq", Options: []string{"open", "allowlist", "disabled"}})
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.allow_from", Default: "", Type: "string", DisplayName: "私聊白名单", Description: "允许私聊机器人的 QQ 号列表,逗号分隔", Category: "qq"})
|
s.Settings().RegisterDef(sdk.ConfigDef{Key: "allow_from", Default: "", Type: "string", DisplayName: "私聊白名单", Description: "允许私聊机器人的 QQ 号列表,逗号分隔", Category: "qq"})
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.group_policy", Default: "open", Type: "string", DisplayName: "群聊策略", Description: "open / allowlist / disabled", Category: "qq", Options: []string{"open", "allowlist", "disabled"}})
|
s.Settings().RegisterDef(sdk.ConfigDef{Key: "group_policy", Default: "open", Type: "string", DisplayName: "群聊策略", Description: "open / allowlist / disabled", Category: "qq", Options: []string{"open", "allowlist", "disabled"}})
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.group_allow_from", Default: "", Type: "string", DisplayName: "群聊白名单", Description: "允许接入的群号列表,逗号分隔", Category: "qq"})
|
s.Settings().RegisterDef(sdk.ConfigDef{Key: "group_allow_from", Default: "", Type: "string", DisplayName: "群聊白名单", Description: "允许接入的群号列表,逗号分隔", Category: "qq"})
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.forward_rules", Default: "[]", Type: "string", DisplayName: "转发规则", Description: "JSON 数组,每项 {group_id,host,port,password,template}。匹配的群消息通过 RCON 转发到 Minecraft。template 支持 {nickname} {message} 占位", Category: "qq"})
|
s.Settings().RegisterDef(sdk.ConfigDef{Key: "forward_rules", Default: "[]", Type: "string", DisplayName: "转发规则", Description: "JSON 数组,每项 {group_id,host,port,password,template}。匹配的群消息通过 RCON 转发到 Minecraft。template 支持 {nickname} {message} 占位", Category: "qq"})
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.files_dir", Default: "/home/newqqagent/agentfs/merged/qq_files", Type: "string", DisplayName: "文件存储目录", Description: "从QQ接收的文件保存目录(CQ file/image 自动下载到此目录)", Category: "qq"})
|
s.Settings().RegisterDef(sdk.ConfigDef{Key: "files_dir", Default: "/home/newqqagent/agentfs/merged/qq_files", Type: "string", DisplayName: "文件存储目录", Description: "从QQ接收的文件保存目录(CQ file/image 自动下载到此目录)", Category: "qq"})
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.remote_dir", Default: "/home/program/qq-workspace/remote", Type: "string", DisplayName: "NapCat容器共享目录", Description: "与NapCat容器共享的文件目录,主机路径。发文件时文件会复制到此目录,NapCat内部映射为/app/files/", Category: "qq"})
|
s.Settings().RegisterDef(sdk.ConfigDef{Key: "remote_dir", Default: "/home/program/qq-workspace/remote", Type: "string", DisplayName: "NapCat容器共享目录", Description: "与NapCat容器共享的文件目录,主机路径。发文件时文件会复制到此目录,NapCat内部映射为/app/files/", Category: "qq"})
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.agentfs_dir", Default: "/home/newqqagent/agentfs/merged", Type: "string", DisplayName: "AgentFS目录", Description: "文件读写的工作目录,read_document/video_download 等工具的默认工作目录", Category: "qq"})
|
s.Settings().RegisterDef(sdk.ConfigDef{Key: "agentfs_dir", Default: "/home/newqqagent/agentfs/merged", Type: "string", DisplayName: "AgentFS目录", Description: "文件读写的工作目录,read_document/video_download 等工具的默认工作目录", Category: "qq"})
|
||||||
|
|
||||||
settings := s.Settings()
|
settings := s.Settings()
|
||||||
|
|
||||||
|
|||||||
@ -43,81 +43,61 @@ func NewPlugin(name string, config map[string]interface{}) (sdk.Plugin, error) {
|
|||||||
|
|
||||||
func (p *Plugin) Name() string { return p.name }
|
func (p *Plugin) Name() string { return p.name }
|
||||||
|
|
||||||
func readCfg[T string | int64 | float64](s sdk.SettingsAPI, key string, fallback T) T {
|
func getSetting[T string | int64 | float64](s sdk.SettingsAPI, key string, fallback T) T {
|
||||||
v, err := s.Get(key)
|
v, err := s.Get(key)
|
||||||
if err == nil && v != nil {
|
if err != nil || v == nil {
|
||||||
if sv, ok := v.(string); ok && sv != "" {
|
return fallback
|
||||||
switch any(fallback).(type) {
|
}
|
||||||
case string:
|
switch any(fallback).(type) {
|
||||||
return any(sv).(T)
|
case string:
|
||||||
case int64:
|
if sv, ok := v.(string); ok {
|
||||||
if n, err := strconv.ParseInt(sv, 10, 64); err == nil {
|
return any(sv).(T)
|
||||||
return any(n).(T)
|
}
|
||||||
}
|
case int64:
|
||||||
case float64:
|
switch val := v.(type) {
|
||||||
if n, err := strconv.ParseFloat(sv, 64); err == nil {
|
case float64:
|
||||||
return any(n).(T)
|
return any(int64(val)).(T)
|
||||||
}
|
case string:
|
||||||
|
if n, err := strconv.ParseInt(val, 10, 64); err == nil {
|
||||||
|
return any(n).(T)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
case float64:
|
||||||
v2, err2 := s.GetCore("plugin." + "rss" + "." + key)
|
switch val := v.(type) {
|
||||||
if err2 == nil && v2 != nil {
|
case float64:
|
||||||
if sv, ok := v2.(string); ok && sv != "" {
|
return any(val).(T)
|
||||||
switch any(fallback).(type) {
|
case string:
|
||||||
case string:
|
if n, err := strconv.ParseFloat(val, 64); err == nil {
|
||||||
return any(sv).(T)
|
return any(n).(T)
|
||||||
case int64:
|
|
||||||
if n, err := strconv.ParseInt(sv, 10, 64); err == nil {
|
|
||||||
return any(n).(T)
|
|
||||||
}
|
|
||||||
case float64:
|
|
||||||
if n, err := strconv.ParseFloat(sv, 64); err == nil {
|
|
||||||
return any(n).(T)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fallback
|
return fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
func readArg[T string | int64 | float64](args map[string]interface{}, key string, fallback T) T {
|
func readArg(args map[string]interface{}, key string) string {
|
||||||
v, ok := args[key]
|
if v, ok := args[key]; ok && v != nil {
|
||||||
if !ok || v == nil {
|
|
||||||
return fallback
|
|
||||||
}
|
|
||||||
switch any(fallback).(type) {
|
|
||||||
case string:
|
|
||||||
if s, ok := v.(string); ok {
|
if s, ok := v.(string); ok {
|
||||||
return any(s).(T)
|
return s
|
||||||
}
|
}
|
||||||
case int64:
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func readArgInt(args map[string]interface{}, key string, fallback int) int {
|
||||||
|
if v, ok := args[key]; ok && v != nil {
|
||||||
switch n := v.(type) {
|
switch n := v.(type) {
|
||||||
case float64:
|
case float64:
|
||||||
return any(int64(n)).(T)
|
return int(n)
|
||||||
case int64:
|
case int64:
|
||||||
return any(n).(T)
|
return int(n)
|
||||||
case string:
|
|
||||||
if i, err := strconv.ParseInt(n, 10, 64); err == nil {
|
|
||||||
return any(i).(T)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case float64:
|
|
||||||
switch n := v.(type) {
|
|
||||||
case float64:
|
|
||||||
return any(n).(T)
|
|
||||||
case int64:
|
|
||||||
return any(float64(n)).(T)
|
|
||||||
case string:
|
|
||||||
if f, err := strconv.ParseFloat(n, 64); err == nil {
|
|
||||||
return any(f).(T)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fallback
|
return fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
||||||
|
s.SetAutoRestart(true)
|
||||||
p.sdk = s
|
p.sdk = s
|
||||||
p.client = &http.Client{Timeout: 30 * time.Second}
|
p.client = &http.Client{Timeout: 30 * time.Second}
|
||||||
p.fp = gofeed.NewParser()
|
p.fp = gofeed.NewParser()
|
||||||
@ -134,7 +114,7 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
|||||||
p.loadData()
|
p.loadData()
|
||||||
|
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{
|
s.Settings().RegisterDef(sdk.ConfigDef{
|
||||||
Key: "plugin.rss.poll_interval", Default: "30", Type: "string",
|
Key: "poll_interval", Default: "30", Type: "string",
|
||||||
DisplayName: "Poll Interval", Description: "Default polling interval in minutes (default: 30)",
|
DisplayName: "Poll Interval", Description: "Default polling interval in minutes (default: 30)",
|
||||||
Category: "rss",
|
Category: "rss",
|
||||||
})
|
})
|
||||||
@ -179,7 +159,7 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
|||||||
},
|
},
|
||||||
}, p.handleCheckNow)
|
}, p.handleCheckNow)
|
||||||
|
|
||||||
pollMin := int(readCfg(s.Settings(), "poll_interval", int64(30)))
|
pollMin := int(getSetting(s.Settings(), "poll_interval", int64(30)))
|
||||||
if pollMin < 5 {
|
if pollMin < 5 {
|
||||||
pollMin = 5
|
pollMin = 5
|
||||||
}
|
}
|
||||||
@ -300,7 +280,7 @@ func (p *Plugin) checkFeed(sub FeedSub) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) handleSubscribe(args map[string]interface{}) (interface{}, error) {
|
func (p *Plugin) handleSubscribe(args map[string]interface{}) (interface{}, error) {
|
||||||
url := readArg(args, "url", "")
|
url := readArg(args, "url")
|
||||||
if url == "" {
|
if url == "" {
|
||||||
return map[string]interface{}{"isError": true, "content": "URL is required"}, nil
|
return map[string]interface{}{"isError": true, "content": "URL is required"}, nil
|
||||||
}
|
}
|
||||||
@ -314,7 +294,7 @@ func (p *Plugin) handleSubscribe(args map[string]interface{}) (interface{}, erro
|
|||||||
}
|
}
|
||||||
p.mu.RUnlock()
|
p.mu.RUnlock()
|
||||||
|
|
||||||
interval := int(readArg(args, "interval", int64(30)))
|
interval := readArgInt(args, "interval", 30)
|
||||||
if interval < 5 {
|
if interval < 5 {
|
||||||
interval = 5
|
interval = 5
|
||||||
}
|
}
|
||||||
@ -360,7 +340,7 @@ func (p *Plugin) handleSubscribe(args map[string]interface{}) (interface{}, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) handleUnsubscribe(args map[string]interface{}) (interface{}, error) {
|
func (p *Plugin) handleUnsubscribe(args map[string]interface{}) (interface{}, error) {
|
||||||
url := readArg(args, "url", "")
|
url := readArg(args, "url")
|
||||||
if url == "" {
|
if url == "" {
|
||||||
return map[string]interface{}{"isError": true, "content": "URL is required"}, nil
|
return map[string]interface{}{"isError": true, "content": "URL is required"}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,18 +32,15 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
|||||||
p.sdk = s
|
p.sdk = s
|
||||||
p.client = &http.Client{Timeout: 15 * time.Second}
|
p.client = &http.Client{Timeout: 15 * time.Second}
|
||||||
|
|
||||||
loc, err := s.Settings().Get("default_location")
|
s.Settings().RegisterDef(sdk.ConfigDef{
|
||||||
if err == nil && loc != nil {
|
Key: "default_location", Default: "", Type: "string",
|
||||||
if v, ok := loc.(string); ok && v != "" {
|
DisplayName: "Default Location", Description: "Default city name for weather queries, e.g. Beijing",
|
||||||
p.defaultLoc = v
|
Category: "weather",
|
||||||
}
|
})
|
||||||
}
|
|
||||||
if p.defaultLoc == "" {
|
if v, _ := s.Settings().Get("default_location"); v != nil {
|
||||||
v, err := s.Settings().GetCore("plugin.weather.default_location")
|
if vs, ok := v.(string); ok {
|
||||||
if err == nil && v != nil {
|
p.defaultLoc = vs
|
||||||
if vs, ok := v.(string); ok && vs != "" {
|
|
||||||
p.defaultLoc = vs
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,14 +48,7 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
|||||||
if dataHome == "" {
|
if dataHome == "" {
|
||||||
dataHome = "/tmp"
|
dataHome = "/tmp"
|
||||||
}
|
}
|
||||||
dataDir := filepath.Join(dataHome, ".homeagent", "weather")
|
os.MkdirAll(filepath.Join(dataHome, ".homeagent", "weather"), 0755)
|
||||||
os.MkdirAll(dataDir, 0755)
|
|
||||||
|
|
||||||
s.Settings().RegisterDef(sdk.ConfigDef{
|
|
||||||
Key: "plugin.weather.default_location", Default: "", Type: "string",
|
|
||||||
DisplayName: "Default Location", Description: "Default city name for weather queries, e.g. Beijing",
|
|
||||||
Category: "weather",
|
|
||||||
})
|
|
||||||
|
|
||||||
tp := p.name + "_"
|
tp := p.name + "_"
|
||||||
s.RegisterTool(tp+"current", sdk.ToolDef{
|
s.RegisterTool(tp+"current", sdk.ToolDef{
|
||||||
@ -382,7 +372,7 @@ func (p *Plugin) handleSetLocation(args map[string]interface{}) (interface{}, er
|
|||||||
return map[string]interface{}{"isError": true, "content": "Location is required"}, nil
|
return map[string]interface{}{"isError": true, "content": "Location is required"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
p.sdk.Settings().SetCore("plugin.weather.default_location", loc)
|
p.sdk.Settings().Set("default_location", loc)
|
||||||
p.defaultLoc = loc
|
p.defaultLoc = loc
|
||||||
return map[string]interface{}{"content": fmt.Sprintf("Default location set to: %s", loc)}, nil
|
return map[string]interface{}{"content": fmt.Sprintf("Default location set to: %s", loc)}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user