Twitterprofilephoto_normalzh

http://twitter.com/zh

Integrate WebSockets (via sunshowers) in Sinatra application

# create config.ru like:
#
#   require 'echowebsocket'
#   run EchoWebSocket.new
#
# and start it with: 
#
#   rackup config.ru -s thin -E production -p 8000
#
# echowebsocket.rb will be:

require 'sinatra'
require 'sunshowers'

class Sinatra::Request < Rack::Request
  include Sunshowers::WebSocket
end

class EchoWebSocket < Sinatra::Base
  set :sessions, true

  get "/echo" do
    if request.ws?
      request.ws_handshake!

      request.ws_io.each do |record|
        ws_io.write_utf8(record)
        break if record == "Goodbye"
      end

      begin
        request.ws_quit!
      rescue
        nil
      end
    end
    "You're not using Web Sockets"
  end
end
Reveal More
Added about 1 month ago

Get your local IP address

# Origin: http://coderrr.wordpress.com/2008/05/28/get-your-local-ip-address/#viewSource

require 'socket'

def local_ip
  # turn off reverse DNS resolution temporarily
  orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true

  UDPSocket.open do |s|
    s.connect '64.233.187.99', 1
    s.addr.last
  end
ensure
  Socket.do_not_reverse_lookup = orig
end
Reveal More
Added 3 months ago

Deploying node.js applications

# Origin: http://howtonode.org/deploying-node-upstart-monit
#

# 1.) in /etc/event.d/yourprogram (old) or /etc/init/yourprogram.conf (new)

description "node.js server"
author      "joe"

start on startup
stop on shutdown

script
  export HOME="/root"
  exec sudo -u username /usr/local/bin/node /where/yourprogram.js 2>&1 >> /var/log/node.log
end script

# 2.) /etc/monitrc

set logfile /var/log/monit.log

check host nodejs with address 127.0.0.1
  start program = "/sbin/start yourprogram"
  stop program  = "/sbin/stop yourprogram"
  if failed port 8000 protocol HTTP
      request /
      with timeout 10 seconds
      then restart
Reveal More
Added 4 months ago

Mock Web

#!/usr/bin/env ruby
#
# unknown source :(

require 'rubygems'
require 'rack'
require 'thin'

# Mock server for testing bad or heavyweight server responses; runs on
# localhost:4000 by default
#
# Example of use
#
# In setup method:
#
# @mock_server = MockServer.new # creating a new instance spawns a
# thread running the TCP server
# @mock_server.register( { 'REQUEST_METHOD' => 'GET' }, 
# [ 200, { 'Content-Type' => 'text/plain', 'Content-Length' => '11' }, 
# [ 'Hello World' ]])
# @mock_server.register( { `REQUEST_METHOD' => `GET' }, [
#  200, { 'Content-Type' => 'text/plain', 'Content-Length' => '11' }, 
#  [ 'Hello Again' ]])
#
# After each test, to remove all expectations:
#
# @mock_server.clear
#
# In teardown method:
#
# @mock_server.stop

class MockServer

  def initialize(options={})
    host = options[:host] || '127.0.0.1'
    port = options[:port] || 4000
    @expectations = []
    @server = Thin::Server.new(host, port, self)
    @thread = Thread.new { @server.start }
  end

  def stop
    @server.stop!
    Thread.kill(@thread)
  end

# env should be a hash mapping elements of a Rack env to expected values 
# (see examples above); note that an expected value can be a Proc which 
# will be passed the value from the request
# and executed - if the Proc returns true on execution, the expectation is met
#
# For example, to check that the querystring contains the value `1234', env could be:
#
# { `QUERY_STRING' => lambda { |qs| !((qs =~ /1234/).nil?) } }
#
# response should be a Rack-formatted response; i.e. [response_code,
# {'header' => 'value', ...}, response_body]
#
# options:
# :transient => false to prevent a response being removed after it has 
# been served (default is true)
  def register(env, response, options={})
    transient = options[:transient]
    transient = true if transient.nil?

    @expectations = []

    @expectations.each_with_index do |expectation, index|
      expectation_env, matched_response, transient = expectation
      matched = false

      expectation_env.each do |env_key, value|
        puts "Trying to match #{env_key} => #{value} to request"
        matched = true

        req_value = env[env_key]

        if value.is_a? Proc
          req_element_matches = value.call(req_value)
        else
          req_element_matches = (value == req_value)
        end

        unless req_element_matches
          puts " Value NOT matched: request value was #{env[env_key]} (needed #{value} to match)"
          matched = false
          break
        end
      end

      if matched
        if transient
          @expectations.delete_at(index)
        end
        response = matched_response
        break
      end
    end
    response
  end

end
Reveal More
Added 5 months ago

Mock Mail

