skynet/src/index.js

120 lines
3.3 KiB
JavaScript
Raw Normal View History

2018-10-06 08:38:21 +00:00
const express = require("express")
const websocket = require("ws")
const cors = require("cors")
const level = require("level")
const expressWS = require("express-ws")
const cuid = require("cuid")
const db = level("./db.level", {
valueEncoding: "json"
})
const app = express()
const eWSS = expressWS(app)
app.use(cors())
app.use(express.static(__dirname))
const validateChannel = channel => { if (typeof channel !== "string" && typeof channel !== "number") throw new Error("Invalid type for channel!") }
const wildcardChannel = "*"
const messageLog = []
const broadcast = (wss, msg, sender) => {
const toSend = {
...msg,
type: "message",
ID: cuid(),
time: new Date().getTime()
}
wss.clients.forEach(socket => {
let send = socket.readyState === websocket.OPEN
if (socket.type === "client") { send = send && (socket.channels.includes(msg.channel) || socket.channels.includes(wildcardChannel)) && socket !== sender }
else if (socket.type === "peer") { send = send && true }
if (send) {
socket.send(JSON.stringify(toSend))
}
})
messageLog.unshift(toSend) // push to front for nice ordering
}
const clientCommands = {
open(message, sendBack, ctx) {
const channel = message.channel
const ws = ctx.ws
validateChannel(channel)
2018-09-15 17:27:45 +00:00
2018-10-06 08:38:21 +00:00
if (!ws.channels.includes(channel)) ws.channels.push(channel)
2018-09-15 17:27:45 +00:00
2018-10-06 08:38:21 +00:00
sendBack({ channels: ws.channels })
},
close(message, sendBack, ctx) {
const channel = message.channel
const ws = ctx.ws
validateChannel(channel)
2018-09-15 17:27:45 +00:00
// Remove channel from list if exists
2018-10-06 08:38:21 +00:00
const index = ws.channels.indexOf(channel)
2018-09-15 17:27:45 +00:00
if (index > -1) {
2018-10-06 08:38:21 +00:00
ws.channels.splice(index, 1)
sendBack({ channels: ws.channels })
2018-09-15 17:27:45 +00:00
} else {
2018-10-06 08:38:21 +00:00
throw new Error("Channel " + channel + " not open.")
2018-09-15 17:27:45 +00:00
}
},
2018-10-06 08:38:21 +00:00
log(message, sendBack) {
const start = message.start || 0
const end = message.end || 100
sendBack({ log: messageLog.slice(start, end) })
2018-10-03 17:18:11 +00:00
},
2018-10-06 08:38:21 +00:00
message(message, sendBack, { wss, ws }) {
broadcast(wss, message, ws)
2018-09-15 17:27:45 +00:00
}
}
2018-10-06 08:38:21 +00:00
const ctx = {
wss: eWSS.getWss(),
db
}
2018-09-15 17:27:45 +00:00
2018-10-06 08:38:21 +00:00
const websocketCommandProcessor = (ws, commands) => {
const send = x => ws.send(JSON.stringify(x))
ws.on("message", raw => {
try {
const message = JSON.parse(raw)
if (typeof message === "object" && message !== null && message !== undefined) {
const commandName = message.type
const command = commands[commandName]
if (!command) { throw new Error("No such command " + commandName) }
const sendBack = x => send({type: "result", for: commandName, ...x})
command(message, sendBack, { ws, ...ctx })
} else {
throw new Error("Message must be object")
2018-09-15 17:27:45 +00:00
}
2018-10-06 08:38:21 +00:00
} catch(e) {
console.error(e)
send({
type: "error",
error: e.toString()
})
return
}
})
}
app.ws("/connect", (ws, req) => {
ws.channels = []
ws.type = "client"
websocketCommandProcessor(ws, clientCommands)
})
app.ws("/peer", (ws, req) => {
})
2018-09-15 17:27:45 +00:00
2018-10-06 08:38:21 +00:00
app.listen(parseInt(process.env.PORT) || 4567)