SlideShare a Scribd company logo
Dancing with
websockets
Dancer


• You’ve heard about it

• It’s simple, powerful,
  flexible
This talk
      • Not an hello world

      • real life example

      • unusual web app

      • unusual technologies

      • goal: show easiness
The background
At $company,

• Many Perl products

• Lot of modules + deps

• Come from CPAN
But,

• CPAN = moving target

• need to stay stable

• local CPAN mirror

• but we need to catch up,
  sometimes
• We have a CLI injecter

• We want a web injecter

• Let’s see the process
The process

• mirror created with minicpan
                                 • it’s «single threaded»
• managed with CPAN::Mini
                                 • one mirror at a time
• injecting = calling
                                 • one injection at a time
  CPAN::Mini::Inject::inject
                                 • one command to perform
• with the mirror’s config file
no user             no database




                     but,
 no session
              a forking process
The web interface
• everything on a single page

• input a string, verify

• get corresponding CPAN module

• check there is a newer version

• confirm/cancel

• inject the module in the mirror

• display the process log

• keep track of the log and the status
W
Status                              ire
                                       fra
           input                          me
schedule    confirm        cancel




                   logs
Technologies
        We need                    We choose

• « instantaneous » update
  of the logs                • WebSockets

• every user see the same    • Event programming
  thing
                             • MetaCPAN::API
• info about the module
Dancer in one sentence
• « Dancer allows you to easily create web applications where you
  can associate http routes to code, which usually end up sending
  back data via a template engine »

• dancer -a plop creates a new application

• templating system:

  • a layout, with a [% content %] placeholder

  • views, template page, that are injected as content
WebSocket
• What are WebSockets ? bidirectional web communication

• The server can push to the client (e.g. add more log lines)

• Dancer::Plugin::WebSocket

   • uses Web::Hippie, websocket/comet Plack implementation

    • which uses AnyEvent

       • so we need an AnyEvent Plack web server : Twiggy
forked injection                   AnyEvent run_cmd
    process                        WebSocket
            logs + status           javascript



                                           status
server process
                                          logs



              server side   client side
Show me the GUI
Dancing with websocket
Dancing with websocket
Show me the code
bin/app.pl                                            config.yml
     use Dancer;                    layout: "main"
     use My::Mirror::Injector;      template: "template_toolkit"
     dance;                         engines:
                                      template_toolkit:
                                        encoding: 'utf8'
views/layouts/main.tt                   start_tag: '[%'
<html>                                  end_tag:   '%]'
<head>
<title>My cool Injector</title>
<script src="...">jquery</script>
</head>
<body>
[% content %]
</body>
</html>
                                                   launch.sh
                     plackup -s Twiggy ./bin/app.pl    -p 5005
views/index.tt
<b>Status</b> : <span id="status">
    <span id="status_text">[% status %]</span>
</span>

<form action="/" method="post">
 Module names (space seperated):
    <input type="text" name="module_name"
                       value="[% module_name %]">
    <br/>
    <input type="submit" name="schedule" value="Schedule">
    <input type="submit" name="confirm" value="Confirm">
    <input type="submit" name="cancel"    value="Cancel">
</form>

<pre>
    <div id="injection_log">[% log %]</div>
</pre>

                 then some javascript...
setup the websocket, handle logs


   var socket = new WebSocket(
       "ws://[% server_host %]:[% server_port %]/_hippie/ws"
   );

   socket.onmessage = function(e) {
       var data = JSON.parse(e.data);
       if (data.msg) {
           $('#injection_log').append(data.msg);
       }
   };

   function send_msg(message) {
       socket.send(JSON.stringify({ msg: message }));
   }
handle status change

var status_regex = /__STATUS_CHANGED:/;
if (status_regex.test(data.msg)) {
    var new_status = data.msg;
    new_status
       = new_status.replace(/__STATUS_CHANGED:(.*)__/, "$1");
    $('#status_text').remove();
    $('#status').append(
       '<span id="status_text">' + new_status + '</span>'
    );
}
package My::Mirror::Injector;
use Dancer;
use Dancer::Plugin::FlashMessage; # for status message
use Dancer::Plugin::WebSocket;    # for WebSocket write
use AnyEvent::Util;               # for run_cmd

my $status = 0;
my $log = '';        # OMG GLOBAL VARIABLES !!!111
my $module_name;

