Repository navigation
Expand file tree
/
Copy pathabi.go
More file actions
138 lines (122 loc) · 4.05 KB
/
Copy pathabi.go
File metadata and controls
138 lines (122 loc) · 4.05 KB
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
134
135
136
137
138
package main
/*
#include "bridge.h"
*/
import "C"
import (
"encoding/json"
"errors"
"unsafe"
"github.com/kpatdev/quota-router/internal/plugin"
"github.com/router-for-me/CLIProxyAPI/v8/sdk/pluginabi"
"github.com/router-for-me/CLIProxyAPI/v8/sdk/pluginapi"
)
const maxRPCBytes = 16 * 1024 * 1024
type nativeHost struct{ api C.cliproxy_host_api }
var runtime = &plugin.Runtime{}
func main() {}
//export cliproxy_plugin_init
func cliproxy_plugin_init(host *C.cliproxy_host_api, api *C.cliproxy_plugin_api) C.int {
if host == nil || api == nil || host.abi_version != C.uint32_t(pluginabi.ABIVersion) || host.call == nil || host.free_buffer == nil {
return 1
}
runtime.Host = &nativeHost{api: *host}
api.abi_version = C.uint32_t(pluginabi.ABIVersion)
api.call = C.plugin_call_fn(C.cliproxyPluginCall)
api.free_buffer = C.plugin_free_fn(C.cliproxyPluginFree)
api.shutdown = C.plugin_shutdown_fn(C.cliproxyPluginShutdown)
return 0
}
//export cliproxyPluginCall
func cliproxyPluginCall(method *C.char, request *C.uint8_t, length C.size_t, response *C.cliproxy_buffer) (code C.int) {
if response == nil {
return 1
}
response.ptr, response.len = nil, 0
// Literal envelopes: the recovery path must not depend on the encoder that may have panicked.
defer func() {
if recover() != nil {
if method != nil && C.GoString(method) == pluginabi.MethodSchedulerPick {
writeResponse(response, []byte(`{"ok":true,"result":{}}`))
code = 0
return
}
writeResponse(response, []byte(`{"ok":false,"error":{"code":"internal_plugin_error","message":"internal_plugin_error"}}`))
code = 1
}
}()
if method == nil || length > maxRPCBytes || request == nil && length != 0 {
writeResponse(response, []byte(`{"ok":false,"error":{"code":"invalid_rpc_request","message":"invalid_rpc_request"}}`))
return 1
}
var raw []byte
if length > 0 {
raw = C.GoBytes(unsafe.Pointer(request), C.int(length))
}
writeResponse(response, runtime.Handle(C.GoString(method), raw))
return 0
}
//export cliproxyPluginFree
func cliproxyPluginFree(ptr unsafe.Pointer, _ C.size_t) {
C.free(ptr)
}
//export cliproxyPluginShutdown
func cliproxyPluginShutdown() {
runtime.Shutdown()
}
func writeResponse(response *C.cliproxy_buffer, raw []byte) {
response.ptr = C.CBytes(raw)
response.len = C.size_t(len(raw))
}
func (h *nativeHost) call(method string, request any, result any) error {
raw, err := json.Marshal(request)
if err != nil {
return errors.New("host_request_encode_failed")
}
m := C.CString(method)
p := C.CBytes(raw)
defer C.free(unsafe.Pointer(m))
defer C.free(p)
var response C.cliproxy_buffer
code := C.bridge_host_call(&h.api, m, (*C.uint8_t)(p), C.size_t(len(raw)), &response)
defer C.bridge_host_free(&h.api, &response)
if response.ptr == nil || response.len == 0 || response.len > maxRPCBytes {
return errors.New("host_callback_failed")
}
var envelope pluginabi.Envelope
if err := json.Unmarshal(C.GoBytes(response.ptr, C.int(response.len)), &envelope); err != nil {
return errors.New("host_response_failed")
}
if !envelope.OK {
if envelope.Error != nil {
return envelope.Error
}
return errors.New("host_response_failed")
}
if code != 0 {
return errors.New("host_callback_failed")
}
if err := json.Unmarshal(envelope.Result, result); err != nil {
return errors.New("host_result_invalid")
}
return nil
}
func (h *nativeHost) List() ([]pluginapi.HostAuthFileEntry, error) {
var result struct {
Files []pluginapi.HostAuthFileEntry `json:"files"`
}
err := h.call(pluginabi.MethodHostAuthList, struct{}{}, &result)
return result.Files, err
}
func (h *nativeHost) Get(index string) (json.RawMessage, error) {
var result pluginapi.HostAuthGetResponse
err := h.call(pluginabi.MethodHostAuthGet, pluginapi.HostAuthGetRequest{AuthIndex: index}, &result)
if err == nil && result.AuthIndex != index {
return nil, errors.New("credential_identity_mismatch")
}
return result.JSON, err
}
// Call exposes authenticated model/stream callbacks to role routing.
func (h *nativeHost) Call(method string, request any, result any) error {
return h.call(method, request, result)
}