#!/usr/bin/env ruby
#
# unknown source :(

require 'socket'

DEBUG = false

def data(sock)
  s = ""

  sock.print "354 End data with <CR><LF>.<CR><LF>\r\n"
  while(line = sock.gets)
    puts line if DEBUG
    break if line =~ /^\.\r?\n?$/
    s += line
  end
  s
end

def session(sock)
  sock.print "220 localhost SMTP mockmail\r\n"
  from = nil
  to = []
  body = nil
  while(line = sock.gets)
    line.chomp!
    puts line if DEBUG
    sock.print case line
      when /HELO/: "250 localhost\r\n"
      when /RSET/: "250 Ok\r\n"
      when /VRFY/:
        /VRFY [^\s]/ =~ line
        "252 #{$1}\r\n"
      when /MAIL FROM/:
        /MAIL FROM:\s*\<?([^\s<>]+)\>?/ =~ line
        from = $1
        puts from if DEBUG
        "250 Ok\r\n"
      when /RCPT TO/:
        /RCPT TO:\s*\<?([^\s\r\n\t\f<>]+)\>?/ =~ line
        to << $1
        puts to if DEBUG
        "250 Ok\r\n"
      when /DATA/:
        body = data(sock)
        "250 Ok\r\n"
      when /QUIT/:
        sock.print "221 Bye\r\n"
        break
      else "500 Err\r\n"
    end
  end
  puts "from: #{from}"
  puts "to: #{to.join '; '}"
  puts "---"
  puts body
  puts "==="
  open("mockmail.txt", "a") { |f|
    f.puts "from: #{from}"
    f.puts "to: #{to.join '; '}"
    f.puts "---"
    f.puts body
    f.puts "==="
  }
  sock.close
end

def main
  begin
    server = TCPServer.new('localhost',25)
    Thread.start {
      loop { sleep 1 }
    }
    loop do 
      Thread.start(server.accept) { |sock|
        begin
          session(sock)
        rescue Exception => e
          p e
        end
      }
    end
  rescue Interrupt => i
    puts "ending..."
  end
end

main
Reveal More
Added 5 months ago

off-site backup to Amazon EBS using dirvish

#!/usr/bin/env python -t
# encoding: utf-8
# origin:   http://overt.org/2010/02/15/off-site-backup-for-010gb-using-dirvish-and-amazon-ec2-and-ebs/
"""
run_offsite_backups.py
 
Wake up the EC2 backup server, run dirvish backup, then shut it down
 
Created by Bryan Klingner (code.b@overt.org) on 2010-02-02.
Feel free to use this code yourself. Maybe email me if you do :)
"""
 
import sys
import os
import boto
import time
import subprocess
 
BACKUP_INSTANCE_ID = 'YOUR_INSTANCE_ID'
 
def main():
 
    conn = boto.connect_ec2()
 
    # get the backup instance object
    instance = conn.get_all_instances(instance_ids=(BACKUP_INSTANCE_ID,))[0].instances[0]
 
    # if the instance is stopped, start it up
    if instance.state != 'running':
        conn.start_instances(instance_ids=(BACKUP_INSTANCE_ID,))
        waited = 0
        while instance.state != 'running':
            instance.update()
            sys.stdout.write("\rInstance starting up (%d sec)..." % (waited))
            sys.stdout.flush()
            time.sleep(1)
            waited += 1
 
    print "\n"
    print "Backup instance running:"
    print "    ID:       ", instance.id
    print "    State:    ", instance.state
    print "    DNS name: ", instance.dns_name
 
    # chill for a few seconds so the SSH server is listening
    time.sleep(10)
 
    print ""
    print "Initiating backup..."
    retcode = ssh_cmd('dirvish-expire; dirvish-runall', instance.dns_name, user='username')
    print ""
 
    # backup is done; shut down the instance
    conn.stop_instances(instance_ids=(BACKUP_INSTANCE_ID,))
    waited = 0
    while instance.state != 'stopped':
        instance.update()
        sys.stdout.write("\rInstance shutting down (%d sec)..." % (waited))
        sys.stdout.flush()
        time.sleep(1)
        waited += 1
    print ""
 
def ssh_cmd(cmd, host, user='root'):
    """ Run a shell command on a remote server via ssh """
 
    ssh_cmd = 'ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no ' + user + '@' + host + " '%s'" % (cmd)
    print "Running SSH command: %s" % ssh_cmd
    returncode = subprocess.call(ssh_cmd, shell=True)
 
    #logging.debug( output, returncode )
    return returncode
 
if __name__ == '__main__':
    main()
Reveal More
Added 5 months ago

make a system call and then kill it if the timeout is reached

require 'timeout'