get '/' => &display_page;
sub display_page {
  my $uri = request->uri_base; my $scheme = request->scheme;
  my $host = $uri =~ m|$scheme://(.*?):|;
  template index => {
     status      => $status,
     module_name => $module_name,
     server_host => $host,
     server_port => request->port,
     log => $log
  };
}
post '/' => sub {
    param 'confirm' or $module_name = param 'module_name';

    if (defined param 'schedule') {
        $status = 1; flash info => "Scheduled injection";
        $log = '';
        launch_command(
"mirror-inject --autoflush --dryrun --module $module_name"
        );
    } elsif (defined param 'confirm') {
        # Same, but status = 2
        # and run command with no --dryrun
    } elsif (defined param 'cancel') {
        # User clicked on Cancel
        $status = 0;
        flash info => "Cancelled injection";
    }
    display_page();
}
my $next_status;
sub launch_command {
    my ($cmd) = @_;
    run_cmd( $cmd ,
'>' => sub {
  my ($data) = @_;
  if ( defined $data ) {
       $data =~ s/__CONFIRM__// and $next_status = 2;
       $data =~ s/__FINISHED__// and $next_status = 0;
       $log .= $data;
       ws_send $data;
  } else {
       # End of execution
       if (defined $next_status) {
           $status = $next_status;
           $next_status = undef;
           ws_send '__STATUS_CHANGED:' . $status . "__n";
       }
  }});
}
Show me the video
Dancing with websocket

More Related Content

What's hot (20)

KEY
The HTML5 WebSocket API
David Lindkvist
 
PDF
AnyMQ, Hippie, and the real-time web
clkao
 
KEY
A language for the Internet: Why JavaScript and Node.js is right for Internet...
Tom Croucher
 
KEY
Pushing the web — WebSockets
Roland M
 
PPT
Triple Blitz Strike
Denis Zhdanov
 
PDF
Going Live! with Comet
Simon Willison
 
PDF
Time for Comet?
Simon Willison
 
PPTX
Solving anything in VCL
Fastly
 
KEY
Node worshop Realtime - Socket.io
Caesar Chi
 
PDF
Using Websockets with Play!
Andrew Conner
 
PDF
Beyond Breakpoints: A Tour of Dynamic Analysis
Fastly
 
PDF
WebSockets wiith Scala and Play! Framework
Fabio Tiriticco
 
PDF
Building Real-Time Applications with Android and WebSockets
Sergi Almar i Graupera
 
PPTX
Intro to WebSockets
Gaurav Oberoi
 
PDF
WEB SOCKET 應用
Jerromy Lee
 
KEY
Operation Oriented Web Applications / Yokohama pm7
Masahiro Nagano
 
PPTX
Ws
Sunghan Kim
 
PDF
VCL template abstraction model and automated deployments to Fastly
Fastly
 
PPTX
Websockets in Node.js - Making them reliable and scalable
Gareth Marland
 
PDF
"Service Worker: Let Your Web App Feel Like a Native "
FDConf
 
The HTML5 WebSocket API
David Lindkvist
 
AnyMQ, Hippie, and the real-time web
clkao
 
A language for the Internet: Why JavaScript and Node.js is right for Internet...
Tom Croucher
 
Pushing the web — WebSockets
Roland M
 
Triple Blitz Strike
Denis Zhdanov
 
Going Live! with Comet
Simon Willison
 
Time for Comet?
Simon Willison
 
Solving anything in VCL
Fastly
 
Node worshop Realtime - Socket.io
Caesar Chi
 
Using Websockets with Play!
Andrew Conner
 
Beyond Breakpoints: A Tour of Dynamic Analysis
Fastly
 
WebSockets wiith Scala and Play! Framework
Fabio Tiriticco
 
Building Real-Time Applications with Android and WebSockets
Sergi Almar i Graupera
 
Intro to WebSockets
Gaurav Oberoi
 
WEB SOCKET 應用
Jerromy Lee
 
Operation Oriented Web Applications / Yokohama pm7
Masahiro Nagano
 
VCL template abstraction model and automated deployments to Fastly
Fastly
 
Websockets in Node.js - Making them reliable and scalable
Gareth Marland
 
"Service Worker: Let Your Web App Feel Like a Native "
FDConf
 

Similar to Dancing with websocket (20)

