I am exploring using Thrift with Eio. Currently, the Thrift support library for OCaml uses plain old Unix sockets. But Thrift is fairly flexible in how the low-level networking is done, and abstracts away the details behind a ‘transport’ interface. The interface however does not use async I/O types, so before Eio it was not possible to adapt it to use Lwt:
class virtual t =
object (self)
method virtual isOpen : bool
method virtual opn : unit
method virtual close : unit
method virtual read : bytes -> int -> int -> int
method readAll (buf:bytes) off len = (* this is implemented *)
method virtual write : bytes -> int -> int -> unit
method virtual write_string : string -> int -> int -> unit
method virtual flush : unit
end
Thanks to Eio though, we can implement this virtual class to use a flow:
(* TFlowTransport.ml *)
open Thrift
module T = Transport
class t flow = object
val mutable opened = true
inherit Transport.t
method isOpen = opened
method opn = ()
method close =
Eio.Net.close flow;
opened <- false
method read buf off len =
let cstruct = Cstruct.create len in
try
Eio.Flow.read_exact flow cstruct;
Cstruct.blit_to_bytes cstruct 0 buf off len;
len
with
| End_of_file ->
raise (T.E (T.END_OF_FILE, (Printf.sprintf "TSocket: Could not read %d because: end of file" len)))
| _ -> raise (T.E (T.UNKNOWN, (Printf.sprintf "TSocket: Could not read %d" len)))
method write buf off len =
let cstruct = Cstruct.of_bytes ~off ~len buf in
Eio.Flow.write flow [cstruct]
method write_string buf off len =
let cstruct = Cstruct.of_string ~off ~len buf in
Eio.Flow.write flow [cstruct]
method flush = ()
end
But as you can see above, reading from/writing to the flow is a little clumsy because flows don’t work directly in terms of byte buffers with offsets and lengths, they work in terms of cstructs. Can anyone advise whether I am missing something or if allocating cstructs is really the way to implement these methods using Eio?