#!/usr/bin/env ruby
#
# xmlStorageSystem.rb
# Revision 1.0 - 21 Nov 2003
#
# Copyright (c) 2003, Rodney Waldhoff
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
require 'net/http'
require 'base64'
# extend Dir with a mkdirs function
class Dir
def Dir.mkdirs path, perm
frags = path.split('/')
for i in 1...frags.length
path = File.join(frags[0...i])
Dir.mkdir(path,perm) unless File.exists?(path)
end
end
end
class XmlStorageSystem
# constructor
def initialize(
uname,
passwd,
basepath,
host = 'radio.weblogs.com',
port = 80,
rpcpath = '/RPC2',
rpchost = 'radio.xmlstoragesystem.com',
rpcport = 80)
@uname = uname
@passwd = passwd
@basepath = basepath
@host = host
@port = port
@rpcpath = rpcpath
@rpchost = rpchost
@rpcport = rpcport
end
# returns an array of relative paths
def getMyDirectory
body = "\n" +
"\n" +
"xmlStorageSystem.getMyDirectory\n" +
"\n" +
unamePasswd +
"\n" +
""
resp, data= postRequest(body)
result = []
data.scan(/relativePath<\/name>[^<]*([^<]*)<\/value>/) {
|match|
result.push(match[0])
}
return result
end
# downloads a copy of all files to the dest directory
def backupMyDirectory destdir
getMyDirectory.each do |f|
client = Net::HTTP.new(@host,80)
resp, data = client.get(@basepath + f)
dest = File.join(destdir,f)
Dir.mkdirs(dest,0744)
File.open(dest, "w", 0644) do |file|
file.write(data)
end
end
end
# uploads the given list of files from basedir to the server
def saveMultipleFilesInBatches basedir, files, batchsize = 10
batch = []
files.each do |f|
batch.push(f)
if batch.size == batchsize then
puts "Uploading the following #{batch.size} files:"
puts batch
saveMultipleFiles(basedir, batch)
puts "done."
batch = []
end
end
if batch.size != 0 then
puts "Uploading the following #{batch.size} files:"
puts batch
saveMultipleFiles(basedir, batch)
puts "done."
end
end
# uploads the given list of files from basedir to the server
def saveMultipleFiles basedir, files
body = "\n"
body += "\n"
body += "xmlStorageSystem.saveMultipleFiles\n"
body += "\n"
body += unamePasswd
body += toRpcFileArray(files)
# file content
body += ""
files.each do |f|
body += ""
body += encode64(File.new(File.join(basedir,f)).read)
body += ""
end
body += ""
body += "\n"
body += ""
postRequest(body)
end
# deletes the given list of files from the server
def deleteMultipleFiles files
body = "\n"
body += "\n"
body += "xmlStorageSystem.deleteMultipleFiles\n"
body += "\n"
body += unamePasswd
body += toRpcFileArray(files)
body += "\n"
body += ""
postRequest(body)
end
def updateFromLocalDirectory dir
puts "Obtaining local listing from #{dir}..."
local = getLocalDirectory(dir)
puts "Obtaining remote listing from server..."
remote = getMyDirectory()
todel = remote - local
puts "Deleting the following #{todel.size} files from the server:"
puts todel
puts "Deleting..."
deleteMultipleFiles(todel)
puts "Uploading files..."
saveMultipleFilesInBatches(dir,local)
puts "Update compelete."
end
def getLocalDirectory basedir, dir = basedir
result = []
Dir.foreach(dir) { |f|
unless f.to_s == '.' or f.to_s == '..'
path = File.join(dir, f)
type = File.ftype(path)
if type == 'file'
result.push(path[basedir.length+1...path.length])
elsif type == 'directory'
result.concat(getLocalDirectory(basedir,path))
end
end
}
result
end
#--------------------------------------------------------------------
private
def toRpcFileArray files
body = ""
files.each do |f|
body += "#{f}"
end
body += ""
return body
end
def unamePasswd
"#{@uname}\n" +
"#{@passwd}\n"
end
# post the given XML-RPC request, returning the response
def postRequest body
client = Net::HTTP.new(@rpchost,@rpcport)
resp, data = client.post(@rpcpath, body, @rpcheaders )
return resp, data
end
end