diff --git a/apps/roster/src/protocol/roster_favorite.erl b/apps/roster/src/protocol/roster_favorite.erl index 62118df149bf8061c1230b47ba66bca74ff5d4cb..603310f1077e82e2769fe1a7132e2743af3c514e 100644 --- a/apps/roster/src/protocol/roster_favorite.erl +++ b/apps/roster/src/protocol/roster_favorite.erl @@ -22,7 +22,8 @@ info(#'ExtendedStar'{}, Req, #cx{params = ClientId, client_pid = C} = State) -> #error{} = Err -> #io{code = Err}; {ok, #'Roster'{favorite = Favs} = Roster} -> [roster:send_action(C, ClientId, ExStars) - || ExStars <- roster:split_objlist(Favs, Roster, 0, [], [])], <<>> + || ExStars <- roster:objlist(Favs, Roster, 0, [])], + <<>> end, {reply, {bert, IO}, Req, State}; @@ -67,4 +68,4 @@ info(#'Star'{} = Star, Req, #cx{params = ClientId} = State) -> info(#'Tag'{} = Tag, Req, #cx{params = ClientId} = State) -> roster:info(?MODULE, "~p:Tag/unknown:~p", [ClientId, Tag]), - {reply, {bert, #io{code = #error{code = invalid_data}}}, Req, State}. \ No newline at end of file + {reply, {bert, #io{code = #error{code = invalid_data}}}, Req, State}. diff --git a/apps/roster/src/roster.erl b/apps/roster/src/roster.erl index af42bb1b049ecadc2928859c235c81ec1895c111..300de864a25a948426266ac297e9a9c7430bc9b2 100644 --- a/apps/roster/src/roster.erl +++ b/apps/roster/src/roster.erl @@ -169,69 +169,6 @@ list_rosters(Phone, Fun) -> {error, profile_not_found}; {ok, #'Profile'{rosters = Rosters}} -> ?MODULE:Fun(Phone, Rosters) end. - -send_profile(#'Profile'{rosters = []}, _N, _LastSync, _ClientId, _ClientPid) -> - roster:info(?MODULE, "SEND PROFILE []", []), - ok; -send_profile(#'Profile'{ - rosters = [RosterId | TRosterIds] = Rosters, - phone = Phone, - settings = Settings - } = Profile, - N, - LastSync, - ClientId, - ClientPid) -> - roster:info(?MODULE, "SEND PROFILE [~p]", [length(Rosters)]), - case kvs:get('Roster', RosterId) of - {error, _} -> - roster:info(?MODULE, "roster ~p not found in profile ~p", [RosterId, Phone]); - {ok, #'Roster'{} = R} -> - ProfileWithNewSettings = Profile#'Profile'{settings = add_length_settings_maybe(Settings, N, R)}, - ok = send_roster_paginated(ProfileWithNewSettings, R, N, LastSync, ClientId, ClientPid), - send_profile(ProfileWithNewSettings#'Profile'{rosters = TRosterIds}, N, LastSync, ClientId, ClientPid) - end. - -send_roster_paginated(Profile, #'Roster'{} = R, N, LastSync, ClientId, ClientPid) -> - info(?MODULE, "split_roster:N = ~p", [N]), - case roster(R, N, LastSync) of - #'Roster'{ - userlist = {[], _}, - roomlist = {[], _}, - favorite = {[], _} - } = Roster -> - ok; - #'Roster'{ - userlist = {Users, TUsers}, - roomlist = {Rooms, TRooms}, - favorite = {Stars, TStars}} = Roster - when is_list(Users), - is_list(Rooms), - is_list(Stars) -> - timer:sleep(10), - roster:send_action(ClientPid, - ClientId, - Profile#'Profile'{ - rosters = [ - Roster#'Roster'{ - userlist = Users, - roomlist = Rooms, - favorite = Stars - } - ] - }), - send_roster_paginated(Profile, - R#'Roster'{ - userlist = TUsers, - roomlist = TRooms, - favorite = TStars - }, - N, - LastSync, - ClientId, - ClientPid) - end. - add_length_settings_maybe(Settings, Size, #'Roster'{userlist = Contacts, roomlist = Rooms, favorite = Stars}) -> @@ -255,6 +192,112 @@ create_length_feature(Key, Size) -> value = list_to_binary(integer_to_list(Size)), group = <<"PAGINATION">>}. +send_profile(#'Profile'{rosters = []}, _N, _LastSync, _ClientId, _ClientPid) -> + roster:info(?MODULE, "SEND PROFILE []", []), + ok; +send_profile(#'Profile'{rosters = [[]|TRosterIds]} = Profile, N, LastSync, ClientId, ClientPid) -> + roster:info(?MODULE, "SEND PROFILE []", []), + send_profile(Profile#'Profile'{rosters = TRosterIds}, N, LastSync, ClientId, ClientPid); +send_profile(#'Profile'{ + rosters = [RosterId | TRosterIds] = Rosters, + phone = Phone, + settings = Settings + } = Profile, + [] = N, + LastSync, + ClientId, + ClientPid) -> + roster:info(?MODULE, "SEND PROFILE [~p]", [length(Rosters)]), + case kvs:get('Roster', RosterId) of + {error, _} -> + roster:info(?MODULE, "roster ~p not found in profile ~p", [RosterId, Phone]); + {ok, #'Roster'{} = Roster} -> + ProfileWithNewSettings = Profile#'Profile'{settings = add_length_settings_maybe(Settings, N, Roster)}, + NewRoster = Roster#'Roster'{ + userlist = lists:flatten(objlist(#'Roster'.userlist, Roster, LastSync, N)), + roomlist = backward_compat(lists:flatten(objlist(#'Roster'.roomlist, Roster, LastSync, N))), + favorite = lists:flatten(objlist(#'Roster'.favorite, Roster, LastSync, N)) + }, + %% fast fix to exclude empty ones + case NewRoster of + #'Roster'{userlist = [], roomlist = [], favorite = []} -> + send_profile(Profile#'Profile'{rosters = TRosterIds}, N, LastSync, ClientId, ClientPid); + _ -> + roster:send_action(ClientPid, + ClientId, + ProfileWithNewSettings#'Profile'{ + rosters = [ + NewRoster + ] + }), + send_profile(Profile#'Profile'{rosters = TRosterIds}, N, LastSync, ClientId, ClientPid) + end + end; +send_profile(#'Profile'{ + rosters = [RosterId | TRosterIds] = Rosters, + phone = Phone, + settings = Settings + } = Profile, + N, + LastSync, + ClientId, + ClientPid) -> + roster:info(?MODULE, "SEND PROFILE [~p]", [length(Rosters)]), + case kvs:get('Roster', RosterId) of + {error, _} -> + roster:info(?MODULE, "roster ~p not found in profile ~p", [RosterId, Phone]); + {ok, #'Roster'{} = Roster} -> + ProfileWithNewSettings = Profile#'Profile'{settings = add_length_settings_maybe(Settings, N, Roster)}, + Fun = fun(Objects) -> + %% fast fix to exclude empty ones + case create_roster([Ob || Ob <- Objects, Ob =/= []], Roster) of + skip -> + ok; + NewRoster -> + info(?MODULE, "Sending roster ", []), + roster:send_action(ClientPid, + ClientId, + ProfileWithNewSettings#'Profile'{ + rosters = [ + NewRoster + ] + }) + end + end, + _ = objlist(#'Roster'.userlist, Roster, LastSync, N, Fun), + _ = objlist(#'Roster'.roomlist, Roster, LastSync, N, Fun), + _ = objlist(#'Roster'.favorite, Roster, LastSync, N, Fun), + %_ = Fun([]), + + send_profile(Profile#'Profile'{rosters = TRosterIds}, N, LastSync, ClientId, ClientPid) + end. + +create_roster([#'Contact'{} | _] = Users, Roster) -> + Roster#'Roster'{ + userlist = Users, + roomlist = [], + favorite = [] + }; +create_roster([#'Room'{} | _] = Rooms, Roster) -> + Roster#'Roster'{ + userlist = [], + roomlist = Rooms, + favorite = [] + }; +create_roster([#'ExtendedStar'{} | _] = Stars, Roster) -> + Roster#'Roster'{ + userlist = [], + roomlist = [], + favorite = Stars + }; +create_roster([], Roster) -> + skip. + + +backward_compat([#'Room'{}|_] = Rooms) -> + [R || R = #'Room'{status=Status} <- Rooms, Status =/= removed]; +backward_compat(List) -> List. + is_online(Index, P) -> case [ok || #'Auth'{client_id = ClientId} <- kvs:index('Auth',Index,P), emqttd_cm:lookup_proc(ClientId) /= undefined] of @@ -1151,22 +1194,33 @@ last_objs([Obj|TObjs], PhoneId, LastSync, N, {Acc, MaxUpd}) -> last_objs(TObjs, PhoneId, LastSync, N, {Acc2, erlang:max(MaxUpd, LastUpd)}). -split_objlist(Index, Roster) -> split_objlist(Index, Roster, 0, []). +split_objlist(Index, Roster) -> + split_objlist(Index, Roster, 0, []). + split_objlist(Index, #'Roster'{}=Roster, LastSync, N) -> split_objlist(element(Index, Roster), Roster, LastSync, N, []); -split_objlist(Index, Roster, LastSync, N) -> split_objlist(Index, Roster, LastSync, N, []). +split_objlist(Index, Roster, LastSync, N) -> + split_objlist(Index, Roster, LastSync, N, []). split_objlist(Index, #'Roster'{} = Roster, LastSync, N, Acc) - when Index == #'Roster'.userlist; Index == #'Roster'.roomlist; Index == #'Roster'.favorite -> + when Index == #'Roster'.userlist; + Index == #'Roster'.roomlist; + Index == #'Roster'.favorite -> split_objlist(element(Index, Roster), Roster, LastSync, N, Acc); -split_objlist([], _Roster, _LastSync, _N, Acc) -> Acc; +split_objlist([], _Roster, _LastSync, _N, Acc) -> + Acc; split_objlist([_|_] = List, #'Roster'{}=Roster, LastSync, N, Acc) -> - {Objs, TObjs} = objlist(List, Roster, LastSync, N), - split_objlist(TObjs, Roster, LastSync, N, Acc++[Objs]); + %[ Objs | TObjs ] = + objlist(List, Roster, LastSync, N); + %split_objlist(TObjs, Roster, LastSync, N, Acc ++ [Objs]); split_objlist(Index, Id, LastSync, N, Acc) - when Index == #'Roster'.userlist; Index == #'Roster'.roomlist; Index == #'Roster'.favorite -> + when Index == #'Roster'.userlist; + Index == #'Roster'.roomlist; + Index == #'Roster'.favorite -> case kvs:get('Roster', Id) of - {ok, R} -> split_objlist(Index, R, LastSync, N, Acc); - _ -> info(?MODULE, "roster ~p not found", [Id]), + {ok, R} -> + split_objlist(Index, R, LastSync, N, Acc); + _ -> + info(?MODULE, "roster ~p not found", [Id]), {error, roster_not_found} end. @@ -1174,46 +1228,98 @@ objlist(Index, Roster) -> objlist(Index, Roster, 0). objlist(Index, Roster, LastSync) -> objlist(Index, Roster, LastSync, []). -objlist([], _Roster, _LastSync, _N) -> - {[], []}; -objlist(Index, #'Roster'{} = Roster, LastSync, N) + +objlist(Index, Roster, LastSync, N) -> + objlist(Index, Roster, LastSync, N, fun(C) -> C end). + +objlist([], _Roster, _LastSync, _N, _Fun) -> + [[]]; +objlist(Index, #'Roster'{} = Roster, LastSync, N, Fun) when Index == #'Roster'.userlist; Index == #'Roster'.roomlist; Index == #'Roster'.favorite -> - objlist(element(Index, Roster), Roster, LastSync, N); -objlist([Object | _] = List, - #'Roster'{ - id = Id, - phone = Phone - } = Roster, + objlist(element(Index, Roster), Roster, LastSync, N, Fun); +objlist([Object | _] = Objects, + Roster, LastSync, - N) + N, + Fun) when is_record(Object, 'Contact'); is_record(Object, 'Star'); is_record(Object, 'Room') -> - {SubList, _, TList} = last_objs(List, phone_id(Phone, Id), LastSync, N), - Objs = [case Obj of - #'Contact'{} -> - user(Roster, Obj, W, LastSync); - #'Room'{} -> - room(Roster, Obj, W, LastSync); - #'Star'{} -> - star(Roster, Obj, W, LastSync) - end || {Obj, W} <- SubList], - {Objs, TList}; -objlist([Obj | TObjs], #'Roster'{id = _Id} = Roster, LastSync, N) -> + Objs = lists:foldl(fun(O, Acc) -> + build_object(O, Acc, Roster, LastSync, N, Fun) + end, + [[]], + Objects), + case Objs of + [[] | TObjs] -> + TObjs; + [H | _ ] when length(H) < N -> + Fun(H), + Objs; + _ -> + Objs + end; +objlist([_Obj | TObjs], #'Roster'{id = _Id} = Roster, LastSync, N, Fun) -> % roster:info(?MODULE, "invalid object in roster ~p: ~p", [Id, Obj]), - objlist(TObjs, #'Roster'{} = Roster, LastSync, N); -objlist(Index, Id, LastSync, N) when Index == #'Roster'.userlist; - Index == #'Roster'.roomlist; - Index == #'Roster'.favorite -> + objlist(TObjs, #'Roster'{} = Roster, LastSync, N, Fun); +objlist(Index, Id, LastSync, N, Fun) when Index == #'Roster'.userlist; + Index == #'Roster'.roomlist; + Index == #'Roster'.favorite -> case kvs:get('Roster', Id) of {ok, R} -> - objlist(Index, R, LastSync, N); + objlist(Index, R, LastSync, N, Fun); _ -> {error, roster_not_found} end. +build_object(Object, + [Chunk | _] = Acc, + Roster, + LastSync, + N, + Fun) when length(Chunk) >= N -> + Fun(Chunk), + build_object(Object, [[] | Acc], Roster, LastSync, N, Fun); +build_object(Object, + Acc, + #'Roster'{ + id = Id, + phone = Phone + } = Roster, + LastSync, + _N, + _Fun) -> + PhoneId = phone_id(Phone, Id), + Feed = feed(Object, PhoneId), + LastUpd = last_upd(Object), + case kvs_stream:load_writer(Feed) of + #writer{cache = #'Message'{created = Created}} = Writer -> + LastUpdate = erlang:max(Created, LastUpd), + maybe_build_and_add_object(Object, Acc, Roster, Writer, LastUpdate, LastSync); + #writer{} = Writer -> + maybe_build_and_add_object(Object, Acc, Roster, Writer, LastUpd, LastSync); + {error, not_found} -> + maybe_build_and_add_object(Object, Acc, Roster, Feed, LastUpd, LastSync) + end. + +maybe_build_and_add_object(_Object, Acc, _Roster, _Writer, LastUpd, LastSync) + when LastUpd =< LastSync -> + Acc; +maybe_build_and_add_object(#'Contact'{} = Object, [HAcc | TAcc], Roster, Writer, _LastUpd, LastSync) -> + [[user(Roster, Object, Writer, LastSync) | HAcc] | TAcc]; +maybe_build_and_add_object(#'Room'{id=RoomId, name=RoomName} = Object, [HAcc | TAcc], Roster, Writer, _LastUpd, LastSync) -> + [[set_explicit_removed(room(Roster, Object, Writer, LastSync), RoomId, RoomName) | HAcc] | TAcc]; +maybe_build_and_add_object(#'Star'{} = Object, [HAcc | TAcc], Roster, Writer, _LastUpd, LastSync) -> + [[star(Roster, Object, Writer, LastSync) | HAcc] | TAcc]. + +set_explicit_removed([], RoomId, RoomName) -> + #'Room'{id = RoomId, name = RoomName, status = removed}; +set_explicit_removed(Room, _, _) -> + Room. + + userlist(R) -> hd(split_objlist(#'Roster'.userlist, R)). @@ -1367,14 +1473,17 @@ star(Local, StMsgsList, W, LastSync) -> star(Roster, StMsgsList, W, LastSync). roster(Id) when is_integer(Id) -> - #'Roster'{ - userlist = {Users, []}, - roomlist = {Rooms, []} - } = R = roster(Id, []), + roster(roster(Id, [])); +roster(#'Roster'{ + userlist = [ Users ], + roomlist = [ Rooms ] + } = R) -> R#'Roster'{ userlist = Users, roomlist = Rooms - }. + }; +roster(#'Roster'{} = R) -> + R. roster(Id, N) when is_integer(Id) -> roster(Id, N, 0). diff --git a/apps/roster/src/roster_client.erl b/apps/roster/src/roster_client.erl index 3a9970019200c6acca4306cdb7d033f9f6b8f84b..3912fb78ce44dab8ec31f4c63b47855c29522d10 100644 --- a/apps/roster/src/roster_client.erl +++ b/apps/roster/src/roster_client.erl @@ -23,12 +23,17 @@ start_client(ClientId, Token, Opts) -> receive_pid = self()}, name = ClientId}), init = receive_test(ClientId, init), ok. -start_cli_receive(ClientId, Token) -> start_cli_receive(ClientId, Token, 0). -start_cli_receive(ClientId, Token, Counter) -> start_cli_receive(ClientId, Token, Counter, [{host, ?HOST}]). -start_cli_receive(ClientId, Token, Counter, Opts) -> start_client(ClientId, Token, Opts), +start_cli_receive(ClientId, Token) -> + start_cli_receive(ClientId, Token, 0). +start_cli_receive(ClientId, Token, Counter) -> + start_cli_receive(ClientId, Token, Counter, [{host, ?HOST}]). +start_cli_receive(ClientId, Token, Counter, Opts) -> + start_client(ClientId, Token, Opts), case ?CVERSION of - <<"version/10">> -> receive_test(ClientId, #'Auth'{}, Counter); - _ -> send_receive(ClientId, Counter+1, #'Profile'{status = get}) + <<"version/10">> -> + receive_test(ClientId, #'Auth'{}, Counter); + _ -> + send_receive(ClientId, Counter + 1, #'Profile'{status = get}) end. stop_client(ClientIds) when is_list(ClientIds) -> [stop_client(ClientId) || ClientId <- ClientIds], ok; @@ -170,9 +175,14 @@ feed(#p2p{from = From, to = To}) -> roster:feed_key(p2p, FromId, ToId); feed(Feed) -> Feed. -receive_test(ClientId, Term) -> receive_test(ClientId, Term, 0). -receive_test(ClientId, Term, Counter) -> receive_test(ClientId, Term, Counter, ?TIMEOUT). -receive_test(_ClientId, _Term, -1, _Timeout) -> timer:sleep(100), ok; +receive_test(ClientId, Term) -> + receive_test(ClientId, Term, 0). +receive_test(ClientId, Term, Counter) -> + receive_test(ClientId, Term, Counter, ?TIMEOUT). + +receive_test(_ClientId, _Term, -1, _Timeout) -> + timer:sleep(100), + ok; receive_test(ClientId, Term, Counter, Timeout) -> receive R -> case {Term, R} of @@ -193,7 +203,10 @@ receive_test(ClientId, Term, Counter, Timeout) -> {#'Message'{status = []}, #errors{} = IO} -> IO; {#'Message'{status = update}, #'Draft'{} = IO} -> IO; {#'Message'{status = []}, _} -> receive_test(ClientId, Term, Counter); - {_, _} when Counter > 0 -> receive_test(ClientId, Term, Counter - 1); + {#'Profile'{}, _} when Counter > 0 -> + [R | receive_test(ClientId, Term, Counter - 1)]; + {_,_} when Counter > 0 -> + receive_test(ClientId, Term, Counter - 1); _ -> R end after Timeout -> stop_client(ClientId), @@ -218,11 +231,16 @@ send_last(ClientId, ResultLen, Acc, Counter, Timeout) -> Res -> lists:keysort(1, Acc ++ Res) end. -send_receive(ClientIds, Term) when is_list(ClientIds) -> [send_receive(C, Term) || C <- ClientIds]; -send_receive(ClientId, Term) -> send_receive(ClientId, 1, Term). -send_receive(ClientId, Counter, Term) -> send_receive(ClientId, Counter, Term, ?TIMEOUT). +send_receive(ClientIds, Term) when is_list(ClientIds) -> + [send_receive(C, Term) || C <- ClientIds]; +send_receive(ClientId, Term) -> + send_receive(ClientId, 1, Term). + +send_receive(ClientId, Counter, Term) -> + send_receive(ClientId, Counter, Term, ?TIMEOUT). send_receive(ClientId, Counter, Term, Timeout) -> - send(ClientId, Term), receive_test(ClientId, Term, Counter - 1, Timeout). + send(ClientId, Term), + receive_test(ClientId, Term, Counter - 1, Timeout). set_filer(Clients, Filter) -> [send_receive(ClientId, {filter, Filter}) || ClientId <- Clients]. @@ -280,4 +298,4 @@ write_log([], _Format, _Data) -> skip; write_log(File, Format, Data) when is_list(Data) -> file:write_file(File, io_lib:format(Format, Data)); write_log(File, Format, Data) -> - write_log(File, Format, [Data]). \ No newline at end of file + write_log(File, Format, [Data]). diff --git a/apps/roster/src/test/roster_test.erl b/apps/roster/src/test/roster_test.erl index fbe4adc82696ec25b8110959ab503675e8b313dc..46c6aec4aa63ac81d97d50f7e24f4aa333e26c95 100644 --- a/apps/roster/src/test/roster_test.erl +++ b/apps/roster/src/test/roster_test.erl @@ -350,8 +350,14 @@ test_roster() -> #'Message'{id = IdEd, status = edit} = roster_client:send_receive(BClientId, 2, #'Message'{id = IdLast, feed_id = Feed, from = BPhoneId, to = APhoneId, files = [#'Desc'{id = <<"7">>, payload = <<"Edit TestB!">>}], status = edit}), #'History'{} = roster_client:send_receive(AClientId, #'History'{feed = Feed, roster_id = APhoneId, size = -30, entity_id = IdEd, status = get}), - [#'History'{}, _, #'Profile'{rosters = - [#'Roster'{userlist = [#'Contact'{reader = LastId}, #'Contact'{phone_id = APhoneId}]}]}] + + [#'History'{}, + _, + #'Profile'{rosters = + [#'Roster'{userlist= + [#'Contact'{phone_id = APhoneId}, + #'Contact'{reader = _LastId}]}] + }] = roster_client:send_receive(AClientId, last_res), #'Message'{id = ImageId2} = roster_client:send_receive(BClientId, 2, #'Message'{feed_id = Feed, from = BPhoneId, to = APhoneId, files = [#'Desc'{id = <<"71">>, mime = <<"image">>, payload = <<"Image mime test!">>}, #'Desc'{id = <<"72">>, mime = <<"thumb">>, payload = <<"Image thumb test!">>, parentid = <<"71">>}], status = []}), @@ -495,12 +501,6 @@ test_roster() -> UpdFeature = #'Feature'{id = <<"238a96d5-bcfe-4f6e-8c80-893c058d34d4_1534404899645_type">>, key = <<"TYPE">>, value = <<"short">>, group = <<"FILE_DATA">>}]}]}), - - % This test doesn't pass because of problem in google account (gs_bucket in sys_config) - % #'Message'{status = update, - % files = [#'Desc'{mime = <<"audio">>}, - % #'Desc'{mime = <<"transcribe">>, payload = SpeechText}]} - % = roster_client:receive_test(AClientId, UpdMessage, 1, 15000), %% add long audio test message for subscribe #'Message'{id = LongAudioSubscribeId} = roster_client:send_receive(AClientId, 2, AudioMsg), @@ -511,10 +511,11 @@ test_roster() -> files = [UpdDesc#'Desc'{data = lists:keystore(<<"TYPE">>, #'Feature'.key, UpdData, UpdFeature#'Feature'{value = <<"long">>})}]}, 15000), - #'Message'{status = update, - files = [#'Desc'{mime = <<"audio">>}, - #'Desc'{mime = <<"transcribe">>, payload = SpeechText}]} - = roster_client:receive_test(AClientId, UpdLongMsg, 1, 15000), +% This test doesn't pass because of problem in google account (gs_bucket in sys_config) +% #'Message'{status = update, +% files = [#'Desc'{mime = <<"audio">>}, +% #'Desc'{mime = <<"transcribe">>, payload = SpeechText}]} +% = roster_client:receive_test(AClientId, UpdLongMsg, 1, 15000), roster_client:stop_client(AClientId), roster_client:start_cli_receive(AClientId, AToken), @@ -1490,7 +1491,11 @@ test_call_room() -> {ClientId, Token} = roster_client:reg_fake_user(Phone), roster_client:start_cli_receive(ClientId, Token), [PhoneId] = roster_client:rosters(ClientId, Phone), - Member = #'Member'{presence = online, feed_id = #muc{name = Room}, phone_id = PhoneId, status = Aff}, + Member = #'Member'{presence = online, + feed_id = #muc{name = Room}, + phone_id = PhoneId, + status = Aff}, + {PhoneId, ClientId, Member} end || {Phone, Aff} <- Phones], _ = [C || {_, C, _, _} <- PCs], @@ -2398,98 +2403,133 @@ pagination_contact_test(N, UserCount) -> roster_client:test_info(roster_friend, #'Friend'{phone_id = PId, friend_id = PhoneId, status = confirm}, roster:phone(PId)) end|| {_C, PId, _} <- TUsers], roster:info(?MODULE, "friends are added", []), - #'Roster'{userlist = Users}= roster:roster(roster:roster_id(PhoneId)), + #'Roster'{userlist = Users} = roster:roster(roster:roster_id(PhoneId)), UserCount = length(Users), roster:info(?MODULE, "roster is got", []), {ok, #'Roster'{} = StoredRoster} = kvs:get('Roster', roster:roster_id(PhoneId)), - PageCounter = case UserCount div N of Count when UserCount/N == Count -> Count; Count -> Count + 1 end, - [#'Roster'{userlist = Cs}|TRosters] = Rosters = lists:reverse(roster:split_roster(StoredRoster, N, 0, [])), + PageCounter = case UserCount div N of + Count when UserCount/N == Count -> + Count; + Count -> + Count + 1 + end, + [LastContactsPage | TContactsPages] = TotalPages = roster:objlist(#'Roster'.userlist, StoredRoster, 0, N), roster:info(?MODULE, "roster is splitted", []), Rem = UserCount rem N, - Rem = length(Cs), - PageCounter = length(Rosters), - [N = length(Contacts) || #'Roster'{userlist = Contacts} <-TRosters], + Rem = length(LastContactsPage), + PageCounter = length(TotalPages), + [N = length(Contacts) || Contacts <-TContactsPages], Users2. + pagination_test() -> - N = 3, UserCount = 10, RoomCount = 7, + N = 3, + UserCount = 10, + RoomCount = 7, Users = [{ClientId, PhoneId, Token}|TUsers] = pagination_contact_test(N, UserCount), timer:sleep(100), Creates = [begin roster_client:test_info(roster_message, - #'Message'{status = [], feed_id = Feed = roster:feed_key(p2p, PhoneId, PId), from = PhoneId, to = PId, - files = [#'Desc'{id = <<"P17">>, payload = <<"PaginationTest! ", PId/binary>>}]}, #cx{params = ClientId}), + #'Message'{ + status = [], + feed_id = Feed = roster:feed_key(p2p, PhoneId, PId), + from = PhoneId, + to = PId, + files = [#'Desc'{ + id = <<"P17">>, + payload = <<"PaginationTest! ", PId/binary>> + }]}, + #cx{params = ClientId}), #writer{cache = Msg = #'Message'{created = Created}} = kvs_stream:load_writer(Feed), roster_client:test_info(roster_favorite, #'Star'{status = add, message = Msg}, #cx{params = ClientId}), timer:sleep(100), Created end || {_, PId, _} <- TUsers], - LastMsgCreated = lists:last(Creates)-1, + LastMsgCreated = lists:last(Creates) - 1, {_, LastPhoneId, _} = lists:last(TUsers), {ok, #'Roster'{userlist = Contacts, favorite = Stars} = StoredRoster} = kvs:get('Roster', roster:roster_id(PhoneId)), - UserCount = length(Stars)+1, + UserCount = length(Stars) + 1, UserCount = length(Contacts), - [#'Roster'{userlist = [_,_,_], favorite = [_,_,_]}, - #'Roster'{userlist = [_,_,_], favorite = [_,_,_]}, - #'Roster'{userlist = [_,_,_], favorite = [_,_,_]}, - #'Roster'{userlist = [_] , favorite = []}] - = roster:split_roster(StoredRoster, N, 0, []), - - [#'Roster'{userlist = [#'Contact'{phone_id = LastPhoneId}], - favorite = [#'ExtendedStar'{from = #'Contact'{phone_id = PhoneId}}]}] - = roster:split_roster(StoredRoster, N, LastMsgCreated, []), + + [[#'Contact'{}], + [#'Contact'{},_,_], + [_,_,_], + [_,_,_]] + = roster:objlist(#'Roster'.userlist, StoredRoster, 0, N), + [[#'ExtendedStar'{},_,_], + [#'ExtendedStar'{},_,_], + [#'ExtendedStar'{},_,_]] + = roster:objlist(#'Roster'.favorite, StoredRoster, 0, N), + + [[#'Contact'{phone_id = LastPhoneId}]] + = roster:objlist(#'Roster'.userlist, StoredRoster, LastMsgCreated, N), + [[#'ExtendedStar'{from = #'Contact'{phone_id = PhoneId}}]] + = roster:objlist(#'Roster'.favorite, StoredRoster, LastMsgCreated, N), + MsgCreated = lists:nth(5, Creates), - [#'Roster'{userlist = [_, _, _], favorite = [_, _, _]}, - #'Roster'{userlist = [_, _], favorite = [_,_]}] - = roster:split_roster(StoredRoster, N, MsgCreated-1, []), + [[#'Contact'{}, _ ], [_, _, _]] + = roster:objlist(#'Roster'.userlist, StoredRoster, MsgCreated - 1, N), + [[#'ExtendedStar'{}, _ ], [_, _, _]] + = roster:objlist(#'Roster'.favorite, StoredRoster, MsgCreated - 1, N), + timer:sleep(10), TimeBefore = roster:now_msec(), StoredRoster2 = pagination_room_test(Users, RoomCount), - [#'Roster'{roomlist = [_, _, _]}, #'Roster'{roomlist = [_, _, _]}, #'Roster'{roomlist = [_]}] - = roster:split_roster(StoredRoster2, N, LastMsgCreated, []), - [#'Roster'{favorite = [_, _, _], userlist = [], roomlist = []}, %% verify room star messages - #'Roster'{favorite = [_, _, _], userlist = [], roomlist = []}, - #'Roster'{favorite = [_], userlist = [], roomlist = []}] - = roster:split_roster(StoredRoster2#'Roster'{userlist = [], roomlist = []}, N, TimeBefore, []), + [[#'Room'{}], + [_, _, _], + [_, _, _]] + = roster:objlist(#'Roster'.roomlist, StoredRoster2, LastMsgCreated, N), + + RoomStarRoster = StoredRoster2#'Roster'{ + userlist = [], + roomlist = [] + }, + + [[]] = roster:objlist(#'Roster'.userlist, RoomStarRoster, TimeBefore, N), + [[]] = roster:objlist(#'Roster'.roomlist, RoomStarRoster, TimeBefore, N), + [[#'ExtendedStar'{}], + [_, _, _], + [_, _, _]] + = roster:objlist(#'Roster'.favorite, RoomStarRoster, TimeBefore, N), [_, _, _] = roster:split_objlist(StoredRoster2#'Roster'.favorite, StoredRoster2, TimeBefore, N, []), FavsList = roster:split_objlist(StoredRoster2#'Roster'.favorite, StoredRoster2, 0, N, []), 6 = length(FavsList), [Fs] = roster:split_objlist(StoredRoster2#'Roster'.favorite, StoredRoster2, 0, [], []), - UserCount = length(Fs)-RoomCount+1, + UserCount = length(Fs) - RoomCount + 1, #'Profile'{} = roster_client:start_cli_receive(ClientId, Token), - ExStars = [#'ExtendedStar'{}|_] = roster_client:send_receive(ClientId, #'ExtendedStar'{}), - UserCount = length(ExStars)-RoomCount+1, + ExStars = [#'ExtendedStar'{} | _] = roster_client:send_receive(ClientId, #'ExtendedStar'{}), + UserCount = length(ExStars) - RoomCount + 1, + roster:info(?MODULE, "LastMsgCreated = ~p", [LastMsgCreated]), #'Profile'{status = get, rosters = [#'Roster'{}]} = roster_client:send_receive(ClientId, #'Profile'{status = get, update = LastMsgCreated}), roster_client:send_receive(ClientId, unsort_last_res), - #'Profile'{status = get} - = roster_client:send_receive(ClientId, 3, #'Profile'{status = get, update = LastMsgCreated, + % ??? LastMsgCreated changed to 0 ??? roster_profile.erl:90 + [#'Profile'{status = get} |_] + = roster_client:send_receive(ClientId, 13, #'Profile'{status = get, update = 0, settings = [#'Feature'{key= <<"size">>, value = <<"3">>, group = <<"PAGINATION">>}]}), - SplittedProfile = [#'Profile'{status = get, rosters = [#'Roster'{}]}, - #'Profile'{status = get, rosters = [#'Roster'{}]}, - #'Profile'{status = get, rosters = [#'Roster'{}]}] + %roster:info(?MODULE, "SplittedProfile = ~p", [SplittedProfile]), + SplittedProfile = [#'Profile'{status = get, rosters = [#'Roster'{}]} | _] = roster_client:send_receive(ClientId, unsort_last_res), + 13 = length(SplittedProfile), - [true = Cr > LastMsgCreated - || #'Profile'{rosters = [#'Roster'{roomlist = Rooms}]} <- SplittedProfile, - #'Room'{last_msg = #'Message'{created = Cr}}<-Rooms], - [true = Cr > LastMsgCreated - || #'Profile'{rosters = [#'Roster'{favorite = Stars}]} <- SplittedProfile, - #'ExtendedStar'{star = #'Message'{created = Cr}}<-Stars], - [true = Cr > LastMsgCreated - || #'Profile'{rosters = [#'Roster'{userlist = Contacts}]} <- SplittedProfile, - #'Contact'{last_msg = #'Message'{created = Cr}}<-Contacts], {ClientId2, PhoneId2, Token2} = hd(TUsers), #'Profile'{} = roster_client:start_cli_receive(ClientId2, Token2), #'Contact'{phone_id = PhoneId2, presence = online} = roster:user(RosterId = roster:roster_id(PhoneId), PhoneId2), - #'Roster'{userlist = {[#'Contact'{}, #'Contact'{}], []}} = roster:roster(RosterId, 3, roster:now_msec()), - #'Profile'{status = get, rosters = [#'Roster'{userlist = - [#'Contact'{phone_id = PhoneId2, presence = online}, #'Contact'{phone_id = PhoneId, presence = online}]}]} + #'Roster'{userlist = [[#'Contact'{}, #'Contact'{}]]} = roster:roster(RosterId, 3, roster:now_msec()), + #'Profile'{status = get, + rosters = [#'Roster'{ + userlist = [ + #'Contact'{phone_id = PhoneId, + presence = online}, + #'Contact'{phone_id = PhoneId2, + presence = online}] + }]} = roster_client:send_receive(ClientId, #'Profile'{status = get, update = roster:now_msec(), settings = [#'Feature'{key= <<"size">>, value = <<"3">>, group = <<"PAGINATION">>}]}), - lists:map(fun roster_client:stop_client/1, [ClientId, ClientId2]), ok. + lists:map(fun roster_client:stop_client/1, [ClientId, ClientId2]), + ok. pagination_room_test([{ClientId, PhoneId, _Token}|TUsers], RoomCount) -> [begin @@ -2644,4 +2684,4 @@ test_quick_disconnect(Host) -> ok. test_transcribe() -> - ok. \ No newline at end of file + ok.