Compare commits

...

15 Commits
master ... ruby

Author SHA1 Message Date
Mateusz
74de221bd1 updates for tracker 2013-01-25 10:29:40 +01:00
Mateusz Zawisza
89d9b42a68 fixes as_code, country 2013-01-25 10:29:40 +01:00
Mateusz Zawisza
8208d88e21 uses proper whois server names 2013-01-25 10:29:40 +01:00
Mateusz Zawisza
50cf589d75 changes as fetcher to use WHOIS db 2013-01-25 10:29:40 +01:00
Mateusz Zawisza
0259b8bf30 fixes SQL syntax 2013-01-25 10:29:40 +01:00
Mateusz Zawisza
aef17086c7 adds updates to peertracker as info fetching 2013-01-25 10:29:40 +01:00
Mateusz Zawisza
33aaee6d4d adds config file for passenger 2013-01-25 10:29:40 +01:00
Mateusz Zawisza
508819ae74 removes mysql.config.php from help 2013-01-25 10:29:40 +01:00
Mateusz Zawisza
ad381404c6 adds as related columns to the php code 2013-01-25 10:29:39 +01:00
Mateusz Zawisza
e8565136a9 adds missing lines 2013-01-25 10:29:39 +01:00
Mateusz Zawisza
a287740880 minor fixes 2013-01-25 10:29:39 +01:00
Mateusz Zawisza
5e050e45fe fixes parameters 2013-01-25 10:29:39 +01:00
Mateusz Zawisza
41ebe20498 moves mysql config to separate file 2013-01-25 10:29:39 +01:00
Mateusz Zawisza
f148f3bf10 adds credits for original repo 2013-01-25 10:29:39 +01:00
Mateusz Zawisza
c378525e08 init commit of peertracker with ruby extension 2013-01-25 10:29:36 +01:00
20 changed files with 793 additions and 558 deletions

View File

@ -1,6 +1,8 @@
PeerTracker - Simple, Efficient and Fast BitTorent Tracker PeerTracker - Simple, Efficient and Fast BitTorent Tracker
-------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------
This is a fork from http://code.google.com/p/peertracker/
What Do You Need? What Do You Need?
-------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------

View File

@ -406,10 +406,10 @@ function setupMySQL()
// we need to locate tracker.mysql.php // we need to locate tracker.mysql.php
// first, try the most obvious location.. which should be in the // first, try the most obvious location.. which should be in the
// same directory as the ./help.php file being ran // same directory as the ./help.php file being ran
if (is_readable('./tracker.mysql.php')) if (is_readable('./mysql/tracker.mysql.php'))
{ {
// require // require
require './tracker.mysql.php'; require './mysql/tracker.mysql.php';
} }
// unfortunately, it does not seem the file is located in the current // unfortunately, it does not seem the file is located in the current
// directory, we will recurse the paths below and attempt to locate it // directory, we will recurse the paths below and attempt to locate it
@ -441,6 +441,8 @@ function setupMySQL()
"`peer_id` binary(20) NOT NULL," . "`peer_id` binary(20) NOT NULL," .
"`compact` binary(6) NOT NULL," . "`compact` binary(6) NOT NULL," .
"`ip` char(15) NOT NULL," . "`ip` char(15) NOT NULL," .
"`as_code` varchar(255) NOT NULL," .
"`country` varchar(255) NOT NULL," .
"`port` smallint(5) unsigned NOT NULL," . "`port` smallint(5) unsigned NOT NULL," .
"`state` tinyint(1) unsigned NOT NULL DEFAULT '0'," . "`state` tinyint(1) unsigned NOT NULL DEFAULT '0'," .
"`updated` int(10) unsigned NOT NULL," . "`updated` int(10) unsigned NOT NULL," .

View File

