Skip to content

Instantly share code, notes, and snippets.

@jahan-addison
Last active August 16, 2018 20:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jahan-addison/093e87eef768073bc9ead499d088df10 to your computer and use it in GitHub Desktop.
Save jahan-addison/093e87eef768073bc9ead499d088df10 to your computer and use it in GitHub Desktop.
qj2
import { ƛ, Connect, server, message, reply, on } from './lib/dsl';
const sandbox = require('sandbox');
const virtual = new sandbox();
ƛ({
server: 'irc.freenode.org',
nick: 'qj2',
channel: '##frontend'
},
Connect(6667) (
line => on(/PING (\S+)/) (_ => {
server`PONG ${_}`
}),
line => message(/^\.js (.+)/) (_ => {
virtual.run(_, out => {
if (_.toLowerCase().includes('mainmodule')) {
reply`Execution halted 🙅‍`
return;
}
let safe = out.result.replace(/\r|\n/g, '')
.replace(/\\'/g, "'")
.slice(0, 400)
reply`${safe}`
})
}),
line => message(/^\.version$/) (_ => {
reply`qj v2.0.2 ( source: https://gist.github.com/jahan-addison/093e87eef768073bc9ead499d088df10 )`
})
),
error => '💥 Something went wrong.'
);
import {
None,
Some,
match,
Authentication
} from './types';
import * as Irc from './irc';
import { Socket } from 'net';
let State: Irc.Machine = {
connection: None,
auth: Some({
server: 'irc.freenode.org',
nick: 'dslbot',
channel: '##dslbottesting'
}),
port: None,
message: None,
line: None,
error: None,
connected: false,
}
function applyMany(context: Irc.Machine, applied: Function[]): void {
applied.forEach((callback: Function) => {
match<string>(context.line,
line => {
callback.apply(line);
},
_ => {
console.warn('context was insufficient');
}
);
});
}
export function ƛ(details: Authentication, _, Error: Function) {
State.auth = Some(details);
State.error = Some(Error);
}
export function Connect(port: number): Function {
State.port = Some(port);
return (...execution) => {
try {
Irc.connect(State).then(state => {
match(State.connection,
client => {
client.on('data', data => {
State.line = Some(data.toString().split(/\r\n/)[0]);
const message = data.toString().match(/PRIVMSG \#\S+ :(.+)/);
if (message) {
State.message = Some(message[1].trim())
}
applyMany(State, execution);
});
},
_ => {
throw new ReferenceError('Failed to connect');
}
);
});
} catch(e) {
match<Function>(State.error,
call => call(),
_ => {
console.error('Uh oh ⚡️', e);
});
}
};
}
export function server(prefix, response): boolean {
return match<Socket>(State.connection,
connection => {
return connection.write(`${prefix[0]} :${response}\r\n`);
},
_ => false);
}
export function reply(response, data?): boolean {
return match<Socket>(State.connection,
connection => {
const where = match<Authentication>(State.auth,
credentials => credentials.channel,
() => '##dslbottesting');
return connection.write(`PRIVMSG ${where} :${data || response}\r\n`);
},
_ => false);
}
export function message(what:RegExp): Function {
return (callback) => {
match(State.message,
line => {
if (what.test(line)) {
const capture = what.exec(line);
callback(capture ? capture[1] : line.split(/:/)[2]);
State.message = None;
}
},
_ => false)
}
}
export function on(what: RegExp): Function {
return (callback) => {
match(State.line,
line => {
if (what.test(line)) {
const capture = what.exec(line);
callback(capture ? capture[1] : line.split(/:/)[2]);
}
},
_ => {
throw new ReferenceError('Connection not established');
})
}
}
import { None, Some, match, Maybe, Authentication } from './types';
import {
createConnection,
Socket
} from 'net';
export interface Machine {
auth: Maybe<Authentication>,
port: Maybe<number>,
line: Maybe<string>,
message: Maybe<string>,
connection: Maybe<Socket>,
error: Maybe<Function>,
connected: boolean,
}
export async function connect(state: Machine): Promise<Machine> {
const auth = state.auth;
const port = state.port;
return match<Authentication>(auth,
credentials => {
return state.connection = Some<Socket>(createConnection({
host: credentials.server, port: match<number>(port,
_ => _,
_ => 6667)
}, () => {
state.connected = true;
authenticate(state);
})), state;
},
_ => {
throw new ReferenceError('No credentials provided');
});
}
export function authenticate(state: Machine): void {
match<Authentication>(state.auth,
credentials => match<Socket>(state.connection,
connection => {
connection.write(`USER ${credentials.nick} * * :bot\r\n`);
connection.write(`NICK ${credentials.nick}\r\n`);
setTimeout(() => {
connection.write(`JOIN ${credentials.channel}\r\n`);
}, 1000);
},
_ => {
throw new ReferenceError('Connection not established');
}),
_ => {
throw new ReferenceError('Not authenticated');
});
}
export type Maybe<T> = Some<T> | None;
export type None = () => undefined;
export type Some<T> = () => T;
export const None: None = () => void(0);
export function Some<T>(_: T): Some<T> {
return () => _;
}
export function match<T>(_: Maybe<T>, some: (_: any) => any, none: Function) {
if (Guard<T>(_)) {
return some(_());
} else {
return none();
}
}
export function Guard<T>(_: Maybe<T>): _ is Maybe<T> {
return (<Maybe<T>>_)() !== None();
}
export interface Authentication {
server: string,
nick: string,
channel: string
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment