Skip to content

Instantly share code, notes, and snippets.

@joepie91

joepie91/.js Secret

Created August 3, 2018 02:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joepie91/053e55ff3a9b798c16f4fca2c890ae96 to your computer and use it in GitHub Desktop.
Save joepie91/053e55ff3a9b798c16f4fca2c890ae96 to your computer and use it in GitHub Desktop.
"use strict";
const net = require("net");
const tls = require("tls");
const dm = require("../data-modelling");
function generateTargetList(targets) {
Array.from(targets).map((target) => {
return target.getTargetName();
}).join(",");
}
/* FIXME: `matches` regex */
let UUID = dm.createType("UUID", dm.string());
let Nickname = dm.createType("Nickname", dm.string({
matches: /^[a-z0-9_`^|\[\]{}\\-]+$/i
}));
let Username = dm.createType("Username", dm.string({
matches: /^[a-z0-9_-]+$/i
}));
let Realname = dm.createType("Realname", dm.string());
let RealHostname = dm.createType("RealHostname", dm.string({
matches: /^[a-z0-9.-]$/i
}));
let MaskedHostname = dm.createType("MaskedHostname", dm.string({
matches: /^user\/.+$/
}));
let ChannelName = dm.createType("ChannelName", dm.string({
matches: /^#[^ \u0007,]$/
}));
let MessageTarget = dm.createTrait("MessageTarget", {
getTargetName: dm.expectFunction([], dm.string())
});
let Channel = dm.createType("Channel", {
name: ChannelName,
presences: dm.setOf(UserPresence)
// .unique("$.user")
.default(() => {
return new Set();
}),
addUser: dm.guard(User, function (user) {
this.presences.add(UserPresence({
user: user,
isOwner: false,
isOperator: false,
hasVoice: false
}));
}),
removeUser: dm.guard(User, function (user) {
this.presences.where({
user: user
}).delete();
})
}).implements(MessageTarget, {
getTargetName: function () {
return this.name;
}
});
let Client = dm.createType("Client", {
id: UUID,
socket: dm.either(
dm.instanceOf(net.Socket),
dm.instanceOf(tls.Socket)
),
user: User,
connectedAt: dm.date(),
lastPong: dm.date(),
send: dm.guard([Message], function (message) {
this.socket.send(message.encode());
})
});
let User = dm.createType("User", {
nickname: Nickname,
username: Username,
realname: Realname,
hostname: dm.either(RealHostname, MaskedHostname)
.validate((hostname, data) => {
if (data.authenticated === true) {
return (hostname instanceof MaskedHostname);
} else {
return (hostname instanceof RealHostname);
}
}),
authenticated: dm.boolean(),
idle: dm.boolean(),
clients: dm.setOf(Client),
joinedChannels: dm.setOf(Channel),
send: dm.guard([Message], function (message) {
this.clients.forEach((client) => {
client.send(message);
});
})
}).implements(MessageTarget, {
getTargetName: function () {
return this.nickname;
}
});
let UserPresence = dm.createType("UserPresence", {
user: User,
isOwner: dm.boolean(),
isOperator: dm.boolean(),
hasVoice: dm.boolean()
});
/* TODO: Allow dm.instanceOf(dm.either(A, B))? */
let Server = dm.createType("Server", {
listeners: dm.setOf(dm.either(
dm.instanceOf(net.Server),
dm.instanceOf(tls.Server)
)),
channels: dm.mapOf(dm.string(), Channel),
users: dm.mapOf(dm.string(), User),
clients: dm.setOf(Client),
broadcast: dm.guard([Message], function (message) {
this.clients.forEach((client) => {
client.send(message);
});
})
});
let Message = dm.createTrait("Message", {
encode: dm.expectFunction([], dm.string())
});
let NoticeMessage = dm.createType("NoticeMessage", {
targets: dm.setOf(MessageTarget),
message: dm.string()
}).implements(Message, {
encode: function () {
return `NOTICE ${generateTargetList(this.targets)} :${this.message}`;
}
});
let TextMessage = dm.createType("TextMessage", {
targets: dm.setOf(MessageTarget),
message: dm.string()
}).implements(Message, {
encode: function () {
return `PRIVMSG ${generateTargetList(this.targets)} :${this.message}`;
}
});
let CTCPType = dm.createType("CTCPType", dm.string({
matches: /^[a-z]+$/i
}));
let CTCPMessage = dm.createType("CTCPMessage", {
targets: dm.setOf(MessageTarget),
type: CTCPType,
message: dm.string()
}).implements(Message, {
encode: function () {
return TextMessage({
targets: this.targets,
message: `\u0001${this.type.toUpperCase()} ${this.message}\u0001`
}).encode();
}
});
let ActionMessage = dm.createType("ActionMessage", {
targets: dm.setOf(MessageTarget),
message: dm.string()
}).implements(Message, {
encode: function () {
return CTCPMessage({
targets: this.targets,
type: "ACTION",
message: this.message
}).encode();
}
});
let CTCPResponse = dm.createType("CTCPResponse", {
targets: dm.setOf(MessageTarget),
type: CTCPType,
message: dm.string()
}).implements(Message, {
encode: function () {
return NoticeMessage({
targets: this.targets,
message: `\u0001${this.type.toUpperCase()} ${this.message}\u0001`
});
}
});
module.exports = {
User,
UserPresence,
Channel,
Client,
Server,
NoticeMessage,
TextMessage,
ActionMessage
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment