-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.js
More file actions
236 lines (201 loc) · 6.61 KB
/
client.js
File metadata and controls
236 lines (201 loc) · 6.61 KB
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
const process = require('process')
const Hyperswarm = require('hyperswarm')
const RPC = require('@hyperswarm/rpc')
const Corestore = require('corestore')
const Hyperbee = require('hyperbee')
const IdEnc = require('hypercore-id-encoding')
const HyperDHT = require('hyperdht')
const minimist = require('minimist')
const args = minimist(process.argv.slice(2))
const bootstrap = [{ host: '127.0.0.1', port: 30001 }]
class UsernameRegistryClient {
constructor(serverPublicKey, coreKey, storagePath = null) {
this.serverPublicKey = serverPublicKey
this.coreKey = coreKey
// Use unique storage path to avoid conflicts
this.storagePath = storagePath || `client-corestore-${Date.now()}`
this.store = new Corestore(this.storagePath)
this.bee = null
this.swarm = null
this.dht = null
this.rpc = null
this.client = null
}
async initialize() {
// Create consistent key pairs
const dhtKeyPair = await this.store.createKeyPair('dht')
const swarmKeyPair = await this.store.createKeyPair('swarm')
// Set up DHT and swarm
this.dht = new HyperDHT({ keyPair: dhtKeyPair, bootstrap })
this.swarm = new Hyperswarm({ dht: this.dht, keyPair: swarmKeyPair })
// Set up corestore replication
this.swarm.on('connection', async (conn) => {
console.log('Hyperswarm connection opened')
this.store.replicate(conn)
})
// Get the hypercore and initialize hyperbee
const core = this.store.get({ key: this.coreKey })
await core.ready()
this.bee = new Hyperbee(core, {
keyEncoding: 'utf8',
valueEncoding: 'utf8'
})
await this.bee.ready()
// Join the discovery key
this.swarm.join(core.discoveryKey)
// Set up RPC client
this.rpc = new RPC({ dht: this.dht })
// Wait a bit for the connection to be fully established
await new Promise(resolve => setTimeout(resolve, 2000))
console.log(`DHT public key: ${IdEnc.normalize(this.dht.defaultKeyPair.publicKey)}`)
console.log(`Swarm public key: ${IdEnc.normalize(this.swarm.keyPair.publicKey)}`)
return this
}
async registerUsername(username, publicKey) {
try {
if (!this.rpc) {
throw new Error('RPC client not initialized')
}
const response = await this.rpc.request(this.serverPublicKey, 'register-username',
Buffer.from(JSON.stringify({ username, publicKey }))
)
return JSON.parse(response.toString())
} catch (error) {
console.error('Error registering username:', error)
return { success: false, error: error.message }
}
}
async deleteUsername(username, publicKey) {
try {
if (!this.rpc) {
throw new Error('RPC client not initialized')
}
const response = await this.rpc.request(this.serverPublicKey, 'delete-username',
Buffer.from(JSON.stringify({ username, publicKey }))
)
return JSON.parse(response.toString())
} catch (error) {
console.error('Error deleting username:', error)
return { success: false, error: error.message }
}
}
async lookupUsername(username) {
try {
const result = await this.bee.get(username)
if (result) {
return {
username: username,
publicKey: result.value.toString()
}
}
return null
} catch (error) {
console.error('Error looking up username:', error)
return null
}
}
async listUsernames() {
try {
const usernames = []
for await (const { key, value } of this.bee.createReadStream()) {
usernames.push({
username: key.toString(),
publicKey: value.toString()
})
}
return usernames
} catch (error) {
console.error('Error listing usernames:', error)
return []
}
}
async destroy() {
if (this.swarm) {
await this.swarm.destroy()
}
if (this.store) {
await this.store.close()
}
}
}
async function main() {
if (args.help) {
console.log(`
Usage: node client.js <command> [options]
Commands:
register <username> <publicKey> - Register a username
delete <username> <publicKey> - Delete a username
lookup <username> - Look up a username
list - List all usernames
server-info - Get server information
Options:
--server-key <key> - Server public key (required)
--core-key <key> - Core key (required)
--help - Show this help
`)
return
}
if (!args['server-key'] || !args['core-key']) {
console.error('Error: --server-key and --core-key are required')
console.log('Use --help for usage information')
process.exit(1)
}
const serverPublicKey = IdEnc.decode(args['server-key'])
const coreKey = IdEnc.decode(args['core-key'])
console.log(`Using server pub key ${IdEnc.normalize(serverPublicKey)} and core key ${IdEnc.normalize(coreKey)}`)
const client = new UsernameRegistryClient(serverPublicKey, coreKey)
try {
await client.initialize()
const command = args._[0]
switch (command) {
case 'register':
if (args._.length < 3) {
console.error('Usage: register <username> <publicKey>')
break
}
const registerResult = await client.registerUsername(args._[1], args._[2])
console.log(JSON.stringify(registerResult, null, 2))
break
case 'delete':
if (args._.length < 3) {
console.error('Usage: delete <username> <publicKey>')
break
}
const deleteResult = await client.deleteUsername(args._[1], args._[2])
console.log(JSON.stringify(deleteResult, null, 2))
break
case 'lookup':
if (args._.length < 2) {
console.error('Usage: lookup <username>')
break
}
const lookupResult = await client.lookupUsername(args._[1])
if (lookupResult) {
console.log(JSON.stringify(lookupResult, null, 2))
} else {
console.log('Username not found')
}
break
case 'list':
const listResult = await client.listUsernames()
console.log(JSON.stringify(listResult, null, 2))
break
case 'server-info':
console.log(`Server public key: ${IdEnc.normalize(serverPublicKey)}`)
console.log(`Core key: ${IdEnc.normalize(coreKey)}`)
break
default:
console.error(`Unknown command: ${command}`)
console.log('Use --help for usage information')
break
}
} catch (error) {
console.error('Client error:', error)
} finally {
await client.destroy()
}
}
if (require.main === module) {
main()
}
module.exports = UsernameRegistryClient