This repository has been archived by the owner on Mar 13, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
bitcoin_otc_crawler.coffee
160 lines (141 loc) · 5.02 KB
/
bitcoin_otc_crawler.coffee
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
rp = require('request-promise')
identifi = require('iris-lib')
GUN = require('gun')
require('gun/sea')
require('gun/lib/then')
require('gun/lib/load')
cheerio = require('cheerio')
Promise = require('bluebird')
fs = Promise.promisifyAll(require('fs'))
osHomedir = require('os-homedir')
datadir = process.env.IDENTIFI_DATADIR || (osHomedir() + '/.identifi')
ipfsAPI = require('ipfs-api')
ipfs = ipfsAPI()
USER_LIST_FILE = "bitcoin-otc-data/bitcoin-otc-wot.html"
RATINGDETAILS_DIR = "bitcoin-otc-data/ratingdetails"
VIEWGPG_DIR = "bitcoin-otc-data/viewgpg"
LISTING_URI = "http://bitcoin-otc.com/viewratings.php"
TIMEOUT_MS = 10000
myIndex = null
myKey = null
myKeyId = null
msgsToAdd = []
ratingsJsonUrl = (username) ->
"http://bitcoin-otc.com/viewratingdetail.php?nick=" +
encodeURIComponent(username) +
"&sign=ANY&type=RECV&outformat=json"
userJsonUrl = (username) ->
"http://bitcoin-otc.com/viewgpg.php?nick=" +
encodeURIComponent(username) +
"&outformat=json"
otcUserID = (username) ->
username + "@bitcoin-otc.com"
parseUserList = ->
console.log "Parsing user list"
$ = cheerio.load(fs.readFileSync(USER_LIST_FILE))
userRows = $('table.datadisplay tr')
users = []
for row in userRows[2..]
$ = cheerio.load(row)
users.push $('td a')[0].children[0].data
return users
downloadRatingDetails = (username) ->
rp({uri: ratingsJsonUrl(username), timeout: TIMEOUT_MS})
.catch (e) -> console.log(e)
.then (res) ->
fs.writeFileAsync(RATINGDETAILS_DIR + '/' + username + '.json', res)
downloadViewGPG = (username) ->
rp({uri: userJsonUrl(username), timeout: TIMEOUT_MS})
.catch (e) -> console.log(e)
.then (res) ->
fs.writeFileAsync(VIEWGPG_DIR + '/' + username + '.json', res)
downloadUserList = ->
console.log "Downloading " + LISTING_URI
rp({uri:LISTING_URI, timeout: TIMEOUT_MS})
.then (res) ->
console.log "Writing user list file"
fs.writeFileAsync(USER_LIST_FILE, res)
download = ->
usernames = parseUserList()
fn = (i) ->
return if i >= usernames.length
username = usernames[i]
console.log i + 1 + ' / ' + usernames.length + ' ' + username
downloadRatingDetails(username).then ->
downloadViewGPG(username)
.then ->
fn(i + 1)
fn(0)
saveUserRatings = (filename) ->
content = fs.readFileSync RATINGDETAILS_DIR + '/' + filename, 'utf-8'
ratings = JSON.parse(content)
for rating in ratings
process.stdout.write(".")
continue unless rating.rater_nick and rating.rated_nick
timestamp = new Date(parseInt(parseFloat(rating.created_at) * 1000)).toISOString()
data =
author: {account: otcUserID(rating.rater_nick), nickname: rating.rater_nick}
recipient: {account: otcUserID(rating.rated_nick), nickname: rating.rated_nick}
rating: parseInt(rating.rating)
comment: rating.notes
timestamp: timestamp
context: 'bitcoin-otc.com'
m = await identifi.Message.createRating(data, myKey)
msgsToAdd.push(m)
process.stdout.write("\n")
saveUserProfile = (filename) ->
content = fs.readFileSync VIEWGPG_DIR + '/' + filename, 'utf-8'
ratedUser = JSON.parse(content)[0]
if !ratedUser
console.log filename + ': no user'
return new Promise (resolve) -> resolve()
ratedUserName = filename[0..-6] # remove .json
recipient =
account: otcUserID(ratedUserName)
nickname: ratedUserName
recipient.bitcoin = ratedUser.bitcoinaddress if ratedUser.bitcoinaddress
recipient.gpg_fingerprint = ratedUser.fingerprint if ratedUser.fingerprint
recipient.gpg_keyid = ratedUser.keyid if ratedUser.keyid
timestamp = new Date(parseInt(ratedUser.last_authed_at) * 1000)
data =
author:
account: otcUserID(ratedUserName)
nickname: ratedUserName
recipient: recipient
timestamp: timestamp
m = await identifi.Message.createVerification(data, myKey)
msgsToAdd.push(m)
saveRatings = ->
# gun = new GUN(['http://localhost:8765/gun', 'https://gun-us.herokuapp.com/gun', 'https://gun-eu.herokuapp.com/gun'])
gun = new GUN({ chunk: 1024 * 250, peers: ['http://localhost:8765/gun', 'https://gun-us.herokuapp.com/gun', 'https://gun-eu.herokuapp.com/gun'] })
myKey = await identifi.Key.getDefault()
myKeyId = identifi.Key.getId(myKey)
myIndex = await identifi.Index.create(gun, myKey, {ipfs})
msgData =
recipient:
account: '[email protected]'
rating:10
comment:'WoT entry point'
m = await identifi.Message.createRating msgData, myKey
await myIndex.addMessage(m)
p = new Promise (resolve) ->
fs.readdir RATINGDETAILS_DIR, (err, filenames) ->
for filename, i in filenames
break if i >= 200
console.log i + ' / ' + filenames.length + ' adding to identifi: ' + filename
try
await saveUserRatings(filename)
await saveUserProfile(filename)
catch e
console.log 'crawling', filename, 'failed:', e
resolve()
.then ->
console.log 'msgsToAdd.length', msgsToAdd.length
myIndex.addMessages(msgsToAdd)
.then (r) ->
console.log r
console.log 'added'
#downloadUserList()
#.then ->
#download()
saveRatings()