ClickSpotter 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +167 -0
- data/bin/clickspotter +4 -0
- data/data/worldmap-large.jpg +0 -0
- data/data/worldmap.png +0 -0
- data/lib/About.rb +22 -0
- data/lib/AboutDlg.rb +169 -0
- data/lib/AppConfig.rb +68 -0
- data/lib/AsyncResolverWithCache.rb +207 -0
- data/lib/BrowserLauncher.rb +23 -0
- data/lib/CSListView.rb +118 -0
- data/lib/CSListViewItem.rb +49 -0
- data/lib/ClickableCanvasView.rb +24 -0
- data/lib/Configuration.rb +123 -0
- data/lib/ConfigurationDlg.rb +372 -0
- data/lib/DNSResolver.rb +53 -0
- data/lib/GSServerLogSettings.rb +24 -0
- data/lib/GeoDistView.rb +351 -0
- data/lib/GeoLocator.rb +91 -0
- data/lib/GlobalSettings.rb +237 -0
- data/lib/HitRecord.rb +39 -0
- data/lib/HostNameDlg.rb +83 -0
- data/lib/LogFileSelector.rb +65 -0
- data/lib/LogFileSelectorDlg.rb +97 -0
- data/lib/LogParser.rb +120 -0
- data/lib/MainWindow.rb +627 -0
- data/lib/MainWindowDlg.rb +1054 -0
- data/lib/OccurenceCounter.rb +65 -0
- data/lib/PageInformation.rb +147 -0
- data/lib/PageInformationDlg.rb +159 -0
- data/lib/PageRecord.rb +77 -0
- data/lib/RefererInformation.rb +114 -0
- data/lib/RefererInformationDlg.rb +106 -0
- data/lib/RefererRecord.rb +51 -0
- data/lib/ServerLogSettings.rb +152 -0
- data/lib/ServerLogSettingsDlg.rb +202 -0
- data/lib/StatusCode.rb +72 -0
- data/lib/TraceRouter.rb +53 -0
- data/lib/VisitorInformation.rb +132 -0
- data/lib/VisitorInformationDlg.rb +351 -0
- data/lib/VisitorRecord.rb +94 -0
- data/lib/WorldMap.rb +93 -0
- data/lib/WorldMapDlg.rb +166 -0
- data/lib/clickspotter.rb +38 -0
- metadata +87 -0
data/lib/DNSResolver.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#
|
2
|
+
# DNSResolver.rb - ClickSpotter
|
3
|
+
#
|
4
|
+
# Copyright (c) 2005, 2006 by Chris Schlaeger <cs@kde.org>
|
5
|
+
# This program is free software; you can redistribute it and/or modify
|
6
|
+
# it under the terms of version 2 of the GNU General Public License as
|
7
|
+
# published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# $Id: DNSResolver.rb 8 2006-01-22 15:19:51Z cs $
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'socket'
|
13
|
+
require 'thread'
|
14
|
+
|
15
|
+
$dnsCache = "DNSResolverCache"
|
16
|
+
|
17
|
+
class DNSRecord
|
18
|
+
attr_reader :host
|
19
|
+
attr_accessor :timeStamp
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
@host = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def resolve(ip)
|
26
|
+
begin
|
27
|
+
a = Socket.gethostbyname(ip)
|
28
|
+
@host = Socket.gethostbyaddr(a[3], a[2])[0]
|
29
|
+
rescue
|
30
|
+
@host = ip
|
31
|
+
end
|
32
|
+
@timeStamp = Time.now()
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
class DNSResolver < AsyncResolverWithCache
|
38
|
+
|
39
|
+
def initialize
|
40
|
+
super('DNSCache', $globals.getSetting('DNSTimeout') * 60 * 60 * 24, 5)
|
41
|
+
@enabled = $globals.getSetting('DNSResolver')
|
42
|
+
end
|
43
|
+
|
44
|
+
def newRecord
|
45
|
+
DNSRecord.new
|
46
|
+
end
|
47
|
+
|
48
|
+
def hostName(ip)
|
49
|
+
(rec = resolve(ip)) ? rec.host : ip
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#
|
2
|
+
# GSServerLogSettings.rb - ClickSpotter
|
3
|
+
#
|
4
|
+
# Copyright (c) 2005, 2006 by Chris Schlaeger <cs@kde.org>
|
5
|
+
# This program is free software; you can redistribute it and/or modify
|
6
|
+
# it under the terms of version 2 of the GNU General Public License as
|
7
|
+
# published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# $Id: GSServerLogSettings.rb 8 2006-01-22 15:19:51Z cs $
|
10
|
+
#
|
11
|
+
|
12
|
+
class GSServerLogSettings
|
13
|
+
|
14
|
+
attr_accessor :name, :logFile, :default, :hostNames
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@name = nil
|
18
|
+
@logFile = nil
|
19
|
+
@default = nil
|
20
|
+
@hostNames = []
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
data/lib/GeoDistView.rb
ADDED
@@ -0,0 +1,351 @@
|
|
1
|
+
#
|
2
|
+
# GeoDistView.rb - ClickSpotter
|
3
|
+
#
|
4
|
+
# Copyright (c) 2005, 2006 by Chris Schlaeger <cs@kde.org>
|
5
|
+
# This program is free software; you can redistribute it and/or modify
|
6
|
+
# it under the terms of version 2 of the GNU General Public License as
|
7
|
+
# published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# $Id: GeoDistView.rb 8 2006-01-22 15:19:51Z cs $
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'GeoLocator'
|
13
|
+
require 'BrowserLauncher'
|
14
|
+
require 'Qt'
|
15
|
+
require 'ClickableCanvasView'
|
16
|
+
|
17
|
+
# This class shows the geographical distribution of visitors on a
|
18
|
+
# world map and as numbers per country in a list.
|
19
|
+
|
20
|
+
class GeoDistView < Qt::Object
|
21
|
+
|
22
|
+
include BrowserLauncher
|
23
|
+
|
24
|
+
slots 'routerListClicked(QListViewItem*)', 'popUpInfo()', 'mapClicked()'
|
25
|
+
|
26
|
+
attr_writer :showRouters, :showRoutes, :showIPs,
|
27
|
+
:showHostNames, :showCities, :showAll,
|
28
|
+
:showLast, :lastMinutes
|
29
|
+
|
30
|
+
# The mapFrame widget will hold the world map and the countryList will
|
31
|
+
# show the distribution by country.
|
32
|
+
def initialize(mapFrame, countryList = nil, routeList = nil, large = false)
|
33
|
+
super(nil)
|
34
|
+
@mapFrame = mapFrame
|
35
|
+
@countryList = countryList
|
36
|
+
@routeList = routeList
|
37
|
+
|
38
|
+
if @countryList
|
39
|
+
@countryListCSLV = CSListView.new(@countryList)
|
40
|
+
@countryList.setSorting(1, false)
|
41
|
+
end
|
42
|
+
if @routeList
|
43
|
+
@routeListCSLV = CSListView.new(@routeList)
|
44
|
+
@routeList.setSorting(0, true)
|
45
|
+
|
46
|
+
connect(@routeList, SIGNAL('clicked(QListViewItem*)'),
|
47
|
+
SLOT('routerListClicked(QListViewItem*)'))
|
48
|
+
end
|
49
|
+
|
50
|
+
# Canvas that shows the map and the location crosses
|
51
|
+
@canvas = Qt::Canvas.new
|
52
|
+
# The canvas view will be a child of the mapFrame widget
|
53
|
+
@mapFrame.setColumnLayout(0, Qt::Vertical)
|
54
|
+
@mapFrame.layout().setSpacing(6)
|
55
|
+
@mapFrame.layout().setMargin(11)
|
56
|
+
lm = Qt::GridLayout.new(mapFrame.layout)
|
57
|
+
# Create the CanvasView that shows the map canvas
|
58
|
+
@mapView = ClickableCanvasView.new(@canvas, @mapFrame)
|
59
|
+
lm.addWidget(@mapView, 0, 0)
|
60
|
+
# The world map is a background image of the canvas
|
61
|
+
pm = Qt::Pixmap.new(large ? AppConfig.dataFile('worldmap-large.jpg') :
|
62
|
+
AppConfig.dataFile('worldmap.png'))
|
63
|
+
if large
|
64
|
+
@mapView.setMaximumSize(pm.width + 2 * @mapView.frameWidth ,
|
65
|
+
pm.height + 2 * @mapView.frameWidth)
|
66
|
+
else
|
67
|
+
@mapView.setFixedSize(pm.width + 2 * @mapView.frameWidth ,
|
68
|
+
pm.height + 2 * @mapView.frameWidth)
|
69
|
+
@mapView.setVScrollBarMode(Qt::ScrollView.AlwaysOff)
|
70
|
+
@mapView.setHScrollBarMode(Qt::ScrollView.AlwaysOff)
|
71
|
+
end
|
72
|
+
connect(@mapView, SIGNAL('clicked()'), self, SLOT('mapClicked()'))
|
73
|
+
|
74
|
+
@canvas.resize(pm.width, pm.height)
|
75
|
+
@canvas.setBackgroundPixmap(pm)
|
76
|
+
|
77
|
+
@showAll = false
|
78
|
+
@showRoutes = false
|
79
|
+
@showRouters = false
|
80
|
+
@showIPs = false
|
81
|
+
@showHostNames = false
|
82
|
+
@showCities = false
|
83
|
+
@showLast = false
|
84
|
+
@lastMinutes = 1
|
85
|
+
|
86
|
+
@layer = 0
|
87
|
+
|
88
|
+
@highlightedVisitor = nil
|
89
|
+
@highlightedRouter = nil
|
90
|
+
end
|
91
|
+
|
92
|
+
# Update the map and the country distribution list.
|
93
|
+
def update(visitors)
|
94
|
+
# Remove all crosses from the map canvas
|
95
|
+
@canvas.allItems().each { |i| i.dispose }
|
96
|
+
@layer = 10
|
97
|
+
|
98
|
+
@highlightedVisitor = nil
|
99
|
+
@highlightedRouter = nil
|
100
|
+
|
101
|
+
# Determine a little square on the map the mouse cursor is over.
|
102
|
+
mouseRect = nil
|
103
|
+
pos = @mapView.mapFromGlobal(Qt::Cursor.new.pos);
|
104
|
+
if pos.x >= 0 && pos.y >= 0 &&
|
105
|
+
pos.x < @mapView.width && pos.y < @mapView.height
|
106
|
+
radius = 4
|
107
|
+
mouseRect = Qt::Rect.new(pos.x - radius, pos.y - radius,
|
108
|
+
2 * radius, 2 * radius)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Count the number of visitors for each country.
|
112
|
+
countries = {}
|
113
|
+
showSurfers = $globals.getSetting('ShowSurfers') != 0
|
114
|
+
showRobots = $globals.getSetting('ShowRobots') != 0
|
115
|
+
deadline = Time.now - @lastMinutes * 60
|
116
|
+
visitors.each do |key, visitor|
|
117
|
+
if (!@showAll &&
|
118
|
+
((visitor.robot != nil && !showRobots) ||
|
119
|
+
(visitor.robot == nil && !showSurfers))) ||
|
120
|
+
(@showLast && visitor.lastHit.timeStamp < deadline)
|
121
|
+
next
|
122
|
+
end
|
123
|
+
markRouteOnMap(visitor.ip, mouseRect)
|
124
|
+
updateRouterList(visitor.ip) if @routeList
|
125
|
+
geoloc = $geoLocator.resolve(visitor.ip)
|
126
|
+
if geoloc == nil || geoloc.country == nil
|
127
|
+
label = '* Unknown *'
|
128
|
+
else
|
129
|
+
label = geoloc.country
|
130
|
+
# Mark all visitors with known locations on the map
|
131
|
+
if markOnMap(geoloc, "red", 8, visitor.ip, mouseRect)
|
132
|
+
@highlightedVisitor = visitor
|
133
|
+
end
|
134
|
+
end
|
135
|
+
countries[label] = 0 if !countries.has_key?(label)
|
136
|
+
countries[label] += 1
|
137
|
+
end
|
138
|
+
@canvas.update
|
139
|
+
if @countryList
|
140
|
+
@countryListCSLV.startUpdate
|
141
|
+
countries.each do |country, count|
|
142
|
+
@countryListCSLV.insertItem(country, country, count,
|
143
|
+
count * 100.0 / visitors.size)
|
144
|
+
end
|
145
|
+
@countryListCSLV.finishUpdate
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
def markRouteOnMap(ip, mouseRect)
|
151
|
+
return unless @showRouters || @showRoutes
|
152
|
+
|
153
|
+
rec = $traceRouter.resolve(ip)
|
154
|
+
return unless rec
|
155
|
+
|
156
|
+
last = nil
|
157
|
+
rec.routers.each do |r|
|
158
|
+
loc = $geoLocator.resolve(r)
|
159
|
+
next unless loc && loc.latitude && loc.longitude
|
160
|
+
drawConnection(last, loc) if @showRoutes
|
161
|
+
last = loc
|
162
|
+
if @showRouters && markOnMap(loc, 'yellow', 6, ip, mouseRect)
|
163
|
+
@highlightedRouter = ip
|
164
|
+
end
|
165
|
+
end
|
166
|
+
# Make sure that we always connect to the destination if we have found
|
167
|
+
# at least one router along the way.
|
168
|
+
if last
|
169
|
+
loc = $geoLocator.resolve(ip)
|
170
|
+
drawConnection(last, loc) if @showRoutes
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def updateRouterList(ip)
|
175
|
+
rec = $traceRouter.resolve(ip)
|
176
|
+
return unless rec
|
177
|
+
|
178
|
+
i = 1
|
179
|
+
@routeListCSLV.startUpdate
|
180
|
+
rec.routers.each do |r|
|
181
|
+
loc = $geoLocator.resolve(r)
|
182
|
+
if loc
|
183
|
+
@routeListCSLV.insertItem(r, i, r, $resolver.hostName(r),
|
184
|
+
loc.country ? loc.country : '',
|
185
|
+
loc.city ? loc.city : '',
|
186
|
+
loc.latitude ? loc.latitude : 0,
|
187
|
+
loc.longitude ? loc.longitude : 0)
|
188
|
+
else
|
189
|
+
@routeListCSLV.insertItem(r, i, '*', '*', '', '', 0, 0)
|
190
|
+
end
|
191
|
+
i += 1
|
192
|
+
end
|
193
|
+
@routeListCSLV.finishUpdate
|
194
|
+
end
|
195
|
+
|
196
|
+
def drawConnection(loc1, loc2)
|
197
|
+
x1, y1 = loc2xy(loc1)
|
198
|
+
return unless x1 > 0 && y1 > 0
|
199
|
+
x2, y2 = loc2xy(loc2)
|
200
|
+
return unless x2 > 0 && y2 > 0
|
201
|
+
|
202
|
+
horizRollover = (x1 - x2).abs > (@canvas.width / 2)
|
203
|
+
vertRollover = (y1 - y2).abs > (@canvas.height / 2)
|
204
|
+
|
205
|
+
if !horizRollover && !vertRollover
|
206
|
+
l = Qt::CanvasLine.new(@canvas)
|
207
|
+
l.setPen(Qt::Pen.new(Qt::Color.new('gray'), 1))
|
208
|
+
l.setPoints(x1, y1, x2, y2)
|
209
|
+
l.z = 2
|
210
|
+
l.show
|
211
|
+
elsif horizRollover
|
212
|
+
xl, yl = x1 < x2 ? [ x1, y1 ] : [ x2, y2 ]
|
213
|
+
xr, yr = x1 > x2 ? [ x1, y1 ] : [ x2, y2 ]
|
214
|
+
l1 = Qt::CanvasLine.new(@canvas)
|
215
|
+
l1.setPen(Qt::Pen.new(Qt::Color.new('gray'), 1))
|
216
|
+
l1.setPoints(xr - @canvas.width, yr, xl, yl)
|
217
|
+
l1.z = 2
|
218
|
+
l1.show
|
219
|
+
|
220
|
+
l2 = Qt::CanvasLine.new(@canvas)
|
221
|
+
l2.setPen(Qt::Pen.new(Qt::Color.new('gray'), 1))
|
222
|
+
l2.setPoints(xl + @canvas.width, yl, xr, yr)
|
223
|
+
l2.z = 2
|
224
|
+
l2.show
|
225
|
+
else
|
226
|
+
xt, yt = y1 < y2 ? [ x1, y1 ] : [ x2, y2 ]
|
227
|
+
xb, yb = y1 > y2 ? [ x1, y1 ] : [ x2, y2 ]
|
228
|
+
l1 = Qt::CanvasLine.new(@canvas)
|
229
|
+
l1.setPen(Qt::Pen.new(Qt::Color.new('gray'), 1))
|
230
|
+
l1.setPoints(xt, yt - @canvas.height, xb, yb)
|
231
|
+
l1.z = 2
|
232
|
+
l1.show
|
233
|
+
|
234
|
+
l2 = Qt::CanvasLine.new(@canvas)
|
235
|
+
l2.setPen(Qt::Pen.new(Qt::Color.new('gray'), 1))
|
236
|
+
l2.setPoints(xb, yb + @canvas.height, xt, yt)
|
237
|
+
l2.z = 2
|
238
|
+
l2.show
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# Mark the specified location with a small red cross on the map
|
243
|
+
def markOnMap(geoloc, color, pLayer, ip, mouseRect)
|
244
|
+
return false unless geoloc
|
245
|
+
x , y = loc2xy(geoloc)
|
246
|
+
return false unless x > 0 && y > 0
|
247
|
+
|
248
|
+
# In case this IP is under the mouse cursor we will show full details
|
249
|
+
# no matter that the show flags say.
|
250
|
+
showFullInfo = mouseRect && mouseRect.contains(x, y)
|
251
|
+
|
252
|
+
# Horizontal line
|
253
|
+
l1 = Qt::CanvasLine.new(@canvas)
|
254
|
+
l1.setPen(Qt::Pen.new(Qt::Color.new(color), 1))
|
255
|
+
l1.setPoints(x - 1, y, x + 2, y)
|
256
|
+
l1.z = pLayer
|
257
|
+
l1.show
|
258
|
+
# Vertical line
|
259
|
+
l2 = Qt::CanvasLine.new(@canvas)
|
260
|
+
l2.setPen(Qt::Pen.new(Qt::Color.new(color), 1))
|
261
|
+
l2.setPoints(x, y - 1, x, y + 2)
|
262
|
+
l2.z = pLayer
|
263
|
+
l2.show
|
264
|
+
|
265
|
+
label = ''
|
266
|
+
label += ip + "\n" if @showIPs || showFullInfo
|
267
|
+
label += $resolver.hostName(ip) + "\n" if @showHostNames || showFullInfo
|
268
|
+
label += geoloc.city + "\n" if (@showCities || showFullInfo) && geoloc.city
|
269
|
+
label += geoloc.country + "\n" if showFullInfo
|
270
|
+
drawLabel(x, y, color, label, showFullInfo) unless label.empty?
|
271
|
+
|
272
|
+
return showFullInfo
|
273
|
+
end
|
274
|
+
|
275
|
+
def loc2xy(geoloc)
|
276
|
+
return [ -1, -1 ] unless geoloc
|
277
|
+
# Check that location is valid
|
278
|
+
latitude = geoloc.latitude
|
279
|
+
longitude = geoloc.longitude
|
280
|
+
return [ -1, -1 ] if latitude == nil || longitude == nil
|
281
|
+
mapW = @canvas.width
|
282
|
+
mapH = @canvas.height
|
283
|
+
# Compute the center of the cross
|
284
|
+
x = (mapW / 2) + longitude * mapW / 360
|
285
|
+
y = (mapH / 2) - latitude * mapH / 180
|
286
|
+
[ x, y ]
|
287
|
+
end
|
288
|
+
|
289
|
+
def drawLabel(px, py, frameColor, text, large)
|
290
|
+
|
291
|
+
x = px + 5
|
292
|
+
y = py - 5
|
293
|
+
|
294
|
+
tl = Qt::CanvasText.new(text, @canvas)
|
295
|
+
tl.setColor(Qt::Color.new('black'))
|
296
|
+
font = Qt::Font.new
|
297
|
+
font.setPixelSize(large ? 11 : 9)
|
298
|
+
tl.setFont(font)
|
299
|
+
tl.x = x
|
300
|
+
tl.y = y
|
301
|
+
tl.z = @layer + 1
|
302
|
+
tl.show
|
303
|
+
|
304
|
+
bg = Qt::CanvasRectangle.new(tl.boundingRect, @canvas)
|
305
|
+
bg.setPen(Qt::Pen.new(Qt::Color.new(frameColor)))
|
306
|
+
bg.setBrush(Qt::Brush.new(Qt::Color.new('white')))
|
307
|
+
bg.z = @layer
|
308
|
+
bg.show
|
309
|
+
|
310
|
+
l = Qt::CanvasLine.new(@canvas)
|
311
|
+
l.setPen(Qt::Pen.new(Qt::Color.new(frameColor), 1))
|
312
|
+
l.setPoints(px, py, x, y + bg.boundingRect.height / 3)
|
313
|
+
l.show
|
314
|
+
l.z = 8
|
315
|
+
|
316
|
+
@layer += 2
|
317
|
+
end
|
318
|
+
|
319
|
+
def selectedItems
|
320
|
+
return [] unless @countryList
|
321
|
+
@countryListCSLV.selectedItems
|
322
|
+
end
|
323
|
+
|
324
|
+
def mapClicked()
|
325
|
+
if @highlightedVisitor
|
326
|
+
correctIP(@highlightedVisitor.ip)
|
327
|
+
elsif @highlightedRouter
|
328
|
+
correctIP(@highlightedRouter)
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
def routerListClicked(item)
|
333
|
+
return unless item
|
334
|
+
|
335
|
+
ip = @routeListCSLV.item(item)
|
336
|
+
return unless ip
|
337
|
+
|
338
|
+
correctIP(ip)
|
339
|
+
end
|
340
|
+
|
341
|
+
def correctIP(ip)
|
342
|
+
browseURL("http://www.hostip.info/correct.html?spip=#{ip}")
|
343
|
+
|
344
|
+
# I don't know how long it takes for the hostip server to provide the
|
345
|
+
# changed information but there seems to be a noticable delay. We set the
|
346
|
+
# record to timeout in 60 minutes to that it will be fetched again then.
|
347
|
+
$geoLocator.expireInMinutes(ip, 60)
|
348
|
+
end
|
349
|
+
|
350
|
+
end
|
351
|
+
|
data/lib/GeoLocator.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
#
|
2
|
+
# GeoLocator.rb - ClickSpotter
|
3
|
+
#
|
4
|
+
# Copyright (c) 2005, 2006 by Chris Schlaeger <cs@kde.org>
|
5
|
+
# This program is free software; you can redistribute it and/or modify
|
6
|
+
# it under the terms of version 2 of the GNU General Public License as
|
7
|
+
# published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# $Id: GeoLocator.rb 8 2006-01-22 15:19:51Z cs $
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'net/http'
|
13
|
+
require 'time'
|
14
|
+
require 'AsyncResolverWithCache'
|
15
|
+
|
16
|
+
class GeoLocatorRecord
|
17
|
+
attr_reader :country, :countryCode, :city, :latitude, :longitude
|
18
|
+
attr_accessor :timeStamp
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@country = nil
|
22
|
+
@countryCode = nil
|
23
|
+
@city = nil
|
24
|
+
@latitude = nil
|
25
|
+
@longitude = nil
|
26
|
+
@timeStamp = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def resolve(ip)
|
30
|
+
begin
|
31
|
+
http = Net::HTTP.new($globals.getSetting('GeolocHost'),
|
32
|
+
$globals.getSetting('GeolocPort'))
|
33
|
+
resp = http.get("/rough.php?ip=#{ip}&position=true", nil)
|
34
|
+
# This is how the data string should look like:
|
35
|
+
# data = <<EOS
|
36
|
+
# Country: GERMANY
|
37
|
+
# Country Code: DE
|
38
|
+
# City: Albstadt
|
39
|
+
# Latitude: 48.25
|
40
|
+
# Longitude: 9.0167
|
41
|
+
# Guessed: false
|
42
|
+
# EOS
|
43
|
+
resp.body.scan(/(.*):\s+(.*)\n/) do |tokens|
|
44
|
+
tokens[1].gsub!(/\|/, '')
|
45
|
+
case tokens[0]
|
46
|
+
when 'Country'
|
47
|
+
@country = tokens[1]
|
48
|
+
when 'Country Code'
|
49
|
+
@countryCode = tokens[1]
|
50
|
+
when 'City'
|
51
|
+
@city = tokens[1]
|
52
|
+
when 'Latitude'
|
53
|
+
val = tokens[1].to_f
|
54
|
+
@latitude = val if val != 0 && val > -90 && val < 90
|
55
|
+
when 'Longitude'
|
56
|
+
val = tokens[1].to_f
|
57
|
+
@longitude = val if val != 0 && val >= -180 && val <= 180
|
58
|
+
else
|
59
|
+
end
|
60
|
+
end
|
61
|
+
rescue
|
62
|
+
return false
|
63
|
+
end
|
64
|
+
@timeStamp = Time.now()
|
65
|
+
return true
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
class GeoLocator < AsyncResolverWithCache
|
71
|
+
|
72
|
+
def initialize
|
73
|
+
super('GeoLocatorCache',
|
74
|
+
$globals.getSetting('GeolocTimeout') * 60 * 60 * 24, 2)
|
75
|
+
@enabled = $globals.getSetting('Geolocator')
|
76
|
+
end
|
77
|
+
|
78
|
+
def newRecord
|
79
|
+
GeoLocatorRecord.new
|
80
|
+
end
|
81
|
+
|
82
|
+
def country(ip)
|
83
|
+
(rec = resolve(ip)) ? rec.country : nil
|
84
|
+
end
|
85
|
+
|
86
|
+
def city(ip)
|
87
|
+
(rec = resolve(ip)) ? rec.city : nil
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|