class System
 def self.system_with_timeout(timeout, *args)
  if ( (pid = fork) == nil )
    #child process
    @@logger.debug(args.join(' '))
    exec(*args)
  else
    success = false
    #parent process
    begin
      #TODO if the process fails return false
      success = Timeout::timeout(timeout){ Process.waitpid(pid) }
    rescue Timeout::Error
      @@logger.error "***** Timeout error"
      Process.kill("HUP", pid)
      Process.detach(pid)
    end
    success
  end
 end
end
Reveal More
Added 6 months ago

rackup startup file for Rails

# config.ru
#
# Start Rails mongrel server with rackup
# $ rackup -p 3000 config.ru
#
# Start server with webrick (or any compatible Rack server) instead
# $ rackup -p 3000 -s webrick config.ru

# Require your environment file to bootstrap Rails
require File.dirname(__FILE__) + '/config/environment'

# Static server middleware
# You can remove this extra check if you use an asset server
use Rails::Rack::Static

# Dispatch the request
run ActionController::Dispatcher.new
Reveal More
Added 6 months ago

Skip building of the not needed erlang OTP parts

wget http://erlang.org/download/otp_src_R13B03.tar.gz
tar -xzf otp_src_R13B03.tar.gz
cd otp_src_R13B03

X="webtool tv toolbar test_server snmp pman percept otp_mibs orber \
      odbc observer megaco jinterface inviso ic gs et cos* common_test asn1"
for a in `cd lib ; echo $X` ;do touch lib/$a/SKIP ; done

./configure && make && sudo make install
Reveal More
Added 6 months ago

Send rich (HTML) XMPP message

require 'xmpp4r/client'
include Jabber

# Login
jid = JID::new('me@jabber.org/Work')
password = '--some_secret--'
cl = Client::new(jid)
cl.connect
cl.auth(password)

# Create a message
to = "you@xmpp.org"
subject = "XMPP4R Rich-Text Test"
body = "Wow, I can do HTML now. But if you see this, your client doesn't support it"
m = Message::new(to, body).set_type(:normal).set_id('1').set_subject(subject)

# Create the html part
h = REXML::Element::new("html")
h.add_namespace('http://jabber.org/protocol/xhtml-im')

# The body part with the correct namespace
b = REXML::Element::new("body")
b.add_namespace('http://www.w3.org/1999/xhtml')

# The html itself
t = REXML::Text.new( "This is so <strong><span style='background: #003EFF; '><span style='font-size: large; '>COOL!!!</span></span></strong>. I can really do <strong>HTML</strong> now.", false, nil, true, nil, %r/.^/ )

# Add the html text to the body, and the body to the html element
b.add(t)
h.add(b)

# Add the html element to the message
m.add_element(h)

# Send it
cl.send m
Reveal More
Added 6 months ago

Posting XMPP (Jabber) messages without external XMPP libraries

# Origin: some challenge on reddit

import socket, base64, ssl

user = "user"
server = "jabber.org"
port = 5222
password = "password"
recipient = "foo@bar.com"
message = "hello"
useSSL = True

def waitfor(socket, element) :
  input = ""  
  while not ("<" + element) in input or not input.endswith(">") :
    input += s.recv(1024)

s = socket.socket()
s.connect((server, port))
header = "<stream:stream version='1.0' xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client' to='" + server + "' xmlns:xml='http://www.w3.org/XML/1998/namespace'>"
if useSSL :
  s.send(header + "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>")
  waitfor(s, "proceed")
  s = ssl.wrap_socket(s)
s.send(header + "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>" + base64.b64encode("\0" + user + "\0" + password)+ "</auth>")
waitfor(s, "success")
s.send(header + "<iq type='set'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/></iq><iq type='set'><session xmlns='urn:ietf:params:xml:ns:xmpp-session'/></iq><message to='" + recipient + "'><body>" + message + "</body></message>")
s.close()
Reveal More
Added 6 months ago

Compress file (zip) in Python

#!/usr/bin/env python

import os
import zipfile


def main():
    zipper('/path/to/test', '/new/path/to/test.zip')


def zipper(dir, zip_file):
    zip = zipfile.ZipFile(zip_file, 'w', compression=zipfile.ZIP_DEFLATED)
    root_len = len(os.path.abspath(dir))
    for root, dirs, files in os.walk(dir):
        archive_root = os.path.abspath(root)[root_len:]
        for f in files:
            fullpath = os.path.join(root, f)
            archive_name = os.path.join(archive_root, f)
            print f
            zip.write(fullpath, archive_name, zipfile.ZIP_DEFLATED)
    zip.close()
    return zip_file


if __name__ == '__main__':
    main()
Reveal More
Added 6 months ago

Send email via GMail

#!/usr/bin/python

import smtplib
from email.MIMEText import MIMEText

