From 6171cb0d7fe0ac8f6352b8d3b9b87d56c56cf791 Mon Sep 17 00:00:00 2001 From: dakkar Date: Thu, 26 Dec 2019 20:13:58 +0000 Subject: restructure store, extract server now Store has a set of Index, which actually do the indexing Store also runs the scan-dir (this may not be ideal, but will do for now) Server handles I/O --- bayes | 46 ++++++------------------------- lib/MaildirIndexer/Email.pm6 | 3 ++- lib/MaildirIndexer/Index.pm6 | 7 +++++ lib/MaildirIndexer/Index/ByRef.pm6 | 36 +++++++++++++++++++++++++ lib/MaildirIndexer/Parser.pm6 | 15 ++++++----- lib/MaildirIndexer/Server.pm6 | 30 +++++++++++++++++++++ lib/MaildirIndexer/Store.pm6 | 55 +++++++++++++++++++++++--------------- 7 files changed, 126 insertions(+), 66 deletions(-) create mode 100644 lib/MaildirIndexer/Index.pm6 create mode 100644 lib/MaildirIndexer/Index/ByRef.pm6 create mode 100644 lib/MaildirIndexer/Server.pm6 diff --git a/bayes b/bayes index e3814fc..0bb9d3e 100644 --- a/bayes +++ b/bayes @@ -1,47 +1,17 @@ #!/usr/bin/env perl6 use v6.d.PREVIEW; use lib 'lib'; -use MaildirIndexer::ScanDir; use MaildirIndexer::Store; -use MaildirIndexer::Parser; +use MaildirIndexer::Server; +use MaildirIndexer::Index::ByRef; sub MAIN($maildir) { - my $store = MaildirIndexer::Store.new; - - my $file-supply = scan-dir($maildir); - my $file-channel = $file-supply.Channel; - - for ^10 { - start react { - whenever $file-channel -> $file { - if $file.e && $file.f { - $store.add-file($file); - } - elsif !$file.e { - $store.del-file($file); - } - } - } - } - - my $listener = IO::Socket::Async.listen( - '127.0.0.1', - 9000, - :enc, + my $store = MaildirIndexer::Store.new( + :$maildir, + indices => MaildirIndexer::Index::ByRef.new, ); - react { - whenever signal(SIGINT) { exit } - whenever signal(SIGHUP) { - $store.dump(); - } - whenever $listener -> $conn { - LEAVE { $conn.close } - with parse-email($conn) -> $email { - with $store.mailbox-for-email($email) -> $mailbox { - await $conn.print("$mailbox\x0d\x0a"); - } - } - } - } + my $server = MaildirIndexer::Server.new(:$store); + $store.start(); + $server.serve() } diff --git a/lib/MaildirIndexer/Email.pm6 b/lib/MaildirIndexer/Email.pm6 index 993d8b1..0cd5bd7 100644 --- a/lib/MaildirIndexer/Email.pm6 +++ b/lib/MaildirIndexer/Email.pm6 @@ -1,10 +1,11 @@ use v6.d.PREVIEW; unit class MaildirIndexer::Email; +has IO $!path; has %!headers; has $!body; -method BUILD(:%!headers,:$!body) { } +method BUILD(:%!headers,:$!body,:$!path = IO) { } method message-id { split-refs(%!headers)[0] // '' } method refs { diff --git a/lib/MaildirIndexer/Index.pm6 b/lib/MaildirIndexer/Index.pm6 new file mode 100644 index 0000000..2cb308a --- /dev/null +++ b/lib/MaildirIndexer/Index.pm6 @@ -0,0 +1,7 @@ +use v6.d; +unit role MaildirIndexer::Index; +use MaildirIndexer::Email; + +method add-mail(MaildirIndexer::Email:D $email, Str:D $mailbox --> Nil) { ... } +method del-path(IO:D $path, Str:D $mailbox --> Nil) { ... } +method mailbox-for-email(MaildirIndexer::Email:D $email --> Str) { ... } diff --git a/lib/MaildirIndexer/Index/ByRef.pm6 b/lib/MaildirIndexer/Index/ByRef.pm6 new file mode 100644 index 0000000..497b5a1 --- /dev/null +++ b/lib/MaildirIndexer/Index/ByRef.pm6 @@ -0,0 +1,36 @@ +use v6.d; +use MaildirIndexer::Index; +unit class MaildirIndexer::Index::ByRef does MaildirIndexer::Index; +use MaildirIndexer::Email; + +has Str %!id-for-file; +has Str %!mailboxes-for-id; + +method dump() { + say "{.key} → {.value}" for %!id-for-file; + say "{.key} ⇒ {.value.perl}" for %!mailboxes-for-id; +} + +method add-mail(MaildirIndexer::Email:D $email, Str:D $mailbox --> Nil) { + my $id = $email.message-id or return; + %!id-for-file{ $email.path } = $id; + %!mailboxes-for-id{ $id }.push($mailbox); + return; +} + +method del-path(IO:D $file, Str:D $mailbox --> Nil) { + my $id = %!id-for-file{ $file.path }:delete; + with %!mailboxes-for-id{ $id } { + with .grep($mailbox):k -> $pos { + .splice($pos,1); + } + } + return; +} + +method mailbox-for-email(MaildirIndexer::Email:D $email --> Str) { + for |$email.refs() -> $ref { + with %!mailboxes-for-id{$ref} { return .[*-1] } + } + return Nil; +} diff --git a/lib/MaildirIndexer/Parser.pm6 b/lib/MaildirIndexer/Parser.pm6 index edcbe6d..e6be32f 100644 --- a/lib/MaildirIndexer/Parser.pm6 +++ b/lib/MaildirIndexer/Parser.pm6 @@ -38,10 +38,12 @@ grammar Message { } class Message-actions { + has $.path = IO; method TOP($/) { make MaildirIndexer::Email.new( headers => $/.made, body => $/.Str, + path => $.path, ); } method headers($/) { @@ -55,21 +57,22 @@ class Message-actions { } } -multi parse-email(IO::Path $p) is export { - return parse-email($p.slurp(:enc)); +multi parse-email(IO::Path:D $p --> MaildirIndexer::Email) is export { + return parse-email($p.slurp(:enc), path => $p.path); } -multi parse-email(IO::Path $p, :$headers-only!) is export { +multi parse-email(IO::Path:D $p, :$headers-only! --> MaildirIndexer::Email) is export { return parse-email( $p.lines( :enc, :nl-in(@separators), :!chomp, )[0], + path => $p.path, ); } -multi parse-email(IO::Socket::Async $s) is export { +multi parse-email(IO::Socket::Async:D $s --> MaildirIndexer::Email) is export { my $string; react { whenever $s.Supply(:enc) { @@ -80,8 +83,8 @@ multi parse-email(IO::Socket::Async $s) is export { return parse-email($string); } -multi parse-email(Str $email-str) is export { - with Message.parse($email-str,:actions(Message-actions.new)) { +multi parse-email(Str:D $email-str, :$path = IO --> MaildirIndexer::Email) is export { + with Message.parse($email-str,:actions(Message-actions.new(:$path))) { return .made; } return Nil; diff --git a/lib/MaildirIndexer/Server.pm6 b/lib/MaildirIndexer/Server.pm6 new file mode 100644 index 0000000..53f4ba9 --- /dev/null +++ b/lib/MaildirIndexer/Server.pm6 @@ -0,0 +1,30 @@ +use v6.d; +unit class MaildirIndexer::Server; +use MaildirIndexer::Parser; +use MaildirIndexer::Store; + +has $.port = 9000; +has MaildirIndexer::Store $.store is required; + +method serve() { + my $listener = IO::Socket::Async.listen( + '127.0.0.1', + 9000, + :enc, + ); + + react { + whenever signal(SIGINT) { exit } + whenever signal(SIGHUP) { + $.store.dump(); + } + whenever $listener -> $conn { + LEAVE { $conn.close } + with parse-email($conn) -> $email { + with $.store.mailbox-for-email($email) -> $mailbox { + await $conn.print("$mailbox\x0d\x0a"); + } + } + } + } +} diff --git a/lib/MaildirIndexer/Store.pm6 b/lib/MaildirIndexer/Store.pm6 index e54fa8f..5c95250 100644 --- a/lib/MaildirIndexer/Store.pm6 +++ b/lib/MaildirIndexer/Store.pm6 @@ -1,45 +1,58 @@ -use v6.d.PREVIEW; +use v6.d; unit class MaildirIndexer::Store; +use MaildirIndexer::Index; +use MaildirIndexer::ScanDir; use MaildirIndexer::Parser; -has %!id-for-file; -has %!mailboxes-for-id; -has $!lock = Lock.new; +has Lock $!lock .= new; +has MaildirIndexer::Index @.indices is required; +has Str $.maildir is required; +has Int $.workers = 10; method dump() { $!lock.protect: { - say "{.key} → {.value}" for %!id-for-file; - say "{.key} ⇒ {.value.perl}" for %!mailboxes-for-id; + .dump() for @!indices; } } -method add-file(IO $file) { +method start() { + my $file-supply = scan-dir($.maildir); + my $file-channel = $file-supply.Channel; + + for ^10 { + start react { + whenever $file-channel -> $file { + if $file.e && $file.f { + self.add-file($file); + } + elsif !$file.e { + self.del-file($file); + } + } + } + } +} + +method add-file(IO:D $file) { my $email = parse-email($file,:headers-only); - my $id = $email.message-id or return; my $mailbox = mailbox-from-path($file.path) or return; $!lock.protect: { - %!id-for-file{ $file.path } = $id; - %!mailboxes-for-id{ $id }.push($mailbox); - }; + .add-mail($email,$mailbox) for @!indices; + } return; } -method del-file(IO $file) { +method del-file(IO:D $file) { my $mailbox = mailbox-from-path($file.path) or return; $!lock.protect: { - my $id = %!id-for-file{ $file.path }:delete; - with %!mailboxes-for-id{ $id } { - with .grep($mailbox):k -> $pos { - .splice($pos,1); - } - } + .del-path($file,$mailbox) for @!indices; } return; } -method mailbox-for-email(MaildirIndexer::Email $email) { - for |$email.refs() -> $ref { - with %!mailboxes-for-id{$ref} { return .[*-1] } +method mailbox-for-email(MaildirIndexer::Email:D $email) { + for @!indices -> $index { + with $index.mailbox-for-email($email) { return $_ }; } return Nil; } -- cgit v1.2.3