Skip to content
This repository has been archived by the owner on Dec 6, 2021. It is now read-only.

Commit

Permalink
Merge pull request #7 from pyraxo/dev
Browse files Browse the repository at this point in the history
0.2.0
  • Loading branch information
ærion authored Jan 3, 2017
2 parents 0460c0f + fc69134 commit c8e2870
Show file tree
Hide file tree
Showing 27 changed files with 508 additions and 31 deletions.
11 changes: 11 additions & 0 deletions .codeclimate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
engines:
duplication:
enabled: false
eslint:
enabled: false
ratings:
paths:
- "**.js"
exclude_paths:
- test/
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Sylphy
<img src="https://discordapp.com/api/guilds/247727924889911297/embed.png" alt="Studio 777"></a> [![npm](https://img.shields.io/npm/v/sylphy.svg)](https://www.npmjs.com/package/sylphy)
[![Studio 777](https://discordapp.com/api/guilds/247727924889911297/embed.png)](https://discord.gg/bBqpAKw) [![NPM version](https://img.shields.io/npm/v/sylphy.svg?style=flat-square)](https://www.npmjs.com/package/sylphy) [![Dependency Status](https://img.shields.io/david/abalabahaha/eris.svg?style=flat-square)](https://david-dm.org/abalabahaha/eris)

<a href="https://nodei.co/npm/sylphy/"><img src="https://nodei.co/npm/sylphy.png?downloads=true&stars=true" alt="NPM info" /></a>

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "sylphy",
"version": "0.1.0a",
"version": "0.2.0",
"description": "The better Discord bot framework",
"main": "build/index.js",
"scripts": {
"docs": "node_modules/.bin/jsdoc --configure .jsdoc.json --verbose",
"pub": "gulp && npm publish",
"test": "gulp && node test/bot.js"
"test": "gulp && node test/sharding.js"
},
"engines": {
"node": ">=6.0.0"
Expand Down
3 changes: 3 additions & 0 deletions src/Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class Client extends Eris {
* @arg {String} [options.modules] Relative path to modules folder
* @arg {String} [options.middleware] Relative path to middleware folder
* @arg {String} [options.locales] Relative path to locales folder
* @arg {String} [options.resolvers] Relative path to resolvers folder
* @arg {Boolean} [options.suppressWarnings=false] Option to suppress console warnings
* @arg {Boolean} [options.noDefaults=false] Option to not use built-in plugins
*/
Expand All @@ -32,6 +33,8 @@ class Client extends Eris {
this.noDefaults = options.noDefaults
this.admins = Array.isArray(options.admins) ? options.admins : []

this._resolvers = options.resolvers

this.plugins = new Collection()

if (!this.noDefaults) {
Expand Down
11 changes: 9 additions & 2 deletions src/core/Bridge.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
let Promise
try {
Promise = require('bluebird')
} catch (err) {
Promise = global.Promise
}

const path = require('path')
const fs = require('fs')

const { readdirRecursive, isDir } = require('../util')
const { requireRecursive, isDir } = require('../util')

/**
* Middleware manager for commands
Expand Down Expand Up @@ -34,7 +41,7 @@ class Bridge {
throw new Error(`Folder path ${filepath} does not exist`)
}
this._cached.push(filepath)
const mw = isDir(filepath) ? readdirRecursive(filepath) : require(filepath)
const mw = isDir(filepath) ? requireRecursive(filepath) : require(filepath)
return this.register(mw)
}
case 'object': {
Expand Down
25 changes: 17 additions & 8 deletions src/core/Logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ class Logger {
/**
* Creates a new Logger instance
* @arg {Object} [options] Logger options
* @arg {String} [options.name] Option for a prefix before logging
* @arg {String} [options.loggerPrefix] Option for a prefix before logging
* @arg {Boolean} [options.suppressWarnings=false] Option to suppress warnings
* @arg {Boolean} [options.timestamps=true] Option to show timestamps
*/
constructor ({ name, suppressWarnings, timestamps = true } = {}) {
constructor ({ loggerPrefix, suppressWarnings, timestamps = true } = {}) {
this.timestamps = timestamps
this.name = name ? `- [${name}] ` : ''
this._name = loggerPrefix ? `- [${loggerPrefix}] ` : ''

this.styles = {}
for (const code in this.codes) {
Expand All @@ -18,44 +18,53 @@ class Logger {
}
}

/**
* Register a new Logger instance
* @arg {Object} options Logger options
* @returns {Logger}
*/
register (options) {
return new this.constructor(options)
}

/**
* Logs to console
* @arg {...String} args Strings to log to console
*/
log (...args) {
console.log(this.timestamp + this.name + args.join(' '))
console.log(this.timestamp + this._name + args.join(' '))
}

/**
* Logs to console at `info` level
* @arg {...String} args Strings to log to console
*/
info (...args) {
console.log(`${this.timestamp}${this.name}${this.styles.green('info')} - ${args.join(' ')}`)
console.log(`${this.timestamp}${this._name}${this.styles.green('info')} - ${args.join(' ')}`)
}

/**
* Logs to console at `warn` level
* @arg {...String} args Strings to log to console
*/
warn (...args) {
console.log(`${this.timestamp}${this.name}${this.styles.yellow('warn')} - ${args.join(' ')}`)
console.log(`${this.timestamp}${this._name}${this.styles.yellow('warn')} - ${args.join(' ')}`)
}

/**
* Logs to console at `error` level
* @arg {...(String|Error)} args Strings or errors to log to console
*/
error (...args) {
console.log(`${this.timestamp}${this.name}${this.styles.red('error')} - ${args.map(e => e instanceof Error ? e.stack : e).join(' ')}`)
console.log(`${this.timestamp}${this._name}${this.styles.red('error')} - ${args.map(e => e instanceof Error ? e.stack : e).join(' ')}`)
}

/**
* Logs to console at `debug` level
* @arg {...String} args Strings to log to console
*/
debug (...args) {
console.log(`${this.timestamp}${this.name}${this.styles.grey('debug')} - ${args.join(' ')}`)
console.log(`${this.timestamp}${this._name}${this.styles.grey('debug')} - ${args.join(' ')}`)
}

get codes () {
Expand Down
4 changes: 2 additions & 2 deletions src/core/Router.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const path = require('path')
const fs = require('fs')

const { readdirRecursive, isDir, Collection } = require('../util')
const { requireRecursive, isDir, Collection } = require('../util')

/**
* Router class for event routing
Expand Down Expand Up @@ -48,7 +48,7 @@ class Router extends Collection {
if (!fs.existsSync(filepath)) {
throw new Error(`Folder path ${filepath} does not exist`)
}
const mods = isDir(filepath) ? readdirRecursive(filepath) : require(filepath)
const mods = isDir(filepath) ? requireRecursive(filepath) : require(filepath)
this._cached.push(filepath)
return this.register(mods)
}
Expand Down
121 changes: 121 additions & 0 deletions src/managers/Crystal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
let Promise
let EventEmitter
try {
Promise = require('bluebird')
} catch (err) {
Promise = global.Promise
}
try {
EventEmitter = require('eventemitter3')
} catch (err) {
EventEmitter = require('events')
}

const path = require('path')

const { Collection, delay } = require('../util')

/**
* Shard cluster manager
* @prop {Collection} clusters Collection of clusters
*/
class Crystal extends EventEmitter {
/**
* Creates a new Crystal instance
* @arg {String} file Relative or absolute path to file to run
* @arg {Number} [count] Number of clusters to create, defaults to number of CPU cores
*/
constructor (file, count = require('os').cpus().length) {
super()
this.clusters = new Collection()
this._count = count
this._file = path.isAbsolute(file) ? file : path.join(process.cwd(), file)
}

/** Spawns new clusters */
async createClusters () {
for (let i = 0; i < this._count; i++) {
this.createCluster(i)
await delay(6000)
}
}

/**
* Spawns a cluster
* @arg {Number} id Cluster ID
*/
createCluster (id) {
const cluster = new (require('../structures')).Cluster(this._file, id)
const worker = cluster.worker
worker.on('exit', this.onExit.bind(this, worker))
worker.on('message', this.onMessage.bind(this, worker))
this.clusters.set(cluster.id, cluster)
}

/**
* Fetches a cluster
* @arg {Number} pid Process ID to find
*/
getCluster (pid) {
return this.clusters.find(s => s.pid === pid)
}

onExit (worker) {
const cluster = this.getCluster(worker)
this.emit('clusterExit', worker.pid, cluster.id)
this.clusters.delete(cluster.id)
this.createCluster(cluster.id)
}

onMessage (worker, message) {
if (!message.op) return
if (message.op === 'resp') return
if (this[message.op]) {
return this[message.op](message)
}

this.awaitResponse(worker, message)
}

awaitResponse (worker, message) {
const promises = []

for (const cluster of this.clusters.values()) {
promises.push(cluster.awaitResponse(message))
}

Promise.all(promises)
.then(results => worker.send({ op: 'resp', d: results, code: message.code }))
.catch(err => worker.send({ op: 'error', d: err, code: message.code }))
}

broadcast (message) {
if (message.op === 'broadcast') {
message = message.d
}

for (const cluster of this.clusters.values()) {
cluster.worker.send(message)
}
}

/**
* Restarts all clusters, or a specific one
* @arg {Object} [message] The message sent
* @arg {Number} [message.d] The cluster ID to restart
*/
async restart (message = {}) {
if (typeof message.d === 'number') {
const cluster = this.clusters.get(message.d)
if (!cluster) return
cluster.worker.kill()
} else {
for (let cluster of this.clusters.values()) {
cluster.worker.kill()
await Promise.delay(6000)
}
}
}
}

module.exports = Crystal
25 changes: 15 additions & 10 deletions src/managers/Resolver.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
const { readdirRecursive, Collection } = require('../util')
let Promise
try {
Promise = require('bluebird')
} catch (err) {
Promise = global.Promise
}

const { requireRecursive, Collection } = require('../util')

/** Resolver manager for resolving usages */
class Resolver extends Collection {
Expand All @@ -24,15 +31,13 @@ class Resolver extends Collection {
* @returns {Promise<ResolverObject>}
*/
loadResolvers (path) {
return readdirRecursive(path).then(resolvers => {
resolvers = resolvers.map(r => require(r))
for (const name in resolvers) {
const resolver = resolvers[name]
if (!resolver.resolve || !resolver.type) continue
this.set(resolver.type, resolver)
}
return resolvers
})
const resolvers = requireRecursive(path)
for (const name in resolvers) {
const resolver = resolvers[name]
if (!resolver.resolve || !resolver.type) continue
this.set(resolver.type, resolver)
}
return resolvers
}

/**
Expand Down
7 changes: 7 additions & 0 deletions src/managers/Responder.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
let Promise
try {
Promise = require('bluebird')
} catch (err) {
Promise = global.Promise
}

const { padEnd, emojis } = require('../util')

class Responder {
Expand Down
7 changes: 7 additions & 0 deletions src/managers/Transmitter.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
let Promise
try {
Promise = require('bluebird')
} catch (err) {
Promise = global.Promise
}

const crypto = require('crypto')

const Collection = require('../util/Collection')
Expand Down
3 changes: 2 additions & 1 deletion src/managers/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module.exports = {
Resolver: require('./Resolver'),
Transmitter: require('./Transmitter'),
Responder: require('./Responder')
Responder: require('./Responder'),
Crystal: require('./Crystal')
}
25 changes: 25 additions & 0 deletions src/resolvers/channel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module.exports = {
type: 'channel',
resolve: (content, { text = true, voice = true } = {}, msg) => {
const guild = msg.guild
content = String(content).toLowerCase()
let channel = content.match(/^<#?(\d{17,18})>$/)
if (!channel) {
let channels = guild.channels.filter(c => {
if (text && c.type !== 0) return
if (voice && c.type !== 2) return
const name = c.name.toLowerCase()
return name === content || name.includes(content)
})
if (channels.length) {
return Promise.resolve(channels)
} else {
return Promise.reject('channel.NOT_FOUND')
}
} else {
let chan = guild.channels.get(channel[1])
if (!chan) return Promise.reject('channel.NOT_FOUND')
return Promise.resolve([chan])
}
}
}
10 changes: 10 additions & 0 deletions src/resolvers/command.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module.exports = {
type: 'command',
resolve: (content, args, msg, { engine }) => {
const command = engine.commands.get(content.toLowerCase())
return !command ||
((command.options || {}).adminOnly && !process.env.ADMIN_IDS.split(', ').includes(msg.author.id))
? Promise.reject('command.NOT_FOUND')
: Promise.resolve(command)
}
}
Loading

0 comments on commit c8e2870

Please sign in to comment.