Eliom客户机到客户机消息传递- Eref范围问题



我最近一直在努力更好地理解Eliom的通信功能,为了做到这一点,我试图建立一个简单的网页,允许用户相互发送消息。

如果我通过Firefox作为一个用户登录,第二个用户通过Chrome登录,网页工作正常。但是,当我登录两个不同的用户在同一个浏览器,并尝试从一个用户发送消息到另一个(即从一个选项卡到另一个选项卡),发送的任何消息显示在所有选项卡,而不是预期的收件人的选项卡。

我认为,我可能有一些问题与选择的范围为eref或我在哪里设置/获取范围和eref(顶层与服务定义)。

我正试图纠正我的错误,以便两个用户可以登录到同一浏览器的两个不同的选项卡,并相互发送消息,消息只显示在正确的用户选项卡上。

注意:部分代码取自Eliom网站教程:http://ocsigen.org/tuto/4.2/manual/how-to-implement-a-notification-system

我的。eliom文件:

(* Example website login: localhost:8080/?user_num=1 *)
{shared{
  open Eliom_lib
  open Eliom_content
  open Html5
  open Html5.F
  open Eliom_registration
  open Eliom_parameter
}}
module Channel_example_app =
  Eliom_registration.App (
    struct
      let application_name = "channel_example"
    end)
let main_service =
  Eliom_service.App.service ~path:[] ~get_params:(string "user_num") ()
let new_message_action =
  Eliom_service.Http.post_coservice'
    ~post_params:(string "from_user_id" ** string "to_user_id" ** string "msg") ()
(* Set the scope used by all erefs *)
let eref_scope = Eliom_common.default_process_scope
(* Create a channel eref *)
let channel_ref =
  Eliom_reference.Volatile.eref_from_fun
    ~scope:eref_scope
    (fun () ->
      let (s, notify) = Lwt_stream.create () in
      let c = Eliom_comet.Channel.create s in
      (c, notify)
    )
(* Reactive string eref *)
let react_string_ref =
  Eliom_reference.Volatile.eref_from_fun
    ~scope:eref_scope
    (fun () ->
      let (client_string, send_client_string) :
          (string React.E.t * (?step:React.step -> string -> unit) ) =
        React.E.create ()
      in
      (client_string, send_client_string)
    )
(* Reactive string to display the users session group *)
let react_session_group_ref =
  Eliom_reference.Volatile.eref_from_fun
    ~scope:eref_scope
    (fun () ->
      let (session_group_string, send_session_group_string) :
          (string React.E.t * (?step:React.step -> string -> unit) ) =
        React.E.create ()
      in
      (session_group_string, send_session_group_string)
    )
(* Reactive string to display the users session group size *)
let react_session_group_size_ref =
  Eliom_reference.Volatile.eref_from_fun
    ~scope:eref_scope
    (fun () ->
      let (session_group_size_string, send_session_group_size_string) :
          (string React.E.t * (?step:React.step -> string -> unit) ) =
        React.E.create ()
      in
      (session_group_size_string, send_session_group_size_string)
    )
(* Send a message from one client to another *)
let notify from_user_id to_user_id s =
  (* Get the session group state for the user *)
  let state =
    Eliom_state.Ext.volatile_data_group_state     ~scope:Eliom_common.default_group_scope to_user_id in
    (* Iterate on all sessions from the group *)
    Eliom_state.Ext.iter_volatile_sub_states ~state
    (fun state ->
      (* Iterate on all client process states in the session *)
      Eliom_state.Ext.iter_volatile_sub_states ~state
      (fun state ->
        let (_, notify) = Eliom_reference.Volatile.Ext.get state channel_ref in
        notify (Some ("Hello from " ^ from_user_id ^ "! You are user " ^ to_user_id ^ "nn" ^ s))
      )
    )
(* Action for a client to send a message *)
let () =
  Eliom_registration.Action.register
    ~options:`NoReload
    ~service:new_message_action
    (fun () (from_user_id, (to_user_id, msg)) ->
      Lwt.return @@ notify from_user_id to_user_id msg
    )
(* Post form for one user to send a message to another user *)
let client_message_form =
  Eliom_content.Html5.F.post_form ~service:new_message_action ~port:8080
  (
    fun (from_user_id, (to_user_id, msg)) ->
      [p [pcdata "To:"];
       string_input ~input_type:`Text ~name:to_user_id ();
       p [pcdata "From:"];
       string_input ~input_type:`Text ~name:from_user_id ();
       p [pcdata "Send a message here:"];
       string_input ~input_type:`Text ~name:msg ();
       button ~button_type:`Submit [pcdata "Send Message"]
      ]
  )
let () =
  Channel_example_app.register
    ~service:main_service
    (fun user_num () ->
      (* Set the session group to which the erefs belong *)
      Eliom_state.set_volatile_data_session_group
        ~set_max:1
        ~scope:Eliom_common.default_session_scope
        ~secure:true
        user_num;
      let (channel, _) = Eliom_reference.Volatile.get channel_ref in
      let my_client_string, my_send_client_string = Eliom_reference.Volatile.get react_string_ref in
      let my_send_client_string' =
        server_function Json.t<string> (fun s -> Lwt.return @@ my_send_client_string s)
      in
      let c_down = Eliom_react.Down.of_react my_client_string in
      (* When a message is received on the channel, push it as a reactive event *)
      let _ =
        {unit{
          Lwt.async
            (fun () ->
              Lwt_stream.iter (fun (s : string) -> ignore @@ %my_send_client_string' s) %channel
            )
        }}
      in
      let my_session_group =
        match
          Eliom_state.get_volatile_data_session_group
            ~scope:Eliom_common.default_session_scope
            ~secure:true ()
        with
        | None -> "No session group"
        | Some sg -> sg
      in
      let my_session_group_size =
        match
          Eliom_state.get_volatile_data_session_group_size
            ~scope:Eliom_common.default_session_scope
            ~secure:true ()
        with
        | None -> "0"
        | Some gs -> string_of_int gs
      in
      Lwt.return
        (Eliom_tools.F.html
           ~title:"channel_example"
           ~css:[["css";"channel_example.css"]]
           Eliom_content.Html5.F.(body [
             h2 [pcdata ("Your are logged in as user " ^ user_num)];
             client_message_form ();
             p [pcdata "Your message is:"];
             C.node {{R.pcdata (React.S.hold "No message yet" %c_down)}};
             p [pcdata ("I am a part of the session group named " ^ my_session_group)];
             p [pcdata ("My session group size is " ^ my_session_group_size)]
           ])))

问题来自于使用遍历所有选项卡的notify函数。我使用了Eliom基础应用程序的哈希表/弱哈希表结构,它纠正了所有的通信问题。关键是修改通知函数,如下所示:

let notify ?(notforme = false) ~id ~to_user ~msg =
  Lwt.async (fun () ->
    I.fold
      (fun (userid_o, ((_, _, send_e) as nn)) (beg : unit Lwt.t) ->
        if notforme && nn == Eliom_reference.Volatile.get notif_e
        then Lwt.return ()
        else
          lwt () = beg in
          let content = if Some to_user = userid_o then Some msg else None in
          match content with
          | Some content -> send_e (id, content); Lwt.return ()
          | None -> Lwt.return ()
      )
      id (Lwt.return ()))

相关内容

  • 没有找到相关文章

最新更新