feat: Add an AI-Proxy Wasm plugin (#921)

Co-authored-by: 澄潭 <zty98751@alibaba-inc.com>
This commit is contained in:
Kent Dong
2024-05-14 17:00:12 +08:00
committed by GitHub
parent 5c7736980c
commit 333f9b48f3
21 changed files with 2124 additions and 1 deletions

View File

@@ -0,0 +1,100 @@
package provider
import (
"errors"
"fmt"
"net/http"
"net/url"
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
"github.com/tidwall/gjson"
)
type ContextConfig struct {
// @Title zh-CN 文件URL
// @Description zh-CN 用于获取对话上下文的文件的URL。目前仅支持HTTP和HTTPS协议纯文本格式文件
fileUrl string `required:"true" yaml:"url" json:"url"`
// @Title zh-CN 上游服务名称
// @Description zh-CN 文件服务所对应的网关内上游服务名称
serviceName string `required:"true" yaml:"serviceName" json:"serviceName"`
// @Title zh-CN 上游服务端口
// @Description zh-CN 文件服务所对应的网关内上游服务名称
servicePort int64 `required:"true" yaml:"serviceName" json:"serviceName"`
fileUrlObj *url.URL `yaml:"-"`
}
func (c *ContextConfig) FromJson(json gjson.Result) {
c.fileUrl = json.Get("fileUrl").String()
c.serviceName = json.Get("serviceName").String()
c.servicePort = json.Get("servicePort").Int()
}
func (c *ContextConfig) Validate() error {
if c.fileUrl == "" {
return errors.New("missing fileUrl in context config")
}
if fileUrlObj, err := url.Parse(c.fileUrl); err != nil {
return fmt.Errorf("invalid fileUrl in context config: %v", err)
} else {
c.fileUrlObj = fileUrlObj
}
if c.serviceName == "" {
return errors.New("missing serviceName in context config")
}
if c.servicePort == 0 {
return errors.New("missing servicePort in context config")
}
return nil
}
type contextCache struct {
client wrapper.HttpClient
fileUrl *url.URL
timeout uint32
loaded bool
content string
}
func (c *contextCache) GetContent(callback func(string, error), log wrapper.Log) error {
if callback == nil {
return errors.New("callback is nil")
}
if c.loaded {
log.Debugf("context file loaded from cache")
callback(c.content, nil)
return nil
}
log.Infof("loading context file from %s", c.fileUrl.String())
return c.client.Get(c.fileUrl.Path, nil, func(statusCode int, responseHeaders http.Header, responseBody []byte) {
if statusCode != http.StatusOK {
callback("", fmt.Errorf("failed to load context file, status: %d", statusCode))
return
}
c.content = string(responseBody)
c.loaded = true
log.Debugf("content: %s", c.content)
callback(c.content, nil)
}, c.timeout)
}
func createContextCache(providerConfig *ProviderConfig) *contextCache {
contextConfig := providerConfig.context
if contextConfig == nil {
return nil
}
fileUrlObj, _ := url.Parse(contextConfig.fileUrl)
cluster := plainCluster{
serviceName: contextConfig.serviceName,
servicePort: contextConfig.servicePort,
hostName: fileUrlObj.Host,
}
return &contextCache{
client: wrapper.NewClusterClient(cluster),
fileUrl: fileUrlObj,
timeout: providerConfig.timeout,
}
}