package mimic
Install
Dune Dependency
Authors
Maintainers
Sources
sha256=49cab86754cfe5370512f1ad410a0e779c5c8a66775a7a801c3965982980322d
sha512=cab646e4b3af476d0baee489266a7631b1a4971bc42d5c4b311c13ac0f14d191b0ec01a87187610da46f38bed03b1d99af96e17ea03e0a14c5ea88893aa21308
Description
A middleware to dispatch protocols
Published: 05 Apr 2024
README
Mimic, a full-abstract way to instantiate a transmission protocol
mimic
is a small project which gives you the opportunity to instantiate a transmission protocol - such as a TCP/IP connection - from dynamic values. A simple tutorial is available here. It explains to implement a ping-pong protocol and upgrade it to TLS.
Some examples
git or paf are examples where they use mimic
as the only transmission protocol implementation available. It permits to be compatible with MirageOS without the complexity of functors (commonly used with functoria to unlock the possibility to abstract anything).
Design
mimic
is pretty-small (~ 700 lines) and the API wants to fit into several different contexts (HTTP, TLS or SSH). It's possible to make helpers from it such as some derivations for unix
or mirage
- as we commonly designed for [conduit][conduit]. However, with a big retro-spective, such piece of code should not include these derivations.
Indeed, they give an opportunity to the user to assert a non-compaibility with MirageOS if you use the unix
derivation for example.
mimic
wants to be abstract and "simple". Then, the user is able to construct something more complex and easy to use at his level - and it's what paf does for example or git-unix.
The goal of mimic
In the context of MirageOS which has a first stage which decides implementation of protocols according to arguments let us to provide a client which can work on many contexts:
as a simple executable which can use the host TCP/IP stack
as a full operating system which integrate its own TCP/IP stack
as something else which wants to use something else than the TCP/IP stack
That mostly means that, de facto, we can not assert a certain implementation of the underlying transmission protocol used by a protocol such as HTTP or SMTP. This required abstraction becomes more complexe when we start to think about composition of protocols (such as TCP/IP and TLS for instance).
This abstraction, in the context of a client, is not only determined by a static application of functors with our implementations. It depends on an user's input value which will choose the right transmission protocol. For instance:
git@github.com:repo/name
expects TCP/IP + SSHhttp://github.com/repo/name
expects TCP/IP + HTTPgit://github.com/repo/name
expects TCP/IPhttps://github.com/repo/name
expects TCP/IP + TLS + HTTP
mimic
gives the opportunity to provide a full implementation of the Mirage_flow.S
interface and require a function to instantiate the given transmission protocol (which respects our interface). By this way and according to user's input values, mimic
is able to choose an try to instantiate a certain transmission protocol and hide it into an not-fully abstracted type Mimic.flow
.
It unlock the ability to implement a protocol such as the Git protocol - or something else such as the HTTP protocol. By this way, this implementation is, de facto compatible with MirageOS in any contexts. In the case of MirageOS, a simple registration of available transmission protocols via functoria is enough. For a more concrete usage such as the Unix usage, a derivation of your protocol with unix
and a registration by default of some transmission protocols is enough too. The main difference is:
one is leaded by arguments of the user (and
functoria
)the second is established by the developer
The result of the mimic's usage
More practically, in the MirageOS world, a device can not provide via its interface the connect
function but it must implement it let write the functoria
glue to to let it to call the connect
function with available arguments (from the command-line).
For instance, a device can be described with this interface:
module type S = sig
type t
val read : t -> buffer
val write : t -> buffer -> unit
end
And its implementation can be described with:
module TCP : sig
include S
val connect : ipv4 -> t
end
That mostly mean that, inside the unikernel.ml
which is your application, you don't have an access to the connect
function:
module Make (My_device : Device.S) = struct
let start (t : My_device.t) =
...
end
A hot-connect can not be available into the interface for a specific reason: the abstraction. Arguments required to connect
/allocate a resource which represents our device depend on the implementation. As we said earlier, ocaml-tls
expects a Tls.Config.client
where Lwt_ssl
expects an Ssl.context
. It can be difficult to shape these values into an ultimate type (which is, of course, non-exhaustive from possible TLS implementations).
Mimic wants to provide this hot-connect function into your application (inside the unikernel.ml
) without a static dependency to ocaml-tls
or lwt_ssl
à priori. Then, the functoria
/mirage
tool will choose right dependency according to the command-line invokation and produce the glue needed to be able to hot-connect a TLS connection over TCP/IP.
Reverse dependencies
mimic
must be thought according to who use it. The API is not designed to be canonic and usable as is. It has been thought to unlock the full abstraction and the compatibility with MirageOS for others projects.
If you think that you can have an usage of mimic
and something is missing, you should implement what you want outside mimic
.
The Mirage_flow.S
interface
Finally, the only assumption about design of protocols, transmission protocols, etc. is Mirage_flow.S
. Several issues exist about this interface but the cost to upgrade the interface (to be unix-friendly for example) is huge when several MirageOS projects trust on this specific interface.
Documentation
mimic
can be hard to explain when we don't know all details about the MirageOS eco-system. The existence of this project can be critized when we don't really understand all details and how this project fits in.
The documentation is not very clear and does not explain the big-picture of mimic
. So it's a real issue and the tutorial wants to fix it but my lack of English does not help me.
Dependencies (5)
-
logs
>= "0.7.0"
-
mirage-flow
>= "4.0.0"
-
lwt
>= "5.3.0"
-
dune
>= "2.8"
-
ocaml
>= "4.08.0"
Dev Dependencies (5)
-
ke
>= "0.4" & with-test
-
cstruct
>= "6.0.0" & with-test
-
bigstringaf
>= "0.7.0" & with-test
-
alcotest-lwt
>= "1.2.3" & with-test
-
alcotest
>= "1.2.3" & with-test
Used by (9)
-
git
>= "3.0.0"
- git-cohttp-mirage
-
git-mirage
>= "3.0.0"
-
git-paf
>= "3.7.0"
-
git-unix
>= "3.4.0" & < "3.16.1"
-
irmin-git
>= "3.1.0"
-
mimic-happy-eyeballs
= "0.0.7"
-
paf
< "0.0.2" | >= "0.0.7" & < "0.1.0" | >= "0.6.0"
- spoke
Conflicts (1)
-
result
< "1.5"