Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file oBus_signal.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292(*
* oBus_signal.ml
* --------------
* Copyright : (c) 2010, Jeremie Dimino <jeremie@dimino.org>
* Licence : BSD3
*
* This file is a part of obus, an ocaml implementation of D-Bus.
*)letsection=Lwt_log.Section.make"obus(signal)"openLwt_react(* +-----------------------------------------------------------------+
| Signal descriptors |
+-----------------------------------------------------------------+ *)type'at={interface:OBus_name.interface;(* The interface of the signal. *)member:OBus_name.member;(* The name of the signal. *)peer:OBus_peer.t;(* The peer emitting the signal. *)path:OBus_path.toption;(* The path of the object emitting the signa or [None] if we want to
match signals comming from any objects. *)map:(OBus_context.t*OBus_path.t*OBus_value.V.sequence)event->(OBus_context.t*'a)event;(* The function which maps the event into an event holding values of
type ['a]. *)filters:OBus_match.arguments;(* Argument filters. *)match_rule:bool;(* Whether the managed mode for the match rule is enabled *)}letempty_filters=OBus_match.make_arguments[](* Cast a message body into an ocaml value: *)letcastsignal(context,path,body)=trySome(context,OBus_value.C.cast_sequence(OBus_value.arg_types(OBus_member.Signal.argssignal))body)withOBus_value.C.Signature_mismatch->ignore(Lwt_log.error_f~section"failed to cast signal from %S, interface %S, member %S with signature %S to %S"(OBus_peer.name(OBus_context.sendercontext))(OBus_member.Signal.interfacesignal)(OBus_member.Signal.membersignal)(OBus_value.string_of_signature(OBus_value.V.type_of_sequencebody))(OBus_value.string_of_signature(OBus_value.C.type_sequence(OBus_value.arg_types(OBus_member.Signal.argssignal)))));Noneletcast_anysignal(context,path,body)=matchcastsignal(context,path,body)with|Some(context,v)->Some(context,(OBus_proxy.make(OBus_context.sendercontext)path,v))|None->Noneletmakesignalproxy={interface=OBus_member.Signal.interfacesignal;member=OBus_member.Signal.membersignal;peer=OBus_proxy.peerproxy;path=Some(OBus_proxy.pathproxy);map=E.fmap(castsignal);filters=empty_filters;match_rule=OBus_connection.name(OBus_proxy.connectionproxy)<>"";}letmake_anysignalpeer={interface=OBus_member.Signal.interfacesignal;member=OBus_member.Signal.membersignal;peer=peer;path=None;map=E.fmap(cast_anysignal);filters=empty_filters;match_rule=OBus_connection.name(OBus_peer.connectionpeer)<>"";}(* +-----------------------------------------------------------------+
| Signals transformations and parameters |
+-----------------------------------------------------------------+ *)letmap_eventfsd={sdwithmap=funevent->f(sd.mapevent)}letmapfsd={sdwithmap=funevent->E.map(fun(context,value)->(context,fvalue))(sd.mapevent)}letmap_with_contextfsd={sdwithmap=funevent->E.map(fun(context,value)->(context,fcontextvalue))(sd.mapevent)}letwith_contextsd={sdwithmap=funevent->E.map(fun(context,value)->(context,(context,value)))(sd.mapevent)}letwith_filtersfilterssd={sdwithfilters}letwith_match_rulematch_rulesd={sdwithmatch_rule}(* +-----------------------------------------------------------------+
| Signals dispatching |
+-----------------------------------------------------------------+ *)moduleSignal_map=Map.Make(structtypet=OBus_path.toption*OBus_name.interface*OBus_name.memberletcompare=Pervasives.compareend)typeinfo={mutablesenders:(OBus_context.t*OBus_path.t*OBus_value.V.sequence->unit)Lwt_sequence.tSignal_map.t;}letdispatchconnectioninfomessage=matchOBus_message.typmessagewith|OBus_message.Signal(path,interface,member)->beginmatchtrySome(Signal_map.find(Somepath,interface,member)info.senders)withNot_found->Nonewith|Somesenders->Lwt_sequence.iter_l(funsend->trysend(OBus_context.makeconnectionmessage,path,OBus_message.bodymessage)withexn->ignore(Lwt_log.error~section~exn"signal event failed with"))senders|None->()end;beginmatchtrySome(Signal_map.find(None,interface,member)info.senders)withNot_found->Nonewith|Somesenders->Lwt_sequence.iter_l(funsend->trysend(OBus_context.makeconnectionmessage,path,OBus_message.bodymessage)withexn->ignore(Lwt_log.error~section~exn"signal event failed with"))senders|None->()end;Somemessage|_->Somemessage(* +-----------------------------------------------------------------+
| Signals connection |
+-----------------------------------------------------------------+ *)letfinalisedisconnect_=ignore(Lazy.forcedisconnect)letkey=OBus_connection.new_key()letconnect?switchsd=Lwt_switch.checkswitch;letconnection=OBus_peer.connectionsd.peerandname=OBus_peer.namesd.peerin(* Switch freeing resources allocated for this signal: *)letresources_switch=Lwt_switch.create()intry%lwt(* Add the match rule if requested: *)let%lwt()=ifsd.match_rulethenOBus_match.export~switch:resources_switchconnection(OBus_match.rule~typ:`Signal~sender:name?path:sd.path~interface:sd.interface~member:sd.member())elseLwt.return()(* Plus the resolver if needed: *)andowner_option=ifOBus_connection.nameconnection<>""&&name<>""thenifOBus_name.is_uniquenamethenLwt.return(Some(S.constname))elselet%lwtowner=OBus_resolver.make~switch:resources_switchconnectionnameinLwt.return(Someowner)elseLwt.returnNoneinletinfo=matchOBus_connection.getconnectionkeywith|Someinfo->info|None->letinfo={senders=Signal_map.empty;}inOBus_connection.setconnectionkey(Someinfo);let_=Lwt_sequence.add_l(dispatchconnectioninfo)(OBus_connection.incoming_filtersconnection)ininfoinletsenders=matchtrySome(Signal_map.find(sd.path,sd.interface,sd.member)info.senders)withNot_found->Nonewith|Somesenders->senders|None->letsenders=Lwt_sequence.create()ininfo.senders<-Signal_map.add(sd.path,sd.interface,sd.member)sendersinfo.senders;sendersinletevent,send=E.create()inletsendv=sendvinletnode=Lwt_sequence.add_rsendsendersinletevent=E.filter(fun(context,path,body)->matchowner_optionwith|SomeownerwhenS.valueowner<>OBus_peer.name(OBus_context.sendercontext)->false|_->OBus_match.match_valuessd.filtersbody)eventinletdisconnect=lazy(try%lwtLwt_sequence.removenode;ifLwt_sequence.is_emptysenderstheninfo.senders<-Signal_map.remove(sd.path,sd.interface,sd.member)info.senders;Lwt_switch.turn_offresources_switchwithexn->let%lwt()=Lwt_log.warning_f~section~exn"failed to disconnect signal \"%s.%s\" of object \"%s\" from \"%s\""sd.interfacesd.member(matchsd.pathwith|Somepath->OBus_path.to_stringpath|None->"<any>")(OBus_peer.namesd.peer)inLwt.failexn)inletevent=E.with_finaliser(finalisedisconnect)(E.mapsnd(sd.mapevent))inlet%lwt()=Lwt_switch.add_hook_or_execswitch(fun()->E.stopevent;Lazy.forcedisconnect)inLwt.returneventwithexn->let%lwt()=Lwt_switch.turn_offresources_switchinLwt.failexn(* +-----------------------------------------------------------------+
| Emitting signals |
+-----------------------------------------------------------------+ *)letemitinfoobj?peerargs=OBus_object.emitobj~interface:(OBus_member.Signal.interfaceinfo)~member:(OBus_member.Signal.memberinfo)?peer(OBus_value.arg_types(OBus_member.Signal.argsinfo))args