@@ -22,16 +22,36 @@ defmodule M51.MatrixClient.ChatHistory do
22
22
def after_ ( sup_pid , room_id , anchor , limit ) do
23
23
client = M51.IrcConn.Supervisor . matrix_client ( sup_pid )
24
24
25
- case parse_anchor ( anchor ) do
26
- { :ok , event_id } ->
25
+ case parse_anchor ( anchor , true ) do
26
+ { :ok , :msgid , event_id } ->
27
27
case M51.MatrixClient.Client . get_event_context (
28
28
client ,
29
29
room_id ,
30
30
event_id ,
31
31
limit * 2
32
32
) do
33
- { :ok , events } -> { :ok , process_events ( sup_pid , room_id , events [ "events_after" ] ) }
34
- { :error , message } -> { :error , Kernel . inspect ( message ) }
33
+ { :ok , events } ->
34
+ { :ok ,
35
+ process_events ( sup_pid , room_id , events [ "events_after" ] , Map . get ( events , "end" ) , nil ) }
36
+
37
+ { :error , message } ->
38
+ { :error , Kernel . inspect ( message ) }
39
+ end
40
+
41
+ { :ok , :cursor , cursor } ->
42
+ case M51.MatrixClient.Client . get_events_from_cursor (
43
+ client ,
44
+ room_id ,
45
+ "f" ,
46
+ cursor ,
47
+ limit
48
+ ) do
49
+ { :ok , events } ->
50
+ { :ok ,
51
+ process_events ( sup_pid , room_id , events [ "chunk" ] , Map . get ( events , "end" ) , nil ) }
52
+
53
+ { :error , message } ->
54
+ { :error , Kernel . inspect ( message ) }
35
55
end
36
56
37
57
{ :error , message } ->
@@ -42,9 +62,9 @@ defmodule M51.MatrixClient.ChatHistory do
42
62
def around ( sup_pid , room_id , anchor , limit ) do
43
63
client = M51.IrcConn.Supervisor . matrix_client ( sup_pid )
44
64
45
- case parse_anchor ( anchor ) do
46
- { :ok , event_id } ->
47
- case M51.MatrixClient.Client . get_event_context ( client , room_id , event_id , limit ) do
65
+ case parse_anchor ( anchor , false ) do
66
+ { :ok , :msgid , event_id } ->
67
+ case M51.MatrixClient.Client . get_event_context ( client , room_id , event_id , limit - 1 ) do
48
68
{ :ok , events } ->
49
69
# TODO: if there aren't enough events after (resp. before), allow more
50
70
# events before (resp. after) than half the limit.
@@ -53,9 +73,16 @@ defmodule M51.MatrixClient.ChatHistory do
53
73
54
74
events_before = events [ "events_before" ] |> Enum . slice ( 0 , nb_before ) |> Enum . reverse ( )
55
75
events_after = events [ "events_after" ] |> Enum . slice ( 0 , nb_after )
56
- events = Enum . concat ( [ events_before , [ events [ "event" ] ] , events_after ] )
76
+ events_list = Enum . concat ( [ events_before , [ events [ "event" ] ] , events_after ] )
57
77
58
- { :ok , process_events ( sup_pid , room_id , events ) }
78
+ { :ok ,
79
+ process_events (
80
+ sup_pid ,
81
+ room_id ,
82
+ events_list ,
83
+ Map . get ( events , "end" ) ,
84
+ Map . get ( events , "start" )
85
+ ) }
59
86
60
87
{ :error , message } ->
61
88
{ :error , Kernel . inspect ( message ) }
@@ -69,16 +96,45 @@ defmodule M51.MatrixClient.ChatHistory do
69
96
def before ( sup_pid , room_id , anchor , limit ) do
70
97
client = M51.IrcConn.Supervisor . matrix_client ( sup_pid )
71
98
72
- case parse_anchor ( anchor ) do
73
- { :ok , event_id } ->
99
+ case parse_anchor ( anchor , true ) do
100
+ { :ok , :msgid , event_id } ->
74
101
case M51.MatrixClient.Client . get_event_context (
75
102
client ,
76
103
room_id ,
77
104
event_id ,
78
105
limit * 2
79
106
) do
80
107
{ :ok , events } ->
81
- { :ok , process_events ( sup_pid , room_id , Enum . reverse ( events [ "events_before" ] ) ) }
108
+ { :ok ,
109
+ process_events (
110
+ sup_pid ,
111
+ room_id ,
112
+ Enum . reverse ( events [ "events_before" ] ) ,
113
+ Map . get ( events , "start" ) ,
114
+ nil
115
+ ) }
116
+
117
+ { :error , message } ->
118
+ { :error , Kernel . inspect ( message ) }
119
+ end
120
+
121
+ { :ok , :cursor , cursor } ->
122
+ case M51.MatrixClient.Client . get_events_from_cursor (
123
+ client ,
124
+ room_id ,
125
+ "b" ,
126
+ cursor ,
127
+ limit
128
+ ) do
129
+ { :ok , events } ->
130
+ { :ok ,
131
+ process_events (
132
+ sup_pid ,
133
+ room_id ,
134
+ Enum . reverse ( events [ "chunk" ] ) ,
135
+ Map . get ( events , "end" ) ,
136
+ nil
137
+ ) }
82
138
83
139
{ :error , message } ->
84
140
{ :error , Kernel . inspect ( message ) }
@@ -98,28 +154,41 @@ defmodule M51.MatrixClient.ChatHistory do
98
154
limit
99
155
) do
100
156
{ :ok , events } ->
101
- { :ok , process_events ( sup_pid , room_id , Enum . reverse ( events [ "chunk" ] ) ) }
157
+ { :ok ,
158
+ process_events (
159
+ sup_pid ,
160
+ room_id ,
161
+ Enum . reverse ( events [ "chunk" ] ) ,
162
+ Map . get ( events , "end" ) ,
163
+ nil
164
+ ) }
102
165
103
166
{ :error , message } ->
104
167
{ :error , Kernel . inspect ( message ) }
105
168
end
106
169
end
107
170
108
- defp parse_anchor ( anchor ) do
171
+ defp parse_anchor ( anchor , allow_cursor ) do
109
172
case String . split ( anchor , "=" , parts: 2 ) do
110
173
[ "msgid" , msgid ] ->
111
- { :ok , msgid }
174
+ { :ok , :msgid , msgid }
175
+
176
+ [ "cursor" , cursor ] when allow_cursor ->
177
+ { :ok , :cursor , cursor }
178
+
179
+ [ "cursor" , _ ] ->
180
+ { :error , "Invalid anchor: '#{ anchor } ', it should start with 'msgid='." }
112
181
113
182
[ "timestamp" , _ ] ->
114
183
{ :error ,
115
184
"CHATHISTORY with timestamps is not supported. See https://github.com/progval/matrix2051/issues/1" }
116
185
117
186
_ ->
118
- { :error , "Invalid anchor: '#{ anchor } ', it should start with 'msgid='." }
187
+ { :error , "Invalid anchor: '#{ anchor } ', it should start with 'msgid=' or 'cursor=' ." }
119
188
end
120
189
end
121
190
122
- defp process_events ( sup_pid , room_id , events ) do
191
+ defp process_events ( sup_pid , room_id , events , next , prev ) do
123
192
pid = self ( )
124
193
write = fn cmd -> send ( pid , { :command , cmd } ) end
125
194
@@ -154,12 +223,45 @@ defmodule M51.MatrixClient.ChatHistory do
154
223
|> Task . await ( )
155
224
156
225
# Collect all commands
157
- Stream . unfold ( nil , fn _ ->
158
- receive do
159
- { :command , cmd } -> { cmd , nil }
160
- { :finished_processing } -> nil
161
- end
162
- end )
163
- |> Enum . to_list ( )
226
+ batch_content =
227
+ Stream . unfold ( nil , fn _ ->
228
+ receive do
229
+ { :command , cmd } -> { cmd , nil }
230
+ { :finished_processing } -> nil
231
+ end
232
+ end )
233
+ |> Enum . to_list ( )
234
+
235
+ # Prepend cursors, if any
236
+ case { next , prev } do
237
+ { nil , nil } ->
238
+ batch_content
239
+
240
+ { next , nil } ->
241
+ cursors = % M51.Irc.Command {
242
+ command: "CHATHISTORY" ,
243
+ params: [ "CURSORS" , room_id , next ]
244
+ }
245
+
246
+ [ cursors | batch_content ]
247
+
248
+ { nil , prev } ->
249
+ # what do we do here?
250
+ # https://github.com/ircv3/ircv3-specifications/pull/525/files#r1214764104
251
+ cursors = % M51.Irc.Command {
252
+ command: "CHATHISTORY" ,
253
+ params: [ "CURSORS" , room_id , "*" , prev ]
254
+ }
255
+
256
+ [ cursors | batch_content ]
257
+
258
+ { next , prev } ->
259
+ cursors = % M51.Irc.Command {
260
+ command: "CHATHISTORY" ,
261
+ params: [ "CURSORS" , room_id , next , prev ]
262
+ }
263
+
264
+ [ cursors | batch_content ]
265
+ end
164
266
end
165
267
end
0 commit comments