@ -1,5 +1,6 @@
<?php <?php
// License Information ///////////////////////////////////////////////////////////////////////////// // License Information /////////////////////////////////////////////////////////////////////////////
/* /*
@ -96,11 +97,17 @@ peertracker::open();
$_GET['info_hash'] = peertracker::$api->escape_sql($_GET['info_hash']); $_GET['info_hash'] = peertracker::$api->escape_sql($_GET['info_hash']);
$_GET['peer_id'] = peertracker::$api->escape_sql($_GET['peer_id']); $_GET['peer_id'] = peertracker::$api->escape_sql($_GET['peer_id']);
$json = file_get_contents("http://localhost:4567/as_info/{$_GET['ip']}.json");
$parsed_json = json_decode($json);
$as_code = $parsed_json->{'as_code'};
$country = $parsed_json->{'country'};
// announce peers // announce peers
peertracker::peers(); // need to pass as_code and country
peertracker::peers($as_code, $country);
// track client // track client
peertracker::event(); peertracker::event($as_code, $country);
// garbage collection // garbage collection
peertracker::clean(); peertracker::clean();

29
mysql/mysql.config.php Normal file
View File

@ -0,0 +1,29 @@
<?php
$_SERVER['tracker'] = array(
// general tracker options
'open_tracker' => true, /* track anything announced to it */
'announce_interval' => 1800, /* how often client will send requests */
'min_interval' => 900, /* how often client can force requests */
'default_peers' => 50, /* default # of peers to announce */
'max_peers' => 100, /* max # of peers to announce */
// advanced tracker options
'external_ip' => true, /* allow client to specify ip address */
'force_compact' => false, /* force compact announces only */
'full_scrape' => false, /* allow scrapes without info_hash */
'random_limit' => 500, /* if peers > #, use alternate SQL RAND() */
'clean_idle_peers' => 10, /* tweaks % of time tracker attempts idle peer removal */
/* if you have a busy tracker, you may adjust this */
/* example: 10 = 10%, 20 = 5%, 50 = 2%, 100 = 1% */
// database options
'db_host' => 'localhost', /* ip or hostname to mysql server */
'db_user' => 'root', /* username used to connect to mysql */
'db_pass' => '', /* password used to connect to mysql */
'db_name' => 'peertracker', /* name of the PeerTracker database */
// advanced database options
'db_prefix' => 'pt_', /* name prefixes for the PeerTracker tables */
'db_persist' => false, /* use persistent connections if available. */
);
?>

View File

