]> Sergey Matveev's repositories - public-inbox.git/blob - lib/PublicInbox/FakeInotify.pm
t/imapd: support FakeInotify and KQNotify
[public-inbox.git] / lib / PublicInbox / FakeInotify.pm
1 # Copyright (C) 2020 all contributors <meta@public-inbox.org>
2 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
3
4 # for systems lacking Linux::Inotify2 or IO::KQueue, just emulates
5 # enough of Linux::Inotify2
6 package PublicInbox::FakeInotify;
7 use strict;
8 use Time::HiRes qw(stat);
9 my $IN_CLOSE = 0x08 | 0x10; # match Linux inotify
10
11 my $poll_intvl = 2; # same as Filesys::Notify::Simple
12 my $for_cancel = bless \(my $x), 'PublicInbox::FakeInotify::Watch';
13
14 sub poll_once {
15         my ($self) = @_;
16         sub {
17                 eval { $self->poll };
18                 warn "E: FakeInotify->poll: $@\n" if $@;
19                 PublicInbox::DS::add_timer($poll_intvl, poll_once($self));
20         };
21 }
22
23 sub new {
24         my $self = bless { watch => {} }, __PACKAGE__;
25         PublicInbox::DS::add_timer($poll_intvl, poll_once($self));
26         $self;
27 }
28
29 # behaves like Linux::Inotify2->watch
30 sub watch {
31         my ($self, $path, $mask, $cb) = @_;
32         my @st = stat($path) or return;
33         $self->{watch}->{"$path\0$mask"} = [ @st, $cb ];
34         $for_cancel;
35 }
36
37 # behaves like non-blocking Linux::Inotify2->poll
38 sub poll {
39         my ($self) = @_;
40         my $watch = $self->{watch} or return;
41         for my $x (keys %$watch) {
42                 my ($path, $mask) = split(/\0/, $x, 2);
43                 my @now = stat($path) or next;
44                 my $prv = $watch->{$x};
45                 my $cb = $prv->[-1];
46                 # 10: ctime, 7: size
47                 if ($prv->[10] != $now[10]) {
48                         if (($mask & $IN_CLOSE) == $IN_CLOSE) {
49                                 eval { $cb->() };
50                         }
51                 }
52                 @$prv = (@now, $cb);
53         }
54 }
55
56 package PublicInbox::FakeInotify::Watch;
57 sub cancel {} # noop
58
59 1;