-
Notifications
You must be signed in to change notification settings - Fork 2
/
plugin_response.go
133 lines (112 loc) · 3.05 KB
/
plugin_response.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright (c) ClaceIO, LLC
// SPDX-License-Identifier: Apache-2.0
package app
import (
"fmt"
"github.com/claceio/clace/internal/app/starlark_type"
"github.com/claceio/clace/internal/types"
"go.starlark.net/starlark"
"go.starlark.net/starlarkstruct"
)
// PluginResponse is a starlark.Value that represents the response to a plugin request
type PluginResponse struct {
errorCode int
err error
value any
errorCallable starlark.Callable
thread *starlark.Thread
}
func NewErrorResponse(err error, errorCallable starlark.Callable, thread *starlark.Thread) *PluginResponse {
return &PluginResponse{
errorCode: 1,
err: err,
value: nil,
errorCallable: errorCallable,
thread: thread,
}
}
func NewErrorCodeResponse(errorCode int, err error, value any) *PluginResponse {
return &PluginResponse{
errorCode: errorCode,
err: err,
value: value,
}
}
func NewResponse(value any) *PluginResponse {
return &PluginResponse{
value: value,
}
}
func (r *PluginResponse) Attr(name string) (starlark.Value, error) {
switch name {
case "error_code":
return starlark.MakeInt(r.errorCode), nil
case "error":
// Error value is being checked in the handler code, clear the thread local state
if r.thread != nil {
r.thread.SetLocal(types.TL_PLUGIN_API_FAILED_ERROR, nil)
}
if r.err == nil {
return starlark.None, nil
}
return starlark.String(r.err.Error()), nil
case "value":
if r.err != nil && r.errorCallable != nil {
// Value is being accessed when there was an error, abort
return nil, r.err
}
if r.value == nil {
return starlark.None, nil
}
if v, ok := r.value.(starlark.Value); ok {
return v, nil
}
if v, ok := r.value.(*starlarkstruct.Struct); ok {
return v, nil
}
return starlark_type.MarshalStarlark(r.value)
default:
return starlark.None, fmt.Errorf("response has no attribute '%s'", name)
}
}
func (r *PluginResponse) AttrNames() []string {
return []string{"error_code", "error", "value"}
}
func (r *PluginResponse) String() string {
return fmt.Sprintf("%d:%s:%s", r.errorCode, r.err, r.value)
}
func (r *PluginResponse) Type() string {
return "Response"
}
func (r *PluginResponse) Freeze() {
}
func (r *PluginResponse) Truth() starlark.Bool {
// Error value is being checked in the handler code, clear the thread local state
if r.thread != nil {
r.thread.SetLocal(types.TL_PLUGIN_API_FAILED_ERROR, nil)
}
return r.err == nil
}
func (r *PluginResponse) Hash() (uint32, error) {
var err error
var errValue starlark.Value
errValue, err = r.Attr("error")
if err != nil {
return 0, err
}
var value starlark.Value
value, err = r.Attr("value")
if err != nil {
return 0, err
}
return starlark.Tuple{starlark.MakeInt(r.errorCode), errValue, value}.Hash()
}
func (r *PluginResponse) UnmarshalStarlarkType() (any, error) {
return map[string]any{
"error_code": r.errorCode,
"error": r.err,
"value": r.value,
}, nil
}
var _ starlark.Value = (*PluginResponse)(nil)
var _ starlark_type.TypeUnmarshaler = (*PluginResponse)(nil)