Search code examples
javascripthtmlhtml5-canvasgtk

Simultaneous connections on GTK Broadway backed


I'm new to GTK Broadway and I succeeded creating an instance of gedit running under it. I can access the interface using any browser and http://localhost:8080 but I can't open two different tabs on the same address. When I try to connect from another tab, the previous disconnects.

What I wish to do is to create a server running a GTK application on one side and serving this application for multiple users, they will be able to visualize the GUI and what's happening but only one user will be able to interact (I'm working on it).

Edit: I thought about a workaround where the server loads the page with the Websockets and the HTML5 Canvas then acts like a proxy and serves the same content to the clients, the proxy would then handle the incoming input from the clients (and manage the parallel connections). Is it technically possible?

Thanks in advance.


Solution

  • I found this on waybackmachine:

    Transparent Proxy for Broadway ( Gtk3 / HTML5 backend )

    Fortunately the source code could be recovered on waybackmachine:

    #!/usr/bin/perl
    #
    # Peteris Krumins ([email protected])
    # http://www.catonmat.net  --  good coders code, great reuse
    #
    # A simple TCP proxy that implements IP-based access control
    # Currently the ports are hard-coded, and it proxies
    # 0.0.0.0:1080 to localhost:55555.
    #
    # Written for the article "Turn any Linux computer into SOCKS5
    # proxy in one command," which can be read here:
    #
    # http://www.catonmat.net/blog/linux-socks5-proxy
    #
    ##############################################################
    #
    # Modified by Dan Kasak ( [email protected] )
    # http://tesla.duckdns.org
    #
    # Added some hacks for proxying based on the value in a cookie,
    # as a proof-of-concept transparent proxy for Gtk+ / broadway
    
    use warnings;
    use strict;
    
    use Data::Dumper;
    
    use IO::Socket;
    use IO::Select;
    
    my $ioset = IO::Select->new;
    my %socket_map;
    
    my $debug = 0;
    
    sub new_server {
        my ($host, $port) = @_;
        my $server = IO::Socket::INET->new(
            LocalAddr => $host,
            LocalPort => $port,
            ReuseAddr => 1,
            Listen    => 100
        ) || die "Unable to listen on $host:$port: $!";
    }
    
    sub close_connection {
        my $client = shift;
        my $client_ip = client_ip($client);
        my $remote = $socket_map{$client};
        
        foreach my $socket ( $client , $remote ) {
            
            if ( ref $socket eq 'ConnectionFuture' ) {
                $socket->disconnect;
            } else {
                $ioset->remove( $socket );
            }
        }
    
        delete $socket_map{$client};
        delete $socket_map{$remote};
    
        $client->close;
        $remote->close;
    
        print "Connection from $client_ip closed.\n" if $debug;
    }
    
    sub client_ip {
        my $client = shift;
        return inet_ntoa($client->sockaddr);
    }
    
    print "Starting a server on 0.0.0.0:10666\n";
    my $server = new_server('0.0.0.0', 10666);
    $ioset->add($server);
    
    while (1) {
        for my $socket ($ioset->can_read) {
            if ($socket == $server) { # $socket is what we're reading from ... $server is our listener. if socket == server, we're reading, and need to create a new target
                ConnectionFuture->new( $server );
            }
            else {
                next unless exists $socket_map{$socket};
                my $remote = $socket_map{$socket};
                my $buffer;
                my $read = $socket->sysread($buffer, 4096);
                if ($read) {
                    $remote->syswrite($buffer);
                }
                else {
                    close_connection($socket);
                }
            }
        }
    }
    
    package ConnectionFuture;
    
    use HTTP::Request;
    
    sub new {
        
        my ( $class, $server ) = @_;
        
        my $self = {
            server  => $server
        };
        
        bless $self, $class;
        
        $self->{client} = $self->{server}->accept;
        
        $socket_map{ $self->{client} } = $self;
        $socket_map{ $self->{server} } = $self->{client};
        
        $ioset->add( $self->{client} );
        
        return $self;
        
    }
    
    sub syswrite {
        
        my ( $self, $buffer ) = @_;
        
        if ( ! exists $self->{remote} ) {
            
            my $host = 'localhost';
            
            my $request = HTTP::Request->parse( $buffer );
            
            my $headers = $request->headers;
            my $cookies = $headers->{cookie};
            
            print "Cookies:\n" . $cookies . "\n";
            
            my $port;
            
            if ( $cookies =~ /port=(\w*)/ ) {
                
                $port = $1;
                
            } elsif ( $cookies = 'cookie1=test' ) {
                
                $port = 10000;
                
            }
            
            if ( $port ) {
                
                $self->{remote} = IO::Socket::INET->new(
                    PeerAddr => $host
                  , PeerPort => $port
                ) || die "Unable to connect to $host:$port: $!";
                
                $socket_map{ $self->{remote} } = $self->{client};
                
                $ioset->add( $self->{remote} );
                
            }
            
        }
        
        if ( $self->{remote} ) {
            $self->{remote}->syswrite( $buffer );
        }
        
    }
    
    sub disconnect {
        
        my $self = shift;
        
        $ioset->remove( $self->{client} );
        $ioset->remove( $self->{remote} );
        
    }
    
    sub close {
        
        my $self = shift;
        
        $self->{client}->close;
        
        if ( $self->{remote} ) {
            $self->{remote}->close;
        }
        
    }
    
    1;

    Hope it helps

    Edited: Fortunately Dan created a github repo, just found it: https://github.com/dankasak/broadway_proxy