Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
plugin.ml
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 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
module Manifest = Extism_manifest type t = { id : int32; ctx : Context.t; mutable functions : Function.t list } let with_context f = let ctx = Context.create () in let x = try f ctx with exc -> Context.free ctx; raise exc in Context.free ctx; x let set_config plugin = function | None -> true | Some config -> let config = Extism_manifest.yojson_of_config config |> Yojson.Safe.to_string in Bindings.extism_plugin_config plugin.ctx.pointer plugin.id config (Unsigned.UInt64.of_int (String.length config)) let free t = if not (Ctypes.is_null t.ctx.pointer) then Bindings.extism_plugin_free t.ctx.pointer t.id let create ?config ?(wasi = false) ?(functions = []) ?context wasm = let ctx = match context with Some c -> c | None -> Context.create () in let func_ptrs = List.map (fun x -> x.Function.pointer) functions in let arr = Ctypes.CArray.of_list Ctypes.(ptr void) func_ptrs in let n_funcs = Ctypes.CArray.length arr in let id = Bindings.extism_plugin_new ctx.Context.pointer wasm (Unsigned.UInt64.of_int (String.length wasm)) (Ctypes.CArray.start arr) (Unsigned.UInt64.of_int n_funcs) wasi in if id < 0l then match Bindings.extism_error ctx.pointer (-1l) with | None -> Error (`Msg "extism_plugin_call failed") | Some msg -> Error (`Msg msg) else let t = { id; ctx; functions } in if not (set_config t config) then Error (`Msg "call to set_config failed") else let () = Gc.finalise free t in Ok t let of_manifest ?wasi ?functions ?context manifest = let data = Manifest.to_json manifest in create ?wasi ?functions ?context data let%test "free plugin" = let manifest = Manifest.(create [ Wasm.file "test/code.wasm" ]) in let plugin = of_manifest manifest |> Error.unwrap in free plugin; true let update plugin ?config ?(wasi = false) ?(functions = []) wasm = let { id; ctx; _ } = plugin in let func_ptrs = List.map (fun x -> x.Function.pointer) functions in let arr = Ctypes.CArray.of_list Ctypes.(ptr void) func_ptrs in let n_funcs = Ctypes.CArray.length arr in let ok = Bindings.extism_plugin_update ctx.pointer id wasm (Unsigned.UInt64.of_int (String.length wasm)) (Ctypes.CArray.start arr) (Unsigned.UInt64.of_int n_funcs) wasi in if not ok then match Bindings.extism_error ctx.pointer (-1l) with | None -> Error (`Msg "extism_plugin_update failed") | Some msg -> Error (`Msg msg) else if not (set_config plugin config) then Error (`Msg "call to set_config failed") else Ok () let update_manifest plugin ?wasi manifest = let data = Manifest.to_json manifest in update plugin ?wasi data let%test "update plugin manifest and config" = let manifest = Manifest.(create [ Wasm.file "test/code.wasm" ]) in let config = [ ("a", Some "1") ] in let plugin = of_manifest manifest |> Error.unwrap in let manifest = Manifest.with_config manifest config in update_manifest plugin manifest |> Result.is_ok let call' f { id; ctx; _ } ~name input len = let rc = f ctx.pointer id name input len in if rc <> 0l then match Bindings.extism_error ctx.pointer id with | None -> Error (`Msg "extism_plugin_call failed") | Some msg -> Error (`Msg msg) else let out_len = Bindings.extism_plugin_output_length ctx.pointer id in let ptr = Bindings.extism_plugin_output_data ctx.pointer id in let buf = Ctypes.bigarray_of_ptr Ctypes.array1 (Unsigned.UInt64.to_int out_len) Char ptr in Ok buf let call_bigstring (t : t) ~name input = let len = Unsigned.UInt64.of_int (Bigstringaf.length input) in let ptr = Ctypes.bigarray_start Ctypes.array1 input in call' Bindings.extism_plugin_call t ~name ptr len let%test "call_bigstring" = let manifest = Manifest.(create [ Wasm.file "test/code.wasm" ]) in let plugin = of_manifest manifest |> Error.unwrap in call_bigstring plugin ~name:"count_vowels" (Bigstringaf.of_string ~off:0 ~len:14 "this is a test") |> Error.unwrap |> Bigstringaf.to_string = "{\"count\": 4}" let call (t : t) ~name input = let len = String.length input in call' Bindings.extism_plugin_call_s t ~name input (Unsigned.UInt64.of_int len) |> Result.map Bigstringaf.to_string let%test "call" = let manifest = Manifest.(create [ Wasm.file "test/code.wasm" ]) in let plugin = of_manifest manifest |> Error.unwrap in call plugin ~name:"count_vowels" "this is a test" |> Error.unwrap = "{\"count\": 4}" let%test "call_functions" = let open Types.Val_type in let hello_world = Function.create "hello_world" ~params:[ I64 ] ~results:[ I64 ] ~user_data:"Hello again!" @@ fun plugin params results user_data -> let open Types.Val_array in let s = Current_plugin.input_string plugin params 0 in let () = print_endline "Hello from OCaml!" in let () = print_endline user_data in let () = print_endline s in results.$[0] <- params.$[0] in let functions = [ hello_world ] in let manifest = Manifest.(create [ Wasm.file "test/code-functions.wasm" ]) in let plugin = of_manifest manifest ~functions ~wasi:true |> Error.unwrap in call plugin ~name:"count_vowels" "this is a test" |> Error.unwrap = "{\"count\": 4}" let function_exists { id; ctx; _ } name = Bindings.extism_plugin_function_exists ctx.pointer id name let%test "function exists" = let manifest = Manifest.(create [ Wasm.file "test/code.wasm" ]) in let plugin = of_manifest manifest |> Error.unwrap in function_exists plugin "count_vowels" && not (function_exists plugin "function_does_not_exist") module Cancel_handle = struct type t = { inner : unit Ctypes.ptr } let cancel { inner } = Bindings.extism_plugin_cancel inner end let cancel_handle { id; ctx; _ } = Cancel_handle.{ inner = Bindings.extism_plugin_cancel_handle ctx.pointer id }