Plugins: Refactor forward of cookies, OAuth token and header modifications by introducing client middlewares (#58132)

Adding support for backend plugin client middlewares. This allows headers in outgoing 
backend plugin and HTTP requests to be modified using client middlewares.

The following client middlewares added:
Forward cookies: Will forward incoming HTTP request Cookies to outgoing plugins.Client 
and HTTP requests if the datasource has enabled forwarding of cookies (keepCookies).
Forward OAuth token: Will set OAuth token headers on outgoing plugins.Client and HTTP 
requests if the datasource has enabled Forward OAuth Identity (oauthPassThru).
Clear auth headers: Will clear any outgoing HTTP headers that was part of the incoming 
HTTP request and used when authenticating to Grafana.
The current suggested way to register client middlewares is to have a separate package, 
pluginsintegration, responsible for bootstrap/instantiate the backend plugin client with 
middlewares and/or longer term bootstrap/instantiate plugin management. 

Fixes #54135
Related to #47734
Related to #57870
Related to #41623
Related to #57065
This commit is contained in:
Marcus Efraimsson
2022-12-01 19:08:36 +01:00
committed by GitHub
parent 632ca67e3f
commit 6dbe3b555f
56 changed files with 2923 additions and 1000 deletions
+36
View File
@@ -29,6 +29,10 @@ func ProvideService(pluginRegistry registry.Service, cfg *config.Cfg) *Service {
}
func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
if req == nil {
return nil, fmt.Errorf("req cannot be nil")
}
plugin, exists := s.plugin(ctx, req.PluginContext.PluginID)
if !exists {
return nil, plugins.ErrPluginNotRegistered.Errorf("%w", backendplugin.ErrPluginNotRegistered)
@@ -65,6 +69,14 @@ func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest)
}
func (s *Service) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
if req == nil {
return fmt.Errorf("req cannot be nil")
}
if sender == nil {
return fmt.Errorf("sender cannot be nil")
}
p, exists := s.plugin(ctx, req.PluginContext.PluginID)
if !exists {
return backendplugin.ErrPluginNotRegistered
@@ -84,6 +96,10 @@ func (s *Service) CallResource(ctx context.Context, req *backend.CallResourceReq
}
func (s *Service) CollectMetrics(ctx context.Context, req *backend.CollectMetricsRequest) (*backend.CollectMetricsResult, error) {
if req == nil {
return nil, fmt.Errorf("req cannot be nil")
}
p, exists := s.plugin(ctx, req.PluginContext.PluginID)
if !exists {
return nil, backendplugin.ErrPluginNotRegistered
@@ -102,6 +118,10 @@ func (s *Service) CollectMetrics(ctx context.Context, req *backend.CollectMetric
}
func (s *Service) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
if req == nil {
return nil, fmt.Errorf("req cannot be nil")
}
p, exists := s.plugin(ctx, req.PluginContext.PluginID)
if !exists {
return nil, backendplugin.ErrPluginNotRegistered
@@ -129,6 +149,10 @@ func (s *Service) CheckHealth(ctx context.Context, req *backend.CheckHealthReque
}
func (s *Service) SubscribeStream(ctx context.Context, req *backend.SubscribeStreamRequest) (*backend.SubscribeStreamResponse, error) {
if req == nil {
return nil, fmt.Errorf("req cannot be nil")
}
plugin, exists := s.plugin(ctx, req.PluginContext.PluginID)
if !exists {
return nil, backendplugin.ErrPluginNotRegistered
@@ -138,6 +162,10 @@ func (s *Service) SubscribeStream(ctx context.Context, req *backend.SubscribeStr
}
func (s *Service) PublishStream(ctx context.Context, req *backend.PublishStreamRequest) (*backend.PublishStreamResponse, error) {
if req == nil {
return nil, fmt.Errorf("req cannot be nil")
}
plugin, exists := s.plugin(ctx, req.PluginContext.PluginID)
if !exists {
return nil, backendplugin.ErrPluginNotRegistered
@@ -147,6 +175,14 @@ func (s *Service) PublishStream(ctx context.Context, req *backend.PublishStreamR
}
func (s *Service) RunStream(ctx context.Context, req *backend.RunStreamRequest, sender *backend.StreamSender) error {
if req == nil {
return fmt.Errorf("req cannot be nil")
}
if sender == nil {
return fmt.Errorf("sender cannot be nil")
}
plugin, exists := s.plugin(ctx, req.PluginContext.PluginID)
if !exists {
return backendplugin.ErrPluginNotRegistered
@@ -0,0 +1,205 @@
package clienttest
import (
"context"
"fmt"
"net/http"
"testing"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/manager/client"
"github.com/grafana/grafana/pkg/services/contexthandler/ctxkey"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/web"
"github.com/stretchr/testify/require"
)
type TestClient struct {
plugins.Client
QueryDataFunc backend.QueryDataHandlerFunc
CallResourceFunc backend.CallResourceHandlerFunc
CheckHealthFunc backend.CheckHealthHandlerFunc
}
func (c *TestClient) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
if c.QueryDataFunc != nil {
return c.QueryDataFunc(ctx, req)
}
return nil, nil
}
func (c *TestClient) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
if c.CallResourceFunc != nil {
return c.CallResourceFunc(ctx, req, sender)
}
return nil
}
func (c *TestClient) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
if c.CheckHealthFunc != nil {
return c.CheckHealthFunc(ctx, req)
}
return nil, nil
}
type MiddlewareScenarioContext struct {
QueryDataCallChain []string
CallResourceCallChain []string
CollectMetricsCallChain []string
CheckHealthCallChain []string
SubscribeStreamCallChain []string
PublishStreamCallChain []string
RunStreamCallChain []string
}
func (ctx *MiddlewareScenarioContext) NewMiddleware(name string) plugins.ClientMiddleware {
return plugins.ClientMiddlewareFunc(func(next plugins.Client) plugins.Client {
return &TestMiddleware{
next: next,
Name: name,
sCtx: ctx,
}
})
}
type TestMiddleware struct {
next plugins.Client
sCtx *MiddlewareScenarioContext
Name string
}
func (m *TestMiddleware) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
m.sCtx.QueryDataCallChain = append(m.sCtx.QueryDataCallChain, fmt.Sprintf("before %s", m.Name))
res, err := m.next.QueryData(ctx, req)
m.sCtx.QueryDataCallChain = append(m.sCtx.QueryDataCallChain, fmt.Sprintf("after %s", m.Name))
return res, err
}
func (m *TestMiddleware) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
m.sCtx.CallResourceCallChain = append(m.sCtx.CallResourceCallChain, fmt.Sprintf("before %s", m.Name))
err := m.next.CallResource(ctx, req, sender)
m.sCtx.CallResourceCallChain = append(m.sCtx.CallResourceCallChain, fmt.Sprintf("after %s", m.Name))
return err
}
func (m *TestMiddleware) CollectMetrics(ctx context.Context, req *backend.CollectMetricsRequest) (*backend.CollectMetricsResult, error) {
m.sCtx.CollectMetricsCallChain = append(m.sCtx.CollectMetricsCallChain, fmt.Sprintf("before %s", m.Name))
res, err := m.next.CollectMetrics(ctx, req)
m.sCtx.CollectMetricsCallChain = append(m.sCtx.CollectMetricsCallChain, fmt.Sprintf("after %s", m.Name))
return res, err
}
func (m *TestMiddleware) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
m.sCtx.CheckHealthCallChain = append(m.sCtx.CheckHealthCallChain, fmt.Sprintf("before %s", m.Name))
res, err := m.next.CheckHealth(ctx, req)
m.sCtx.CheckHealthCallChain = append(m.sCtx.CheckHealthCallChain, fmt.Sprintf("after %s", m.Name))
return res, err
}
func (m *TestMiddleware) SubscribeStream(ctx context.Context, req *backend.SubscribeStreamRequest) (*backend.SubscribeStreamResponse, error) {
m.sCtx.SubscribeStreamCallChain = append(m.sCtx.SubscribeStreamCallChain, fmt.Sprintf("before %s", m.Name))
res, err := m.next.SubscribeStream(ctx, req)
m.sCtx.SubscribeStreamCallChain = append(m.sCtx.SubscribeStreamCallChain, fmt.Sprintf("after %s", m.Name))
return res, err
}
func (m *TestMiddleware) PublishStream(ctx context.Context, req *backend.PublishStreamRequest) (*backend.PublishStreamResponse, error) {
m.sCtx.PublishStreamCallChain = append(m.sCtx.PublishStreamCallChain, fmt.Sprintf("before %s", m.Name))
res, err := m.next.PublishStream(ctx, req)
m.sCtx.PublishStreamCallChain = append(m.sCtx.PublishStreamCallChain, fmt.Sprintf("after %s", m.Name))
return res, err
}
func (m *TestMiddleware) RunStream(ctx context.Context, req *backend.RunStreamRequest, sender *backend.StreamSender) error {
m.sCtx.RunStreamCallChain = append(m.sCtx.RunStreamCallChain, fmt.Sprintf("before %s", m.Name))
err := m.next.RunStream(ctx, req, sender)
m.sCtx.RunStreamCallChain = append(m.sCtx.RunStreamCallChain, fmt.Sprintf("after %s", m.Name))
return err
}
var _ plugins.Client = &TestClient{}
type ClientDecoratorTest struct {
T *testing.T
Context context.Context
TestClient *TestClient
Middlewares []plugins.ClientMiddleware
Decorator *client.Decorator
ReqContext *models.ReqContext
QueryDataReq *backend.QueryDataRequest
QueryDataCtx context.Context
CallResourceReq *backend.CallResourceRequest
CallResourceCtx context.Context
CheckHealthReq *backend.CheckHealthRequest
CheckHealthCtx context.Context
}
type ClientDecoratorTestOption func(*ClientDecoratorTest)
func NewClientDecoratorTest(t *testing.T, opts ...ClientDecoratorTestOption) *ClientDecoratorTest {
cdt := &ClientDecoratorTest{
T: t,
Context: context.Background(),
}
cdt.TestClient = &TestClient{
QueryDataFunc: func(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
cdt.QueryDataReq = req
cdt.QueryDataCtx = ctx
return nil, nil
},
CallResourceFunc: func(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
cdt.CallResourceReq = req
cdt.CallResourceCtx = ctx
return nil
},
CheckHealthFunc: func(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
cdt.CheckHealthReq = req
cdt.CheckHealthCtx = ctx
return nil, nil
},
}
require.NotNil(t, cdt)
for _, opt := range opts {
opt(cdt)
}
d, err := client.NewDecorator(cdt.TestClient, cdt.Middlewares...)
require.NoError(t, err)
require.NotNil(t, d)
cdt.Decorator = d
return cdt
}
func WithReqContext(req *http.Request, user *user.SignedInUser) ClientDecoratorTestOption {
return ClientDecoratorTestOption(func(cdt *ClientDecoratorTest) {
if cdt.ReqContext == nil {
cdt.ReqContext = &models.ReqContext{
Context: &web.Context{},
SignedInUser: user,
}
}
cdt.Context = ctxkey.Set(cdt.Context, cdt.ReqContext)
*req = *req.WithContext(cdt.Context)
cdt.ReqContext.Req = req
})
}
func WithMiddlewares(middlewares ...plugins.ClientMiddleware) ClientDecoratorTestOption {
return ClientDecoratorTestOption(func(cdt *ClientDecoratorTest) {
if cdt.Middlewares == nil {
cdt.Middlewares = []plugins.ClientMiddleware{}
}
cdt.Middlewares = append(cdt.Middlewares, middlewares...)
})
}
+126
View File
@@ -0,0 +1,126 @@
package client
import (
"context"
"fmt"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/plugins"
)
// Decorator allows a plugins.Client to be decorated with middlewares.
type Decorator struct {
client plugins.Client
middlewares []plugins.ClientMiddleware
}
// NewDecorator creates a new plugins.client decorator.
func NewDecorator(client plugins.Client, middlewares ...plugins.ClientMiddleware) (*Decorator, error) {
if client == nil {
return nil, fmt.Errorf("client cannot be nil")
}
return &Decorator{
client: client,
middlewares: middlewares,
}, nil
}
func (d *Decorator) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
if req == nil {
return nil, fmt.Errorf("req cannot be nil")
}
client := clientFromMiddlewares(d.middlewares, d.client)
return client.QueryData(ctx, req)
}
func (d *Decorator) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
if req == nil {
return fmt.Errorf("req cannot be nil")
}
if sender == nil {
return fmt.Errorf("sender cannot be nil")
}
client := clientFromMiddlewares(d.middlewares, d.client)
return client.CallResource(ctx, req, sender)
}
func (d *Decorator) CollectMetrics(ctx context.Context, req *backend.CollectMetricsRequest) (*backend.CollectMetricsResult, error) {
if req == nil {
return nil, fmt.Errorf("req cannot be nil")
}
client := clientFromMiddlewares(d.middlewares, d.client)
return client.CollectMetrics(ctx, req)
}
func (d *Decorator) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
if req == nil {
return nil, fmt.Errorf("req cannot be nil")
}
client := clientFromMiddlewares(d.middlewares, d.client)
return client.CheckHealth(ctx, req)
}
func (d *Decorator) SubscribeStream(ctx context.Context, req *backend.SubscribeStreamRequest) (*backend.SubscribeStreamResponse, error) {
if req == nil {
return nil, fmt.Errorf("req cannot be nil")
}
client := clientFromMiddlewares(d.middlewares, d.client)
return client.SubscribeStream(ctx, req)
}
func (d *Decorator) PublishStream(ctx context.Context, req *backend.PublishStreamRequest) (*backend.PublishStreamResponse, error) {
if req == nil {
return nil, fmt.Errorf("req cannot be nil")
}
client := clientFromMiddlewares(d.middlewares, d.client)
return client.PublishStream(ctx, req)
}
func (d *Decorator) RunStream(ctx context.Context, req *backend.RunStreamRequest, sender *backend.StreamSender) error {
if req == nil {
return fmt.Errorf("req cannot be nil")
}
if sender == nil {
return fmt.Errorf("sender cannot be nil")
}
client := clientFromMiddlewares(d.middlewares, d.client)
return client.RunStream(ctx, req, sender)
}
func clientFromMiddlewares(middlewares []plugins.ClientMiddleware, finalClient plugins.Client) plugins.Client {
if len(middlewares) == 0 {
return finalClient
}
reversed := reverseMiddlewares(middlewares)
next := finalClient
for _, m := range reversed {
next = m.CreateClientMiddleware(next)
}
return next
}
func reverseMiddlewares(middlewares []plugins.ClientMiddleware) []plugins.ClientMiddleware {
reversed := make([]plugins.ClientMiddleware, len(middlewares))
copy(reversed, middlewares)
for i, j := 0, len(reversed)-1; i < j; i, j = i+1, j-1 {
reversed[i], reversed[j] = reversed[j], reversed[i]
}
return reversed
}
var _ plugins.Client = &Decorator{}
@@ -0,0 +1,229 @@
package client
import (
"context"
"fmt"
"testing"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/plugins"
"github.com/stretchr/testify/require"
)
func TestDecorator(t *testing.T) {
var queryDataCalled bool
var callResourceCalled bool
var checkHealthCalled bool
c := &TestClient{
QueryDataFunc: func(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
queryDataCalled = true
return nil, nil
},
CallResourceFunc: func(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
callResourceCalled = true
return nil
},
CheckHealthFunc: func(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
checkHealthCalled = true
return nil, nil
},
}
require.NotNil(t, c)
ctx := MiddlewareScenarioContext{}
mwOne := ctx.NewMiddleware("mw1")
mwTwo := ctx.NewMiddleware("mw2")
d, err := NewDecorator(c, mwOne, mwTwo)
require.NoError(t, err)
require.NotNil(t, d)
_, _ = d.QueryData(context.Background(), &backend.QueryDataRequest{})
require.True(t, queryDataCalled)
sender := callResourceResponseSenderFunc(func(res *backend.CallResourceResponse) error {
return nil
})
_ = d.CallResource(context.Background(), &backend.CallResourceRequest{}, sender)
require.True(t, callResourceCalled)
_, _ = d.CheckHealth(context.Background(), &backend.CheckHealthRequest{})
require.True(t, checkHealthCalled)
require.Len(t, ctx.QueryDataCallChain, 4)
require.EqualValues(t, []string{"before mw1", "before mw2", "after mw2", "after mw1"}, ctx.QueryDataCallChain)
require.Len(t, ctx.CallResourceCallChain, 4)
require.EqualValues(t, []string{"before mw1", "before mw2", "after mw2", "after mw1"}, ctx.CallResourceCallChain)
require.Len(t, ctx.CheckHealthCallChain, 4)
require.EqualValues(t, []string{"before mw1", "before mw2", "after mw2", "after mw1"}, ctx.CheckHealthCallChain)
}
func TestReverseMiddlewares(t *testing.T) {
t.Run("Should reverse 1 middleware", func(t *testing.T) {
ctx := MiddlewareScenarioContext{}
middlewares := []plugins.ClientMiddleware{
ctx.NewMiddleware("mw1"),
}
reversed := reverseMiddlewares(middlewares)
require.Len(t, reversed, 1)
require.Equal(t, "mw1", reversed[0].CreateClientMiddleware(nil).(*TestMiddleware).Name)
})
t.Run("Should reverse 2 middlewares", func(t *testing.T) {
ctx := MiddlewareScenarioContext{}
middlewares := []plugins.ClientMiddleware{
ctx.NewMiddleware("mw1"),
ctx.NewMiddleware("mw2"),
}
reversed := reverseMiddlewares(middlewares)
require.Len(t, reversed, 2)
require.Equal(t, "mw2", reversed[0].CreateClientMiddleware(nil).(*TestMiddleware).Name)
require.Equal(t, "mw1", reversed[1].CreateClientMiddleware(nil).(*TestMiddleware).Name)
})
t.Run("Should reverse 3 middlewares", func(t *testing.T) {
ctx := MiddlewareScenarioContext{}
middlewares := []plugins.ClientMiddleware{
ctx.NewMiddleware("mw1"),
ctx.NewMiddleware("mw2"),
ctx.NewMiddleware("mw3"),
}
reversed := reverseMiddlewares(middlewares)
require.Len(t, reversed, 3)
require.Equal(t, "mw3", reversed[0].CreateClientMiddleware(nil).(*TestMiddleware).Name)
require.Equal(t, "mw2", reversed[1].CreateClientMiddleware(nil).(*TestMiddleware).Name)
require.Equal(t, "mw1", reversed[2].CreateClientMiddleware(nil).(*TestMiddleware).Name)
})
t.Run("Should reverse 4 middlewares", func(t *testing.T) {
ctx := MiddlewareScenarioContext{}
middlewares := []plugins.ClientMiddleware{
ctx.NewMiddleware("mw1"),
ctx.NewMiddleware("mw2"),
ctx.NewMiddleware("mw3"),
ctx.NewMiddleware("mw4"),
}
reversed := reverseMiddlewares(middlewares)
require.Len(t, reversed, 4)
require.Equal(t, "mw4", reversed[0].CreateClientMiddleware(nil).(*TestMiddleware).Name)
require.Equal(t, "mw3", reversed[1].CreateClientMiddleware(nil).(*TestMiddleware).Name)
require.Equal(t, "mw2", reversed[2].CreateClientMiddleware(nil).(*TestMiddleware).Name)
require.Equal(t, "mw1", reversed[3].CreateClientMiddleware(nil).(*TestMiddleware).Name)
})
}
type TestClient struct {
plugins.Client
QueryDataFunc backend.QueryDataHandlerFunc
CallResourceFunc backend.CallResourceHandlerFunc
CheckHealthFunc backend.CheckHealthHandlerFunc
}
func (c *TestClient) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
if c.QueryDataFunc != nil {
return c.QueryDataFunc(ctx, req)
}
return nil, nil
}
func (c *TestClient) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
if c.CallResourceFunc != nil {
return c.CallResourceFunc(ctx, req, sender)
}
return nil
}
func (c *TestClient) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
if c.CheckHealthFunc != nil {
return c.CheckHealthFunc(ctx, req)
}
return nil, nil
}
type MiddlewareScenarioContext struct {
QueryDataCallChain []string
CallResourceCallChain []string
CollectMetricsCallChain []string
CheckHealthCallChain []string
SubscribeStreamCallChain []string
PublishStreamCallChain []string
RunStreamCallChain []string
}
func (ctx *MiddlewareScenarioContext) NewMiddleware(name string) plugins.ClientMiddleware {
return plugins.ClientMiddlewareFunc(func(next plugins.Client) plugins.Client {
return &TestMiddleware{
next: next,
Name: name,
sCtx: ctx,
}
})
}
type TestMiddleware struct {
next plugins.Client
sCtx *MiddlewareScenarioContext
Name string
}
func (m *TestMiddleware) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
m.sCtx.QueryDataCallChain = append(m.sCtx.QueryDataCallChain, fmt.Sprintf("before %s", m.Name))
res, err := m.next.QueryData(ctx, req)
m.sCtx.QueryDataCallChain = append(m.sCtx.QueryDataCallChain, fmt.Sprintf("after %s", m.Name))
return res, err
}
func (m *TestMiddleware) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
m.sCtx.CallResourceCallChain = append(m.sCtx.CallResourceCallChain, fmt.Sprintf("before %s", m.Name))
err := m.next.CallResource(ctx, req, sender)
m.sCtx.CallResourceCallChain = append(m.sCtx.CallResourceCallChain, fmt.Sprintf("after %s", m.Name))
return err
}
func (m *TestMiddleware) CollectMetrics(ctx context.Context, req *backend.CollectMetricsRequest) (*backend.CollectMetricsResult, error) {
m.sCtx.CollectMetricsCallChain = append(m.sCtx.CollectMetricsCallChain, fmt.Sprintf("before %s", m.Name))
res, err := m.next.CollectMetrics(ctx, req)
m.sCtx.CollectMetricsCallChain = append(m.sCtx.CollectMetricsCallChain, fmt.Sprintf("after %s", m.Name))
return res, err
}
func (m *TestMiddleware) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
m.sCtx.CheckHealthCallChain = append(m.sCtx.CheckHealthCallChain, fmt.Sprintf("before %s", m.Name))
res, err := m.next.CheckHealth(ctx, req)
m.sCtx.CheckHealthCallChain = append(m.sCtx.CheckHealthCallChain, fmt.Sprintf("after %s", m.Name))
return res, err
}
func (m *TestMiddleware) SubscribeStream(ctx context.Context, req *backend.SubscribeStreamRequest) (*backend.SubscribeStreamResponse, error) {
m.sCtx.SubscribeStreamCallChain = append(m.sCtx.SubscribeStreamCallChain, fmt.Sprintf("before %s", m.Name))
res, err := m.next.SubscribeStream(ctx, req)
m.sCtx.SubscribeStreamCallChain = append(m.sCtx.SubscribeStreamCallChain, fmt.Sprintf("after %s", m.Name))
return res, err
}
func (m *TestMiddleware) PublishStream(ctx context.Context, req *backend.PublishStreamRequest) (*backend.PublishStreamResponse, error) {
m.sCtx.PublishStreamCallChain = append(m.sCtx.PublishStreamCallChain, fmt.Sprintf("before %s", m.Name))
res, err := m.next.PublishStream(ctx, req)
m.sCtx.PublishStreamCallChain = append(m.sCtx.PublishStreamCallChain, fmt.Sprintf("after %s", m.Name))
return res, err
}
func (m *TestMiddleware) RunStream(ctx context.Context, req *backend.RunStreamRequest, sender *backend.StreamSender) error {
m.sCtx.RunStreamCallChain = append(m.sCtx.RunStreamCallChain, fmt.Sprintf("before %s", m.Name))
err := m.next.RunStream(ctx, req, sender)
m.sCtx.RunStreamCallChain = append(m.sCtx.RunStreamCallChain, fmt.Sprintf("after %s", m.Name))
return err
}
type callResourceResponseSenderFunc func(res *backend.CallResourceResponse) error
func (fn callResourceResponseSenderFunc) Send(res *backend.CallResourceResponse) error {
return fn(res)
}
var _ plugins.Client = &TestClient{}