GMAIL_LOGIN = '__me__@gmail.com'
GMAIL_PASSWORD = '__secret__'
TO_EMAIL = '__you__@gmail.com'

def send_email(subject, message,to_addr=GMAIL_LOGIN,from_addr=GMAIL_LOGIN):
    msg = MIMEText(message)
    msg['Subject'] = subject
    msg['From'] = from_addr
    msg['To'] = to_addr

    server = smtplib.SMTP('smtp.gmail.com',587) #port 465 or 587
    server.ehlo()
    server.starttls()
    server.ehlo()
    server.login(GMAIL_LOGIN,GMAIL_PASSWORD)
    server.sendmail(from_addr, to_addr, msg.as_string())
    server.close()

if __name__=="__main__":
    send_email('test', 'This is a test email', TO_EMAIL)
Reveal More
Added 6 months ago

Poor Man's Fiber (API compatible Thread based Fiber implementation for Ruby 1.8)

# Origin: http://gist.github.com/4631
# Poor Man's Fiber (API compatible Thread based Fiber implementation for Ruby 1.8)
# (c) 2008 Aman Gupta (tmm1)

unless defined? Fiber
  require 'thread'

  class FiberError < StandardError; end

  class Fiber
    def initialize
      raise ArgumentError, 'new Fiber requires a block' unless block_given?

      @yield = Queue.new
      @resume = Queue.new

      @thread = Thread.new{ @yield.push [ *yield(*@resume.pop) ] }
      @thread.abort_on_exception = true
      @thread[:fiber] = self
    end
    attr_reader :thread

    def resume *args
      raise FiberError, 'dead fiber called' unless @thread.alive?
      @resume.push(args)
      result = @yield.pop
      result.size > 1 ? result : result.first
    end

    def yield *args
      @yield.push(args)
      result = @resume.pop
      result.size > 1 ? result : result.first
    end

    def self.yield *args
      raise FiberError, "can't yield from root fiber" unless fiber = Thread.current[:fiber]
      fiber.yield(*args)
    end

    def self.current
      Thread.current[:fiber] or raise FiberError, 'not inside a fiber'
    end

    def inspect
      "#<#{self.class}:0x#{self.object_id.to_s(16)}>"
    end
  end
end

if __FILE__ == $0
  f = Fiber.new{ puts 'hi'; p Fiber.yield(1); puts 'bye'; :done }
  p f.resume
  p f.resume(2)
end

__END__

$ ruby fbr.rb 
hi
1
2
bye
:done

$ ruby1.9 fbr.rb 
hi
1
2
bye
:done
Reveal More
Added 6 months ago

EventMachine based chat

#!/usr/bin/env ruby

require 'rubygems'
require 'eventmachine'

module Chat

  # Called after the connection with a client has been established
  def post_init
    # Add ourselves to the list of clients
    (@@connections ||= []) << self
    send_data "Please enter your name: "
  end

  # Called on new incoming data from the client
  def receive_data data
    # The first message from the user is its name
    @name ||= data.strip

    @@connections.each do |client|
      # Send the message from the client to all other clients
      client.send_data "#{@name} says: #{data}"
    end
  end
end

# Start a server on localhost, using port 8081 and hosting our Chat application
EM::run do
  EM::start_server "0.0.0.0", 8081, Chat
end
Reveal More
Added 6 months ago

AMQP based chat

#!/usr/bin/env ruby
#
# Purpose: AMQP based chat
#

require 'rubygems'
gem 'amqp'
require 'mq'

unless ARGV.length == 2
  STDERR.puts "Usage: #{$0} <channel> <nick>"
  exit 1
end
$channel, $nick = ARGV

AMQP.start(:host => 'localhost') do
  $chat = MQ.topic('chat')

  # Print any messages on our channel.
  queue = MQ.queue($nick)
  queue.bind('chat', :key => $channel)
  queue.subscribe do |msg|
    if msg.index("#{$nick}:") != 0
      puts msg
    end
  end

  # Forward console input to our channel.
  module KeyboardInput
    include EM::Protocols::LineText2
    def receive_line data
      $chat.publish("#{$nick}: #{data}",
                    :routing_key => $channel)
    end
  end
  EM.open_keyboard(KeyboardInput)
end
Reveal More
Added 6 months ago

Rack middleware: Rewriting content types

# Rewrite content types based on file extensions
class RewriteContentType
  def initialize app, opts
    @app = app
    @map = opts
  end

  def call env
    res = @app.call(env)
    ext = env["PATH_INFO"].split(".")[-1]
    res[1]["Content-Type"] = @map[ext] if @map.has_key?(ext)
    res
  end
end

# Inside config.ru
use RewriteContentType, {"js" => "text/javascript"}
Reveal More
Added 6 months ago
Post Code