PPTX
WebSocket protocol
Kensaku Komatsu
 
PDF
PerlDancer for Perlers (FOSDEM 2011)
xSawyer
 
ODP
Exploiting the newer perl to improve your plugins
Marian Marinov
 
PDF
Perl Dancer for Python programmers
xSawyer
 
PDF
Toster - Understanding the Rails Web Model and Scalability Options
Fabio Akita
 
PDF
Understanding the Rails web model and scalability options
.toster
 
PDF
Modern Perl Web Development with Dancer
Dave Cross
 
PDF
Real Time Web - What's that for?
Martyn Loughran
 
PDF
Asynchronous programming patterns in Perl
deepfountainconsulting
 
KEY
PSGI/Plack OSDC.TW
Tatsuhiko Miyagawa
 
KEY
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Tatsuhiko Miyagawa
 
PDF
appborg, coffeesurgeon, moof, logging-system
endian7000
 
PDF
Building a desktop app with HTTP::Engine, SQLite and jQuery
Tatsuhiko Miyagawa
 
PPTX
CN UNIT5.pptxCN unit5CN unit5CN unit5CN unit5CN unit5CN unit5CN unit5CN unit5...
RanjiniRanju13
 
PPT
Distributed System by Pratik Tambekar
Pratik Tambekar
 
KEY
Messaging, interoperability and log aggregation - a new framework
Tomas Doran
 
KEY
Deploying Plack Web Applications: OSCON 2011
Tatsuhiko Miyagawa
 
PDF
Nginx Internals
Joshua Zhu
 
KEY
Cooking a rabbit pie
Tomas Doran
 
WebSocket protocol
Kensaku Komatsu
 
PerlDancer for Perlers (FOSDEM 2011)
xSawyer
 
Exploiting the newer perl to improve your plugins
Marian Marinov
 
Perl Dancer for Python programmers
xSawyer
 
Toster - Understanding the Rails Web Model and Scalability Options
Fabio Akita
 
Understanding the Rails web model and scalability options
.toster
 
Modern Perl Web Development with Dancer
Dave Cross
 
Real Time Web - What's that for?
Martyn Loughran
 
Asynchronous programming patterns in Perl
deepfountainconsulting
 
PSGI/Plack OSDC.TW
Tatsuhiko Miyagawa
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Tatsuhiko Miyagawa
 
appborg, coffeesurgeon, moof, logging-system
endian7000
 
Building a desktop app with HTTP::Engine, SQLite and jQuery
Tatsuhiko Miyagawa
 
CN UNIT5.pptxCN unit5CN unit5CN unit5CN unit5CN unit5CN unit5CN unit5CN unit5...
RanjiniRanju13
 
Distributed System by Pratik Tambekar
Pratik Tambekar
 
Messaging, interoperability and log aggregation - a new framework
Tomas Doran
 
Deploying Plack Web Applications: OSCON 2011
Tatsuhiko Miyagawa
 
Nginx Internals
Joshua Zhu
 
Cooking a rabbit pie
Tomas Doran
 
Ad

More from Damien Krotkine (6)

PDF
Stockage et analyse temps réel d'événements avec Riak chez Booking.com
Damien Krotkine
 
PDF
Using Riak for Events storage and analysis at Booking.com
Damien Krotkine
 
PDF
Riak introduction
Damien Krotkine
 
KEY
Message passing
Damien Krotkine
 
KEY
Comma versus list
Damien Krotkine
 
ZIP
Curses::Toolkit
Damien Krotkine
 
Stockage et analyse temps réel d'événements avec Riak chez Booking.com
Damien Krotkine
 
Using Riak for Events storage and analysis at Booking.com
Damien Krotkine
 
Riak introduction
Damien Krotkine
 
Message passing
Damien Krotkine
 
Comma versus list
Damien Krotkine
 
Curses::Toolkit
Damien Krotkine
 
Ad

Recently uploaded (20)

PDF
Upskill to Agentic Automation 2025 - Kickoff Meeting
DianaGray10
 
PDF
Arcee AI - building and working with small language models (06/25)
Julien SIMON
 
PDF
Shuen Mei Parth Sharma Boost Productivity, Innovation and Efficiency wit...
AWS Chicago
 
PDF
Rethinking Security Operations - SOC Evolution Journey.pdf
Haris Chughtai
 
