2929-behaviour (gen_mod ).
3030
3131-export ([start /2 , stop /1 , reload /3 , depends /2 , mod_doc /0 ,
32- muc_online_rooms /1 , muc_online_rooms_by_regex /2 ,
33- muc_register_nick /3 , muc_register_nick /4 ,
34- muc_unregister_nick /2 , muc_unregister_nick /3 ,
32+ muc_online_rooms /1 , muc_online_rooms_by_regex /2 ,
33+ muc_register_nick /3 , muc_register_nick /4 ,
34+ muc_unregister_nick /2 , muc_unregister_nick /3 ,
3535 muc_get_registered_nick /3 ,
3636 muc_get_registered_nicks /1 ,
37- create_room_with_opts /4 , create_room /3 , destroy_room /2 ,
38- create_rooms_file /1 , destroy_rooms_file /1 ,
39- rooms_unused_list /2 , rooms_unused_destroy /2 ,
40- rooms_empty_list /1 , rooms_empty_destroy /1 , rooms_empty_destroy_restuple /1 ,
41- get_user_rooms /2 , get_user_subscriptions /2 , get_room_occupants /2 ,
42- get_room_occupants_number /2 , send_direct_invitation /5 ,
43- change_room_option /4 , get_room_options /2 ,
44- set_room_affiliation /4 , set_room_affiliation /5 , get_room_affiliations /2 ,
45- get_room_affiliations_v3 /2 , get_room_affiliation /3 ,
46- subscribe_room /4 , subscribe_room /6 ,
47- subscribe_room_many /3 , subscribe_room_many_v3 /4 ,
48- unsubscribe_room /2 , unsubscribe_room /4 , get_subscribers /2 ,
49- get_room_serverhost /1 ,
50- web_menu_main /2 , web_page_main /2 ,
37+ create_room_with_opts /4 , create_room /3 , destroy_room /2 ,
38+ create_rooms_file /1 , destroy_rooms_file /1 ,
39+ rooms_unused_list /2 , rooms_unused_destroy / 2 , rooms_unused_destroy_skip_notifications /2 ,
40+ rooms_empty_list /1 , rooms_empty_destroy /1 , rooms_empty_destroy_restuple /1 ,
41+ get_user_rooms /2 , get_user_subscriptions /2 , get_room_occupants /2 ,
42+ get_room_occupants_number /2 , send_direct_invitation /5 ,
43+ change_room_option /4 , get_room_options /2 ,
44+ set_room_affiliation /4 , set_room_affiliation /5 , get_room_affiliations /2 ,
45+ get_room_affiliations_v3 /2 , get_room_affiliation /3 ,
46+ subscribe_room /4 , subscribe_room /6 ,
47+ subscribe_room_many /3 , subscribe_room_many_v3 /4 ,
48+ unsubscribe_room /2 , unsubscribe_room /4 , get_subscribers /2 ,
49+ get_room_serverhost /1 ,
50+ web_menu_main /2 , web_page_main /2 ,
5151 web_menu_host /3 , web_page_host /3 ,
5252 web_menu_hostuser /4 , web_page_hostuser /4 ,
5353 webadmin_muc /2 ,
54- mod_opt_type /1 , mod_options /1 ,
55- get_commands_spec /0 , find_hosts /1 , room_diagnostics /2 ,
56- get_room_pid /2 , get_room_history /2 , muc_online_rooms_count /1 ]).
54+ mod_opt_type /1 , mod_options /1 ,
55+ get_commands_spec /0 , find_hosts /1 , room_diagnostics /2 ,
56+ get_room_pid /2 , get_room_history /2 , muc_online_rooms_count /1 ]).
5757
5858-import (ejabberd_web_admin , [make_command /4 , make_command_raw_value /3 , make_table /4 ]).
5959
@@ -286,6 +286,21 @@ get_commands_spec() ->
286286 args = [{service , binary }, {days , integer }],
287287 args_rename = [{host , service }],
288288 result = {rooms , {list , {room , string }}}},
289+ # ejabberd_commands {name = rooms_unused_destroy_skip_notifications , tags = [muc ],
290+ desc = " Destroy the rooms that are unused for many days in the service, but may skip notifications to subscribers" ,
291+ note = " added in 26.XX" ,
292+ longdesc = " The room recent history is used, so it's recommended "
293+ " to wait a few days after service start before running this."
294+ " The MUC service argument can be `global` to get all hosts."
295+ " This version may skip sending notifications to subscribers, for performance reasons" ,
296+ module = ? MODULE , function = rooms_unused_destroy_skip_notifications ,
297+ args_desc = [" MUC service, or `global` for all" , " Number of days" ],
298+ args_example = [" conference.example.com" , 31 ],
299+ result_desc = " List of unused rooms that has been destroyed" ,
300+ result_example = [" room1@conference.example.com" , " room2@conference.example.com" ],
301+ args = [{service , binary }, {days , integer }],
302+ args_rename = [{host , service }],
303+ result = {rooms , {list , {room , string }}}},
289304
290305 # ejabberd_commands {name = rooms_empty_list , tags = [muc ],
291306 desc = " List the rooms that have no messages in archive" ,
@@ -1510,10 +1525,112 @@ get_host_details(Host, ServerHostsDetails) ->
15101525% %---------------
15111526% % Control
15121527
1513- rooms_unused_list (Service , Days ) ->
1514- rooms_report (unused , list , Service , Days ).
1515- rooms_unused_destroy (Service , Days ) ->
1516- rooms_report (unused , destroy , Service , Days ).
1528+ get_unused_rooms (Service , ServerHost , Days ) ->
1529+ Mod = gen_mod :db_mod (ServerHost , mod_muc ),
1530+ RMod = gen_mod :ram_db_mod (ServerHost , mod_muc ),
1531+ NodeStartTime = erlang :system_time (microsecond ) -
1532+ 1000000 * (erlang :monotonic_time (second ) - ejabberd_config :get_node_start ()),
1533+ DaysMs = Days * timer :hours (24 ),
1534+ Timestamp = erlang :system_time (microsecond ) - DaysMs * 1000 ,
1535+
1536+ DbRooms = case erlang :function_exported (Mod , get_hibernated_rooms_older_than , 3 ) of
1537+ true ->
1538+ lists :filtermap (
1539+ fun (R ) ->
1540+ case RMod :find_online_room (ServerHost , R , Service ) of
1541+ error ->
1542+ {true , {R , Service , undefined }};
1543+ _ ->
1544+ false
1545+ end
1546+ end , Mod :get_hibernated_rooms_older_than (ServerHost , Service , Timestamp ));
1547+ _ ->
1548+ lists :filtermap (
1549+ fun (# muc_room {name_host = {R , _ }, opts = Opts }) ->
1550+ case RMod :find_online_room (ServerHost , R , Service ) of
1551+ error ->
1552+ TS = case lists :keyfind (hibernation_time , 1 , Opts ) of
1553+ false -> NodeStartTime ;
1554+ {_ , undefined } -> NodeStartTime ;
1555+ {_ , T } -> T
1556+ end ,
1557+ if TS > Timestamp ->
1558+ false ;
1559+ true ->
1560+ {true , {R , Service , undefined }}
1561+ end ;
1562+ _ ->
1563+ false
1564+ end
1565+ end , Mod :get_rooms (ServerHost , Service ))
1566+ end ,
1567+ case mod_muc_opt :hibernation_timeout (ServerHost ) < DaysMs of
1568+ true ->
1569+ DbRooms ;
1570+ false ->
1571+ OldOnline = lists :filtermap (
1572+ fun ({RoomName , RoomHost , RoomPid }) ->
1573+ case mod_muc_room :get_state (RoomPid ) of
1574+ {ok , # state {just_created = true }} ->
1575+ false ;
1576+ {ok , # state {just_created = TS , users = U }} when TS =< Timestamp , map_size (U ) == 0 ->
1577+ {true , {RoomName , RoomHost , RoomPid }};
1578+ _ ->
1579+ false
1580+ end
1581+ end , RMod :get_online_rooms (ServerHost , Service , undefined )),
1582+ OldOnline ++ DbRooms
1583+ end .
1584+
1585+ destroy_room_helper (Msg , _Room , _Service , _ServerHost , Pid , _ ) when is_pid (Pid ) ->
1586+ mod_muc_room :destroy (Pid , Msg );
1587+ destroy_room_helper (Msg , Room , Service , _ServerHost , _Pid , true ) ->
1588+ case get_room_pid (Room , Service ) of
1589+ Pid2 when is_pid (Pid2 ) ->
1590+ mod_muc_room :destroy (Pid2 , Msg );
1591+ _ ->
1592+ ok
1593+ end ;
1594+ destroy_room_helper (_Msg , Room , Service , ServerHost , _Pid , false ) ->
1595+ mod_muc :forget_room (ServerHost , Service , Room ).
1596+
1597+ rooms_unused_list (ServiceArg , Days ) ->
1598+ Services = find_services (ServiceArg ),
1599+ lists :flatmap (
1600+ fun (Service ) ->
1601+ ServerHost = get_room_serverhost (Service ),
1602+ lists :map (
1603+ fun ({R , S , _ }) ->
1604+ jid :encode ({R , S , <<>>})
1605+ end ,
1606+ get_unused_rooms (Service , ServerHost , Days ))
1607+ end , Services ).
1608+
1609+ rooms_unused_destroy (ServiceArg , Days ) ->
1610+ Services = find_services (ServiceArg ),
1611+ Msg = <<" Room destroyed by rooms_unused_destroy" >>,
1612+ lists :flatmap (
1613+ fun (Service ) ->
1614+ ServerHost = get_room_serverhost (Service ),
1615+ lists :map (
1616+ fun ({R , S , Pid }) ->
1617+ destroy_room_helper (Msg , R , S , ServerHost , Pid , true ),
1618+ jid :encode ({R , S , <<>>})
1619+ end , get_unused_rooms (Service , ServerHost , Days ))
1620+ end , Services ).
1621+
1622+ rooms_unused_destroy_skip_notifications (ServiceArg , Days ) ->
1623+ Services = find_services (ServiceArg ),
1624+ Msg = <<" Room destroyed by rooms_unused_destroy" >>,
1625+ lists :flatmap (
1626+ fun (Service ) ->
1627+ ServerHost = get_room_serverhost (Service ),
1628+ lists :map (
1629+ fun ({R , S , Pid }) ->
1630+ destroy_room_helper (Msg , R , S , ServerHost , Pid , false ),
1631+ jid :encode ({R , S , <<>>})
1632+ end , get_unused_rooms (Service , ServerHost , Days ))
1633+ end , Services ).
15171634
15181635rooms_empty_list (Service ) ->
15191636 rooms_report (empty , list , Service , 0 ).
@@ -1532,10 +1649,10 @@ rooms_report(Method, Action, Service, Days) ->
15321649
15331650muc_unused (Method , Action , Service , Last_allowed ) ->
15341651 % % Get all required info about all existing rooms
1535- Rooms_all = get_all_rooms (Service , erlang : system_time ( microsecond ) - Last_allowed * 24 * 60 * 60 * 1000 ),
1652+ Rooms_all = get_all_rooms (Service ),
15361653
15371654 % % Decide which ones pass the requirements
1538- Rooms_pass = decide_rooms (Method , Rooms_all , Last_allowed ),
1655+ Rooms_pass = decide_rooms ( Rooms_all , Last_allowed ),
15391656
15401657 Num_rooms_all = length (Rooms_all ),
15411658 Num_rooms_pass = length (Rooms_pass ),
@@ -1557,14 +1674,14 @@ get_online_rooms(ServiceArg) ->
15571674 || {RoomName , RoomHost , Pid } <- mod_muc :get_online_rooms (Host )]
15581675 end , Hosts ).
15591676
1560- get_all_rooms (ServiceArg , Timestamp ) ->
1677+ get_all_rooms (ServiceArg ) ->
15611678 Hosts = find_services (ServiceArg ),
15621679 lists :flatmap (
15631680 fun (Host ) ->
1564- get_all_rooms2 (Host , Timestamp )
1681+ get_all_rooms2 (Host )
15651682 end , Hosts ).
15661683
1567- get_all_rooms2 (Host , Timestamp ) ->
1684+ get_all_rooms2 (Host ) ->
15681685 ServerHost = ejabberd_router :host_of_route (Host ),
15691686 OnlineRooms = get_online_rooms (Host ),
15701687 OnlineMap = lists :foldl (
@@ -1574,11 +1691,8 @@ get_all_rooms2(Host, Timestamp) ->
15741691
15751692 Mod = gen_mod :db_mod (ServerHost , mod_muc ),
15761693 DbRooms =
1577- case {erlang :function_exported (Mod , get_rooms_without_subscribers , 2 ),
1578- erlang :function_exported (Mod , get_hibernated_rooms_older_than , 3 )} of
1579- {_ , true } ->
1580- Mod :get_hibernated_rooms_older_than (ServerHost , Host , Timestamp );
1581- {true , _ } ->
1694+ case erlang :function_exported (Mod , get_rooms_without_subscribers , 2 ) of
1695+ true ->
15821696 Mod :get_rooms_without_subscribers (ServerHost , Host );
15831697 _ ->
15841698 Mod :get_rooms (ServerHost , Host )
@@ -1605,54 +1719,11 @@ get_room_state(Room_pid) ->
16051719% %---------------
16061720% % Decide
16071721
1608- decide_rooms (Method , Rooms , Last_allowed ) ->
1609- Decide = fun (R ) -> decide_room (Method , R , Last_allowed ) end ,
1722+ decide_rooms (Rooms , Last_allowed ) ->
1723+ Decide = fun (R ) -> decide_room (R , Last_allowed ) end ,
16101724 lists :filter (Decide , Rooms ).
16111725
1612- decide_room (unused , {_Room_name , _Host , ServerHost , Room_pid }, Last_allowed ) ->
1613- NodeStartTime = erlang :system_time (microsecond ) -
1614- 1000000 * (erlang :monotonic_time (second )- ejabberd_config :get_node_start ()),
1615- OnlyHibernated = case mod_muc_opt :hibernation_timeout (ServerHost ) of
1616- Value when Value < Last_allowed * 24 * 60 * 60 * 1000 ->
1617- true ;
1618- _ ->
1619- false
1620- end ,
1621- {Just_created , Num_users } =
1622- case Room_pid of
1623- Pid when is_pid (Pid ) andalso OnlyHibernated ->
1624- {erlang :system_time (microsecond ), 0 };
1625- Pid when is_pid (Pid ) ->
1626- case mod_muc_room :get_state (Room_pid ) of
1627- {ok , # state {just_created = JC , users = U }} ->
1628- {JC , maps :size (U )};
1629- _ ->
1630- {erlang :system_time (microsecond ), 0 }
1631- end ;
1632- Opts ->
1633- case lists :keyfind (hibernation_time , 1 , Opts ) of
1634- false ->
1635- {NodeStartTime , 0 };
1636- {_ , undefined } ->
1637- {NodeStartTime , 0 };
1638- {_ , T } ->
1639- {T , 0 }
1640- end
1641- end ,
1642- Last = case Just_created of
1643- true ->
1644- 0 ;
1645- _ ->
1646- (erlang :system_time (microsecond )
1647- - Just_created ) div 1000000
1648- end ,
1649- case {Num_users , seconds_to_days (Last )} of
1650- {0 , Last_days } when (Last_days >= Last_allowed ) ->
1651- true ;
1652- _ ->
1653- false
1654- end ;
1655- decide_room (empty , {Room_name , Host , ServerHost , Room_pid }, _Last_allowed ) ->
1726+ decide_room ({Room_name , Host , ServerHost , Room_pid }, _Last_allowed ) ->
16561727 case gen_mod :is_loaded (ServerHost , mod_mam ) of
16571728 true ->
16581729 Room_options = case Room_pid of
@@ -1671,9 +1742,6 @@ decide_room(empty, {Room_name, Host, ServerHost, Room_pid}, _Last_allowed) ->
16711742 false
16721743 end .
16731744
1674- seconds_to_days (S ) ->
1675- S div (60 * 60 * 24 ).
1676-
16771745% %---------------
16781746% % Act
16791747
0 commit comments