# HG changeset patch # User df@i1600 # Date 1259862465 -3600 # Node ID 02576525bddb29c6922bc9c5dce3e7b54873888c # Parent b0436bc63f9ee19fa0440362bb2de681079d032f Added the \!isk command, had to change some stuff at 2 files of WebService::EveOnline (cpan: WebService-EveOnline-0.62) added those in a seperate folder. (Tried checking the http://theantipop.org/eve/trunk/WebService-EveOnline/ svn repo, but that seems to be in diff with the one offered via cpan.) diff -r b0436bc63f9e -r 02576525bddb WebService-EveOnline_changes/API/Character.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebService-EveOnline_changes/API/Character.pm Thu Dec 03 18:47:45 2009 +0100 @@ -0,0 +1,302 @@ +package WebService::EveOnline::API::Character; + +use base qw/ WebService::EveOnline::Base /; + +our $VERSION = "0.61"; + +=head4 new + +This is called under the hood when an $eve->character object is requested. + +It returns an array of character objects for each characters available via +your API key. You probably won't need to call this directly. + +=cut + +sub new { + my ($self, $c, $name) = @_; + + my $character_data = $self->call_api('character', {}, $c); + + # XML::Simple is a big pile of shit: + $character_data = ($character_data->{name}) ? { $character_data->{name} => $character_data } : $character_data; + + my $characters = []; + foreach my $character (sort keys %{$character_data}) { + next if $character =~ /^_/; # skip meta keys + + my $char_obj = bless({ + _character_name => $character, + _corporation_name => $character_data->{$character}->{corporationName}, + _corporation_id => $character_data->{$character}->{corporationID}, + _character_id => $character_data->{$character}->{characterID}, + _api_key => $c->{_api_key}, + _user_id => $c->{_user_id}, + _evecache => $c->{_evecache}, + }, __PACKAGE__ ); + + if ($name) { + return $char_obj if $char_obj->name eq $name; + } else { + push(@{$characters}, $char_obj); + } + } + + return @{$characters}; +} + +=head2 $character->hashref + +Returns a character hashref on a character object containing the following keys: + + character_id + character_name + character_race + character_gender + character_bloodline + corporation_name + corporation_id + +=cut + +sub hashref { + my ($self) = @_; + return { + character_name => $self->{_character_name}, + corporation_name => $self->{_corporation_name}, + character_id => $self->{_character_id}, + corporation_id => $self->{_corporation_id}, + character_race => $self->character_race, + character_gender => $self->character_gender, + character_bloodline => $self->character_bloodline, + }; +} + +=head2 assets + +Placeholder + +=cut + +sub assets { + my ($self, $params) = @_; + my $assets = $self->call_api('assets', { characterID => $self->{_character_id} }, $self); + return $assets; +} + +=head2 assets + +Shows the char his balance (limited api key). + +=cut + +sub balance { + my ($self) = @_; + my $balance = $self->call_api('balance', { characterID => $self->{_character_id} }, $self); + return $balance->{balance}; +} + +=head2 kills + +Placeholder + +=cut + +sub kills { + my ($self, $params) = @_; + my $kills = $self->call_api('kills', { characterID => $self->{_character_id} }, $self); + return $kills; +} + +=head2 orders + +Placeholder + +=cut + +sub orders { + my ($self, $params) = @_; + my $orders = $self->call_api('orders', { characterID => $self->{_character_id} }, $self); + return $orders; +} + +=head2 $character->name + +Returns the name of the current character based on the character object. + +=cut + +sub name { + my ($self) = @_; + return $self->{_character_name}; +} + +=head2 $character->id + +Returns a character object based on the character id you provide, assuming +your API key allows it. + +=cut + +sub id { + my ($self) = @_; + return $self->{_character_id}; +} + +=head2 $character->race + +The race of the selected character. + +=cut + +sub race { + my ($self, $params) = @_; + my $race = $self->call_api('race', { characterID => $self->{_character_id} }, $self); + return $race->{race}; +} + +=head2 $character->bloodline + +The bloodline of the selected character. + +=cut + +sub bloodline { + my ($self, $params) = @_; + my $bloodline = $self->call_api('bloodline', { characterID => $self->{_character_id} }, $self); + return $bloodline->{bloodLine}; +} + +=head2 $character->gender, sex + +The gender of the selected character. + +=cut + +sub gender { + my ($self, $params) = @_; + my $gender = $self->call_api('gender', { characterID => $self->{_character_id} }, $self); + return $gender->{gender}; +} + +sub sex { + my ($self, $params) = @_; + my $gender = $self->call_api('gender', { characterID => $self->{_character_id} }, $self); + return $gender->{gender}; +} + +=head2 $character->attributes + +Sets the base attributes held by the selected character. + +=cut + +sub attributes { + my ($self, $params) = @_; + my $attributes = $self->call_api('attributes', { characterID => $self->{_character_id} }, $self); + + $self->{_attributes} = { + _memory => $attributes->{memory}, + _intelligence => $attributes->{intelligence}, + _charisma => $attributes->{charisma}, + _perception => $attributes->{perception}, + _willpower => $attributes->{willpower}, + }; + + return bless($self, __PACKAGE__); +} + +=head2 $character->attributes->memory, $attributes->memory + +Returns the base memory attribute of the current character + +=cut + +sub memory { + my ($self) = @_; + return $self->{_attributes}->{_memory}; +} + +=head2 $character->attributes->intelligence, $attributes->intelligence + +Returns the base intelligence attribute of the current character + +=cut + +sub intelligence { + my ($self) = @_; + return $self->{_attributes}->{_intelligence}; +} + +=head2 $character->attributes->charisma, $attributes->charisma + +Returns the base charisma attribute of the current character + +=cut + +sub charisma { + my ($self) = @_; + return $self->{_attributes}->{_charisma}; +} + +=head2 $character->attributes->perception, $attributes->perception + +Returns the base perception attribute of the current character + +=cut + +sub perception { + my ($self) = @_; + return $self->{_attributes}->{_perception}; +} + +=head2 $character->attributes->willpower, $attributes->willpower + +Returns the base willpower attribute of the current character + +=cut + +sub willpower { + my ($self) = @_; + return $self->{_attributes}->{_willpower}; +} + +=head2 $character->attributes->attr_hashref, $attributes->attr_hashref + +Returns a hashref containing the base attributes of the +current character with the following keys: + + memory + intelligence + charisma + perception + willpower + +=cut + +sub attr_hashref { + my ($self) = @_; + return { + memory => $self->{_attributes}->{_memory}, + intelligence => $self->{_attributes}->{_intelligence}, + charisma => $self->{_attributes}->{_charisma}, + perception => $self->{_attributes}->{_perception}, + willpower => $self->{_attributes}->{_willpower}, + }; +} + +=head2 $character->attribute_enhancers + +Returns a hash of hashes of the attribute enhancers held by the selected character. +The interface to this is highly likely to change to be more consistent with the rest of the +interface, so use with caution. + +=cut + +sub attribute_enhancers { + my ($self, $params) = @_; + my $enhancers = $self->call_api('enhancers', { characterID => $self->{_character_id} }, $self); + return $enhancers; +} + +1; diff -r b0436bc63f9e -r 02576525bddb WebService-EveOnline_changes/Base.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebService-EveOnline_changes/Base.pm Thu Dec 03 18:47:45 2009 +0100 @@ -0,0 +1,395 @@ +package WebService::EveOnline::Base; + +our $VERSION = "0.62"; + +use LWP::UserAgent; +use HTTP::Request; +use XML::Simple; + +use WebService::EveOnline::Cache; + +use WebService::EveOnline::API::Character; +use WebService::EveOnline::API::Corporation; +use WebService::EveOnline::API::Skills; +use WebService::EveOnline::API::Transactions; +use WebService::EveOnline::API::Journal; +use WebService::EveOnline::API::Account; +use WebService::EveOnline::API::Map; + +# U.G.L.Y. You ain't got no alibi (this is where we set up the API mappings, sort out the internal symbol conversion and set max cache times) +# max_cache overrides the cache time set in the default EVE webservice response XML (e.g. shorter for wallet, longer for bloodline which +# probably won't update every hour...) + +our $API_MAP = { + # Character + skills => { endpoint => 'char/CharacterSheet', params => [ [ 'character_id', 'characterID' ] ], max_cache => 900 }, + balance => { endpoint => 'char/CharacterSheet', params => [ [ 'character_id', 'characterID' ] ], max_cache => 60 }, + race => { endpoint => 'char/CharacterSheet', params => [ [ 'character_id', 'characterID' ] ], max_cache => 604800 }, + bloodline => { endpoint => 'char/CharacterSheet', params => [ [ 'character_id', 'characterID' ] ], max_cache => 604800 }, + attributes => { endpoint => 'char/CharacterSheet', params => [ [ 'character_id', 'characterID' ] ], }, + enhancers => { endpoint => 'char/CharacterSheet', params => [ [ 'character_id', 'characterID' ] ], }, + gender => { endpoint => 'char/CharacterSheet', params => [ [ 'character_id', 'characterID' ] ], max_cache => 604800 }, + training => { endpoint => 'char/SkillInTraining', params => [ [ 'character_id', 'characterID' ] ], }, + accounts => { endpoint => 'char/AccountBalance', params => [ [ 'character_id', 'characterID' ] ], max_cache => 60 }, + transactions => { endpoint => 'char/WalletTransactions', params => [ + [ 'character_id', 'characterID' ], + [ 'before_trans_id', 'beforeTransID' ], + [ 'account_key', 'accountKey' ], + ], max_cache => 3600 }, + kills => { endpoint => 'char/Killlog', params => [ [ 'character_id', 'characterID' ] ], }, + orders => { endpoint => 'char/MarketOrders', params => [ [ 'character_id', 'characterID' ] ], }, + assets => { endpoint => 'char/AssetList', params => [ [ 'character_id', 'characterID' ] ], }, + + # Corporation + corp_accounts => { endpoint => 'corp/AccountBalance', params => [ [ 'character_id', 'characterID' ] ], max_cache => 60 }, + corp_members => { endpoint => 'corp/MemberTracking', params => [ [ 'character_id', 'characterID' ] ], }, + corp_assets => { endpoint => 'corp/AssetList', params => [ [ 'character_id', 'characterID' ] ], }, + corp_sheet => { endpoint => 'corp/CorporationSheet', params => [ [ 'character_id', 'characterID' ] ], }, + corp_transactions => { endpoint => 'corp/WalletTransactions', params => [ + [ 'character_id', 'characterID' ], + [ 'before_trans_id', 'beforeTransID' ], + [ 'account_key', 'accountKey' ], + ], max_cache => 3600 }, + corp_kills => { endpoint => 'corp/Killlog', params => [ [ 'character_id', 'characterID' ] ], }, + corp_orders => { endpoint => 'corp/MarketOrders', params => [ [ 'character_id', 'characterID' ] ], }, + corp_baselist => { endpoint => 'corp/StarbaseList', params => [ [ 'character_id', 'characterID' ] ], }, + corp_base => { endpoint => 'corp/StarbaseDetail', params => [ [ 'character_id', 'characterID' ] ], }, + + # Map + map_jumps => { endpoint => 'map/Jumps', params => [ [ 'character_id', 'characterID' ] ], }, + map_kills => { endpoint => 'map/Kills', params => [ [ 'character_id', 'characterID' ] ], }, + map => { endpoint => 'map/Sovereignty', params => undef , }, + + # Global/Misc + character => { endpoint => 'account/Characters', params => undef, max_cache => 3600 }, + all_skills => { endpoint => 'eve/SkillTree', params => undef, max_cache => 86400 }, + all_reftypes => { endpoint => 'eve/RefTypes', params => undef, }, +}; + +=head2 new + +Called by WebService::EveOnline->new -- sets things up at the backend without cluttering things up. +Doesn't die if not passed an api_key/user_id combination, unlike the latter. + +=cut + +sub new { + my ($class, $params) = @_; + + $params ||= {}; + $params->{cache_type} ||= "SQLite"; + $params->{cache_user} ||= ""; + $params->{cache_pass} ||= ""; + $params->{cache_dbname} ||= ($^O =~ /MSWin/) ? "c:/windows/temp/webservice_eveonline.db" : "/tmp/webservice_eveonline.db"; + $params->{cache_init} ||= "yes"; + $params->{cache_maxage} ||= (86400 * 7 * 4); # time (s) between cache rebuilds. 28 days, for now. + + my $evecache = WebService::EveOnline::Cache->new( { eve_user_id => $params->{user_id}, cache_type => $params->{cache_type}, cache_dbname => $params->{cache_dbname} } ) if $params->{cache_init} eq "yes"; + if ($evecache && $evecache->cache_age >= $params->{cache_maxage}) { + $evecache->repopulate( { skills => call_api('all_skills'), map => call_api('map') } ); + } else { + $evecache ||= WebService::EveOnline::Cache->new( { cache_type => "no_cache" } ); + } + + return bless({ _user_id => $params->{user_id}, _api_key => $params->{api_key}, _evecache => $evecache }, $class); +} + +=head2 character, characters + +Pull back character objects based on your API key -- see examples/show_characters + +Singlar and plural are provided so as to allow grammatically correct usage given +the appropriate context (they both do exactly the same thing under the hood and +can be used interchangeably -- handy for contractors... ;-) ) + +=cut + +sub characters { + return WebService::EveOnline::API::Character->new(@_); +} + +sub character { + return WebService::EveOnline::API::Character->new(@_); +} + +=head2 corporation + +Pull back a corporation information object -- use on a character object for best effect. +See examples/show_corporation + +=cut + +sub corporation { + return WebService::EveOnline::API::Corporation->new(@_); +} + +=head2 skill, skills + +Pull back skill objects on a character. See examples/skills_overview for more +details. + +Singlar and plural are provided so as to allow grammatically correct usage given +the appropriate context (they both do exactly the same thing under the hood and +can be used interchangeably). + +=cut + +sub skill { + return WebService::EveOnline::API::Skills->new(@_); +} + +sub skills { + return WebService::EveOnline::API::Skills->new(@_); +} + +=head2 transaction, transactions + +Returns transaction objects for a particular character/corporation. Singular/plural as above; +See examples/show_transactions for more details. + +=cut + +sub transaction { + return WebService::EveOnline::API::Transactions->new(@_); +} + +sub transactions { + return WebService::EveOnline::API::Transactions->new(@_); +} + +=head2 journal + +Placeholder, for the moment. + +=cut + +sub journal { + return WebService::EveOnline::API::Journal->new(@_); +} + +=head2 account, accounts + +Return detailed account objects for a particular character, including corporate +account info. The first member of the array ALWAYS returns the selected character's +personal account object -- subsequent accounts are from the corporation the +character belongs to. See examples/show_character for an example of how to use this. + +=cut + +sub account { + return WebService::EveOnline::API::Account->new(@_); +} + +sub accounts { + return WebService::EveOnline::API::Account->new(@_); +} + +=head2 map + +Another placeholder. + +=cut + +sub map { + return WebService::EveOnline::API::Map->new(@_); +} + + +=head2 $eve->user_id + +Returns the current user_id. + +=cut + +sub user_id { + my ($self, $user_id) = @_; + $self->{_user_id} = $user_id if $user_id; + return $self->{_user_id}; +} + +=head2 $eve->api_key + +Returns the current api_key. + +=cut + +sub api_key { + my ($self, $api_key) = @_; + $self->{_api_key} = $api_key if $api_key; + return $self->{_api_key}; +} + +=head2 $eve->call_api(, ) + +Call the Eve API and retrieve the results. Look in the cache first. Cache results according to API map settings. + +=cut + +sub call_api { + my ($self, $command, $params, $base) = @_; + + my $auth = { user_id => "", api_key => "" }; + + if (ref($base)) { + $auth = { user_id => $base->user_id, api_key => $base->api_key }; + } else { + $command = $self; + } + + if ( defined($API_MAP->{$command}) ) { + my $cache = ref($self) ? $self->{_evecache} : $base->{_evecache}; + + my $gen_params = _gen_params($self, $API_MAP->{$command}->{params}, $params); + + my $cached_response = $cache->retrieve( { command => "$command", params => $gen_params } ) if ref($cache); + return $cached_response if $cached_response; + + my $ua = LWP::UserAgent->new; + $ua->agent("$WebService::EveOnline::AGENT/$WebService::EveOnline::VERSION"); + + my $req = HTTP::Request->new( POST => $WebService::EveOnline::EVE_API . $API_MAP->{$command}->{endpoint} . '.xml.aspx' ); + $req->content_type("application/x-www-form-urlencoded"); + + my $content = 'userid=' . $auth->{user_id} . '&apikey=' . $auth->{api_key} . $gen_params; + + $req->content($content) ; + + my $res = $ua->request($req); + + if ($res->is_success) { + my $xs = XML::Simple->new(); + my $xml = $res->content; + + warn "RAW XML is:\n$xml\n" if $ENV{EVE_DEBUG} =~ m/xml/i; + + my $pre = $xs->XMLin($xml); + my $data = {}; + my $in_error_state = undef; + + # print out any error content if it's set. + if ($pre->{error}) { + # error 206 is returned on characters without corp permissions. ignore. FIXME: nasty hack + if ($pre->{error}->{code} != "206") { + $in_error_state = 1; + $data->{error} = "EVE API Error: " . $pre->{error}->{content} . " (" . $pre->{error}->{code} . ")"; + } + } + + # at the moment, we deal in hashrefs. one day, these will be objects (like everything else will be ;-P) + unless ($in_error_state) { + if ($command eq "character") { + $data = $pre->{result}->{rowset}->{row}; + } elsif ($command eq "skills") { + $data->{skills} = $pre->{result}->{rowset}->{skills}->{row} if $pre->{result}->{rowset}->{skills}->{row}; + } elsif ($command eq "attributes") { + $data = $pre->{result}->{attributes}; + } elsif ($command eq "enhancers") { + $data = $pre->{result}->{attributeEnhancers}; + } elsif ($command eq "gender") { + $data = $pre->{result}; + } elsif ($command eq "race") { + $data = $pre->{result}; + } elsif ($command eq "bloodline") { + $data = $pre->{result}; + } elsif ($command eq "balance") { + $data = $pre->{result}; + } elsif ($command eq "training") { + $data = $pre->{result}; + } elsif ($command eq "kills") { + $data = $pre->{result}->{rowset}->{row}; + } elsif ($command eq "orders") { + $data = $pre->{result}->{rowset}->{row}; + } elsif ($command eq "corp_kills") { + $data = $pre->{result}->{rowset}->{row}; + } elsif ($command eq "corp_members") { + $data = $pre->{result}->{rowset}->{row}; + } elsif ($command eq "corp_orders") { + $data = $pre->{result}->{rowset}->{row}; + } elsif ($command eq "assets") { + $data = $pre->{result}->{rowset}->{row}; + } elsif ($command eq "transactions") { + $data->{transactions} = $pre->{result}->{rowset}->{row} if $pre->{result}->{rowset}->{row}; + } elsif ($command =~ /accounts/) { + my $acc = $pre->{result}->{rowset}->{row}; + $data->{accounts} = ref($acc) eq "HASH" ? [ $acc ] : $acc; + } else { + $data = $pre; + return $data; + } + } + + $data->{_status} ||= "ok"; + $data->{_xml} = $xml; + $data->{_parsed_as} = $pre; + + my $stripped_data = undef; + + unless ($WebService::EveOnline::DEBUG_MODE) { + $stripped_data = {}; + foreach my $strip_debug (keys %{$data}) { + next if $strip_debug =~ /^_/; # skip meta keys + $stripped_data->{$strip_debug} = $data->{$strip_debug}; + } + } + + + if ($cache && ($stripped_data || $data) && !$in_error_state) { + # error results are not cached + return $cache->store( { command => $command, obj => $self, data => $stripped_data || $data, params => $gen_params, cache_until => $pre->{cachedUntil}, max_cache => $API_MAP->{$command}->{max_cache} } ); + } elsif ($in_error_state) { + warn $data->{error} . "\n"; + return undef; # better error handling is required...; + } else { + return $stripped_data || $data; + } + } else { + warn "Error code received: " . $res->status_line . "\n" if $ENV{EVE_DEBUG}; + return { _status => "error", message => $res->status_line, _raw => undef }; + } + } else { + return { _status => "error", message => "Bad command", _raw => undef }; + } + +} + +=head2 $character->before_trans_id + +Set to return transactions older than a particular trans id for character/corp transactions. + +=cut + +sub before_trans_id { + my ($self, $before_trans_id) = @_; + $self->{_before_trans_id} = $before_trans_id if $before_trans_id; + return $self->{_before_trans_id} || undef; +} + +=head2 id + +This will not return anything useful on the base class; call id on characters, accounts, transactions, etc. +where appropriate. + +=cut + +sub id { + return undef; +} + +sub _gen_params { + my ($self, $keys, $passed) = @_; + return "" unless defined $keys; + + my @kvp = (); + foreach my $param (@{$keys}) { + my ($intkey, $evekey) = @{$param}; + if ($self->can($intkey)) { + push(@kvp, "$evekey=" . ($self->$intkey || $passed->{$intkey})) if ($self->$intkey || $passed->{$intkey}); + } else { + push(@kvp, "$evekey=" . ($passed->{$evekey} || $passed->{$intkey})) if ($passed->{$evekey} || $passed->{$intkey}); + } + } + + return '&' . (join('&', @kvp)); +} + +1; diff -r b0436bc63f9e -r 02576525bddb skillbot.pl --- a/skillbot.pl Sun Dec 07 11:18:23 2008 +0000 +++ b/skillbot.pl Thu Dec 03 18:47:45 2009 +0100 @@ -13,6 +13,7 @@ Copyright ©2008 Andy Smith Portions copyright ©2008 Dominic Cleal +Small changes made by Bjorn Hamels Artistic license same as Perl. =cut @@ -225,6 +226,17 @@ my ($self, $event) = @_; my ($their_nick, $msg) = ($event->nick, $event->args); + # lists the isk amounts per character + if ($msg =~ /^\!isk/i) { + my $text = "Isk: "; + for my $f (sort { $b->{char}->balance <=> $a->{char}->balance } + grep(defined $_->{char}->balance, @friends)) { + my $isk = int($f->{char}->balance/1000000); + $text .= $f->{char}->name . " (" . $isk . "M) | " if ($isk>0); + } + $self->privmsg('#' . $config{channel}, $text); + } + # lists the current chars in training of the caller if ($msg =~ /^\!eta(\s+(.+))?/i) { my $found = 0; @@ -403,7 +415,7 @@ if (! $frienduids{$uid}) { my $api = WebService::EveOnline->new( { user_id => $uid, - api_key => $key } ); + api_key => $key } ); my $loaded = 0; foreach my $character ($api->characters) {