PDF
Women in Automation Presents: Reinventing Yourself — Bold Career Pivots That ...
DianaGray10
 
PDF
Empowering Cloud Providers with Apache CloudStack and Stackbill
ShapeBlue
 
PDF
Ampere Offers Energy-Efficient Future For AI And Cloud
ShapeBlue
 
PDF
Novus-Safe Pro: Brochure-What is Novus Safe Pro?.pdf
Novus Hi-Tech
 
PDF
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
PDF
Complete JavaScript Notes: From Basics to Advanced Concepts.pdf
haydendavispro
 
PDF
Windsurf Meetup Ottawa 2025-07-12 - Planning Mode at Reliza.pdf
Pavel Shukhman
 
PDF
TrustArc Webinar - Data Privacy Trends 2025: Mid-Year Insights & Program Stra...
TrustArc
 
PPTX
Building Search Using OpenSearch: Limitations and Workarounds
Sease
 
PDF
Building Resilience with Digital Twins : Lessons from Korea
SANGHEE SHIN
 
PDF
DevBcn - Building 10x Organizations Using Modern Productivity Metrics
Justin Reock
 
PDF
SFWelly Summer 25 Release Highlights July 2025
Anna Loughnan Colquhoun
 
PDF
Productivity Management Software | Workstatus
Lovely Baghel
 
PPTX
Top iOS App Development Company in the USA for Innovative Apps
SynapseIndia
 
PDF
SWEBOK Guide and Software Services Engineering Education
Hironori Washizaki
 
PDF
UiPath vs Other Automation Tools Meeting Presentation.pdf
Tracy Dixon
 
Upskill to Agentic Automation 2025 - Kickoff Meeting
DianaGray10
 
Arcee AI - building and working with small language models (06/25)
Julien SIMON
 
Shuen Mei Parth Sharma Boost Productivity, Innovation and Efficiency wit...
AWS Chicago
 
Rethinking Security Operations - SOC Evolution Journey.pdf
Haris Chughtai
 
Women in Automation Presents: Reinventing Yourself — Bold Career Pivots That ...
DianaGray10
 
Empowering Cloud Providers with Apache CloudStack and Stackbill
ShapeBlue
 
Ampere Offers Energy-Efficient Future For AI And Cloud
ShapeBlue
 
Novus-Safe Pro: Brochure-What is Novus Safe Pro?.pdf
Novus Hi-Tech
 
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
Complete JavaScript Notes: From Basics to Advanced Concepts.pdf
haydendavispro
 
Windsurf Meetup Ottawa 2025-07-12 - Planning Mode at Reliza.pdf
Pavel Shukhman
 
TrustArc Webinar - Data Privacy Trends 2025: Mid-Year Insights & Program Stra...
TrustArc
 
Building Search Using OpenSearch: Limitations and Workarounds
Sease
 
Building Resilience with Digital Twins : Lessons from Korea
SANGHEE SHIN
 
DevBcn - Building 10x Organizations Using Modern Productivity Metrics
Justin Reock
 
SFWelly Summer 25 Release Highlights July 2025
Anna Loughnan Colquhoun
 
Productivity Management Software | Workstatus
Lovely Baghel
 
Top iOS App Development Company in the USA for Innovative Apps
SynapseIndia
 
SWEBOK Guide and Software Services Engineering Education
Hironori Washizaki
 
UiPath vs Other Automation Tools Meeting Presentation.pdf
Tracy Dixon
 

