line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package BusyBird::Main::PSGI; |
2
|
5
|
|
|
5
|
|
6224
|
use v5.8.0; |
|
5
|
|
|
|
|
13
|
|
|
5
|
|
|
|
|
230
|
|
3
|
5
|
|
|
5
|
|
21
|
use strict; |
|
5
|
|
|
|
|
5
|
|
|
5
|
|
|
|
|
146
|
|
4
|
5
|
|
|
5
|
|
18
|
use warnings; |
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
146
|
|
5
|
5
|
|
|
5
|
|
21
|
use BusyBird::Util qw(set_param future_of); |
|
5
|
|
|
|
|
38
|
|
|
5
|
|
|
|
|
262
|
|
6
|
5
|
|
|
5
|
|
2282
|
use BusyBird::Main::PSGI::View; |
|
5
|
|
|
|
|
135
|
|
|
5
|
|
|
|
|
231
|
|
7
|
5
|
|
|
5
|
|
3302
|
use Router::Simple; |
|
5
|
|
|
|
|
16860
|
|
|
5
|
|
|
|
|
192
|
|
8
|
5
|
|
|
5
|
|
2988
|
use Plack::Request; |
|
5
|
|
|
|
|
229743
|
|
|
5
|
|
|
|
|
221
|
|
9
|
5
|
|
|
5
|
|
2920
|
use Plack::Builder (); |
|
5
|
|
|
|
|
29255
|
|
|
5
|
|
|
|
|
155
|
|
10
|
5
|
|
|
5
|
|
2752
|
use Plack::App::File; |
|
5
|
|
|
|
|
35983
|
|
|
5
|
|
|
|
|
198
|
|
11
|
5
|
|
|
5
|
|
50
|
use Try::Tiny; |
|
5
|
|
|
|
|
13
|
|
|
5
|
|
|
|
|
364
|
|
12
|
5
|
|
|
5
|
|
33
|
use JSON qw(decode_json); |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
47
|
|
13
|
5
|
|
|
5
|
|
764
|
use Scalar::Util qw(looks_like_number); |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
354
|
|
14
|
5
|
|
|
5
|
|
40
|
use List::Util qw(min); |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
406
|
|
15
|
5
|
|
|
5
|
|
30
|
use Carp; |
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
329
|
|
16
|
5
|
|
|
5
|
|
29
|
use Exporter 5.57 qw(import); |
|
5
|
|
|
|
|
142
|
|
|
5
|
|
|
|
|
214
|
|
17
|
5
|
|
|
5
|
|
31
|
use URI::Escape qw(uri_unescape); |
|
5
|
|
|
|
|
7
|
|
|
5
|
|
|
|
|
324
|
|
18
|
5
|
|
|
5
|
|
31
|
use Encode qw(decode_utf8); |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
506
|
|
19
|
5
|
|
|
5
|
|
32
|
use Future::Q; |
|
5
|
|
|
|
|
13
|
|
|
5
|
|
|
|
|
194
|
|
20
|
5
|
|
|
5
|
|
30
|
use POSIX qw(ceil); |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
54
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
our @EXPORT_OK = qw(create_psgi_app); |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub create_psgi_app { |
26
|
45
|
|
|
45
|
1
|
1592
|
my ($main_obj) = @_; |
27
|
45
|
|
|
|
|
385
|
my $self = __PACKAGE__->_new(main_obj => $main_obj); |
28
|
45
|
|
|
|
|
183
|
return $self->_to_app; |
29
|
|
|
|
|
|
|
} |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
sub _new { |
32
|
45
|
|
|
45
|
|
144
|
my ($class, %params) = @_; |
33
|
45
|
|
|
|
|
386
|
my $self = bless { |
34
|
|
|
|
|
|
|
router => Router::Simple->new, |
35
|
|
|
|
|
|
|
view => undef, ## lazy build |
36
|
|
|
|
|
|
|
}, $class; |
37
|
45
|
|
|
|
|
632
|
$self->set_param(\%params, "main_obj", undef, 1); |
38
|
45
|
|
|
|
|
182
|
$self->_build_routes(); |
39
|
45
|
|
|
|
|
2449
|
return $self; |
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
sub _to_app { |
43
|
45
|
|
|
45
|
|
77
|
my $self = shift; |
44
|
45
|
|
|
|
|
205
|
my $sharedir = $self->{main_obj}->get_config("sharedir_path"); |
45
|
45
|
|
|
|
|
259
|
$sharedir =~ s{/+$}{}; |
46
|
|
|
|
|
|
|
return Plack::Builder::builder { |
47
|
45
|
|
|
45
|
|
2185
|
Plack::Builder::enable 'ContentLength'; |
48
|
45
|
|
|
|
|
8324
|
Plack::Builder::mount '/static' => Plack::App::File->new( |
49
|
|
|
|
|
|
|
root => File::Spec->catdir($sharedir, 'www', 'static') |
50
|
|
|
|
|
|
|
)->to_app; |
51
|
45
|
|
|
|
|
3536
|
Plack::Builder::mount '/' => $self->_my_app; |
52
|
45
|
|
|
|
|
506
|
}; |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
sub _my_app { |
56
|
45
|
|
|
45
|
|
96
|
my ($self) = @_; |
57
|
|
|
|
|
|
|
return sub { |
58
|
185
|
|
|
185
|
|
1076169
|
my ($env) = @_; |
59
|
185
|
|
66
|
|
|
1500
|
$self->{view} ||= BusyBird::Main::PSGI::View->new(main_obj => $self->{main_obj}, script_name => $env->{SCRIPT_NAME}); |
60
|
185
|
100
|
|
|
|
1235
|
if(my $dest = $self->{router}->match($env)) { |
61
|
179
|
|
|
|
|
18684
|
my $req = Plack::Request->new($env); |
62
|
179
|
|
|
|
|
1767
|
my $code = $dest->{code}; |
63
|
179
|
|
|
|
|
348
|
my $method = $dest->{method}; |
64
|
179
|
50
|
|
|
|
1043
|
return defined($code) ? $code->($self, $req, $dest) : $self->$method($req, $dest); |
65
|
|
|
|
|
|
|
}else { |
66
|
6
|
|
|
|
|
595
|
return $self->{view}->response_notfound(); |
67
|
|
|
|
|
|
|
} |
68
|
45
|
|
|
|
|
316
|
}; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
sub _build_routes { |
72
|
45
|
|
|
45
|
|
73
|
my ($self) = @_; |
73
|
45
|
|
|
|
|
302
|
my $tl_mapper = $self->{router}->submapper( |
74
|
|
|
|
|
|
|
'/timelines/{timeline}', {} |
75
|
|
|
|
|
|
|
); |
76
|
45
|
|
|
|
|
1527
|
$tl_mapper->connect('/statuses.{format}', |
77
|
|
|
|
|
|
|
{method => '_handle_tl_get_statuses'}, {method => 'GET'}); |
78
|
45
|
|
|
|
|
7172
|
$tl_mapper->connect('/statuses.json', |
79
|
|
|
|
|
|
|
{method => '_handle_tl_post_statuses'}, {method => 'POST'}); |
80
|
45
|
|
|
|
|
4508
|
$tl_mapper->connect('/ack.json', |
81
|
|
|
|
|
|
|
{method => '_handle_tl_ack'}, {method => 'POST'}); |
82
|
45
|
|
|
|
|
4141
|
$tl_mapper->connect('/updates/unacked_counts.json', |
83
|
|
|
|
|
|
|
{method => '_handle_tl_get_unacked_counts'}, {method => 'GET'}); |
84
|
45
|
|
|
|
|
4459
|
$tl_mapper->connect($_, {method => '_handle_tl_index'}) foreach "", qw(/ /index.html /index.htm); |
85
|
45
|
|
|
|
|
13904
|
$self->{router}->connect('/updates/unacked_counts.json', |
86
|
|
|
|
|
|
|
{method => '_handle_get_unacked_counts'}, {method => 'GET'}); |
87
|
45
|
|
|
|
|
2773
|
foreach my $path ("/", "/index.html") { |
88
|
90
|
|
|
|
|
2601
|
$self->{router}->connect($path, {method => '_handle_get_timeline_list'}, {method => 'GET'}); |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub _get_timeline_name { |
93
|
152
|
|
|
152
|
|
241
|
my ($dest) = @_; |
94
|
152
|
|
|
|
|
303
|
my $name = $dest->{timeline}; |
95
|
152
|
50
|
|
|
|
403
|
$name = "" if not defined($name); |
96
|
152
|
|
|
|
|
422
|
$name =~ s/\+/ /g; |
97
|
152
|
|
|
|
|
468
|
return decode_utf8(uri_unescape($name)); |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
sub _get_timeline { |
101
|
135
|
|
|
135
|
|
268
|
my ($self, $dest) = @_; |
102
|
135
|
|
|
|
|
424
|
my $name = _get_timeline_name($dest); |
103
|
135
|
|
|
|
|
4825
|
my $timeline = $self->{main_obj}->get_timeline($name); |
104
|
135
|
100
|
|
|
|
1555
|
if(!defined($timeline)) { |
105
|
4
|
|
|
|
|
38
|
die qq{No timeline named $name}; |
106
|
|
|
|
|
|
|
} |
107
|
131
|
|
|
|
|
241
|
return $timeline; |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub _handle_tl_get_statuses { |
111
|
70
|
|
|
70
|
|
193
|
my ($self, $req, $dest) = @_; |
112
|
|
|
|
|
|
|
return sub { |
113
|
70
|
|
|
70
|
|
4227
|
my $responder = shift; |
114
|
70
|
|
|
|
|
91
|
my $timeline; |
115
|
70
|
|
|
|
|
340
|
my $only_statuses = !!($req->query_parameters->{only_statuses}); |
116
|
70
|
100
|
100
|
|
|
7507
|
my $format = !defined($dest->{format}) ? "" |
|
|
50
|
|
|
|
|
|
117
|
|
|
|
|
|
|
: (lc($dest->{format}) eq "json" && $only_statuses) ? "json_only_statuses" |
118
|
|
|
|
|
|
|
: $dest->{format}; |
119
|
|
|
|
|
|
|
Future::Q->try(sub { |
120
|
70
|
|
|
|
|
3061
|
$timeline = $self->_get_timeline($dest); |
121
|
69
|
|
100
|
|
|
203
|
my $count = $req->query_parameters->{count} || 20; |
122
|
69
|
50
|
33
|
|
|
1064
|
if(!looks_like_number($count) || int($count) != $count) { |
123
|
0
|
|
|
|
|
0
|
die "count parameter must be an integer\n"; |
124
|
|
|
|
|
|
|
} |
125
|
69
|
|
100
|
|
|
164
|
my $ack_state = $req->query_parameters->{ack_state} || 'any'; |
126
|
69
|
|
|
|
|
550
|
my $max_id = decode_utf8($req->query_parameters->{max_id}); |
127
|
69
|
|
|
|
|
1057
|
return future_of($timeline, "get_statuses", |
128
|
|
|
|
|
|
|
count => $count, ack_state => $ack_state, max_id => $max_id); |
129
|
|
|
|
|
|
|
})->then(sub { |
130
|
65
|
|
|
|
|
13624
|
my $statuses = shift; |
131
|
65
|
|
|
|
|
447
|
$responder->($self->{view}->response_statuses( |
132
|
|
|
|
|
|
|
statuses => $statuses, http_code => 200, format => $format, |
133
|
|
|
|
|
|
|
timeline_name => $timeline->name |
134
|
|
|
|
|
|
|
)); |
135
|
|
|
|
|
|
|
})->catch(sub { |
136
|
5
|
|
|
|
|
2471
|
my ($error, $is_normal_error) = @_; |
137
|
5
|
100
|
|
|
|
58
|
$responder->($self->{view}->response_statuses( |
|
|
100
|
|
|
|
|
|
138
|
|
|
|
|
|
|
error => "$error", http_code => ($is_normal_error ? 500 : 400), format => $format, |
139
|
|
|
|
|
|
|
($timeline ? (timeline_name => $timeline->name) : ()) |
140
|
|
|
|
|
|
|
)); |
141
|
70
|
|
|
|
|
794
|
}); |
142
|
70
|
|
|
|
|
854
|
}; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
sub _handle_tl_post_statuses { |
146
|
31
|
|
|
31
|
|
69
|
my ($self, $req, $dest) = @_; |
147
|
|
|
|
|
|
|
return sub { |
148
|
31
|
|
|
31
|
|
1972
|
my $responder = shift; |
149
|
|
|
|
|
|
|
Future::Q->try(sub { |
150
|
31
|
|
|
|
|
1412
|
my $timeline = $self->_get_timeline($dest); |
151
|
30
|
|
|
|
|
139
|
my $posted_obj = decode_json($req->content); |
152
|
29
|
100
|
|
|
|
29906
|
if(ref($posted_obj) ne 'ARRAY') { |
153
|
5
|
|
|
|
|
18
|
$posted_obj = [$posted_obj]; |
154
|
|
|
|
|
|
|
} |
155
|
29
|
|
|
|
|
175
|
return future_of($timeline, "add_statuses", statuses => $posted_obj); |
156
|
|
|
|
|
|
|
})->then(sub { |
157
|
27
|
|
|
|
|
6177
|
my $added_num = shift; |
158
|
27
|
|
|
|
|
252
|
$responder->($self->{view}->response_json(200, {count => $added_num + 0})); |
159
|
|
|
|
|
|
|
})->catch(sub { |
160
|
4
|
|
|
|
|
1873
|
my ($e, $is_normal_error) = @_; |
161
|
4
|
100
|
|
|
|
43
|
$responder->($self->{view}->response_json(($is_normal_error ? 500 : 400), {error => "$e"})); |
162
|
31
|
|
|
|
|
351
|
}); |
163
|
31
|
|
|
|
|
396
|
}; |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
sub _handle_tl_ack { |
167
|
28
|
|
|
28
|
|
70
|
my ($self, $req, $dest) = @_; |
168
|
|
|
|
|
|
|
return sub { |
169
|
28
|
|
|
28
|
|
1686
|
my $responder = shift; |
170
|
|
|
|
|
|
|
Future::Q->try(sub { |
171
|
28
|
|
|
|
|
1292
|
my $timeline = $self->_get_timeline($dest); |
172
|
27
|
|
|
|
|
56
|
my $max_id = undef; |
173
|
27
|
|
|
|
|
42
|
my $ids = undef; |
174
|
27
|
100
|
|
|
|
126
|
if($req->content) { |
175
|
23
|
|
|
|
|
22497
|
my $body_obj = decode_json($req->content); |
176
|
23
|
50
|
|
|
|
619
|
if(ref($body_obj) ne 'HASH') { |
177
|
0
|
|
|
|
|
0
|
die "Response body must be an object.\n"; |
178
|
|
|
|
|
|
|
} |
179
|
23
|
|
|
|
|
67
|
$max_id = $body_obj->{max_id}; |
180
|
23
|
|
|
|
|
66
|
$ids = $body_obj->{ids}; |
181
|
|
|
|
|
|
|
} |
182
|
27
|
|
|
|
|
537
|
return future_of($timeline, "ack_statuses", max_id => $max_id, ids => $ids); |
183
|
|
|
|
|
|
|
})->then(sub { |
184
|
25
|
|
|
|
|
5083
|
my $acked_num = shift; |
185
|
25
|
|
|
|
|
261
|
$responder->($self->{view}->response_json(200, {count => $acked_num + 0})); |
186
|
|
|
|
|
|
|
})->catch(sub { |
187
|
3
|
|
|
|
|
1328
|
my ($e, $is_normal_error) = @_; |
188
|
3
|
100
|
|
|
|
33
|
$responder->($self->{view}->response_json(($is_normal_error ? 500 : 400), {error => "$e"})); |
189
|
28
|
|
|
|
|
310
|
}); |
190
|
28
|
|
|
|
|
340
|
}; |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
sub _handle_tl_get_unacked_counts { |
194
|
6
|
|
|
6
|
|
12
|
my ($self, $req, $dest) = @_; |
195
|
|
|
|
|
|
|
return sub { |
196
|
6
|
|
|
6
|
|
278
|
my $responder = shift; |
197
|
|
|
|
|
|
|
Future::Q->try(sub { |
198
|
6
|
|
|
|
|
253
|
my $timeline = $self->_get_timeline($dest); |
199
|
5
|
|
|
|
|
18
|
my $query_params = $req->query_parameters; |
200
|
5
|
|
|
|
|
388
|
my %assumed = (); |
201
|
5
|
100
|
|
|
|
17
|
if(defined $query_params->{total}) { |
202
|
3
|
|
|
|
|
11
|
$assumed{total} = delete $query_params->{total}; |
203
|
|
|
|
|
|
|
} |
204
|
5
|
|
|
|
|
16
|
foreach my $query_key (keys %$query_params) { |
205
|
5
|
50
|
|
|
|
18
|
next if !looks_like_number($query_key); |
206
|
5
|
50
|
|
|
|
46
|
next if int($query_key) != $query_key; |
207
|
5
|
|
|
|
|
13
|
$assumed{$query_key} = $query_params->{$query_key}; |
208
|
|
|
|
|
|
|
} |
209
|
5
|
|
|
|
|
18
|
my $ret_future = Future::Q->new; |
210
|
|
|
|
|
|
|
$timeline->watch_unacked_counts(assumed => \%assumed, callback => sub { |
211
|
5
|
|
|
|
|
5
|
my ($error, $w, $unacked_counts) = @_; |
212
|
5
|
|
|
|
|
24
|
$w->cancel(); ## immediately cancel the watcher to prevent multiple callbacks |
213
|
5
|
50
|
|
|
|
60
|
if($error) { |
214
|
0
|
|
|
|
|
0
|
$ret_future->reject($error, 1); |
215
|
|
|
|
|
|
|
}else { |
216
|
5
|
|
|
|
|
20
|
$ret_future->fulfill($unacked_counts); |
217
|
|
|
|
|
|
|
} |
218
|
5
|
|
|
|
|
106
|
}); |
219
|
5
|
|
|
|
|
29
|
return $ret_future; |
220
|
|
|
|
|
|
|
})->then(sub { |
221
|
5
|
|
|
|
|
651
|
my ($unacked_counts) = @_; |
222
|
5
|
|
|
|
|
28
|
$responder->($self->{view}->response_json(200, {unacked_counts => $unacked_counts})); |
223
|
|
|
|
|
|
|
})->catch(sub { |
224
|
1
|
|
|
|
|
265
|
my ($e, $is_normal_error) = @_; |
225
|
1
|
50
|
|
|
|
10
|
$responder->($self->{view}->response_json(($is_normal_error ? 500 : 400), {error => "$e"})); |
226
|
6
|
|
|
|
|
50
|
}); |
227
|
6
|
|
|
|
|
62
|
}; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
sub _handle_get_unacked_counts { |
231
|
17
|
|
|
17
|
|
35
|
my ($self, $req, $dest) = @_; |
232
|
|
|
|
|
|
|
return sub { |
233
|
17
|
|
|
17
|
|
958
|
my $responder = shift; |
234
|
|
|
|
|
|
|
Future::Q->try(sub { |
235
|
17
|
|
|
|
|
658
|
my $query_params = $req->query_parameters; |
236
|
17
|
|
|
|
|
2305
|
my $level = $query_params->{level}; |
237
|
17
|
100
|
33
|
|
|
125
|
if(not defined($level)) { |
|
|
50
|
66
|
|
|
|
|
238
|
3
|
|
|
|
|
6
|
$level = "total"; |
239
|
|
|
|
|
|
|
}elsif($level ne 'total' && (!looks_like_number($level) || int($level) != $level)) { |
240
|
0
|
|
|
|
|
0
|
die "level parameter must be an integer\n"; |
241
|
|
|
|
|
|
|
} |
242
|
17
|
|
|
|
|
37
|
my %assumed = (); |
243
|
17
|
|
|
|
|
53
|
foreach my $query_key (keys %$query_params) { |
244
|
62
|
100
|
|
|
|
677
|
next if substr($query_key, 0, 3) ne 'tl_'; |
245
|
46
|
|
|
|
|
138
|
$assumed{decode_utf8(substr($query_key, 3))} = $query_params->{$query_key}; |
246
|
|
|
|
|
|
|
} |
247
|
17
|
|
|
|
|
217
|
my $ret_future = Future::Q->new; |
248
|
|
|
|
|
|
|
$self->{main_obj}->watch_unacked_counts( |
249
|
|
|
|
|
|
|
level => $level, assumed => \%assumed, callback => sub { |
250
|
15
|
|
|
|
|
20
|
my ($error, $w, $tl_unacked_counts) = @_; |
251
|
15
|
|
|
|
|
53
|
$w->cancel(); ## immediately cancel the watcher to prevent multiple callbacks |
252
|
15
|
50
|
|
|
|
428
|
if($error) { |
253
|
0
|
|
|
|
|
0
|
$ret_future->reject($error, 1); |
254
|
|
|
|
|
|
|
}else { |
255
|
15
|
|
|
|
|
53
|
$ret_future->fulfill($tl_unacked_counts); |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
} |
258
|
17
|
|
|
|
|
372
|
); |
259
|
15
|
|
|
|
|
98
|
return $ret_future; |
260
|
|
|
|
|
|
|
})->then(sub { |
261
|
15
|
|
|
|
|
2064
|
my ($tl_unacked_counts) = @_; |
262
|
15
|
|
|
|
|
84
|
$responder->($self->{view}->response_json(200, {unacked_counts => $tl_unacked_counts})); |
263
|
|
|
|
|
|
|
})->catch(sub { |
264
|
2
|
|
|
|
|
883
|
my ($e, $is_normal_error) = @_; |
265
|
2
|
50
|
|
|
|
20
|
$responder->($self->{view}->response_json(($is_normal_error ? 500 : 400), {error => "$e"})); |
266
|
17
|
|
|
|
|
144
|
}); |
267
|
17
|
|
|
|
|
168
|
}; |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
sub _handle_tl_index { |
271
|
17
|
|
|
17
|
|
37
|
my ($self, $req, $dest) = @_; |
272
|
17
|
|
|
|
|
69
|
return $self->{view}->response_timeline(_get_timeline_name($dest)); |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
sub _handle_get_timeline_list { |
276
|
10
|
|
|
10
|
|
24
|
my ($self, $req, $dest) = @_; |
277
|
|
|
|
|
|
|
return sub { |
278
|
10
|
|
|
10
|
|
951
|
my $responder = shift; |
279
|
|
|
|
|
|
|
Future::Q->try(sub { |
280
|
10
|
|
|
|
|
682
|
my $num_per_page = $self->{main_obj}->get_config('timeline_list_per_page'); |
281
|
112
|
|
|
|
|
1577
|
my @timelines = grep { |
282
|
10
|
|
|
|
|
53
|
!$self->{main_obj}->get_timeline_config($_->name, "hidden") |
283
|
|
|
|
|
|
|
} $self->{main_obj}->get_all_timelines(); |
284
|
10
|
50
|
|
|
|
101
|
if(@timelines == 0) { |
285
|
0
|
|
|
|
|
0
|
die "No visible timeline. Probably you must configure config.psgi to create a timeline."; |
286
|
|
|
|
|
|
|
} |
287
|
10
|
|
|
|
|
92
|
my $page_num = ceil(scalar(@timelines) / $num_per_page); |
288
|
10
|
|
|
|
|
21
|
my $cur_page = 0; |
289
|
10
|
|
|
|
|
91
|
my $query = $req->query_parameters; |
290
|
10
|
100
|
|
|
|
1167
|
if(defined $query->{page}) { |
291
|
7
|
100
|
100
|
|
|
118
|
if(!looks_like_number($query->{page}) || $query->{page} < 0 || $query->{page} >= $page_num) { |
|
|
|
100
|
|
|
|
|
292
|
4
|
|
|
|
|
51
|
die "Invalid page parameter\n"; |
293
|
|
|
|
|
|
|
} |
294
|
3
|
|
|
|
|
8
|
$cur_page = $query->{page}; |
295
|
|
|
|
|
|
|
} |
296
|
6
|
|
|
|
|
94
|
my @target_timelines = @timelines[($cur_page * $num_per_page) .. min(($cur_page+1) * $num_per_page - 1, $#timelines)]; |
297
|
24
|
|
|
|
|
728
|
return Future::Q->needs_all(map { future_of($_, "get_unacked_counts") } @target_timelines)->then(sub { |
298
|
6
|
|
|
|
|
3160
|
my (@unacked_counts_list) = @_; |
299
|
24
|
|
|
|
|
78
|
my @timeline_unacked_counts = map { |
300
|
6
|
|
|
|
|
59
|
+{ name => $target_timelines[$_]->name, counts => $unacked_counts_list[$_] } |
301
|
|
|
|
|
|
|
} 0 .. $#target_timelines; |
302
|
6
|
|
|
|
|
63
|
$responder->( $self->{view}->response_timeline_list( |
303
|
|
|
|
|
|
|
timeline_unacked_counts => \@timeline_unacked_counts, |
304
|
|
|
|
|
|
|
total_page_num => $page_num, |
305
|
|
|
|
|
|
|
cur_page => $cur_page |
306
|
|
|
|
|
|
|
) ); |
307
|
6
|
|
|
|
|
19
|
}); |
308
|
|
|
|
|
|
|
})->catch(sub { |
309
|
4
|
|
|
|
|
1148
|
my ($error, $is_normal_error) = @_; |
310
|
4
|
50
|
|
|
|
42
|
$responder->($self->{view}->response_error_html( |
311
|
|
|
|
|
|
|
($is_normal_error ? 500 : 400), $error |
312
|
|
|
|
|
|
|
)); |
313
|
10
|
|
|
|
|
184
|
}); |
314
|
10
|
|
|
|
|
159
|
}; |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
1; |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
__END__ |