* [Caml-list] js_of_ocaml with node
@ 2015-04-27 20:32 Helmut Brandl
2015-04-27 21:02 ` Sébastien Dailly
` (2 more replies)
0 siblings, 3 replies; 12+ messages in thread
From: Helmut Brandl @ 2015-04-27 20:32 UTC (permalink / raw)
To: caml-list
Hello all,
I am currently writing a software package in ocaml and I want to be able
to compile it from ocaml to javascript to be able to run it under
nodejs. I have found js_of_ocaml which seems to do a rather good job in
compiling from bytecode to javascript.
I achieved the compilation to javascript which can run under nodejs as
long as I don't use anything from the unix library. Unfortunately I need
two functions from the unix library: 1. Get the last modification time
of a file. 2. Create a directory. I cannot find anything equivalent in
the standard library.
I tried to find some hints in the js_of_ocaml documentation but I
haven't succeeded because to documentation is hard to read.
Can anybody give me some hints on how to get these two functions in a
way that js_of_ocaml does the correct compilation?
Thanks in advance
Regards
Helmut
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] js_of_ocaml with node
2015-04-27 20:32 [Caml-list] js_of_ocaml with node Helmut Brandl
@ 2015-04-27 21:02 ` Sébastien Dailly
2015-04-27 21:16 ` Helmut Brandl
2015-04-27 21:11 ` Daniel Bünzli
2015-04-27 22:03 ` Alain Frisch
2 siblings, 1 reply; 12+ messages in thread
From: Sébastien Dailly @ 2015-04-27 21:02 UTC (permalink / raw)
To: caml-list
Le 27/04/2015 22:32, Helmut Brandl a écrit :
> I achieved the compilation to javascript which can run under nodejs as
> long as I don't use anything from the unix library. Unfortunately I need
> two functions from the unix library: 1. Get the last modification time
> of a file. 2. Create a directory. I cannot find anything equivalent in
> the standard library.
This a javascript limitation, not a js_of_ocaml one. I think (and hope)
there is no such possibilities with standard javascript to create
directories on the client fs. (and this would be a great security flaw
if browsers would allow that).
Regards,
--
Sébastien Dailly
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] js_of_ocaml with node
2015-04-27 21:02 ` Sébastien Dailly
@ 2015-04-27 21:16 ` Helmut Brandl
2015-04-28 7:08 ` Sébastien Dailly
0 siblings, 1 reply; 12+ messages in thread
From: Helmut Brandl @ 2015-04-27 21:16 UTC (permalink / raw)
To: caml-list
On 04/27/2015 04:02 PM, Sébastien Dailly wrote:
> Le 27/04/2015 22:32, Helmut Brandl a écrit :
>
>> I achieved the compilation to javascript which can run under nodejs as
>> long as I don't use anything from the unix library. Unfortunately I need
>> two functions from the unix library: 1. Get the last modification time
>> of a file. 2. Create a directory. I cannot find anything equivalent in
>> the standard library.
>
> This a javascript limitation, not a js_of_ocaml one. I think (and
> hope) there is no such possibilities with standard javascript to
> create directories on the client fs. (and this would be a great
> security flaw if browsers would allow that).
Maybe I have been misunderstood. I am not trying to run my code in a
browser and access the client fs from the browers. My software package
is compiled to bytecode of native using the ocam compiler. All I want to
do is to create a javascript version and run it under nodejs (which runs
on the client machine) to provide user which don't have an installed
ocaml compiler suite on their machine to run my software package.
Note that nodejs has full access to the filesystem like any other
program written in any programming language like C, ocaml, java, scala,...
>
> Regards,
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] js_of_ocaml with node
2015-04-27 21:16 ` Helmut Brandl
@ 2015-04-28 7:08 ` Sébastien Dailly
0 siblings, 0 replies; 12+ messages in thread
From: Sébastien Dailly @ 2015-04-28 7:08 UTC (permalink / raw)
To: caml-list
Le 2015-04-27 23:16, Helmut Brandl a écrit :
>> This a javascript limitation, not a js_of_ocaml one. I think (and
>> hope) there is no such possibilities with standard javascript to
>> create directories on the client fs. (and this would be a great
>> security flaw if browsers would allow that).
> Maybe I have been misunderstood. I am not trying to run my code in a
> browser and access the client fs from the browers. My software package
> is compiled to bytecode of native using the ocam compiler. All I want
> to do is to create a javascript version and run it under nodejs (which
> runs on the client machine) to provide user which don't have an
> installed ocaml compiler suite on their machine to run my software
> package.
>
> Note that nodejs has full access to the filesystem like any other
> program written in any programming language like C, ocaml, java,
> scala,...
>
You'r right. I was only thinking of client side javascript.
Sorry for the noise.
--
Sébastien Dailly
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] js_of_ocaml with node
2015-04-27 20:32 [Caml-list] js_of_ocaml with node Helmut Brandl
2015-04-27 21:02 ` Sébastien Dailly
@ 2015-04-27 21:11 ` Daniel Bünzli
2015-04-27 22:03 ` Alain Frisch
2 siblings, 0 replies; 12+ messages in thread
From: Daniel Bünzli @ 2015-04-27 21:11 UTC (permalink / raw)
To: Helmut Brandl; +Cc: caml-list
Le lundi, 27 avril 2015 à 22:32, Helmut Brandl a écrit :
> Can anybody give me some hints on how to get these two functions in a
> way that js_of_ocaml does the correct compilation?
If you are getting unknown primitive errors at link time then you can simply try to implement them yourself using node's filesystem APIs see:
http://ocsigen.org/js_of_ocaml/2.5/manual/linker
If you are not concerned about using Unix directly (because node.js is your only target) and simply need these functions you can bind the corresponding node API functions directly:
http://ocsigen.org/js_of_ocaml/2.5/manual/bindings
Best,
Daniel
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] js_of_ocaml with node
2015-04-27 20:32 [Caml-list] js_of_ocaml with node Helmut Brandl
2015-04-27 21:02 ` Sébastien Dailly
2015-04-27 21:11 ` Daniel Bünzli
@ 2015-04-27 22:03 ` Alain Frisch
2015-04-27 22:41 ` Daniel Bünzli
2 siblings, 1 reply; 12+ messages in thread
From: Alain Frisch @ 2015-04-27 22:03 UTC (permalink / raw)
To: Helmut Brandl, caml-list
On 27/04/2015 22:32, Helmut Brandl wrote:
> Hello all,
>
> I am currently writing a software package in ocaml and I want to be able
> to compile it from ocaml to javascript to be able to run it under
> nodejs. I have found js_of_ocaml which seems to do a rather good job in
> compiling from bytecode to javascript.
>
> I achieved the compilation to javascript which can run under nodejs as
> long as I don't use anything from the unix library. Unfortunately I need
> two functions from the unix library: 1. Get the last modification time
> of a file. 2. Create a directory. I cannot find anything equivalent in
> the standard library.
You need to define bindings to node.js' "fs" API:
https://nodejs.org/api/fs.html
It should be possible to implement a subset of the Unix module through
this API, or just to expose the few functions you would need.
For instance, with the gen_js_api I announced earlier today, binding the
synchronous mkdir function would look like:
val mkdir: string -> int -> unit
[@@js.global "fs.mkdirAsync"]
Alain
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] js_of_ocaml with node
2015-04-27 22:03 ` Alain Frisch
@ 2015-04-27 22:41 ` Daniel Bünzli
2015-04-28 7:53 ` Alain Frisch
0 siblings, 1 reply; 12+ messages in thread
From: Daniel Bünzli @ 2015-04-27 22:41 UTC (permalink / raw)
To: Alain Frisch; +Cc: Helmut Brandl, caml-list
Le mardi, 28 avril 2015 à 00:03, Alain Frisch a écrit :
> val mkdir: string -> int -> unit
> [@@js.global "fs.mkdirAsync"]
That should be "fs.mkdirSync". Just curious, how would the binding to the async fs.mkdir look like ?
Daniel
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] js_of_ocaml with node
2015-04-27 22:41 ` Daniel Bünzli
@ 2015-04-28 7:53 ` Alain Frisch
2015-04-28 8:11 ` Alain Frisch
2015-04-28 11:17 ` Drup
0 siblings, 2 replies; 12+ messages in thread
From: Alain Frisch @ 2015-04-28 7:53 UTC (permalink / raw)
To: Daniel Bünzli; +Cc: Helmut Brandl, caml-list
On 04/28/2015 12:41 AM, Daniel Bünzli wrote:
> Le mardi, 28 avril 2015 à 00:03, Alain Frisch a écrit :
>> val mkdir: string -> int -> unit
>> [@@js.global "fs.mkdirAsync"]
>
> That should be "fs.mkdirSync".
Indeed!
> Just curious, how would the binding to the async fs.mkdir look like ?
Something like:
val mkdir_async: string -> int -> (js_exn option -> unit) -> unit
[@@js.global "fs.mkdir"]
assuming some predefined bindings for js_exn. (One could also decide to
bind JS exception to OCaml's exn type, but the gain is not clear.)
There are other possible variations, such as making the mode optional:
val mkdir_async:
string ->
?mode:(int[@js.default 0o777]) ->
(js_exn option -> unit) ->
unit
[@@js.global "fs.mkdir"]
Here js.default forces the default value for the optional mode argument.
Without it, a missing value will send an `undefined` as the second
argument (I don't know if fs.mkdir would be happy with it). This is
currently not supported, but one could also extend the tool to allow:
val mkdir_async:
string ->
?mode:(int[@js.drop_if_missing]) ->
(js_exn option -> unit) -> unit
[@@js.global "fs.mkdir"]
so that the second argument is dropped in the JS call if not provided
(but I don't see how to support that for OCaml callbacks in full
generality, since the function needs to check the type of arguments to
decide how to interpret them).
Alain
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] js_of_ocaml with node
2015-04-28 7:53 ` Alain Frisch
@ 2015-04-28 8:11 ` Alain Frisch
2015-04-28 11:17 ` Drup
1 sibling, 0 replies; 12+ messages in thread
From: Alain Frisch @ 2015-04-28 8:11 UTC (permalink / raw)
To: Daniel Bünzli; +Cc: Helmut Brandl, caml-list
On 04/28/2015 09:53 AM, Alain Frisch wrote:
> val mkdir_async:
> string ->
> ?mode:(int[@js.default 0o777]) ->
> (js_exn option -> unit) ->
> unit
> [@@js.global "fs.mkdir"]
>
>
> Here js.default forces the default value for the optional mode argument.
> Without it, a missing value will send an `undefined` as the second
> argument (I don't know if fs.mkdir would be happy with it).
Just to clarify: the issue here is that node.js documents the function as:
fs.mkdir(path[, mode], callback)
and its implementation is more liberal:
=================
function modeNum(m, def) {
if (util.isNumber(m))
return m;
if (util.isString(m))
return parseInt(m, 8);
if (def)
return modeNum(def);
return undefined;
}
fs.mkdir = function(path, mode, callback) {
if (util.isFunction(mode)) callback = mode;
...
modeNum(mode, 511 /*=0777*/)
...
};
=================
(welcome to Javascript wonderful calling conventions!)
So both conventions are supported to omit the mode argument:
fs.mkdir(path, undefined, callback)
fs.mkdir(path, callback)
(one could actually pass anything as the second argument as long as it
is not a number, not a string and not a function).
So it is ok to bind it simply as:
val mkdir_async: string -> ?mode:int -> (js_exn option -> unit) -> unit
[@@js.global "fs.mkdir"]
Alain
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] js_of_ocaml with node
2015-04-28 7:53 ` Alain Frisch
2015-04-28 8:11 ` Alain Frisch
@ 2015-04-28 11:17 ` Drup
2015-04-29 22:03 ` Helmut Brandl
1 sibling, 1 reply; 12+ messages in thread
From: Drup @ 2015-04-28 11:17 UTC (permalink / raw)
To: Alain Frisch, Daniel Bünzli; +Cc: Helmut Brandl, caml-list
You can go one step further here and expose lwt threads instead. It
could be done automatically too, since transforming callbacks into lwt
thread is always done the same way.
Le 28/04/2015 09:53, Alain Frisch a écrit :
> On 04/28/2015 12:41 AM, Daniel Bünzli wrote:
>> Le mardi, 28 avril 2015 à 00:03, Alain Frisch a écrit :
>>> val mkdir: string -> int -> unit
>>> [@@js.global "fs.mkdirAsync"]
>>
>> That should be "fs.mkdirSync".
>
> Indeed!
>
>> Just curious, how would the binding to the async fs.mkdir look like ?
>
> Something like:
>
> val mkdir_async: string -> int -> (js_exn option -> unit) -> unit
> [@@js.global "fs.mkdir"]
>
> assuming some predefined bindings for js_exn. (One could also decide
> to bind JS exception to OCaml's exn type, but the gain is not clear.)
>
> There are other possible variations, such as making the mode optional:
>
> val mkdir_async:
> string ->
> ?mode:(int[@js.default 0o777]) ->
> (js_exn option -> unit) ->
> unit
> [@@js.global "fs.mkdir"]
>
>
> Here js.default forces the default value for the optional mode
> argument. Without it, a missing value will send an `undefined` as the
> second argument (I don't know if fs.mkdir would be happy with it).
> This is currently not supported, but one could also extend the tool to
> allow:
>
> val mkdir_async:
> string ->
> ?mode:(int[@js.drop_if_missing]) ->
> (js_exn option -> unit) -> unit
> [@@js.global "fs.mkdir"]
>
> so that the second argument is dropped in the JS call if not provided
> (but I don't see how to support that for OCaml callbacks in full
> generality, since the function needs to check the type of arguments to
> decide how to interpret them).
>
>
> Alain
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] js_of_ocaml with node
2015-04-28 11:17 ` Drup
@ 2015-04-29 22:03 ` Helmut Brandl
2015-04-29 22:49 ` Mauricio Fernández
0 siblings, 1 reply; 12+ messages in thread
From: Helmut Brandl @ 2015-04-29 22:03 UTC (permalink / raw)
To: caml-list
Thanks to all for the hints.
I think I have to dig into the documentation of js_of_ocaml to resolve
the problem.
Regards
Helmut
On 04/28/2015 06:17 AM, Drup wrote:
> You can go one step further here and expose lwt threads instead. It
> could be done automatically too, since transforming callbacks into lwt
> thread is always done the same way.
>
> Le 28/04/2015 09:53, Alain Frisch a écrit :
>> On 04/28/2015 12:41 AM, Daniel Bünzli wrote:
>>> Le mardi, 28 avril 2015 à 00:03, Alain Frisch a écrit :
>>>> val mkdir: string -> int -> unit
>>>> [@@js.global "fs.mkdirAsync"]
>>>
>>> That should be "fs.mkdirSync".
>>
>> Indeed!
>>
>>> Just curious, how would the binding to the async fs.mkdir look like ?
>>
>> Something like:
>>
>> val mkdir_async: string -> int -> (js_exn option -> unit) -> unit
>> [@@js.global "fs.mkdir"]
>>
>> assuming some predefined bindings for js_exn. (One could also decide
>> to bind JS exception to OCaml's exn type, but the gain is not clear.)
>>
>> There are other possible variations, such as making the mode optional:
>>
>> val mkdir_async:
>> string ->
>> ?mode:(int[@js.default 0o777]) ->
>> (js_exn option -> unit) ->
>> unit
>> [@@js.global "fs.mkdir"]
>>
>>
>> Here js.default forces the default value for the optional mode
>> argument. Without it, a missing value will send an `undefined` as
>> the second argument (I don't know if fs.mkdir would be happy with
>> it). This is currently not supported, but one could also extend the
>> tool to allow:
>>
>> val mkdir_async:
>> string ->
>> ?mode:(int[@js.drop_if_missing]) ->
>> (js_exn option -> unit) -> unit
>> [@@js.global "fs.mkdir"]
>>
>> so that the second argument is dropped in the JS call if not provided
>> (but I don't see how to support that for OCaml callbacks in full
>> generality, since the function needs to check the type of arguments
>> to decide how to interpret them).
>>
>>
>> Alain
>>
>
>
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Caml-list] js_of_ocaml with node
2015-04-29 22:03 ` Helmut Brandl
@ 2015-04-29 22:49 ` Mauricio Fernández
0 siblings, 0 replies; 12+ messages in thread
From: Mauricio Fernández @ 2015-04-29 22:49 UTC (permalink / raw)
To: Helmut Brandl, caml-list
On Wed, Apr 29, 2015 at 05:03:21PM -0500, Helmut Brandl wrote:
> Thanks to all for the hints.
>
> I think I have to dig into the documentation of js_of_ocaml to
> resolve the problem.
I've got some bindings for nodejs stuff including FS operations, sockets,
events, processes, etc.; will try to publish it tomorrow. Note that some
nodejs functions require variadic callbacks as supported by the patches
available at https://github.com/ocsigen/js_of_ocaml/issues/273
The hand-written bindings look like this (just a sneak peek):
node_require.eliom:
{client{
let require x =
let require = Js.Unsafe.eval_string "require" in
require##call(require, Js.string x)
}}
(* vim: set ft=ocaml: *)
node_fs.eliom:
{client{
open Printf
open Lwt
class type error =
object
method message : Js.js_string Js.t Js.prop
end
type maybe_error = error Js.t Js.opt
class type stats =
object
method dev : int Js.readonly_prop
method ino : int Js.readonly_prop
method mode : int Js.readonly_prop
method nlink : int Js.readonly_prop
method uid : int Js.readonly_prop
method gid : int Js.readonly_prop
method rdev : int Js.readonly_prop
method size : float Js.t Js.readonly_prop
method blksize : int Js.readonly_prop
method blocks : int Js.readonly_prop
method atime : Js.date Js.t Js.readonly_prop
method mtime : Js.date Js.t Js.readonly_prop
method ctime : Js.date Js.t Js.readonly_prop
end
and watch_options =
object
method persistent : bool Js.t Js.prop
end
class type fs =
object
method existsSync : Js.js_string Js.t -> bool Js.t Js.meth
method exists : Js.js_string Js.t -> (bool Js.t -> unit) Js.callback -> unit Js.meth
method readFile :
Js.js_string Js.t ->
(maybe_error -> Node_net.buffer Js.t -> unit) Js.callback -> unit Js.meth
method readFileSync : Js.js_string Js.t -> Node_net.buffer Js.t Js.meth
method readdirSync : Js.js_string Js.t -> Js.js_string Js.t Js.js_array Js.t Js.meth
method statSync : Js.js_string Js.t -> stats Js.t Js.opt Js.meth
method lstatSync : Js.js_string Js.t -> stats Js.t Js.opt Js.meth
method mkdir :
Js.js_string Js.t -> int -> (maybe_error -> unit) Js.callback -> unit Js.meth
method mkdirSync : Js.js_string Js.t -> int -> unit Js.meth
method unlink : Js.js_string Js.t -> (maybe_error -> unit) Js.callback -> unit Js.meth
method unlinkSync : Js.js_string Js.t -> unit Js.meth
method watch : 'a. Js.js_string Js.t -> (#watch_options as 'a) Js.t ->
(Js.js_string -> Js.js_string -> unit) Js.callback -> unit Js.meth
end
let fs : fs Js.t = Node_require.require "fs"
let err_callback1 u err =
match Js.Opt.to_option err with
None -> Lwt.wakeup_later u ()
| Some err -> Lwt.wakeup_later_exn u (Failure (Js.to_string err##message))
let bool_callback1 u b = Lwt.wakeup_later u (Js.to_bool b)
let wrap_async1 callback f =
let t, u = Lwt.wait () in
f (Js.wrap_callback (callback u));
t
let exists s = wrap_async1 bool_callback1 (fun cb -> fs##exists(Js.string s, cb))
let unlink s = wrap_async1 err_callback1 (fun cb -> fs##unlink(Js.string s, cb))
let read_file fname =
let t, u = Lwt.wait () in
let on_read err data =
if Js.Opt.test err then
Lwt.wakeup_later_exn u (Failure (sprintf "could not read %S" fname))
else Lwt.wakeup_later u (Js.to_string data##toString())
in
fs##readFile(Js.string fname, Js.wrap_callback on_read);
t
}}
(* vim: set ft=ocaml: *)
--
Mauricio Fernández
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2015-04-29 22:49 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-27 20:32 [Caml-list] js_of_ocaml with node Helmut Brandl
2015-04-27 21:02 ` Sébastien Dailly
2015-04-27 21:16 ` Helmut Brandl
2015-04-28 7:08 ` Sébastien Dailly
2015-04-27 21:11 ` Daniel Bünzli
2015-04-27 22:03 ` Alain Frisch
2015-04-27 22:41 ` Daniel Bünzli
2015-04-28 7:53 ` Alain Frisch
2015-04-28 8:11 ` Alain Frisch
2015-04-28 11:17 ` Drup
2015-04-29 22:03 ` Helmut Brandl
2015-04-29 22:49 ` Mauricio Fernández
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox