Calamity Lane » Marriage. Programming. Calamity. It all seems to go together, somehow.

Them what deals with th' Devil...

Tags: #

With my recent spate of GServer problems, I thought I’d post something that, surprisingly, turned out not to be much of a problem at all: turning a Ruby GServer into a Windows service.

First, it helps tremendously if you already have Cygwin installed. If you don’t, you should, as you get lots of UNIX-y command-line goodness (for example, a “Find In Files” functionality (grep) that actually finds stuff in files. Uncanny!)

I’d used Cygwin’s “cygrunsrv” to run Cygwin’s SSH server on Windows, because I love SSH and it seemed like a good idea at the time. I didn’t realize you could use it to create service out of arbitrary programs. With the following command (broken up for readability):

cygrunsrv /
           --install "Bill Gates is Reading My Source Code Service" /
           --path c:/ruby/bin/rubyw.exe /
           --args c:/Projects/source_viewer/source_viewer_server.rb

…you can be running your server under your very own Windows service! (Pardon me while I run and gargle with some bleach.)

Basically, you just need a name, the path to your Ruby executable, and the path to your application, and you’re good to go.

Notice here that I’ve used “rubyw.exe” which is a “windowless” version of Ruby. It does not try to open Window’s crippled console, but runs strictly in the background, which is nice if you want to launch a server from a windows shortcut without distracting little black screens popping up. I have no idea if this helps any, but I figured it couldn’t hurt (famous last words).

One other important thing to be aware of is that Windows does not respond to standard system signals, so you will need to add the following method to your server class (as seen here):

 def trap(signal)
   Kernel::trap(signal){yield} 
   Thread.new{loop{sleep 1}} # Stupid Windows...
 end

This lets you stop the service from services.msc– if you don’t have this, chances are good that the whole thing will hang when you try to stop or restart your service.

There are a number of other (probably better) methods to turn programs into Windows services, but this one was quick, easy and served my needs well.

More GServer Goodness

Tags: #

In a previous posting, I mentioned that you could create a telnet server from a Rails application. After having actually pushed a small GServer-based app into production, I can add a few notes to it:

ACCESSING YOUR SERVER REMOTELY

This one took way too long to figure out. Every example I’ve seen online (even the library documentation) will only let you connect from localhost, which seemed even more exceptionally pointless than the stuff I usually do. Most of the sample code runs along these lines:

require 'gserver'

class SomeNewServer < GServer
...
end

server = SomeNewServer.new 1234
server.start
server.join

…where “1234” is the port used to access the server. With this setup, you simply cannot access the server from another box, period. Change the following line:

server = SomeNewServer.new 1234

…to:

server = SomeNewServer.new 1234, 'myserver.example.com'

…to make your new server accessible to the outside world. You can use an IP address in place of the domain name.

On the one hand, I was able to just guess at this parameter, and Ruby’s Principle of Least Surprise came through for me. It’s more secure, as you don’t have to worry about accidentally exposing a massive security hole on your box during development. On the other hand, it would have been nice to have it clearly listed out somewhere. Here’s hoping that this saves some future googler a guessing game.

Multi-line strings in Ruby-- I Love Carriage Returns!

Tags: #

If you’ve ever done any serious development in VB or the old VBScript, you’ve probably done something like this:

strSQL = "SELECT o.* " & _
         "FROM people p " & _
         "INNER JOIN orders o " & _
         "ON o.person_id = p.id " & _
         "WHERE person_id = " & PersonID & ";"

…which is highly readable, but a huge pain to debug, especially when trying to cut-n-paste into the query window. How many of us have learned BkSp-BkSp-BkSp-Down-End-repeat-ad-infinitum? In fact, if you were to take every ‘” & _’ and ’ “’ I’ve ever deleted and stack them up on top of one another, you would probably end up with a stack… well, several inches high. Let’s face it, electrons just aren’t that big.

Fed up with this state of affairs, many of us moved to C# for development, leading to:

strSQL =        "SELECT o.* ";
strSQL = strSQL + "FROM people p ";
strSQL = strSQL + "INNER JOIN orders o ";
strSQL = strSQL + "  ON o.person_id = p.id ";
strSQL = strSQL + "WHERE person_id = " + PersonID.ToString() + ";

In the computer industry, this is called “progress.”

Of course, if you wanted to make debugging simpler, you could stuff the entire string on one line:

strSQL = "SELECT o.* FROM people p INNER JOIN orders o ON o.person_id = p.id WHERE person_id = " + PersonID.ToString() + ";"

…which is a lot easier to cut-n-paste, but a lot less easy to read.

Which is where Ruby comes in. Same query in Ruby:

strSQL = " 
    SELECT o.*
      FROM people p
      INNER JOIN orders o ON o.person_id = p.id
      WHERE person_id = #{person_id.to_s};
"

Isn’t it bee-yoo-tee-ful? Readable, functional, and oh so copy-pasteable. Also, it does not require extra punctuation to patch together a simple multi-line query.

There are about 19,000 different ways to define a string in Ruby, but it’s the simple timesavers like this that make the language really shine.

Of course, if you were using Rails, you could just

Person.find(person_id).orders

