#!/usr/bin/perl # LCD Display Thingy for CCS CS Lab # # Douglas Thrift # # $Id$ use strict; use warnings; use threads; use threads::shared; use IO::Socket; use Fcntl; use File::Basename; use JSON; use LWP::UserAgent; use MIME::Base64; use POSIX qw(:time_h); use Thread::Queue; $ENV{HTTPS_CA_FILE} = "/ccs/ssl/cacert.pem"; my $debug = 0; while (defined (my $arg = shift)) { if ($arg eq '-debug') { $debug = 1; } else { print 'Usage: ' . basename($0) . " [-debug]\n"; exit 2; } } my $lcd = new IO::Socket::INET(Proto => 'tcp', PeerAddr => 'localhost', PeerPort => 13666) or die basename($0) . ": $!"; $lcd->autoflush(1); sub command; sub response; sub get; sub escape; command 'hello'; print response if ($debug); command 'client_set', '-name "CCS CS Lab"'; command 'screen_add', 'welcome'; command 'screen_set', 'welcome', '-name "CCS CS Lab Welcome"', '-heartbeat off', '-backlight on', '-duration 120'; command 'widget_add', 'welcome', 'time', 'string'; command 'widget_add', 'welcome', 'greeting', 'scroller'; command 'widget_set', 'welcome', 'greeting', 1, 2, 20, 4, 'v', 8, '"Mayor Richard Daley welcomes you to the CCS CS Lab."'; fcntl($lcd, F_SETFL, O_NONBLOCK); my $agent = new LWP::UserAgent; { open SECRET, '/ccs/etc/lcd.secret' or die basename($0) . ": $!"; my $secret = ; close SECRET; chomp $secret; $secret =~ tr/A-Za-z/N-ZA-Mn-za-m/; my ($user, $password) = split /:/, decode_base64($secret), 2; $agent->credentials(new URI('cscl.creativestudies.org:443'), 'Wall LCD', $user, $password); my $pid = fork; if (!defined $pid) { die basename($0) . ": $!"; } elsif ($pid != 0) { open PID, '>/var/run/CCSlcd.pid'; print PID "$pid\n"; close PID; exit; } $SIG{CHLD} = 'IGNORE'; $SIG{INT} = \&stop; $SIG{TERM} = \&stop; open STDIN, '>/var/log/CCSlcd.log'; open STDERR, '>&STDOUT'; } my $json = new JSON; my $wall :shared; my %postids; async { while (1) { eval { my $get = get 'https://cscl.creativestudies.org/wall/lcd'; lock $wall; $wall = $get; }; sleep 60 - time % 60; } }; while (1) { command 'widget_set', 'welcome', 'time', 5, 1, strftime('"%T %Z"', localtime); { lock $wall; if (defined $wall) { eval { my %postids_; foreach my $post (@{$json->decode($wall)}) { my $postid = $post->{postid}; if (!defined $postids{$postid}) { command 'screen_add', "wall_$postid"; my $text = $post->{post} .' '; command 'screen_set', "wall_$postid", "-name \"CCS CS Lab Wall $postid\"", '-heartbeat off', '-backlight on', '-duration', length($text); command 'widget_add', "wall_$postid", 'name', 'string'; command 'widget_set', "wall_$postid", 'name', 1, 1, escape $post->{name}; command 'widget_add', "wall_$postid", 'posted', 'string'; command 'widget_set', "wall_$postid", 'posted', 1, 2, escape $post->{posted}; command 'widget_add', "wall_$postid", 'post', 'scroller'; command 'widget_set', "wall_$postid", 'post', 1, 4, 20, 4, 'm', 1, escape($text); } $postids_{$postid} = 1; } foreach my $postid (keys %postids) { command 'screen_del', "wall_$postid" if (!defined $postids_{$postid}); } %postids = %postids_; }; undef $wall; } } while (defined (my $response = response)) { if ($debug) { chomp $response; print "$response\n" if ($response !~ /^success$/); } } sleep 1; } sub stop { unlink '/var/run/CCSlcd.pid'; exit; } sub command { print $lcd "@_\n"; } sub response { my $response = <$lcd>; return $response; } sub get { my $uri = shift; my $response = $agent->get($uri); $response->is_success or die basename($0) . ': ' . $response->status_line; return $response->content; } sub escape { my $string = shift; $string =~ s/"/\\"/g; return "\"$string\""; }