Tag Archives: ruby

Disable the ←’s in Rails on Windows

If you run the demo Rails server on Windows you’ll soon see something like this in the console:

Started GET "/rails/info/properties" for 127.0.0.1 at 2011-03-05 19:45:31 +0200
Processing by Rails::InfoController#properties as HTML
←[1m←[36mSQL (0.0ms)←[0m ←[1m SELECT name
FROM sqlite_master
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
←[0m
Rendered inline template (0.0ms)
Completed 200 OK in 80ms (Views: 1.0ms | ActiveRecord: 0.0ms)

The weird sequences with the arrows are ANSI escape codes which are supposed to make the output colorful (the arrows represent the ASCII “escape” character). Unfortunately, cmd.exe (the Windows console) doesn’t support these sequences and displays them in their raw ugliness.

On Rails 3, you can tell Rails not to use these sequences by setting the colorize_logging variable to false. Add these lines to the Application class in application.rb:

    # Windows cmd.exe doesn't support ANSI colors, so disable them
    config.colorize_logging = false

If you’re wondering how some Windows programs such as PowerShell have color output in the console, the answer is that they probably use the Windows API function SetConsoleTextAttribute for this.

win32console

An alternative solution is to to use win32console. This is a ruby module which overrides ruby’s output methods so they emulate ANSI color support. To use it, add this line to your application’s Gemfile (located at the application root directory):

    gem 'win32console', :platforms => :mingw
Advertisements

A TCP proxy in Ruby

A TCP proxy (or a tunnel, or a bridge) is a program that listens at a certain network address for connections. Whenever a connection is made to that address, the program connects to another predefined network address and starts transferring data between the two ends.

The reason I wanted a TCP proxy is this: I needed to run a program on a virtual machine. This program needs Internet access, but I couldn’t make the VM’s Internet access to work — it could only connect to programs on the host machine, i.e. my computer. I thus used a TCP proxy on the host machine to connect the VM to the outside world. (The fact that the program running on the VM needed to access only one predefined network address simplified things greatly).

Below is a Ruby script I used, made from bits of example code that I found on the Web. I tested it with Ruby 1.8.6 on Windows 7.

Several notes regarding the script:

Preventing threads from disappearing

The script is designed to exit with a stack trace on exception. More extensive error handling would be overkill for a quick script. The problem is that in Ruby, by default, threads silently exit on exception — it caused me quite a headache before figuring this out. This is fixed by setting Thread.abort_on_exception to true.

Exiting with Ctrl-C

It’s nice to be able to exit the script by pressing Ctrl-C. On Windows, Ruby doesn’t handle Ctrl-C keypresses inside socket.accept (and apparently during other blocking calls). To fix this, we need a special thread that spends most of its life sleeping, but wakes up once in a second. During that time Ruby will be able to process the keypress and exit.

The script

require 'socket'

if ARGV.length < 1
    $stderr.puts "Usage: #{$0} remoteHost:remotePort [ localPort [ localHost ] ]"
    exit 1
end

$remoteHost, $remotePort = ARGV.shift.split(":")
puts "target address: #{$remoteHost}:#{$remotePort}"
localPort = ARGV.shift || $remotePort
localHost = ARGV.shift

$blockSize = 1024

server = TCPServer.open(localHost, localPort)

port = server.addr[1]
addrs = server.addr[2..-1].uniq

puts "*** listening on #{addrs.collect{|a|"#{a}:#{port}"}.join(' ')}"

# abort on exceptions, otherwise threads will be silently killed in case
# of unhandled exceptions
Thread.abort_on_exception = true

# have a thread just to process Ctrl-C events on Windows
# (although Ctrl-Break always works)
Thread.new { loop { sleep 1 } }

def connThread(local)
    port, name = local.peeraddr[1..2]
    puts "*** receiving from #{name}:#{port}"

    # open connection to remote server
    remote = TCPSocket.new($remoteHost, $remotePort)
    
    # start reading from both ends
    loop do
        ready = select([local, remote], nil, nil)
        if ready[0].include? local
            # local -> remote
            data = local.recv($blockSize)
            if data.empty?
                puts "local end closed connection"
                break
            end
            remote.write(data)
        end
        if ready[0].include? remote
            # remote -&gt; local
            data = remote.recv($blockSize)
            if data.empty?
                puts "remote end closed connection"
                break
            end
            local.write(data)
        end
    end
    
    local.close
    remote.close
    
    puts "*** done with #{name}:#{port}"
end

loop do
    # whenever server.accept returns a new connection, start
    # a handler thread for that connection
    Thread.start(server.accept) { |local| connThread(local) }
end

PS

When I started writing this script I got a cryptic error message if a didn’t add a “require ‘rubygems'” line at the beginning. However I can’t reproduce the problem now. In fact the browser history doesn’t show all the googling I’ve done to find the solution and I’m beginning to think that I hallucinated it all.