#!/usr/bin/ruby require 'mysql' require 'xmlrpc/server' require 'xmlrpc/utils' module XMLRPC module Service class BetterPublicInstanceMethodsInterface < BasicInterface def initialize(prefix) @filtered_methods = (Object.methods + Kernel.methods) @prefix = prefix super(prefix) end def get_methods(obj, delim = '.') (obj.class.public_instance_methods - @filtered_methods).collect do |name| prefix = @prefix + '.' [prefix + name, obj.method(name).to_proc, nil, nil] end end end end def self.iBPIMethods(prefix) Service::BetterPublicInstanceMethodsInterface.new(prefix) end end module Gah class RPCServer < ::XMLRPC::CGIServer # # get a list of people # def listPeople(flds = nil) ret = [] query = "SELECT nick FROM #@tbl WHERE is_verified = 1" @db.query(query).each { |row| ret << row[0].dup } ret end # # instant #gah blogroll! # def listBlogs ret = [] cols = %w{nick web rss secondary_web} # build query query = "SELECT #{cols.join(',')} FROM #@tbl WHERE is_verified = 1 AND web LIKE 'http%'" # query database, then iterate over rows and build result @db.query(query).each do |row| hash = {} cols.each_with_index { |key, i| hash[key] = row[i].dup } ret << hash end # return result ret end # # list all rss feeds # def listFeeds ret = [] query = "SELECT nick,rss FROM #@tbl WHERE is_verified = 1 AND LIKE 'http%'" @db.query(query).each do |row| ret << { 'nick' => row[0].dup, 'rss' => row[1].dup } end ret end # # find people matching the given search criteria # def findPeople(find_str) ret = [] # build condition string cond_str = find_str.split(/\s+/).inject(nil) do |cond_str, str| str = Mysql::escape_string(str) fld_strs = @flds[:find].map { |fld| "#{fld} LIKE '%#{str}%' " }.join(' OR ') if cond_str cond_str << " AND (#{fld_strs})" else cond_str = "(#{fld_strs})" end end # build/exec query query = "SELECT nick FROM #@tbl WHERE is_verified = 1 AND (#{cond_str})" @db.query(query).each { |row| ret << row[0].dup } # return results ret end # # get information about person with a specific nickname # def personInfo(str) ret = {} str = Mysql::escape_string(str) fld_str = @flds[:all].join(',') query = "SELECT #{fld_str} FROM #@tbl WHERE nick = '#{str}'" @db.query(query).each_hash do |hash| ret = hash.keys.inject({}) { |r, k| r[k] = hash[k]; r } end ret end # # list fields for table (MySQL-specific) # (private method) # def list_flds ret = [] @db.query("DESCRIBE #@tbl").each { |row| ret << row[0].downcase } ret end # # build field list # (private method) # def build_fld_list @flds = { :hide => %w{id email show_email secondary_email password is_admin is_verified}, :dont_find => %w{birthday last_seen updated last_login}, :web => %w{web secondary_web rss}, } @flds[:all] = list_flds - @flds[:hide] @flds[:find] = @flds[:all] - @flds[:dont_find] end private :build_fld_list, :list_flds # # create new Gah XML-RPC Serverc def initialize(db_opt) super() # connect to db @db = Mysql::connect(db_opt[:host], db_opt[:user], db_opt[:pass]) @db.select_db(db_opt[:db]) @tbl = db_opt[:tbl] # set up XML-RPC stuff self.add_introspection self.add_multicall # build a list of fields for handlers build_fld_list # svs = XMLRPC::Service::PublicInstanceMethodsInterface.new('gah') svs = XMLRPC::iBPIMethods('gah') self.add_handler(svs, self) set_default_handler do |name, *args| err_str = "Method #{name} missing, or wrong number of arguments." raise XMLRPC::FaultException.new(-99, err_str) end end end end # database options db_opt = { :host => 'localhost', :user => 'gah-web', :pass => '#g4h-w3b', :db => 'gah', :tbl => 'users', } # # create server, handle query # rpc = Gah::RPCServer.new(db_opt) rpc.serve