-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver-combined.js
More file actions
162 lines (135 loc) · 5.13 KB
/
server-combined.js
File metadata and controls
162 lines (135 loc) · 5.13 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
const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')
const { Server } = require('socket.io')
const { initDatabase, createUser, getUser, updateBalance, createTransaction, addToEscrow, getBalance, saveMessage, getUserMessages, getUnreadCount } = require('./lib/database')
const dev = process.env.NODE_ENV !== 'production'
const hostname = 'localhost'
const port = parseInt(process.env.PORT || '8081', 10)
// Initialize Next.js
const app = next({ dev, hostname, port })
const handle = app.getRequestHandler()
app.prepare().then(() => {
// Create HTTP server
const httpServer = createServer(async (req, res) => {
try {
const parsedUrl = parse(req.url, true)
await handle(req, res, parsedUrl)
} catch (err) {
console.error('Error occurred handling', req.url, err)
res.statusCode = 500
res.end('internal server error')
}
})
// Attach Socket.io to the same server
const io = new Server(httpServer, {
cors: {
origin: [
'http://localhost:3000',
'http://localhost:5173',
'http://localhost:8080',
'http://localhost:8081',
'https://sunerichat.netlify.app',
'https://sunerichat.onrender.com'
],
methods: ['GET', 'POST'],
credentials: true
},
path: '/socket.io/'
})
// Initialize database
let db = initDatabase()
const users = new Map()
io.on('connection', (socket) => {
console.log('SuneriChat - User connected:', socket.id)
const userNpub = socket.handshake.query.userNpub
if (userNpub) {
// Reload database to get fresh data
db = initDatabase()
users.set(userNpub, socket.id)
console.log('User registered:', userNpub)
let user = getUser(db, userNpub)
if (!user) {
console.log('Creating new user in database:', userNpub)
user = createUser(db, userNpub)
}
const balance = getBalance(db, userNpub)
console.log('Sending balance to user:', balance)
socket.emit('balance-update', { balance })
const messages = getUserMessages(db, userNpub)
socket.emit('message-history', { messages })
const unreadCount = getUnreadCount(db, userNpub)
socket.emit('unread-count', { count: unreadCount })
}
socket.on('send-message', (data) => {
// Support both old (from/to) and new (sender/recipient) field names
const from = data.from || data.sender
const to = data.to || data.recipient
const { content, amount } = data
console.log('Received message:', { from, to, content, amount })
const sender = getUser(db, from)
const recipient = getUser(db, to)
if (!sender || !recipient) {
console.log('User not found:', { sender: !!sender, recipient: !!recipient })
socket.emit('error', { message: 'User not found' })
return
}
if (sender.balance < amount) {
console.log('Insufficient balance:', { balance: sender.balance, amount })
socket.emit('error', { message: 'Insufficient balance' })
return
}
// Update balances (updateBalance ADDS the amount, so use negative for sender)
updateBalance(db, from, -amount)
updateBalance(db, to, amount)
createTransaction(db, from, to, amount, 'message')
const message = saveMessage(db, {
from,
to,
content,
amount,
timestamp: Date.now()
})
console.log('Message saved:', message.id, 'From:', from.slice(0, 12), 'To:', to.slice(0, 12))
const senderBalance = getBalance(db, from)
socket.emit('balance-update', { balance: senderBalance })
const recipientSocketId = users.get(to)
console.log('Recipient socket ID:', recipientSocketId, 'Sending to recipient...')
if (recipientSocketId) {
io.to(recipientSocketId).emit('new-message', { message })
const recipientBalance = getBalance(db, to)
io.to(recipientSocketId).emit('balance-update', { balance: recipientBalance })
console.log('Sent to recipient socket:', recipientSocketId)
} else {
console.log('Recipient not connected:', to.slice(0, 12))
}
// Only send confirmation back to sender, not the message itself (to avoid duplicates)
console.log('Message sent successfully')
})
socket.on('user-updated', (user) => {
console.log('User updated:', user.npub, 'Username:', user.username)
// Broadcast to all connected clients
io.emit('user-updated', user)
})
socket.on('disconnect', () => {
console.log('SuneriChat - User disconnected:', socket.id)
for (const [npub, socketId] of users.entries()) {
if (socketId === socket.id) {
users.delete(npub)
break
}
}
})
})
// Start the combined server
httpServer.listen(port, (err) => {
if (err) throw err
console.log(`> Ready on http://${hostname}:${port}`)
console.log('WebSocket and Next.js running on the same port')
})
// Cleanup on exit
process.on('SIGINT', () => {
console.log('Shutting down...')
process.exit()
})
})