mirror of
https://github.com/roleypoly/roleypoly-v1.git
synced 2025-04-29 05:49:11 +00:00
[bot] break out RPC and shared packages for bot service breakout
This commit is contained in:
parent
544ae65c58
commit
50b5e334a3
31 changed files with 233 additions and 111 deletions
|
@ -22,9 +22,8 @@ APP_URL=http://localhost:6769
|
||||||
# CHANGE THIS ALWAYS. BUT EXACTLY ONCE.
|
# CHANGE THIS ALWAYS. BUT EXACTLY ONCE.
|
||||||
# signing key for sessions. changing this will invalidate all sessions.
|
# signing key for sessions. changing this will invalidate all sessions.
|
||||||
APP_KEY=PJoayPGqi8vfYVFYBDgSeJSDYUpzBX
|
APP_KEY=PJoayPGqi8vfYVFYBDgSeJSDYUpzBX
|
||||||
|
# shared secret for bot authenticated requests.
|
||||||
# does this instance start a bot?
|
SHARED_SECRET=EJ1LongZLRJgHBhkSROsGh8MeaE0YvMo
|
||||||
IS_BOT=true
|
|
||||||
|
|
||||||
# your and your friend's user ID for using admin tools.
|
# your and your friend's user ID for using admin tools.
|
||||||
ROOT_USERS=62601275618889721
|
ROOT_USERS=62601275618889721
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -9,3 +9,4 @@ yarn-error\.log
|
||||||
*.log
|
*.log
|
||||||
\.next/
|
\.next/
|
||||||
coverage/
|
coverage/
|
||||||
|
packages/*/lib
|
|
@ -5,7 +5,9 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lerna": "lerna",
|
"lerna": "lerna",
|
||||||
"start": "node packages/roleypoly-server/dist/index.js",
|
"start": "node packages/roleypoly-server/dist/index.js",
|
||||||
"dev": "babel-node packages/roleypoly-server/index.js",
|
"dev": "run-p dev:*",
|
||||||
|
"dev:backend": "babel-node packages/roleypoly-server/index.js",
|
||||||
|
"dev:bot": "babel-node packages/roleypoly-bot/index.js",
|
||||||
"build": "lerna run build",
|
"build": "lerna run build",
|
||||||
"flow:install": "flow-mono install-types",
|
"flow:install": "flow-mono install-types",
|
||||||
"flow": "flow",
|
"flow": "flow",
|
||||||
|
@ -77,7 +79,8 @@
|
||||||
"$Call"
|
"$Call"
|
||||||
],
|
],
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"flow-typed/*"
|
"flow-typed/*",
|
||||||
|
"packages/*/lib/*"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
packages/roleypoly-bot/.babelrc
Normal file
14
packages/roleypoly-bot/.babelrc
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"presets": [ ["@babel/preset-env", {
|
||||||
|
"targets": {
|
||||||
|
"node": true
|
||||||
|
}
|
||||||
|
}], "@babel/preset-flow" ],
|
||||||
|
"plugins": [
|
||||||
|
"@babel/plugin-syntax-dynamic-import",
|
||||||
|
"@babel/plugin-proposal-class-properties",
|
||||||
|
"@babel/plugin-proposal-optional-chaining",
|
||||||
|
["@babel/plugin-transform-runtime",
|
||||||
|
{ "helpers": false }]
|
||||||
|
]
|
||||||
|
}
|
0
packages/roleypoly-bot/Bot.js
Normal file
0
packages/roleypoly-bot/Bot.js
Normal file
5
packages/roleypoly-bot/index.js
Normal file
5
packages/roleypoly-bot/index.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
// @flow
|
||||||
|
import Bot from './Bot'
|
||||||
|
|
||||||
|
const B = new Bot()
|
||||||
|
B.start()
|
70
packages/roleypoly-bot/logger.js
Normal file
70
packages/roleypoly-bot/logger.js
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
// @flow
|
||||||
|
import chalk from 'chalk'
|
||||||
|
|
||||||
|
export class Logger {
|
||||||
|
debugOn: boolean
|
||||||
|
name: string
|
||||||
|
quietSql: boolean
|
||||||
|
|
||||||
|
constructor (name: string, debugOverride: boolean = false) {
|
||||||
|
this.name = name
|
||||||
|
this.debugOn = (process.env.DEBUG === 'true' || process.env.DEBUG === '*') || debugOverride
|
||||||
|
this.quietSql = (process.env.DEBUG_SQL !== 'true')
|
||||||
|
}
|
||||||
|
|
||||||
|
fatal (text: string, ...data: any) {
|
||||||
|
this.error(text, data)
|
||||||
|
|
||||||
|
if (typeof data[data.length - 1] === 'number') {
|
||||||
|
process.exit(data[data.length - 1])
|
||||||
|
} else {
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error (text: string, ...data: any) {
|
||||||
|
console.error(chalk.red.bold(`ERR ${this.name}:`) + `\n ${text}`, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
warn (text: string, ...data: any) {
|
||||||
|
console.warn(chalk.yellow.bold(`WARN ${this.name}:`) + `\n ${text}`, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
notice (text: string, ...data: any) {
|
||||||
|
console.log(chalk.cyan.bold(`NOTICE ${this.name}:`) + `\n ${text}`, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
info (text: string, ...data: any) {
|
||||||
|
console.info(chalk.blue.bold(`INFO ${this.name}:`) + `\n ${text}`, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
bot (text: string, ...data: any) {
|
||||||
|
console.log(chalk.yellowBright.bold(`BOT CMD:`) + `\n ${text}`, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
deprecated (text: string, ...data: any) {
|
||||||
|
console.warn(chalk.yellowBright(`DEPRECATED ${this.name}:`) + `\n ${text}`, data)
|
||||||
|
console.trace()
|
||||||
|
}
|
||||||
|
|
||||||
|
request (text: string, ...data: any) {
|
||||||
|
console.info(chalk.green.bold(`HTTP ${this.name}:`) + `\n ${text}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
debug (text: string, ...data: any) {
|
||||||
|
if (this.debugOn) {
|
||||||
|
console.log(chalk.gray.bold(`DEBUG ${this.name}:`) + `\n ${text}`, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sql (logger: Logger, ...data: any) {
|
||||||
|
if (logger.debugOn && !logger.quietSql) {
|
||||||
|
console.log(chalk.bold('DEBUG SQL:\n '), data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (pathname: string) => {
|
||||||
|
const name = pathname.replace(__dirname, '').replace('.js', '')
|
||||||
|
return new Logger(name)
|
||||||
|
}
|
17
packages/roleypoly-bot/package.json
Normal file
17
packages/roleypoly-bot/package.json
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"name": "@roleypoly/bot",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"build": "babel --delete-dir-on-start -d lib .",
|
||||||
|
"dev": "yarn build --watch"
|
||||||
|
},
|
||||||
|
"main": "./lib/Bot.js",
|
||||||
|
"dependencies": {
|
||||||
|
"eris": "^0.9.0",
|
||||||
|
"@roleypoly/rpc-client": "2.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/cli": "^7.4.3"
|
||||||
|
}
|
||||||
|
}
|
14
packages/roleypoly-rpc-client/.babelrc
Normal file
14
packages/roleypoly-rpc-client/.babelrc
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"presets": [ ["@babel/preset-env", {
|
||||||
|
"targets": {
|
||||||
|
"node": true
|
||||||
|
}
|
||||||
|
}], "@babel/preset-flow" ],
|
||||||
|
"plugins": [
|
||||||
|
"@babel/plugin-syntax-dynamic-import",
|
||||||
|
"@babel/plugin-proposal-class-properties",
|
||||||
|
"@babel/plugin-proposal-optional-chaining",
|
||||||
|
["@babel/plugin-transform-runtime",
|
||||||
|
{ "helpers": false }]
|
||||||
|
]
|
||||||
|
}
|
21
packages/roleypoly-rpc-client/error.js
Normal file
21
packages/roleypoly-rpc-client/error.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// @flow
|
||||||
|
import type { RPCResponse } from './index'
|
||||||
|
|
||||||
|
class RPCError extends Error {
|
||||||
|
code: ?number
|
||||||
|
extra: any[]
|
||||||
|
remoteStack: ?string
|
||||||
|
constructor (msg: string, code?: number, ...extra: any[]) {
|
||||||
|
super(msg)
|
||||||
|
this.code = code
|
||||||
|
this.extra = extra
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromResponse (body: RPCResponse, status: number) {
|
||||||
|
const e = new RPCError(body.msg, status)
|
||||||
|
e.remoteStack = body.trace
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = RPCError
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import superagent from 'superagent'
|
import superagent from 'superagent'
|
||||||
import RPCError from '@roleypoly/server/rpc/_error'
|
import RPCError from './error'
|
||||||
|
|
||||||
export type RPCResponse = {
|
export type RPCResponse = {
|
||||||
response?: mixed,
|
response?: mixed,
|
||||||
|
@ -8,7 +8,7 @@ export type RPCResponse = {
|
||||||
|
|
||||||
// error stuff
|
// error stuff
|
||||||
error?: boolean,
|
error?: boolean,
|
||||||
msg?: string,
|
msg: string,
|
||||||
trace?: string
|
trace?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,10 @@ export default class RPCClient {
|
||||||
recentHash: string
|
recentHash: string
|
||||||
cookieHeader: string
|
cookieHeader: string
|
||||||
|
|
||||||
|
headerMixins: {
|
||||||
|
[x:string]: string
|
||||||
|
} = {}
|
||||||
|
|
||||||
rpc: {
|
rpc: {
|
||||||
[fn: string]: (...args: any[]) => Promise<any>
|
[fn: string]: (...args: any[]) => Promise<any>
|
||||||
} = {}
|
} = {}
|
||||||
|
@ -55,7 +59,12 @@ export default class RPCClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
withCookies = (h: string) => {
|
withCookies = (h: string) => {
|
||||||
this.cookieHeader = h
|
this.headerMixins['Set-Cookie'] = h
|
||||||
|
return this.rpc
|
||||||
|
}
|
||||||
|
|
||||||
|
withBotAuth = (h: string) => {
|
||||||
|
this.headerMixins['Authorization'] = `Bot ${h}`
|
||||||
return this.rpc
|
return this.rpc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,12 +94,11 @@ export default class RPCClient {
|
||||||
|
|
||||||
async call (fn: string, ...args: any[]): mixed {
|
async call (fn: string, ...args: any[]): mixed {
|
||||||
const req: RPCRequest = { fn, args }
|
const req: RPCRequest = { fn, args }
|
||||||
const rq = superagent.post(this.baseUrl)
|
const rq = superagent.post(this.baseUrl).set({ ...this.headerMixins })
|
||||||
if (this.cookieHeader != null) {
|
|
||||||
rq.cookies = this.cookieHeader
|
|
||||||
}
|
|
||||||
const rsp = await rq.send(req).ok(() => true)
|
const rsp = await rq.send(req).ok(() => true)
|
||||||
const body: RPCResponse = rsp.body
|
const body: RPCResponse = rsp.body
|
||||||
|
|
||||||
// console.log(body)
|
// console.log(body)
|
||||||
if (body.error === true) {
|
if (body.error === true) {
|
||||||
console.error(body)
|
console.error(body)
|
16
packages/roleypoly-rpc-client/package.json
Normal file
16
packages/roleypoly-rpc-client/package.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"name": "@roleypoly/rpc-client",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"postinstall": "yarn build",
|
||||||
|
"build": "babel --delete-dir-on-start -d lib ."
|
||||||
|
},
|
||||||
|
"main": "./lib/index.js",
|
||||||
|
"dependencies": {
|
||||||
|
"superagent":"^5.0.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/cli": "^7.4.3"
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,7 +34,8 @@ export type AppContext = {
|
||||||
config: {
|
config: {
|
||||||
appUrl: string,
|
appUrl: string,
|
||||||
dev: boolean,
|
dev: boolean,
|
||||||
hotReload: boolean
|
hotReload: boolean,
|
||||||
|
sharedSecret: string
|
||||||
},
|
},
|
||||||
ui: Next,
|
ui: Next,
|
||||||
uiHandler: Next.Handler,
|
uiHandler: Next.Handler,
|
||||||
|
@ -85,7 +86,8 @@ class Roleypoly {
|
||||||
config: {
|
config: {
|
||||||
appUrl,
|
appUrl,
|
||||||
dev,
|
dev,
|
||||||
hotReload: process.env.NO_HOT_RELOAD !== '1'
|
hotReload: process.env.NO_HOT_RELOAD !== '1',
|
||||||
|
sharedSecret: process.env.SHARED_SECRET
|
||||||
},
|
},
|
||||||
io,
|
io,
|
||||||
ui,
|
ui,
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
// @flow
|
|
||||||
import type DiscordService from '../services/discord'
|
|
||||||
import logger from '../logger'
|
|
||||||
const log = logger(__filename)
|
|
||||||
|
|
||||||
export default class Bot {
|
|
||||||
svc: DiscordService
|
|
||||||
log: typeof log
|
|
||||||
constructor (DS: DiscordService) {
|
|
||||||
this.svc = DS
|
|
||||||
this.log = log
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,7 +3,6 @@
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "babel-node index.js",
|
|
||||||
"start": "NODE_ENV=production node dist/index.js",
|
"start": "NODE_ENV=production node dist/index.js",
|
||||||
"pretest": "standard --fix",
|
"pretest": "standard --fix",
|
||||||
"build": "NODE_ENV=production babel --delete-dir-on-start -d dist ."
|
"build": "NODE_ENV=production babel --delete-dir-on-start -d dist ."
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
class RPCError extends Error {
|
|
||||||
constructor (msg, code, ...extra) {
|
|
||||||
super(msg)
|
|
||||||
this.code = code
|
|
||||||
this.extra = extra
|
|
||||||
}
|
|
||||||
|
|
||||||
static fromResponse (body, status) {
|
|
||||||
const e = new RPCError(body.msg, status)
|
|
||||||
e.remoteStack = body.trace
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = RPCError
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { type AppContext } from '../Roleypoly'
|
import { type AppContext } from '../Roleypoly'
|
||||||
import { type Context } from 'koa'
|
import { type Context } from 'koa'
|
||||||
import RPCError from './_error'
|
import RPCError from '@roleypoly/rpc-client/error'
|
||||||
|
|
||||||
import logger from '../logger'
|
import logger from '../logger'
|
||||||
const log = logger(__filename)
|
const log = logger(__filename)
|
||||||
|
@ -122,6 +122,29 @@ export const any = (
|
||||||
silent: boolean = false
|
silent: boolean = false
|
||||||
) => (...args: any) => fn(...args)
|
) => (...args: any) => fn(...args)
|
||||||
|
|
||||||
|
export const bot = (
|
||||||
|
$: AppContext,
|
||||||
|
fn: (ctx: Context, ...args: any[]) => any,
|
||||||
|
silent: boolean = false
|
||||||
|
) => (
|
||||||
|
ctx: Context,
|
||||||
|
...args: any
|
||||||
|
) => {
|
||||||
|
const authToken: ?string = ctx.request.headers['Authorization']
|
||||||
|
|
||||||
|
if (authToken != null && authToken.startsWith('Bot ')) {
|
||||||
|
if (authToken === `Bot ${$.config.sharedSecret}`) {
|
||||||
|
return fn(ctx, ...args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!silent) {
|
||||||
|
log.info('RPC bot check failed', logFacts(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
throw PermissionError
|
||||||
|
}
|
||||||
|
|
||||||
type Handler = (ctx: Context, ...args: any[]) => any
|
type Handler = (ctx: Context, ...args: any[]) => any
|
||||||
type Strategy = (
|
type Strategy = (
|
||||||
$: AppContext,
|
$: AppContext,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import fnv from 'fnv-plus'
|
import fnv from 'fnv-plus'
|
||||||
import autoloader from './_autoloader'
|
import autoloader from './_autoloader'
|
||||||
import RPCError from './_error'
|
import RPCError from '@roleypoly/rpc-client/error'
|
||||||
import type Roleypoly, { Router } from '../Roleypoly'
|
import type Roleypoly, { Router } from '../Roleypoly'
|
||||||
import type { Context } from 'koa'
|
import type { Context } from 'koa'
|
||||||
// import logger from '../logger'
|
// import logger from '../logger'
|
||||||
|
@ -121,7 +121,6 @@ export default class RPCServer {
|
||||||
if (err instanceof RPCError || err.constructor.name === 'RPCError') {
|
if (err instanceof RPCError || err.constructor.name === 'RPCError') {
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
ctx.status = err.code
|
ctx.status = err.code
|
||||||
console.log(err.code)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { type AppContext } from '../Roleypoly'
|
||||||
import { type Context } from 'koa'
|
import { type Context } from 'koa'
|
||||||
import { type Guild } from 'eris'
|
import { type Guild } from 'eris'
|
||||||
import * as secureAs from './_security'
|
import * as secureAs from './_security'
|
||||||
import RPCError from './_error'
|
import RPCError from '@roleypoly/rpc-client/error'
|
||||||
|
|
||||||
export default ($: AppContext) => ({
|
export default ($: AppContext) => ({
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,8 @@ import * as secureAs from './_security'
|
||||||
export default ($: AppContext) => ({
|
export default ($: AppContext) => ({
|
||||||
|
|
||||||
getCurrentUser: secureAs.authed($, async (ctx: Context) => {
|
getCurrentUser: secureAs.authed($, async (ctx: Context) => {
|
||||||
return $.discord.getUserPartial(ctx.session.userId)
|
const u = await $.discord.getUserPartial(ctx.session.userId)
|
||||||
|
return u
|
||||||
}),
|
}),
|
||||||
|
|
||||||
isRoot: secureAs.root($, () => {
|
isRoot: secureAs.root($, () => {
|
||||||
|
|
|
@ -31,20 +31,25 @@ export default class AuthService extends Service {
|
||||||
async isLoggedIn (ctx: Context, { refresh = false }: { refresh: boolean } = {}) {
|
async isLoggedIn (ctx: Context, { refresh = false }: { refresh: boolean } = {}) {
|
||||||
const { userId, expiresAt, authType } = ctx.session
|
const { userId, expiresAt, authType } = ctx.session
|
||||||
if (userId == null) {
|
if (userId == null) {
|
||||||
|
this.log.debug('isLoggedIn failed, no userId', ctx.session)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expiresAt < Date.now()) {
|
if (expiresAt < Date.now()) {
|
||||||
|
this.log.debug('session has expired.', expiresAt, Date.now())
|
||||||
if (refresh && authType === 'oauth') {
|
if (refresh && authType === 'oauth') {
|
||||||
|
this.log.debug('was oauth and we can refresh')
|
||||||
const tokens = await this.ctx.discord.refreshOAuth(ctx.session)
|
const tokens = await this.ctx.discord.refreshOAuth(ctx.session)
|
||||||
this.injectSessionFromOAuth(ctx, tokens, userId)
|
this.injectSessionFromOAuth(ctx, tokens, userId)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.log.debug('was not oauth, we are destroying the session')
|
||||||
ctx.session = null // reset session as well
|
ctx.session = null // reset session as well
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.log.debug('this user is logged in', userId)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import Service from './Service'
|
import Service from './Service'
|
||||||
import type { AppContext } from '../Roleypoly'
|
import type { AppContext } from '../Roleypoly'
|
||||||
import Bot from '../bot'
|
|
||||||
import Eris, { type Member, Role, type Guild, type Permission as ErisPermission } from 'eris'
|
import Eris, { type Member, Role, type Guild, type Permission as ErisPermission } from 'eris'
|
||||||
import LRU from 'lru-cache'
|
import LRU from 'lru-cache'
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
|
@ -9,13 +8,13 @@ import { OrderedSet } from 'immutable'
|
||||||
import superagent from 'superagent'
|
import superagent from 'superagent'
|
||||||
import type { AuthTokens } from './auth'
|
import type { AuthTokens } from './auth'
|
||||||
import type { IFetcher } from './discord/types'
|
import type { IFetcher } from './discord/types'
|
||||||
|
import RestFetcher from './discord/restFetcher'
|
||||||
|
|
||||||
type DiscordServiceConfig = {
|
type DiscordServiceConfig = {
|
||||||
token: string,
|
token: string,
|
||||||
clientId: string,
|
clientId: string,
|
||||||
clientSecret: string,
|
clientSecret: string,
|
||||||
rootUsers: Set<string>,
|
rootUsers: Set<string>
|
||||||
isBot: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Permissions = {
|
export type Permissions = {
|
||||||
|
@ -56,7 +55,6 @@ export type MemberExt = Member & {
|
||||||
|
|
||||||
export default class DiscordService extends Service {
|
export default class DiscordService extends Service {
|
||||||
ctx: AppContext
|
ctx: AppContext
|
||||||
bot: Bot
|
|
||||||
client: Eris
|
client: Eris
|
||||||
|
|
||||||
cfg: DiscordServiceConfig
|
cfg: DiscordServiceConfig
|
||||||
|
@ -77,8 +75,7 @@ export default class DiscordService extends Service {
|
||||||
rootUsers: new Set((process.env.ROOT_USERS || '').split(',')),
|
rootUsers: new Set((process.env.ROOT_USERS || '').split(',')),
|
||||||
token: process.env.DISCORD_BOT_TOKEN || '',
|
token: process.env.DISCORD_BOT_TOKEN || '',
|
||||||
clientId: process.env.DISCORD_CLIENT_ID || '',
|
clientId: process.env.DISCORD_CLIENT_ID || '',
|
||||||
clientSecret: process.env.DISCORD_CLIENT_SECRET || '',
|
clientSecret: process.env.DISCORD_CLIENT_SECRET || ''
|
||||||
isBot: process.env.IS_BOT === 'true'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.oauthCallback = `${ctx.config.appUrl}/api/oauth/callback`
|
this.oauthCallback = `${ctx.config.appUrl}/api/oauth/callback`
|
||||||
|
@ -86,37 +83,12 @@ export default class DiscordService extends Service {
|
||||||
this.ownRoleCache = new LRU()
|
this.ownRoleCache = new LRU()
|
||||||
this.topRoleCache = new LRU()
|
this.topRoleCache = new LRU()
|
||||||
|
|
||||||
if (this.cfg.isBot) {
|
|
||||||
this.client = new Eris(this.cfg.token, {
|
|
||||||
disableEveryone: true,
|
|
||||||
maxShards: 'auto',
|
|
||||||
messageLimit: 10,
|
|
||||||
disableEvents: {
|
|
||||||
CHANNEL_PINS_UPDATE: true,
|
|
||||||
USER_SETTINGS_UPDATE: true,
|
|
||||||
USER_NOTE_UPDATE: true,
|
|
||||||
RELATIONSHIP_ADD: true,
|
|
||||||
RELATIONSHIP_REMOVE: true,
|
|
||||||
GUILD_BAN_ADD: true,
|
|
||||||
GUILD_BAN_REMOVE: true,
|
|
||||||
TYPING_START: true,
|
|
||||||
MESSAGE_UPDATE: true,
|
|
||||||
MESSAGE_DELETE: true,
|
|
||||||
MESSAGE_DELETE_BULK: true,
|
|
||||||
VOICE_STATE_UPDATE: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.bot = new Bot(this)
|
|
||||||
const BotFetcher = require('./discord/botFetcher').default
|
|
||||||
this.fetcher = new BotFetcher(this)
|
|
||||||
} else {
|
|
||||||
this.client = new Eris(`Bot ${this.cfg.token}`, {
|
this.client = new Eris(`Bot ${this.cfg.token}`, {
|
||||||
restMode: true
|
restMode: true
|
||||||
})
|
})
|
||||||
const RestFetcher = require('./discord/restFetcher').default
|
|
||||||
this.fetcher = new RestFetcher(this)
|
this.fetcher = new RestFetcher(this)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
isRoot (id: string): boolean {
|
isRoot (id: string): boolean {
|
||||||
return this.cfg.rootUsers.has(id)
|
return this.cfg.rootUsers.has(id)
|
||||||
|
@ -272,6 +244,7 @@ export default class DiscordService extends Service {
|
||||||
async getUserPartial (userId: string): Promise<?UserPartial> {
|
async getUserPartial (userId: string): Promise<?UserPartial> {
|
||||||
const u = await this.fetcher.getUser(userId)
|
const u = await this.fetcher.getUser(userId)
|
||||||
if (u == null) {
|
if (u == null) {
|
||||||
|
this.log.debug('userPartial got a null user', userId, u)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
// @flow
|
|
||||||
import type { IFetcher } from './types'
|
|
||||||
import type DiscordSvc from '../discord'
|
|
||||||
import type ErisClient, { User, Member, Guild } from 'eris'
|
|
||||||
|
|
||||||
export default class BotFetcher implements IFetcher {
|
|
||||||
ctx: DiscordSvc
|
|
||||||
client: ErisClient
|
|
||||||
constructor (ctx: DiscordSvc) {
|
|
||||||
this.ctx = ctx
|
|
||||||
this.client = ctx.client
|
|
||||||
}
|
|
||||||
|
|
||||||
getUser = async (id: string): Promise<?User> =>
|
|
||||||
this.client.users.get(id)
|
|
||||||
|
|
||||||
getMember = async (server: string, user: string): Promise<?Member> =>
|
|
||||||
this.client.guilds.get(server)?.members.get(user)
|
|
||||||
|
|
||||||
getGuild = async (server: string): Promise<?Guild> =>
|
|
||||||
this.client.guilds.get(server)
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
import RPCClient from '../rpc'
|
import RPCClient from '@roleypoly/rpc-client'
|
||||||
|
|
||||||
const client = new RPCClient({ forceDev: false })
|
const client = new RPCClient({ forceDev: false })
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@roleypoly/types": "^2.0.0",
|
"@roleypoly/types": "^2.0.0",
|
||||||
|
"@roleypoly/rpc-client": "^2.0.0",
|
||||||
"color": "^3.1.0",
|
"color": "^3.1.0",
|
||||||
"eventemitter3": "^3.1.0",
|
"eventemitter3": "^3.1.0",
|
||||||
"fast-redux": "^0.7.1",
|
"fast-redux": "^0.7.1",
|
||||||
|
|
|
@ -42,6 +42,7 @@ class RoleypolyApp extends App {
|
||||||
ctx.user = user
|
ctx.user = user
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.code === 403) {
|
if (e.code === 403) {
|
||||||
|
console.error('user not found')
|
||||||
ctx.user = null
|
ctx.user = null
|
||||||
} else {
|
} else {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
|
|
|
@ -3,7 +3,7 @@ import * as React from 'react'
|
||||||
import Head from 'next/head'
|
import Head from 'next/head'
|
||||||
import type { PageProps } from '../../types'
|
import type { PageProps } from '../../types'
|
||||||
import SocialCards from '../../components/social-cards'
|
import SocialCards from '../../components/social-cards'
|
||||||
import redirect from '../../lib/redirect'
|
import redirect from '../../util/redirect'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { fetchServerIfNeed, getCurrentServerState, type ServerState } from '../../stores/currentServer'
|
import { fetchServerIfNeed, getCurrentServerState, type ServerState } from '../../stores/currentServer'
|
||||||
import { renderRoles, getCategoryViewState, toggleRole, type ViewState } from '../../stores/roles'
|
import { renderRoles, getCategoryViewState, toggleRole, type ViewState } from '../../stores/roles'
|
||||||
|
|
|
@ -4,7 +4,7 @@ import styled from 'styled-components'
|
||||||
import { md } from '../../kit/media'
|
import { md } from '../../kit/media'
|
||||||
import DiscordButton from '../../components/discord-button'
|
import DiscordButton from '../../components/discord-button'
|
||||||
import RPC from '../../config/rpc'
|
import RPC from '../../config/rpc'
|
||||||
import redirect from '../../lib/redirect'
|
import redirect from '../../util/redirect'
|
||||||
import dynamic from 'next/dynamic'
|
import dynamic from 'next/dynamic'
|
||||||
import type { PageProps } from '../../types'
|
import type { PageProps } from '../../types'
|
||||||
import type { ServerSlug } from '@roleypoly/types'
|
import type { ServerSlug } from '@roleypoly/types'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import redirect from '../lib/redirect'
|
import redirect from '../util/redirect'
|
||||||
// import Link from 'next/link'
|
// import Link from 'next/link'
|
||||||
// import Head from '../components/head'
|
// import Head from '../components/head'
|
||||||
// import Nav from '../components/nav'
|
// import Nav from '../components/nav'
|
||||||
|
|
|
@ -10769,7 +10769,7 @@ standard-engine@~9.0.0:
|
||||||
minimist "^1.1.0"
|
minimist "^1.1.0"
|
||||||
pkg-conf "^2.0.0"
|
pkg-conf "^2.0.0"
|
||||||
|
|
||||||
standard@12.0.1:
|
standard@12.0.1, standard@^12.0.1:
|
||||||
version "12.0.1"
|
version "12.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/standard/-/standard-12.0.1.tgz#0fc5a8aa6c34c546c5562aae644242b24dae2e61"
|
resolved "https://registry.yarnpkg.com/standard/-/standard-12.0.1.tgz#0fc5a8aa6c34c546c5562aae644242b24dae2e61"
|
||||||
integrity sha512-UqdHjh87OG2gUrNCSM4QRLF5n9h3TFPwrCNyVlkqu31Hej0L/rc8hzKqVvkb2W3x0WMq7PzZdkLfEcBhVOR6lg==
|
integrity sha512-UqdHjh87OG2gUrNCSM4QRLF5n9h3TFPwrCNyVlkqu31Hej0L/rc8hzKqVvkb2W3x0WMq7PzZdkLfEcBhVOR6lg==
|
||||||
|
|
Loading…
Add table
Reference in a new issue