-
-
Save jahan-addison/093e87eef768073bc9ead499d088df10 to your computer and use it in GitHub Desktop.
qj2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.' | |
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'); | |
}) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'); | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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