Skip to content
This repository was archived by the owner on Aug 15, 2022. It is now read-only.

Commit 439c3c8

Browse files
committed
fix rooms, add discord bot
1 parent 5db2b42 commit 439c3c8

File tree

7 files changed

+345
-98
lines changed

7 files changed

+345
-98
lines changed

package.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@
1313
"@dstack-js/lib": "^0.2.23",
1414
"@oclif/command": "^1",
1515
"@oclif/config": "^1",
16-
"@oclif/plugin-help": "^3",
16+
"@oclif/plugin-help": "^5.1.10",
1717
"blessed": "^0.1.81",
18+
"discord.js": "^13.6.0",
1819
"tslib": "^1",
1920
"wrtc": "^0.4.7"
2021
},
@@ -42,7 +43,11 @@
4243
"license": "GPL-3.0",
4344
"main": "lib/index.js",
4445
"oclif": {
45-
"bin": "peerchat"
46+
"commands": "./lib/commands",
47+
"bin": "peerchat",
48+
"plugins": [
49+
"@oclif/plugin-help"
50+
]
4651
},
4752
"repository": "dstack-js/chat",
4853
"scripts": {

src/commands/discord/index.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import {Command, flags} from '@oclif/command'
2+
import PeerChat from '..'
3+
import {getStack} from '../../services/stack'
4+
import Discord, {Intents} from 'discord.js'
5+
6+
class DiscordRelay extends Command {
7+
static description = 'Peerchat <-> Discord'
8+
9+
static flags = {
10+
version: flags.version({char: 'v'}),
11+
}
12+
13+
static examples = [
14+
'$ peerchat discord',
15+
'$ peerchat discord [ROOM]',
16+
'$ peerchat discord dstack',
17+
]
18+
19+
static args = [{name: 'room', default: PeerChat.args[0].default, description: 'chat room'}]
20+
21+
async run() {
22+
const {args} = this.parse(DiscordRelay)
23+
24+
if (!process.env.DISCORD_KEY) {
25+
throw new Error('DISCORD_KEY env is missing')
26+
}
27+
28+
const {pubsub} = await getStack()
29+
const client = new Discord.Client({intents: [Intents.FLAGS.GUILD_MESSAGES, Intents.FLAGS.GUILDS, Intents.FLAGS.DIRECT_MESSAGES]})
30+
await client.login(process.env.DISCORD_KEY)
31+
32+
client.on('message', async msg => {
33+
if (msg.author.bot) return
34+
35+
await pubsub.publish(args.room, {nickname: msg.author.tag, message: msg.content})
36+
})
37+
38+
await pubsub.subscribe(args.room, async event => {
39+
const channel = await client.channels.fetch(process.env.CHANNEL_ID || '936448590170177556')
40+
41+
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
42+
// @ts-ignore
43+
if (!channel || !channel.isText()) {
44+
throw new Error('CHANNEL_ID env is invalid')
45+
}
46+
47+
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
48+
// @ts-ignore
49+
channel.send(`${event.data.nickname ? `${event.data.nickname} (${event.from.slice(-5)})` : event.from.slice(-5)}: ${event.data.message}`)
50+
})
51+
}
52+
}
53+
54+
export = DiscordRelay

src/commands/index.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import {Command, flags} from '@oclif/command'
2+
import {run} from '../services/chat'
3+
4+
export default class PeerChat extends Command {
5+
static description = 'Peer-to-peer terminal chat running on DStack'
6+
7+
static flags = {
8+
version: flags.version({char: 'v'}),
9+
}
10+
11+
static examples = [
12+
'$ peerchat',
13+
'$ peerchat [ROOM] [NICKNAME]',
14+
'$ peerchat dstack myCoolNickname',
15+
]
16+
17+
static args = [{name: 'room', default: 'dstack', description: 'chat room'}, {name: 'nickname', description: 'your nickname'}]
18+
19+
async run() {
20+
const {args} = this.parse(PeerChat)
21+
await run(args.room, args.nickname)
22+
}
23+
}

src/index.ts

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1 @@
1-
import {Command, flags} from '@oclif/command'
2-
import {run} from './chat'
3-
4-
class DstackJsChat extends Command {
5-
static description = 'start chat'
6-
7-
static flags = {
8-
version: flags.version({char: 'v'}),
9-
}
10-
11-
static examples = [
12-
'$ peerchat',
13-
'$ peerchat ROOM NICKNAME',
14-
'$ peerchat dstack myCoolNickname',
15-
]
16-
17-
static args = [{name: 'room', default: 'dstack', description: 'chat room'}, {name: 'nickname', description: 'your nickname'}]
18-
19-
async run() {
20-
const {args} = this.parse(DstackJsChat)
21-
run(args.room, args.nickname)
22-
}
23-
}
24-
25-
export = DstackJsChat
1+
export {run} from '@oclif/command'

src/chat.ts renamed to src/services/chat.ts

Lines changed: 5 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,10 @@
1-
/* eslint-disable node/no-extraneous-import */
21
/* eslint-disable no-process-exit */
32
/* eslint-disable unicorn/no-process-exit */
4-
import {create} from '@dstack-js/ipfs'
5-
import {Stack} from '@dstack-js/lib'
6-
import {PubSub} from '@dstack-js/lib/src/pubsub'
7-
const wrtc = require('wrtc')
83
import * as blessed from 'blessed'
9-
10-
interface Message {
11-
nickname?: string;
12-
message: string;
13-
}
4+
import {getStack} from './stack'
145

156
export const run = async (room: string, nickname?: string) => {
16-
const ipfs = await create({
17-
repo: process.env.IPFS_REPO,
18-
relay: {
19-
enabled: true, // enable relay dialer/listener (STOP)
20-
hop: {
21-
enabled: true, // make this node a relay (HOP)
22-
},
23-
},
24-
config: {
25-
Addresses: {
26-
Swarm: ['/ip4/0.0.0.0/tcp/0', '/dns4/dstack-relay.herokuapp.com/tcp/443/wss/p2p-webrtc-star'],
27-
},
28-
Discovery: {
29-
MDNS: {
30-
Enabled: true,
31-
Interval: 1,
32-
},
33-
webRTCStar: {
34-
Enabled: true,
35-
},
36-
},
37-
Bootstrap: ['/dns4/dstack-relay.herokuapp.com/tcp/443/wss/p2p-webrtc-star/p2p/QmV2uXBKbii29iJKHKVy8sx5m49qdDTBYNybVoa5uLJtrf'],
38-
},
39-
}, wrtc)
40-
41-
const stack = await Stack.create('dstack-chat', ipfs)
42-
const pubsub = stack.pubsub as PubSub<Message>
7+
const {ipfs, stack, pubsub} = await getStack()
438

449
const screen = blessed.screen({
4510
smartCSR: true,
@@ -129,7 +94,7 @@ export const run = async (room: string, nickname?: string) => {
12994
}
13095

13196
try {
132-
await pubsub.publish('chat', {nickname, message})
97+
await pubsub.publish(room, {nickname, message})
13398
} catch {
13499
// error handling
135100
} finally {
@@ -146,21 +111,14 @@ export const run = async (room: string, nickname?: string) => {
146111
screen.append(input)
147112
input.focus()
148113

149-
await pubsub.subscribe('chat', event => {
114+
await pubsub.subscribe(room, event => {
150115
messageList.addItem(`${event.data.nickname ? `${event.data.nickname} (${event.from.slice(-5)})` : event.from.slice(-5)}: ${event.data.message}`)
151116
messageList.scrollTo(100)
152117
screen.render()
153118
})
154119

155-
stack.onPeerConnect(async peer => {
156-
messageList.setLabel(` Messages #${room} - Peers: ${await pubsub.peers('chat')} `)
157-
messageList.addItem(`dstack: peer connected ${peer.id.slice(-5)}`)
158-
messageList.scrollTo(100)
159-
screen.render()
160-
})
161-
162120
setInterval(async () => {
163-
messageList.setLabel(` Messages #${room} - Peers: ${await pubsub.peers('chat')} `)
121+
messageList.setLabel(` Messages #${room} - Peers: ${await pubsub.peers(room)} `)
164122
screen.render()
165123
}, 1000)
166124

src/services/stack.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import {create} from '@dstack-js/ipfs'
2+
import {Stack} from '@dstack-js/lib'
3+
import {PubSub} from '@dstack-js/lib/src/pubsub'
4+
const wrtc = require('wrtc')
5+
6+
interface Message {
7+
nickname?: string;
8+
message: string;
9+
}
10+
11+
export const getStack = async () => {
12+
const ipfs = await create({
13+
repo: process.env.IPFS_REPO,
14+
init: {
15+
privateKey: process.env.PEERCHAT_PRIVATE_KEY,
16+
},
17+
relay: {
18+
enabled: true,
19+
hop: {
20+
enabled: true,
21+
},
22+
},
23+
config: {
24+
Addresses: {
25+
Swarm: ['/ip4/0.0.0.0/tcp/0', '/dns4/dstack-relay.herokuapp.com/tcp/443/wss/p2p-webrtc-star'],
26+
},
27+
Discovery: {
28+
MDNS: {
29+
Enabled: true,
30+
Interval: 1,
31+
},
32+
webRTCStar: {
33+
Enabled: true,
34+
},
35+
},
36+
Bootstrap: ['/dns4/dstack-relay.herokuapp.com/tcp/443/wss/p2p-webrtc-star/p2p/QmV2uXBKbii29iJKHKVy8sx5m49qdDTBYNybVoa5uLJtrf'],
37+
},
38+
}, wrtc)
39+
40+
const stack = await Stack.create('dstack-chat', ipfs)
41+
const pubsub = stack.pubsub as PubSub<Message>
42+
43+
return {pubsub, stack, ipfs}
44+
}

0 commit comments

Comments
 (0)