…which just goes to show how much smarter and more sexually attractive Railers are than everybody else.

NOTE: Originally, I was going to include connection and execution of the query, but that would have blown the VBScript and Ruby examples up an extra four lines of code each. Using recommended practices, it would have bloated the C# code up another 15 lines, plus a stored procedure definition.

The Rails example would still have been only one line. Simplicity ftw!

How to Turn a Rails Application Into a Telnet Server in 30 Lines of Code!

Tags: #

Ruby on Rails is a beautiful thing; simple, fast, and powerful. As they say, it takes the pain out of web development.

I’m fortunate enough to have been able to use Rails at work for a few months now, and the more I learn about the Rails framework and the Ruby language, the more enamored I become of the simplicity, beauty, and zen-like nature of these tools. But you didn’t come here to see me gush with adoration like a schoolgirl at an Elvis concert (I hope), you came to see:

How to Turn a Rails Application Into a Telnet Server in 30 Lines of Code!

First, some code:

#!/usr/bin/env ruby
require 'config/environment'
require 'gserver'

class TestServer < GServer
  def serve( io )
    begin
      io.puts ">> WELCOME <<" 
      loop do
        begin
          telnet_input = io.gets
          break if telnet_input =~ /\Aquit\b/
          io.puts eval(telnet_input)
        rescue Exception
          io.puts "Oops - " + $!
        end
        log "Rec'd " + telnet_input
      end
      io.puts ">> GOODBYE <<" 
      io.close
    rescue Exception
      puts "OOPS - " + $!
      raise
    end
  end
end

ts = TestServer.new 1234
ts.start
ts.audit = true
ts.join

This code should work, as is, on just about any Rails application (as far as I’ve been able to tell; it’s worked on the few I’ve tried).

Last night I was tooling around, playing with code. I’d had an idea for some server software I’d like to write, so I mocked up a quick throwaway system in Rails, and started playing around with some of the logic. I liked the results, and I’d already decided I wanted to write the server in Ruby, but the thought of taking all that functionality and porting everything to DBI calls or whatever was handy just made me tired, especially since Rails does all of the tedious database tasks for you.

Fortunately, I’m slowly learning that Ruby is written for lazy programmers, and after a little googling and some educated guesses, I was able to whack the entire Rails app into a script simply by including:

require 'config/environment'

…at the top of a file in the project root. This makes everything available (so far as I’ve been able to tell) to your application.

For a piece-by-piece analysis:

#!/usr/bin/env ruby
require 'config/environment'
    require 'gserver'

class TestServer < GServer
  def serve( io )

This sets the scripting environment, includes the Rails app, and makes the “GServer” class available. GServer is a freebie that comes with Ruby, so there’s no need for gem installs or other libraries. We’re then creating our own class which inherits from GServer, and overriding its “serve” method.

      io.puts ">> WELCOME <<" 
      loop do
        telnet_input = io.gets
        break if telnet_input =~ /\Aquit\b/
        io.puts eval(telnet_input)
        log "Rec'd " + telnet_input
      end
      io.puts ">> GOODBYE <<" 
      io.close

This is the heart of the server (note that I’ve left out the exception handling for readability). Simply speaking, the serve() method is what handles user connections, and the “io” object lets us do gets and puts across the wire.

When a user connects, we spit out a welcome message, then go into an endless loop that responds to user requests. The following:

telnet_input = io.gets

…grabs whatever line the user types in. This line:

break if telnet_input =~ /\Aquit\b/

…kicks us out of the loop if the user types “quit”. Note that I’m using a regex instead of a static string because io.gets() returns the linefeed that the user types in, and this was an easy way to cheat out the functionality. The “\A” portion of the regex matches the beginning of the string, and the “\b” matches a “word boundary” character, in this case, the linefeed.

        io.puts eval(telnet_input)
        log "Rec'd " + telnet_input

The first line here does an eval() on whatever the user typed in, returning the value back across the wire. This should allow the user to run any command that Ruby (and your Rails app) will accept. The second line spits whatever the user typed in to the console where the server is running.

      io.puts ">> GOODBYE <<" 
      io.close

Once the loop is broken, we burp out a fond farewell and cleanly close the connection.

ts = TestServer.new 1234
ts.start
ts.audit = true
ts.join

The rest of the code just sets a few variables and kicks on the service. The “1234” on the creation of the “ts” object sets the listening port. Turning on auditing allows us to see when someone logs on and off from the console (which can be redirected to a log file).

CAVEATS:

This is an extremely simple server. It has no security, no performance optimization, and probably has more holes than a cheesecloth factory. It is very naive, and while it technically allows multiple users to log on, they’ll all share the same class variables. Really, it’s only interesting at this point to show that it can be done.

That having been said, the ease with which it was accomplished is one of the many testaments to Ruby’s power and simplicity. I’ve been programming for many years, coded a number of servers, and this was the first time I’ve ever felt drunk with power after a coding session. “I can do anything!” I bellowed as I reeled around the room, knocking old monitors and dusty programming tomes off the desk. “No one can stop me!” Fortunately, my wife, who is a lot more level-headed than I am, pointed out that she could, indeed, stop me, since it had gone past two in the morning.