forked from cmurphy/lilurl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
translate.rb
141 lines (127 loc) · 3.87 KB
/
translate.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
require 'rubygems'
require 'sqlite3'
require 'digest/sha1'
require 'uri'
$dbfile = 'lilurl.db'
def geturl(hash)
urldb = open_or_create_db($dbfile)
statement = urldb.prepare "SELECT url FROM urls WHERE hash = ?"
statement.bind_param 1, dbstring(hash)
response = statement.execute
row = response.next # since hash is a primary key this query should only return one result
if !row.nil?
return row.join "\s"
else
raise ArgumentError.new('LilUrl didn\'t find that URL. Are you sure you copied it right?')
end
rescue SQLite3::Exception => e
statement.close if statement
urldb.close if urldb
raise SQLite3::Exception.new(e.to_s)
ensure
statement.close if statement
urldb.close if urldb
end
def makeurl(oldurl, postfix = nil)
validate_url(oldurl)
if postfix.to_s.empty?
hash = generate_hash(oldurl)
else
validate_postfix(postfix)
hash = postfix
end
urldb = open_or_create_db($dbfile)
statement = urldb.prepare "INSERT INTO urls VALUES (?, ?)"
statement.bind_param 1, dbstring(hash)
statement.bind_param 2, dbstring(oldurl)
response = statement.execute
statement.close if statement
urldb.close if urldb
return hash
rescue SQLite3::ConstraintException => e
# column hash is not unique
# 1) URL already exists in the database and will hash to the same index
# 2) someone already tried to use that postfix
# 3) by random chance a new URL hashed to an existing index
# First, see if the postfix was set and is already in there
if !postfix.to_s.empty?
statement = urldb.prepare "SELECT hash FROM urls WHERE hash = ?"
statement.bind_param 1, dbstring(postfix)
response = statement.execute
row = response.next
statement.close if statement
unless row.nil? # returned at least one row
raise ArgumentError.new('That postfix has already been taken. Please use a different one or let me generate one.')
end
urldb.close if urldb
elsif url_exists?(oldurl)
#URL already exists in the database, don't bother to generate a new one
return hash
else # URL doesn't exist in the database but the hash does -> collision resolution needed
b = 1
e = 6
until url_exists?(oldurl)
hash = sha[b..e]
statement = urldb.prepare "SELECT hash FROM urls WHERE hash = ?"
statement.bind_param 1, dbstring(hash)
response = statement.execute
row = response.next
statement.close if statement
if row.nil? # We resolved the collision, insert it there
statement = urldb.prepare "INSERT INTO urls VALUES (?, ?)"
statement.bind_param 1, dbstring(hash)
statement.bind_param 2, dbstring(oldurl)
response = statement.execute
statement.close if statement
end
++b
++e
end
return hash
end
rescue SQLite3::Exception => e
statement.close if statement
urldb.close if urldb
raise SQLite3::Exception.new(e.to_s)
end
def dbstring(s)
if s.respond_to?(:encode)
return s.encode("UTF-8")
else
return s
end
end
def generate_hash(url)
sha = Digest::SHA1.hexdigest url
return sha[0..5]
end
def open_or_create_db(filename)
db = SQLite3::Database.open filename
db.execute "CREATE TABLE IF NOT EXISTS urls(hash varchar(20) primary key, url varchar(500))"
return db
end
def url_exists?(url)
urldb = SQLite3::Database.open $dbfile
statement = urldb.prepare "SELECT hash FROM urls WHERE url = ?"
statement.bind_param 1, dbstring(url)
response = statement.execute
row = response.next
statement.close if statement
if !row.nil?
return true
end
return false
end
def validate_postfix(postfix)
if postfix.length > 20
raise ArgumentError.new('Your postfix must be 20 characters or less.')
end
end
def validate_url(url)
uri = URI(url)
if uri.scheme.nil?
raise ArgumentError.new('Please submit a valid URL.')
end
rescue URI::InvalidURIError => e
raise ArgumentError.new('Please submit a valid URL.')
end