-
Notifications
You must be signed in to change notification settings - Fork 6
/
nostrTerm.mjs
executable file
·128 lines (105 loc) · 3.19 KB
/
nostrTerm.mjs
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
#!/usr/bin/env node
import os from 'os'
import pty from 'node-pty'
import dotenv from 'dotenv'
import path from 'path'
import { writeFile } from 'fs'
import { parseArgs } from 'util'
import QREncoder from 'qrcode'
import NostrEmitter from '@cmdcode/nostr-emitter'
// Setup our utility libraries.
const ec = new TextEncoder()
// Define our dotenv config.
const configSchema = { override: true }
// Define our argument parser interface.
const optSchema = {
'silent' : { type: 'boolean', short: 's' },
'verbose' : { type: 'boolean', short: 'v' },
'config' : { type: 'string', short: 'c' },
'output' : { type: 'string', short: 'o' }
}
// Parse our arguments.
const { values: opt, positionals: arg } = parseArgs({
options: optSchema,
args: process.argv.slice(2),
allowPositionals: true
})
// If a config path is specified, add to dotenv config.
if (opt.config) {
configSchema.path = path.resolve(opt.config)
}
// Apply the dotenv configuration.
const { parsed: config } = dotenv.config(configSchema)
if (opt.verbose) console.log('Startup config:', opt ?? {}, arg, config)
// Define our connection parameters.
let relayUrl = arg[0] || config.ADDRESS || 'relay.nostrich.de',
secret = arg[1] || config.SECRET || Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toString('hex')
// Initialize our emitter object.
const emitter = new NostrEmitter({ silent: opt.silent, verbose: opt.verbose })
// Setup our shell process.
const shell = os.platform() === 'win32' ? 'powershell.exe' : 'bash'
const ptyProcess = pty.spawn(shell, [], {
name: 'xterm-color',
cols: 80,
rows: 30,
cwd: process.env.HOME,
env: process.env
})
// Initialize our buffers.
let hasBuffer = false
let sendBuffer = false
emitter.on('init', () => {
// On init, send clear command.
ptyProcess.write('clear\r')
})
emitter.on('buff', (data) => {
// If data sent via buffer,
// set hasBuffer flag.
const keys = ec.encode(data)
if (keys.at(-1) === 9) {
// If there's a trailing tab,
// send a return buffer.
sendBuffer = true
} else {
sendBuffer = false
}
hasBuffer = true
if (opt.verbose) console.log('buff:', ec.encode(data))
ptyProcess.write(data)
})
emitter.on('data', (data) => {
if (opt.verbose) console.log('data', ec.encode(data))
ptyProcess.write(data)
})
// Define our main connection function.
async function main() {
await emitter.connect(relayUrl, secret)
ptyProcess.onData((data) => {
if (hasBuffer) {
// If buffer flag is set,
// skip returning chunk.
hasBuffer = false
} else {
// Return chunk.
if (sendBuffer) {
sendBuffer = false
emitter.publish('buff', data)
} else {
emitter.publish('data', data)
}
}
sendBuffer = false
})
console.log('Listening for connections ...')
}
// Output our connection details.
const sharelink = [ secret, relayUrl ].join('@')
const qrcode = await QREncoder.toString(sharelink, { type:'terminal', small: true })
if (typeof opt.output === 'string') {
const data = ec.encode(sharelink)
writeFile(opt.output, data, { mode: 0o644 })
} else {
console.log(qrcode, `\nShare Link: ${sharelink}`)
}
// Start main.
main()