@ -4,7 +4,7 @@
/* /*
* PeerTracker - OpenSource BitTorrent Tracker * PeerTracker - OpenSource BitTorrent Tracker
* Revision - $Id: tracker.mysql.php 164 2010-01-23 22:08:58Z trigunflame $ * Revision - $Id: tracker.mysql.php 148 2009-11-16 23:18:28Z trigunflame $
* Copyright (C) 2009 PeerTracker Team * Copyright (C) 2009 PeerTracker Team
* *
* PeerTracker is free software: you can redistribute it and/or modify * PeerTracker is free software: you can redistribute it and/or modify
@ -24,32 +24,7 @@
// Configuration /////////////////////////////////////////////////////////////////////////////////// // Configuration ///////////////////////////////////////////////////////////////////////////////////
// tracker state // tracker state
$_SERVER['tracker'] = array( require 'mysql.config.php';
// general tracker options
'open_tracker' => true, /* track anything announced to it */
'announce_interval' => 1800, /* how often client will send requests */
'min_interval' => 900, /* how often client can force requests */
'default_peers' => 50, /* default # of peers to announce */
'max_peers' => 100, /* max # of peers to announce */
// advanced tracker options
'external_ip' => true, /* allow client to specify ip address */
'force_compact' => false, /* force compact announces only */
'full_scrape' => false, /* allow scrapes without info_hash */
'random_limit' => 500, /* if peers > #, use alternate SQL RAND() */
'clean_idle_peers' => 10, /* tweaks % of time tracker attempts idle peer removal */
/* if you have a busy tracker, you may adjust this */
/* example: 10 = 10%, 20 = 5%, 50 = 2%, 100 = 1% */
// database options
'db_host' => 'localhost', /* ip or hostname to mysql server */
'db_user' => 'root', /* username used to connect to mysql */
'db_pass' => '', /* password used to connect to mysql */
'db_name' => 'peertracker', /* name of the PeerTracker database */
// advanced database options
'db_prefix' => 'pt_', /* name prefixes for the PeerTracker tables */
'db_persist' => false, /* use persistent connections if available. */
);
// Tracker Operations ////////////////////////////////////////////////////////////////////////////// // Tracker Operations //////////////////////////////////////////////////////////////////////////////
@ -392,25 +367,27 @@ class peertracker
} }
// insert new peer // insert new peer
public static function new_peer() public static function new_peer($as_code, $country)
{ {
// insert peer // insert peer
self::$api->query( self::$api->query(
// insert into the peers table // insert into the peers table
"INSERT IGNORE INTO `{$_SERVER['tracker']['db_prefix']}peers` " . "INSERT IGNORE INTO `{$_SERVER['tracker']['db_prefix']}peers` " .
// table columns // table columns
'(info_hash, peer_id, compact, ip, port, state, updated) ' . '(info_hash, peer_id, compact, ip, port, state, as_code, country, updated)' .
// 20-byte info_hash, 20-byte peer_id // 20-byte info_hash, 20-byte peer_id
"VALUES ('{$_GET['info_hash']}', '{$_GET['peer_id']}', '" . "VALUES ('{$_GET['info_hash']}', '{$_GET['peer_id']}', '" .
// 6-byte compacted peer info // 6-byte compacted peer info
self::$api->escape_sql(pack('Nn', ip2long($_GET['ip']), $_GET['port'])) . "', " . self::$api->escape_sql(pack('Nn', ip2long($_GET['ip']), $_GET['port'])) . "', " .
// dotted decimal string ip, integer port, integer state and unix timestamp updated // dotted decimal string ip, integer port, integer state and unix timestamp updated
"'{$_GET['ip']}', {$_GET['port']}, {$_SERVER['tracker']['seeding']}, " . time() . '); ' "'{$_GET['ip']}', {$_GET['port']}, {$_SERVER['tracker']['seeding']}, " .
"'{$as_code}', '{$country}', " . time() . ');'
) OR tracker_error('failed to add new peer data'); ) OR tracker_error('failed to add new peer data');
exit;
} }
// full peer update // full peer update
public static function update_peer() public static function update_peer($as_code, $country)
{ {
// update peer // update peer
self::$api->query( self::$api->query(
@ -420,6 +397,7 @@ class peertracker
"SET compact='" . self::$api->escape_sql(pack('Nn', ip2long($_GET['ip']), $_GET['port'])) . "SET compact='" . self::$api->escape_sql(pack('Nn', ip2long($_GET['ip']), $_GET['port'])) .
// dotted decimal string ip, integer port // dotted decimal string ip, integer port
"', ip='{$_GET['ip']}', port={$_GET['port']}, " . "', ip='{$_GET['ip']}', port={$_GET['port']}, " .
//"as_code='{$as_code}', country='{$country}', " .
// integer state and unix timestamp updated // integer state and unix timestamp updated
"state={$_SERVER['tracker']['seeding']}, updated=" . time() . "state={$_SERVER['tracker']['seeding']}, updated=" . time() .
// that matches the given info_hash and peer_id // that matches the given info_hash and peer_id
@ -452,7 +430,7 @@ class peertracker
} }
// tracker event handling // tracker event handling
public static function event() public static function event($as_code, $country)
{ {
// execute peer select // execute peer select
$pState = self::$api->fetch_once( $pState = self::$api->fetch_once(
@ -479,7 +457,7 @@ class peertracker
// client continuing download // client continuing download
default: default:
// new peer // new peer
if (!isset($pState[2])) self::new_peer(); if (!isset($pState[2])) self::new_peer($as_code, $country);
// peer status // peer status
elseif ( elseif (
// check that ip addresses match // check that ip addresses match
@ -495,7 +473,7 @@ class peertracker
} }
// tracker peer list // tracker peer list
public static function peers() public static function peers($as_code, $country)
{ {
// fetch peer total // fetch peer total
$total = self::$api->fetch_once( $total = self::$api->fetch_once(
@ -515,15 +493,17 @@ class peertracker
// from peers table matching info_hash // from peers table matching info_hash
"FROM `{$_SERVER['tracker']['db_prefix']}peers` WHERE info_hash='{$_GET['info_hash']}'" . "FROM `{$_SERVER['tracker']['db_prefix']}peers` WHERE info_hash='{$_GET['info_hash']}'" .
// less peers than requested, so return them all // less peers than requested, so return them all
($total[0] <= $_GET['numwant'] ? ';' : // ($total[0] <= $_GET['numwant'] ? ';' :
// if the total peers count is low, use SQL RAND // if the total peers count is low, use SQL RAND
($total[0] <= $_SERVER['tracker']['random_limit'] ? //($total[0] <= $_SERVER['tracker']['random_limit'] ?
" ORDER BY RAND() LIMIT {$_GET['numwant']};" : // " ORDER BY RAND() LIMIT {$_GET['numwant']};" :
" ORDER BY as_code='{$as_code}' DESC, country='{$country}' DESC LIMIT 4;"
// use a more efficient but less accurate RAND // use a more efficient but less accurate RAND
" LIMIT {$_GET['numwant']} OFFSET " . //" LIMIT {$_GET['numwant']} OFFSET " .
mt_rand(0, ($total[0]-$_GET['numwant'])) //mt_rand(0, ($total[0]-$_GET['numwant']))
) //)
); //)
;
// begin response // begin response
$response = 'd8:intervali' . $_SERVER['tracker']['announce_interval'] . $response = 'd8:intervali' . $_SERVER['tracker']['announce_interval'] .
@ -627,7 +607,7 @@ class peertracker
case 'xml': case 'xml':
header('Content-Type: text/xml'); header('Content-Type: text/xml');
echo '<?xml version="1.0" encoding="ISO-8859-1"?>' . echo '<?xml version="1.0" encoding="ISO-8859-1"?>' .
'<tracker version="$Id: tracker.mysql.php 164 2010-01-23 22:08:58Z trigunflame $">' . '<tracker version="$Id: tracker.mysql.php 148 2009-11-16 23:18:28Z trigunflame $">' .
'<peers>' . number_format($stats[0] + $stats[1]) . '</peers>' . '<peers>' . number_format($stats[0] + $stats[1]) . '</peers>' .
'<seeders>' . number_format($stats[0]) . '</seeders>' . '<seeders>' . number_format($stats[0]) . '</seeders>' .
'<leechers>' . number_format($stats[1]) . '</leechers>' . '<leechers>' . number_format($stats[1]) . '</leechers>' .
@ -637,7 +617,7 @@ class peertracker
// json // json
case 'json': case 'json':
header('Content-Type: text/javascript'); header('Content-Type: text/javascript');
echo '{"tracker":{"version":"$Id: tracker.mysql.php 164 2010-01-23 22:08:58Z trigunflame $",' . echo '{"tracker":{"version":"$Id: tracker.mysql.php 148 2009-11-16 23:18:28Z trigunflame $",' .
'"peers": "' . number_format($stats[0] + $stats[1]) . '",' . '"peers": "' . number_format($stats[0] + $stats[1]) . '",' .
'"seeders":"' . number_format($stats[0]) . '",' . '"seeders":"' . number_format($stats[0]) . '",' .
'"leechers":"' . number_format($stats[1]) . '",' . '"leechers":"' . number_format($stats[1]) . '",' .
@ -647,7 +627,7 @@ class peertracker
// standard // standard
default: default:
echo '<!doctype html><html><head><meta http-equiv="content-type" content="text/html; charset=UTF-8">' . echo '<!doctype html><html><head><meta http-equiv="content-type" content="text/html; charset=UTF-8">' .
'<title>PeerTracker: $Id: tracker.mysql.php 164 2010-01-23 22:08:58Z trigunflame $</title>' . '<title>PeerTracker: $Id: tracker.mysql.php 148 2009-11-16 23:18:28Z trigunflame $</title>' .
'<body><pre>' . number_format($stats[0] + $stats[1]) . '<body><pre>' . number_format($stats[0] + $stats[1]) .
' peers (' . number_format($stats[0]) . ' seeders + ' . number_format($stats[1]) . ' peers (' . number_format($stats[0]) . ' seeders + ' . number_format($stats[1]) .
' leechers) in ' . number_format($stats[2]) . ' torrents</pre></body></html>'; ' leechers) in ' . number_format($stats[2]) . ' torrents</pre></body></html>';

7
ruby/Gemfile Normal file
View File

@ -0,0 +1,7 @@
source "http://rubygems.org"
gem 'activerecord', :require => "active_record"
gem 'sinatra'
gem 'mysql2'
gem "rspec"
gem "json"

48
ruby/Gemfile.lock Normal file
View File

@ -0,0 +1,48 @@
GEM
remote: http://rubygems.org/
specs:
activemodel (3.2.8)
activesupport (= 3.2.8)
builder (~> 3.0.0)
activerecord (3.2.8)
activemodel (= 3.2.8)
activesupport (= 3.2.8)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
activesupport (3.2.8)
i18n (~> 0.6)
multi_json (~> 1.0)
arel (3.0.2)
builder (3.0.0)
diff-lcs (1.1.3)
i18n (0.6.0)
json (1.7.4)
multi_json (1.3.6)
mysql2 (0.3.11)
rack (1.4.1)
rack-protection (1.2.0)
rack
rspec (2.11.0)
rspec-core (~> 2.11.0)
rspec-expectations (~> 2.11.0)
rspec-mocks (~> 2.11.0)
rspec-core (2.11.1)
rspec-expectations (2.11.2)
diff-lcs (~> 1.1.3)
rspec-mocks (2.11.1)
sinatra (1.3.2)
rack (~> 1.3, >= 1.3.6)
rack-protection (~> 1.2)
tilt (~> 1.3, >= 1.3.3)
tilt (1.3.3)
tzinfo (0.3.33)
PLATFORMS
ruby
DEPENDENCIES
activerecord
json
mysql2
rspec
sinatra

4
ruby/bin/get_as_info.rb Executable file
View File

@ -0,0 +1,4 @@
#! /usr/bin/ruby
require File.join(File.dirname(__FILE__),'../lib/as_info.rb')
Peertracker::ASInfo.set_as_info

View File

@ -0,0 +1,7 @@
Bundler.require
require File.join(File.dirname(__FILE__),'../lib/as_info.rb')
get '/as_info/:ip_address.json' do |ip_address|
response = Peertracker::ASInfo.new.set_as_info_for_ip(ip_address)
{:as_code => response[0], :country => response[1]}.to_json
end

2
ruby/config.ru Normal file
View File

@ -0,0 +1,2 @@
require './bin/web_interface.rb'
run Sinatra::Application

7
ruby/config/database.rb Normal file
View File

@ -0,0 +1,7 @@
ActiveRecord::Base.establish_connection(
:adapter => "mysql2",
:host => "localhost",
:username => "root",
:password => "",
:database => "peertracker"
)

16
ruby/config/migration.rb Normal file
View File

@ -0,0 +1,16 @@
Bundler.require
require File.join(File.dirname(__FILE__), "database.rb")
class AddASInfoToPeers < ActiveRecord::Migration
def up
add_column :pt_peers, :as_code, :string
add_column :pt_peers, :country, :string
end
def down
remove_column :pt_peers, :as_code
remove_column :pt_peers, :country
end
end
AddASInfoToPeers.new.up

32
ruby/lib/as_info.rb Normal file
View File

@ -0,0 +1,32 @@
Bundler.require
require File.join(File.dirname(__FILE__), "../config/database.rb")
require File.join(File.dirname(__FILE__), "./model/peer.rb")
require File.join(File.dirname(__FILE__), "./url_creator.rb")
require File.join(File.dirname(__FILE__), "./http_request.rb")
require File.join(File.dirname(__FILE__), "./whois_request.rb")
require File.join(File.dirname(__FILE__), "./as_parser.rb")
module Peertracker
class ASInfo
def set_as_info_for_ip(ip_address)
raw_code = WhoisRequest.new.get_as_info(ip_address)
raw_country = WhoisRequest.new.get_country_info(ip_address)
ASParser.new.parse_response(raw_code, raw_country)
end
class << self
def set_as_info
Peer.without_as_info.each do |peer|
begin
puts "Parsing #{peer.ip}"
peer.as_code, peer.country = self.new.set_as_info_for_ip(peer.ip)
peer.save
rescue => e
puts "Could not fetch AS for #{peer.ip}"
puts "#{e.to_s}"
end
end
end
end
end
end

23
ruby/lib/as_parser.rb Normal file
View File

@ -0,0 +1,23 @@
class ASParser
def parse_response(raw_code, raw_country)
[parse_as(raw_code),parse_country(raw_country)]
end
def parse_as(raw_code)
begin
raw_code.scan(/origin:\s*([A-Z0-9]*)\s/i)[0][0]
rescue => e
puts "Could not parse AS"
nil
end
end
def parse_country(raw_country)
begin
raw_country.scan(/country:\s*([A-Z0-9]*)\s/i)[0][0]
rescue => e
puts "Could not parse Country"
nil
end
end
end

14
ruby/lib/http_request.rb Normal file
View File

@ -0,0 +1,14 @@
module Peertracker
class HTTPRequest
def initialize(host, path = "")
@host = host
@path = path
end
def perform_request
uri = URI("http://#{@host}#{@path}/")
response = Net::HTTP.get_response(uri)
response.body
end
end
end

5
ruby/lib/model/peer.rb Normal file
View File

@ -0,0 +1,5 @@
class Peer < ActiveRecord::Base
self.table_name = "pt_peers"
self.primary_key = "peer_id"
scope :without_as_info, lambda{ where("pt_peers.as_code IS NULL") }
end

18
ruby/lib/url_creator.rb Normal file
View File

@ -0,0 +1,18 @@
require "net/http"
module Peertracker
class URLCreator
def initialize(url_host, ip_address)
@ip_address = ip_address
@url_host = url_host
end
def create_subdomain
"%02x%02x%02x%02x" % @ip_address.scan(/(.*)\.(.*)\.(.*)\.(.*)/)[0]
end
def create_url
"#{create_subdomain}.#{@url_host}"
end
end
end

11
ruby/lib/whois_request.rb Normal file
View File

@ -0,0 +1,11 @@
module Peertracker
class WhoisRequest
def get_as_info(ip_address)
`whois -h whois.radb.net #{ip_address}`
end
def get_country_info(ip_address)
`whois -h whois.lacnic.net #{ip_address}`
end
end
end

View File

@ -0,0 +1,20 @@
require File.join(File.dirname(__FILE__), "../../spec/spec_helper.rb")
describe "ASInfo" do
context "when given IP address" do
describe "sets as info for ip address" do
let(:ip_address) {"12.12.12.12"}
it "stores as_info to database" do
ASInfo.new.set_as_info_for_ip(ip_address)
Peer.find_by_ip_address(ip_address).as.should_not be_null
end
end
end
describe ".set_as_info" do
it "stores as info for all addresses"
ASInfo.set_as_info
Peer.all.each {|peer| peer.as.should_not be_null}
end
end

1
ruby/spec/spec_helper.rb Normal file
View File

@ -0,0 +1 @@
require File.join(File.dirname(__FILE__), "../lib/as_info.rb")