@@ -92,6 +92,28 @@ type abiLifecycleRequest struct {
9292 PluginDir string `json:"plugin_dir,omitempty"`
9393}
9494
95+ type abiRequestInterceptRequest struct {
96+ pluginapi.RequestInterceptRequest
97+ HostCallbackID string `json:"host_callback_id,omitempty"`
98+ }
99+
100+ type abiResponseInterceptRequest struct {
101+ pluginapi.ResponseInterceptRequest
102+ HostCallbackID string `json:"host_callback_id,omitempty"`
103+ }
104+
105+ type abiStreamChunkInterceptRequest struct {
106+ pluginapi.StreamChunkInterceptRequest
107+ HostCallbackID string `json:"host_callback_id,omitempty"`
108+ }
109+
110+ type abiHostLogRequest struct {
111+ HostCallbackID string `json:"host_callback_id,omitempty"`
112+ Level string `json:"level,omitempty"`
113+ Message string `json:"message,omitempty"`
114+ Fields map [string ]any `json:"fields,omitempty"`
115+ }
116+
95117type abiRegistration struct {
96118 SchemaVersion uint32 `json:"schema_version"`
97119 Metadata pluginapi.Metadata `json:"metadata"`
@@ -192,25 +214,25 @@ func handleJSHandlerABIMethod(ctx context.Context, method string, request []byte
192214 defer done ()
193215 switch method {
194216 case pluginabi .MethodRequestInterceptBefore :
195- var req pluginapi. RequestInterceptRequest
217+ var req abiRequestInterceptRequest
196218 if errDecode := json .Unmarshal (request , & req ); errDecode != nil {
197219 return nil , errDecode
198220 }
199- resp , errCall := p .InterceptRequest (ctx , req )
221+ resp , errCall := p .interceptRequest (ctx , req . RequestInterceptRequest , req . HostCallbackID )
200222 return abiOKEnvelopeWithError (resp , errCall )
201223 case pluginabi .MethodResponseInterceptAfter :
202- var req pluginapi. ResponseInterceptRequest
224+ var req abiResponseInterceptRequest
203225 if errDecode := json .Unmarshal (request , & req ); errDecode != nil {
204226 return nil , errDecode
205227 }
206- resp , errCall := p .InterceptResponse (ctx , req )
228+ resp , errCall := p .interceptResponse (ctx , req . ResponseInterceptRequest , req . HostCallbackID )
207229 return abiOKEnvelopeWithError (resp , errCall )
208230 case pluginabi .MethodResponseInterceptStreamChunk :
209- var req pluginapi. StreamChunkInterceptRequest
231+ var req abiStreamChunkInterceptRequest
210232 if errDecode := json .Unmarshal (request , & req ); errDecode != nil {
211233 return nil , errDecode
212234 }
213- resp , errCall := p .InterceptStreamChunk (ctx , req )
235+ resp , errCall := p .interceptStreamChunk (ctx , req . StreamChunkInterceptRequest , req . HostCallbackID )
214236 return abiOKEnvelopeWithError (resp , errCall )
215237 default :
216238 return abiErrorEnvelope ("unknown_method" , "unknown method: " + method ), nil
@@ -289,3 +311,85 @@ func writeABIResponse(response *C.cliproxy_buffer, raw []byte) {
289311 response .ptr = ptr
290312 response .len = C .size_t (len (raw ))
291313}
314+
315+ func newHostJSConsoleLogger (hostCallbackID string ) jsConsoleLogger {
316+ return func (message string ) error {
317+ if errLog := writeHostJSConsoleLog (hostCallbackID , message ); errLog != nil {
318+ return defaultJSConsoleLogger (message )
319+ }
320+ return nil
321+ }
322+ }
323+
324+ func writeHostJSConsoleLog (hostCallbackID string , message string ) error {
325+ raw , errMarshal := json .Marshal (abiHostLogRequest {
326+ HostCallbackID : hostCallbackID ,
327+ Level : "info" ,
328+ Message : "JS console log: " + message ,
329+ Fields : map [string ]any {
330+ "plugin_id" : pluginName ,
331+ },
332+ })
333+ if errMarshal != nil {
334+ return errMarshal
335+ }
336+
337+ rawResp , errCall := callHost (pluginabi .MethodHostLog , raw )
338+ if errCall != nil {
339+ return errCall
340+ }
341+ if len (rawResp ) == 0 {
342+ return nil
343+ }
344+ var resp abiEnvelope
345+ if errDecode := json .Unmarshal (rawResp , & resp ); errDecode != nil {
346+ return fmt .Errorf ("decode host log response: %w" , errDecode )
347+ }
348+ if ! resp .OK {
349+ if resp .Error != nil {
350+ return fmt .Errorf ("host log failed: %s" , resp .Error .Message )
351+ }
352+ return fmt .Errorf ("host log failed" )
353+ }
354+ return nil
355+ }
356+
357+ func callHost (method string , payload []byte ) ([]byte , error ) {
358+ jsHandlerABIState .RLock ()
359+ defer jsHandlerABIState .RUnlock ()
360+ if jsHandlerABIState .host == nil {
361+ return nil , fmt .Errorf ("host callback is unavailable" )
362+ }
363+
364+ cMethod := C .CString (method )
365+ defer C .free (unsafe .Pointer (cMethod ))
366+
367+ var cPayload unsafe.Pointer
368+ if len (payload ) > 0 {
369+ cPayload = C .CBytes (payload )
370+ if cPayload == nil {
371+ return nil , fmt .Errorf ("allocate host callback payload" )
372+ }
373+ defer C .free (cPayload )
374+ }
375+
376+ var response C.cliproxy_buffer
377+ rc := C .jshandler_call_host (
378+ jsHandlerABIState .host ,
379+ cMethod ,
380+ (* C .uint8_t )(cPayload ),
381+ C .size_t (len (payload )),
382+ & response ,
383+ )
384+ var out []byte
385+ if response .ptr != nil && response .len > 0 {
386+ out = C .GoBytes (response .ptr , C .int (response .len ))
387+ }
388+ if response .ptr != nil {
389+ C .jshandler_free_host_buffer (jsHandlerABIState .host , response .ptr , response .len )
390+ }
391+ if rc != 0 {
392+ return nil , fmt .Errorf ("host callback %s returned %d: %s" , method , int (rc ), string (out ))
393+ }
394+ return out , nil
395+ }
0 commit comments