Posted by Dan Sosedoff
on May 20, 2009
Ruby has very powerful tools to create random jabber bots with XMPP protocol. In this article i`ll show just a small sample with a few commands available.
I got xmpp4r-simple library from Google Code page – http://code.google.com/p/xmpp4r-simple/. Its kinda old, not updated since 2006, but the sources are really easy to read and understand, and probably modify.
First, we need to install dependencies (gems):
$ gem install xmpp4r
$ gem install xmpp4r-simple
And now, the actual ruby code:
#!/usr/bin/ruby
require 'rubygems'
require 'xmpp4r'
require 'xmpp4r-simple'
$jabber_login = "YOUR_JABBER_ID_HERE" # test@jabber.org
$jabber_password = "YOUR_PASSWORD_HERE"
$client = nil
# create jabber connection
def jabber_connect()
begin
conn = Jabber::Simple.new($jabber_login,$jabber_password)
return conn
rescue
return nil
end
end
# send message to jabber client
def jabber_respond(to, msg)
$client.deliver(to,msg,:chat)
end
# get sender jabber id
def jabber_get_jid(str)
matches = str.match(/([a-z\d_.\-]{1,32})@([a-z\d.-]{1,32})\//i)
return "#{matches[1]}@#{matches[2]}"
end
# ------------------------------------------------------------------- #
# send server time
def app_time(jid)
jabber_respond(jid, "Server time is: #{Time.now}")
end
# send some 'help' :)
def app_help(jid)
jabber_respond(jid, "Nobody can help you. You`re alone.")
end
# process received message
def app_parse_msg(jid, msg)
cmd = msg.body.strip
begin
case cmd
when /^help$/i then app_help(jid)
when /^time$/i then app_time(jid)
when /^jid$/i then jabber_respond(jid, "Your jabber id: #{jid}")
else
jabber_respond(jid, "Unknown command. Try something different.")
end
rescue Exception => ex
jabber_respond(jid, "SYSTEM_ERROR: #{ex}")
end
end
# ------------------------------------------------------------------- #
puts "Connecting to jabber server..."
$client = jabber_connect()
if $client
puts "Connected. Waiting for messages..."
loop do
$client.received_messages do |message|
jid = jabber_get_jid(message.from.to_s)
puts "Received message from #{jid}: #{message.body}"
app_parse_msg(jid, message)
end
sleep 0.1
end
else
puts "Cannot connect. Please try again later."
end
I think, the comments in source code are enough to understand what this bot supposed to do. There are 3 commands available: ‘help’, ‘time’, ‘jid’
Download script here – http://files.sosedoff.com/204ab61c/
Posted by Dan Sosedoff
on May 02, 2009
Here is a simple example how to make native WebDAV client with Ruby sockets. No additional gems or extensions needed – just all basic classes.
class WebDAV
attr_reader :host, :port, :protocol, :chunk_size
@socket = nil
def initialize(host,port=80,protocol='HTTP/1.1',chunk=8096)
@host = host.to_s
@port = port.to_i
@protocol = protocol
@chunk_size = chunk.to_i
end
def build_header(method, path, content_length=nil)
header = "#{method} #{path} #{@protocol} \r\n"
header += "Content-Length: #{content_length}\r\n" if !content_length.nil?
header += "Host: #{@host}\r\n"
header += "Connection: close\r\n\r\n"
return header
end
def request(method, path)
open
header = build_header(method, path)
if @socket.write(header) == header.length then
return @socket.gets.split[1]
end
end
def delete(path)
request('DELETE', path)
end
def head(path)
request('HEAD', path)
end
def mkcol(path)
request('MKCOL', path)
end
def put(path, localfile, auto_head=true)
if !File.exists?(localfile) || !File.readable?(localfile)
raise "File not exists or not accessible for reading!"
end
open
datalen = File.size(localfile)
header = build_header('PUT', path, datalen)
begin
if @socket.write(header) == header.length then
written = 0
File.open(localfile,'r') do |f|
until f.eof? do
written += @socket.write(f.read(@chunk_size))
end
end
if written == datalen
close
if !auto_head
return true
else
return head(path)
end
end
end
rescue Exception => e
puts e
return false
end
end
def open
begin
@socket = TCPSocket.open(@host,@port)
return true
rescue Exception => e
puts e
return false
end
end
def close
begin
return @socket.close
rescue
return false
end
end
end
This class supports only basic http/dav methods (PUT, DELETE, MKCOL, HEAD) and can be extended very easily and designed to work with all files, reading them by small chunks (default is 8096 bytes).
Im using this class sometimes with nginx.
Deps:
require 'socket'
require 'digest'
Usage:
# create connection
conn = WebDAV.new('your.host.com')
# upload file (without autocheck), return true/false value
result = conn.put('/test.mp3','/home/.../..../..../file.mp3', false)
# upload file with autocheck, returns http response code (201, 404, ... ) so you`ll know what exactly happened
result = conn.put('/test2.mp3','/home/.../file.mp3')
Also, here is a wrapper class to produce MD5, SHA1 file hashes that supports big files.
class FileHash
def self.md5(path)
d = Digest::MD5.new
File.open(path,'r') do |f|
d.update(f.read(8192)) until f.eof?
end
return d.hexdigest
end
def self.sha1(path)
d = Digest::SHA1.new
File.open(path,'r') do |f|
d.update(f.read(8192)) until f.eof?
end
return d.hexdigest
end
end
Usage:
FileHash.md5('/path/to/file')
FileHash.sha1('/path/to/file')
This webdav class not pretending to be stable in production environment, but can be useful for some “one-time” tasks with less code.