Dancing with websocket

  • 2. Dancer • You’ve heard about it • It’s simple, powerful, flexible
  • 3. This talk • Not an hello world • real life example • unusual web app • unusual technologies • goal: show easiness
  • 5. At $company, • Many Perl products • Lot of modules + deps • Come from CPAN
  • 6. But, • CPAN = moving target • need to stay stable • local CPAN mirror • but we need to catch up, sometimes
  • 7. • We have a CLI injecter • We want a web injecter • Let’s see the process
  • 8. The process • mirror created with minicpan • it’s «single threaded» • managed with CPAN::Mini • one mirror at a time • injecting = calling • one injection at a time CPAN::Mini::Inject::inject • one command to perform • with the mirror’s config file
  • 9. no user no database but, no session a forking process
  • 10. The web interface • everything on a single page • input a string, verify • get corresponding CPAN module • check there is a newer version • confirm/cancel • inject the module in the mirror • display the process log • keep track of the log and the status
  • 11. W Status ire fra input me schedule confirm cancel logs
  • 12. Technologies We need We choose • « instantaneous » update of the logs • WebSockets • every user see the same • Event programming thing • MetaCPAN::API • info about the module
  • 13. Dancer in one sentence • « Dancer allows you to easily create web applications where you can associate http routes to code, which usually end up sending back data via a template engine » • dancer -a plop creates a new application • templating system: • a layout, with a [% content %] placeholder • views, template page, that are injected as content
  • 14. WebSocket • What are WebSockets ? bidirectional web communication • The server can push to the client (e.g. add more log lines) • Dancer::Plugin::WebSocket • uses Web::Hippie, websocket/comet Plack implementation • which uses AnyEvent • so we need an AnyEvent Plack web server : Twiggy
  • 15. forked injection AnyEvent run_cmd process WebSocket logs + status javascript status server process logs server side client side
  • 16. Show me the GUI
  • 19. Show me the code
  • 20. bin/app.pl config.yml use Dancer; layout: "main" use My::Mirror::Injector; template: "template_toolkit" dance; engines: template_toolkit: encoding: 'utf8' views/layouts/main.tt start_tag: '[%' <html> end_tag: '%]' <head> <title>My cool Injector</title> <script src="...">jquery</script> </head> <body> [% content %] </body> </html> launch.sh plackup -s Twiggy ./bin/app.pl -p 5005
  • 21. views/index.tt <b>Status</b> : <span id="status"> <span id="status_text">[% status %]</span> </span> <form action="/" method="post"> Module names (space seperated): <input type="text" name="module_name" value="[% module_name %]"> <br/> <input type="submit" name="schedule" value="Schedule"> <input type="submit" name="confirm" value="Confirm"> <input type="submit" name="cancel" value="Cancel"> </form> <pre> <div id="injection_log">[% log %]</div> </pre> then some javascript...
  • 22. setup the websocket, handle logs var socket = new WebSocket( "ws://[% server_host %]:[% server_port %]/_hippie/ws" ); socket.onmessage = function(e) { var data = JSON.parse(e.data); if (data.msg) { $('#injection_log').append(data.msg); } }; function send_msg(message) { socket.send(JSON.stringify({ msg: message })); }
  • 23. handle status change var status_regex = /__STATUS_CHANGED:/; if (status_regex.test(data.msg)) { var new_status = data.msg; new_status = new_status.replace(/__STATUS_CHANGED:(.*)__/, "$1"); $('#status_text').remove(); $('#status').append( '<span id="status_text">' + new_status + '</span>' ); }
  • 24. package My::Mirror::Injector; use Dancer; use Dancer::Plugin::FlashMessage; # for status message use Dancer::Plugin::WebSocket; # for WebSocket write use AnyEvent::Util; # for run_cmd my $status = 0; my $log = ''; # OMG GLOBAL VARIABLES !!!111 my $module_name; get '/' => &display_page; sub display_page { my $uri = request->uri_base; my $scheme = request->scheme; my $host = $uri =~ m|$scheme://(.*?):|; template index => { status => $status, module_name => $module_name, server_host => $host, server_port => request->port, log => $log }; }
  • 25. post '/' => sub { param 'confirm' or $module_name = param 'module_name'; if (defined param 'schedule') { $status = 1; flash info => "Scheduled injection"; $log = ''; launch_command( "mirror-inject --autoflush --dryrun --module $module_name" ); } elsif (defined param 'confirm') { # Same, but status = 2 # and run command with no --dryrun } elsif (defined param 'cancel') { # User clicked on Cancel $status = 0; flash info => "Cancelled injection"; } display_page(); }
  • 26. my $next_status; sub launch_command { my ($cmd) = @_; run_cmd( $cmd , '>' => sub { my ($data) = @_; if ( defined $data ) { $data =~ s/__CONFIRM__// and $next_status = 2; $data =~ s/__FINISHED__// and $next_status = 0; $log .= $data; ws_send $data; } else { # End of execution if (defined $next_status) { $status = $next_status; $next_status = undef; ws_send '__STATUS_CHANGED:' . $status . "__n"; } }}); }
  • 27. Show me the video

Editor's Notes