#!/usr/bin/perl use strict; use warnings; use feature 'state'; use Mojolicious::Lite; use Mojo::Server::Daemon; use EV; use AnyEvent; use Linux::Inotify2; use constant FILE_NAME => 'data/content.pl'; use constant LISTEN => 'http://localhost:8880'; use constant TIMEOUT => 600; my %clients; our $content; sub getcontent{ my $init = shift; state $old; my $out = {}; local $content; do FILE_NAME; for my $key (keys %$content) { $out->{$key} = $content->{$key} if $init || $old->{$key} ne $content->{$key}; } app->log->info("read content from file"); $old = $content; return $out;; } sub push_all { my $content = shift; my $data = {msg => $content}; foreach my $client (values %clients) { app->log->info("pushing data to client"); $client->send({json => $data}); Mojo::IOLoop->stream($client->connection)->timeout(TIMEOUT); } }; my $inotify = new Linux::Inotify2 or die $!; sub app_file_changed { my $e = shift; app->log->info("got file modify event"); my $content = getcontent(); push_all($content) if %$content; if ($e->IN_ATTRIB) { $inotify->watch(FILE_NAME, IN_CLOSE_WRITE | IN_ATTRIB, \&app_file_changed); } }; $inotify->watch(FILE_NAME, IN_CLOSE_WRITE | IN_ATTRIB, \&app_file_changed); my $ino_w = AnyEvent->io(fh => $inotify->fileno, poll => 'r', cb => sub {$inotify->poll}); AnyEvent->signal(signal => 'INT', cb => sub {exit 1;}); AnyEvent->signal(signal => 'QUIT', cb => sub {exit 1;}); AnyEvent->signal(signal => 'TERM', cb => sub {exit 1;}); my $cond = AnyEvent->condvar; get "/" => sub { my $self = shift; $self->reply->static("index.html"); }; websocket "/ws/data/" => sub { my $c = shift; my $tx = $c->tx; my $cid = "$tx"; $clients{$cid} = $tx; $c->inactivity_timeout(TIMEOUT); $c->on(json => sub { my ($c, $data) = @_; my $content = getcontent(1); app->log->info("sending initial data to client"); $data->{msg} = $content; $c->send({json => $data}); }); $c->on(finish => sub { delete $clients{$cid}; } ); $c->on(error => sub { delete $clients{$cid}; } ); }; app->secrets(['not so secret']); my $daemon = Mojo::Server::Daemon->new(app => app, listen => [LISTEN]); $daemon->start; $cond->recv; #### Update Demo

Update Demo

Text

{{text}}

Image

##
## (function() { 'use strict'; var demoModule = angular.module('demoModule', []); demoModule.controller('demoController', function($rootScope, initService) { $rootScope.text = 'text from root scope'; $rootScope.hash = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'; }); demoModule.service('initService', function($rootScope, data) { }); demoModule.factory('data', function($rootScope) { var Server = {}; var socketUri = 'ws://localhost:8880/ws/data/'; var ws = new WebSocket(socketUri); ws.onopen= function(evt) { ws.send(JSON.stringify({msg: 'init'})); }; ws.onmessage = function(evt) { var msg = JSON.parse(evt.data).msg; for (var name in msg) { $rootScope.$apply(set_parm(name, msg[name])); }; }; function set_parm(name, value) { $rootScope[name] = value; }; return Server; }); })(); #### $content = { text => 'text from server', hash => 'da39a3ee5e6b4b0d3255bfef95601890afd80709', };