Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file oBus_property.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364(*
* oBus_property.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(property)"openLwt.InfixopenLwt_reactopenOBus_interfaces.Org_freedesktop_DBus_Properties(* +-----------------------------------------------------------------+
| Types |
+-----------------------------------------------------------------+ *)moduleString_map=Map.Make(String)typemap=(OBus_context.t*OBus_value.V.single)String_map.ttypemonitor=OBus_proxy.t->OBus_name.interface->Lwt_switch.t->mapsignalLwt.ttype('a,'access)t={p_interface:OBus_name.interface;(* The interface of the property. *)p_member:OBus_name.member;(* The name of the property. *)p_proxy:OBus_proxy.t;(* The object owning the property. *)p_monitor:monitor;(* Monitor for this property. *)p_cast:OBus_context.t->OBus_value.V.single->'a;p_make:'a->OBus_value.V.single;}type'ar=('a,[`readable])ttype'aw=('a,[`writable])ttype'arw=('a,[`readable|`writable])ttypegroup={g_interface:OBus_name.interface;(* The interface of the group *)g_proxy:OBus_proxy.t;(* The object owning the group of properties *)g_monitor:monitor;(* Monitor for this group. *)}moduleGroup_map=Map.Make(structtypet=OBus_name.bus*OBus_path.t*OBus_name.interface(* Groups are indexed by:
- name of the owner of the property
- path of the object owning the property
- interfaec of the property *)letcompare=Pervasives.compareend)(* Type of a cache for a group *)typecache={mutablec_count:int;(* Numbers of monitored properties using this group. *)c_map:mapsignal;(* The signal holding the current state of properties. *)c_switch:Lwt_switch.t;(* Switch for the signal used to monitor the group. *)}typeinfo={mutablecache:cacheLwt.tGroup_map.t;(* Cache of all monitored properties. *)}(* +-----------------------------------------------------------------+
| Default monitor |
+-----------------------------------------------------------------+ *)letupdate_mapcontextdictmap=List.fold_left(funmap(name,value)->String_map.addname(context,value)map)mapdictletmap_of_listcontextdict=update_mapcontextdictString_map.emptyletget_all_no_cacheproxyinterface=OBus_method.call_with_contextm_GetAllproxyinterfaceletdefault_monitorproxyinterfaceswitch=let%lwtevent=OBus_signal.connect~switch(OBus_signal.with_filters(OBus_match.make_arguments[(0,OBus_match.AF_stringinterface)])(OBus_signal.with_context(OBus_signal.makes_PropertiesChangedproxy)))andcontext,dict=get_all_no_cacheproxyinterfaceinLwt.return(S.mapsnd(S.fold_s~eq:(fun(_,a)(_,b)->String_map.equal(=)ab)(fun(_,map)(sig_context,(interface,updates,invalidates))->ifinvalidates=[]thenLwt.return(sig_context,update_mapsig_contextupdatesmap)elselet%lwtcontext,dict=get_all_no_cacheproxyinterfaceinLwt.return(sig_context,map_of_listcontextdict))(context,map_of_listcontextdict)event))(* +-----------------------------------------------------------------+
| Property creation |
+-----------------------------------------------------------------+ *)letmake?(monitor=default_monitor)descproxy={p_interface=OBus_member.Property.interfacedesc;p_member=OBus_member.Property.memberdesc;p_proxy=proxy;p_monitor=monitor;p_cast=(funcontextvalue->OBus_value.C.cast_single(OBus_member.Property.typdesc)value);p_make=(OBus_value.C.make_single(OBus_member.Property.typdesc));}letgroup?(monitor=default_monitor)proxyinterface={g_proxy=proxy;g_interface=interface;g_monitor=monitor;}(* +-----------------------------------------------------------------+
| Transformations |
+-----------------------------------------------------------------+ *)letmap_rwfgproperty={propertywithp_cast=(funcontextx->f(property.p_castcontextx));p_make=(funx->property.p_make(gx));}letmap_rw_with_contextfgproperty={propertywithp_cast=(funcontextx->fcontext(property.p_castcontextx));p_make=(funx->property.p_make(gx));}letmap_rfproperty={propertywithp_cast=(funcontextx->f(property.p_castcontextx));p_make=(funx->assertfalse);}letmap_r_with_contextfproperty={propertywithp_cast=(funcontextx->fcontext(property.p_castcontextx));p_make=(funx->assertfalse);}letmap_wgproperty={propertywithp_cast=(funcontextx->assertfalse);p_make=(funx->property.p_make(gx));}(* +-----------------------------------------------------------------+
| Operations on maps |
+-----------------------------------------------------------------+ *)letfindpropertymap=letcontext,value=String_map.findproperty.p_membermapinproperty.p_castcontextvalueletfind_with_contextpropertymap=letcontext,value=String_map.findproperty.p_membermapin(context,property.p_castcontextvalue)letfind_valuenamemap=letcontext,value=String_map.findnamemapinvalueletfind_value_with_contextnamemap=String_map.findnamemapletprint_mapppmap=letopenFormatinpp_open_boxpp2;pp_print_stringpp"{";pp_print_cutpp();pp_open_hvboxpp0;String_map.iter(funname(context,value)->pp_open_boxpp0;pp_print_stringppname;pp_print_spacepp();pp_print_stringpp"=";pp_print_spacepp();OBus_value.V.print_singleppvalue;pp_print_stringpp";";pp_close_boxpp();pp_print_cutpp())map;pp_close_boxpp();pp_print_cutpp();pp_print_stringpp"}";pp_close_boxpp()letstring_of_mapmap=letopenFormatinletbuf=Buffer.create42inletpp=formatter_of_bufferbufinpp_set_marginppmax_int;print_mapppmap;pp_print_flushpp();Buffer.contentsbuf(* +-----------------------------------------------------------------+
| Properties reading/writing |
+-----------------------------------------------------------------+ *)letkey=OBus_connection.new_key()letget_with_contextprop=matchOBus_connection.get(OBus_proxy.connectionprop.p_proxy)keywith|Someinfo->beginmatchtrySome(Group_map.find(OBus_proxy.nameprop.p_proxy,OBus_proxy.pathprop.p_proxy,prop.p_interface)info.cache)withNot_found->Nonewith|Somecache_thread->let%lwtcache=cache_threadinLwt.return(find_with_contextprop(S.valuecache.c_map))|None->let%lwtcontext,value=OBus_method.call_with_contextm_Getprop.p_proxy(prop.p_interface,prop.p_member)inLwt.return(context,prop.p_castcontextvalue)end|None->let%lwtcontext,value=OBus_method.call_with_contextm_Getprop.p_proxy(prop.p_interface,prop.p_member)inLwt.return(context,prop.p_castcontextvalue)letgetprop=get_with_contextprop>|=sndletsetpropvalue=OBus_method.callm_Setprop.p_proxy(prop.p_interface,prop.p_member,prop.p_makevalue)letget_groupgroup=matchOBus_connection.get(OBus_proxy.connectiongroup.g_proxy)keywith|Someinfo->beginmatchtrySome(Group_map.find(OBus_proxy.namegroup.g_proxy,OBus_proxy.pathgroup.g_proxy,group.g_interface)info.cache)withNot_found->Nonewith|Somecache_thread->let%lwtcache=cache_threadinLwt.return(S.valuecache.c_map)|None->let%lwtcontext,dict=get_all_no_cachegroup.g_proxygroup.g_interfaceinLwt.return(map_of_listcontextdict)end|None->let%lwtcontext,dict=get_all_no_cachegroup.g_proxygroup.g_interfaceinLwt.return(map_of_listcontextdict)(* +-----------------------------------------------------------------+
| Monitoring |
+-----------------------------------------------------------------+ *)letfinalisedisable_=ignore(Lazy.forcedisable)letmonitor_group?switchgroup=Lwt_switch.checkswitch;letcache_key=(OBus_proxy.namegroup.g_proxy,OBus_proxy.pathgroup.g_proxy,group.g_interface)inletinfo=matchOBus_connection.get(OBus_proxy.connectiongroup.g_proxy)keywith|Someinfo->info|None->letinfo={cache=Group_map.empty}inOBus_connection.set(OBus_proxy.connectiongroup.g_proxy)key(Someinfo);infoinlet%lwtcache=matchtrySome(Group_map.findcache_keyinfo.cache)withNot_found->Nonewith|Somecache_thread->cache_thread|None->letwaiter,wakener=Lwt.wait()ininfo.cache<-Group_map.addcache_keywaiterinfo.cache;letswitch=Lwt_switch.create()intry%lwtlet%lwtsignal=group.g_monitorgroup.g_proxygroup.g_interfaceswitchinletcache={c_count=0;c_map=signal;c_switch=switch;}inLwt.wakeupwakenercache;Lwt.returncachewithexn->info.cache<-Group_map.removecache_keyinfo.cache;Lwt.wakeup_exnwakenerexn;let%lwt()=Lwt_switch.turn_offswitchinLwt.failexnincache.c_count<-cache.c_count+1;letdisable=lazy(try%lwtcache.c_count<-cache.c_count-1;ifcache.c_count=0thenbegininfo.cache<-Group_map.removecache_keyinfo.cache;Lwt_switch.turn_offcache.c_switchendelseLwt.return()withexn->let%lwt()=Lwt_log.warning_f~section~exn"failed to disable monitoring of properties for interface %S on object %S from %S"group.g_interface(OBus_path.to_string(OBus_proxy.pathgroup.g_proxy))(OBus_proxy.namegroup.g_proxy)inLwt.failexn)inletsignal=S.with_finaliser(finalisedisable)cache.c_mapinlet%lwt()=Lwt_switch.add_hook_or_execswitch(fun()->S.stopsignal;Lazy.forcedisable)inLwt.returnsignalletmonitor?switchprop=let%lwtsignal=monitor_group?switch{g_interface=prop.p_interface;g_proxy=prop.p_proxy;g_monitor=prop.p_monitor}inLwt.return(S.map(findprop)signal)