60 lines
1.2 KiB
Perl
60 lines
1.2 KiB
Perl
|
|
#!/usr/bin/env perl
|
||
|
|
# 20260219 ChatGPT
|
||
|
|
# $Id$
|
||
|
|
# $HeadURL$
|
||
|
|
|
||
|
|
use strict;
|
||
|
|
use warnings;
|
||
|
|
|
||
|
|
use Mojolicious::Lite -signatures;
|
||
|
|
use Mojo::IOLoop;
|
||
|
|
use IO::Socket::INET;
|
||
|
|
|
||
|
|
my $udp_port = 1777;
|
||
|
|
|
||
|
|
# Track websocket clients
|
||
|
|
my %clients;
|
||
|
|
|
||
|
|
websocket '/stream' => sub ($c) {
|
||
|
|
my $id = sprintf("%x", rand(0xffffffff));
|
||
|
|
$clients{$id} = $c->tx;
|
||
|
|
|
||
|
|
$c->on(finish => sub ($c, $code, $reason) {
|
||
|
|
delete $clients{$id};
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
# UDP socket (non-blocking)
|
||
|
|
my $udp = IO::Socket::INET->new(
|
||
|
|
LocalPort => $udp_port,
|
||
|
|
Proto => 'udp',
|
||
|
|
) or die "udp bind $udp_port: $!\n";
|
||
|
|
|
||
|
|
$udp->blocking(0);
|
||
|
|
|
||
|
|
# Register UDP fd with Mojo reactor
|
||
|
|
my $loop = Mojo::IOLoop->singleton;
|
||
|
|
|
||
|
|
#Mojo::IOLoop->reactor->io($udp => sub ($reactor, $writable) {
|
||
|
|
$loop->reactor->io($udp => sub ($reactor, $writable) {
|
||
|
|
my $datagram = '';
|
||
|
|
my $peer = $udp->recv($datagram, 2048);
|
||
|
|
return unless defined $peer && length $datagram;
|
||
|
|
|
||
|
|
$datagram =~ s/\r?\n$//;
|
||
|
|
|
||
|
|
for my $id (keys %clients) {
|
||
|
|
my $tx = $clients{$id};
|
||
|
|
next unless $tx && !$tx->is_finished;
|
||
|
|
$tx->send($datagram);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
#Mojo::IOLoop->reactor->watch($udp, 1, 0);
|
||
|
|
$loop->reactor->watch($udp, 1, 0);
|
||
|
|
|
||
|
|
get '/' => sub ($c) {
|
||
|
|
$c->render(text => "udp2ws up (udp:$udp_port ws:/stream)\n");
|
||
|
|
};
|
||
|
|
|
||
|
|
app->start;
|