From 0ccebc121a2c4733a2974e9e4b53f6efec229035 Mon Sep 17 00:00:00 2001 From: Gianni Ceccarelli Date: Mon, 29 Jul 2019 16:20:29 +0100 Subject: perl6 implementation --- p6/META6.json | 9 +++ p6/mixed-server.pl | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 p6/META6.json create mode 100644 p6/mixed-server.pl diff --git a/p6/META6.json b/p6/META6.json new file mode 100644 index 0000000..81d9eb3 --- /dev/null +++ b/p6/META6.json @@ -0,0 +1,9 @@ +{ + "perl": "6.d", + "name": "mixed-server", + "version": "1", + "depends": [ + "Cro::HTTP::Router", + "Cro::HTTP::Server", + ], +} diff --git a/p6/mixed-server.pl b/p6/mixed-server.pl new file mode 100644 index 0000000..7f9b8a8 --- /dev/null +++ b/p6/mixed-server.pl @@ -0,0 +1,163 @@ +#!/usr/bin/env perl6 +use v6.d; + +class Model { + has Lock::Async $!lock .= new; + has BagHash $!words .= new; + + method add_words(@words --> Promise) { + return $!lock.lock.then: { + LEAVE $!lock.unlock; + ++$!words{$_} for @words; + } + } + + method get_most_common_pairs(Int() $how_many=10 --> Promise) { + return $!lock.lock.then: { + LEAVE $!lock.unlock; + reverse $!words.sort(*.value).head($how_many); + } + } +} + +class View { + method words_from_input(Str() $input --> Seq) { + return $input.split(/\s+/,:skip-empty); + } + + method table_from_ranked_pairs(@ranked_pairs) { + return @ranked_pairs.map({ sprintf '%-15s %3d',$^p.key,$^p.value }).join("\n"); + } +} + +class HTTPController { + use Cro::HTTP::Router; + + has $.model is required; + has $.view is required; + + sub respond($body) { + response.status = 200; + response.set-body("{$body}\n"); + } + + method routes() { + return route { + get -> *@, :$n! is query { + self.get_words($n); + } + get -> *@ { + self.get_words(); + } + post -> *@ { + request-body-text -> $body { + self.post_words($body); + } + } + } + } + + method get_words($n=10) { + my @most_common_pairs = await $!model.get_most_common_pairs($n); + my $table = $!view.table_from_ranked_pairs(@most_common_pairs); + respond($table); + } + + method post_words($body) { + my @words = $!view.words_from_input($body); + await $!model.add_words(@words); + respond('ok'); + } +} + +class LineController { + has $.model is required; + has $.view is required; + + method on_command(:$stream,:$command,:$args_string) { + if $command eq 'get' { + self.get_words($stream,$args_string); + } + elsif $command eq 'put' { + self.put_words($stream,$args_string); + } + else { + reply($stream,"bad command, only 'get' and 'put'"); + } + } + + sub reply($stream,$text) { + await $stream.print("$text\n"); + } + + method get_words($stream,$args_string) { + my $how_many = $args_string || 10; + + my @most_common_pairs = await $!model.get_most_common_pairs($how_many); + my $table = $!view.table_from_ranked_pairs(@most_common_pairs); + + reply($stream,$table); + } + + method put_words($stream,$args_string) { + my @words = $!view.words_from_input($args_string); + await $!model.add_words(@words); + + reply($stream,'ok'); + } +} + +class TextServer { + + has $.controller is required; + has $.host is required; + has $.port is required; + + has $!stop = Promise.new; + + method start() { + start react { + whenever IO::Socket::Async.listen($!host,$!port) -> $conn { + whenever $conn.Supply.lines -> $line { + my ($command,$args_string) = $line.split(/\s+/,2); + $.controller.on_command( + stream => $conn, + :$command, :$args_string + ); + } + } + whenever $!stop -> { + last; + } + }; + } + + method stop() { $!stop.keep } +} + +use Cro::HTTP::Server; + +my Model $model .= new; +my View $view .= new; + +my HTTPController $httpcontroller .= new(:$model,:$view); +my $httpserver = Cro::HTTP::Server.new( + host => 'localhost', + port => 8080, + application => $httpcontroller.routes, +); +$httpserver.start; + +my LineController $linecontroller .= new(:$model,:$view); +my TextServer $textserver .=new( + host => 'localhost', + port => 2020, + controller => $linecontroller, +); +$textserver.start; + +react whenever signal(SIGINT) { + $httpserver.stop; + $textserver.stop; + exit; +} -- cgit v1.2.3