mirror of
https://github.com/roleypoly/roleypoly-v1.git
synced 2025-04-26 04:29:11 +00:00
temp commit
This commit is contained in:
parent
e86f7ff68e
commit
6fb39d6c4d
22 changed files with 282 additions and 39 deletions
|
@ -11,3 +11,4 @@
|
||||||
esproposal.optional_chaining=enable
|
esproposal.optional_chaining=enable
|
||||||
munge_underscores=true
|
munge_underscores=true
|
||||||
emoji=true
|
emoji=true
|
||||||
|
esproposal.export_star_as=enable
|
|
@ -1,6 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
import Eris, { type Message, type TextChannel } from 'eris'
|
import Eris, { type Message, type TextChannel, type Guild } from 'eris'
|
||||||
import logger from './logger.js'
|
|
||||||
import RPCClient from '@roleypoly/rpc-client'
|
import RPCClient from '@roleypoly/rpc-client'
|
||||||
import randomEmoji from './random-emoji'
|
import randomEmoji from './random-emoji'
|
||||||
import DMCommands from './commands/dm'
|
import DMCommands from './commands/dm'
|
||||||
|
@ -8,6 +7,8 @@ import TextCommands from './commands/text'
|
||||||
import RootCommands from './commands/root'
|
import RootCommands from './commands/root'
|
||||||
import type { Command } from './commands/_types'
|
import type { Command } from './commands/_types'
|
||||||
import retry from 'async-retry'
|
import retry from 'async-retry'
|
||||||
|
|
||||||
|
import logger from './logger'
|
||||||
const log = logger(__filename)
|
const log = logger(__filename)
|
||||||
|
|
||||||
export type BotConfig = $Shape<{
|
export type BotConfig = $Shape<{
|
||||||
|
@ -228,8 +229,18 @@ export default class Bot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async syncGuild (type: string, guild: Guild) {
|
||||||
|
await this.rpc.syncGuild(type, guild.id)
|
||||||
|
}
|
||||||
|
|
||||||
async start () {
|
async start () {
|
||||||
this.client.on('messageCreate', this.handleMessage)
|
this.client.on('messageCreate', this.handleMessage)
|
||||||
|
|
||||||
|
const guildSyncTriggers = ['guildCreate', 'guildDelete', 'guildRoleAdd', 'guildRoleDelete', 'guildRoleUpdate']
|
||||||
|
for (const trigger of guildSyncTriggers) {
|
||||||
|
this.client.on(trigger, this.syncGuild.bind(this, trigger))
|
||||||
|
}
|
||||||
|
|
||||||
await this.client.connect()
|
await this.client.connect()
|
||||||
log.info('started bot')
|
log.info('started bot')
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
"dev": "yarn build --watch"
|
"dev": "yarn build --watch"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@roleypoly/rpc-client": "2.0.0",
|
|
||||||
"async-retry": "^1.2.3",
|
"async-retry": "^1.2.3",
|
||||||
"dotenv": "^7.0.0",
|
"dotenv": "^7.0.0",
|
||||||
"eris": "^0.9.0"
|
"eris": "^0.9.0"
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
"dev": "yarn build --watch",
|
"dev": "yarn build --watch",
|
||||||
"postinstall": "test -d lib || npm run build"
|
"postinstall": "test -d lib || npm run build"
|
||||||
},
|
},
|
||||||
"types": "src/",
|
"types": "src/index.js",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"files": ["lib"],
|
"files": ["lib"],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
// @flow
|
// @flow
|
||||||
import superagent from 'superagent'
|
import superagent from 'superagent'
|
||||||
import RPCError from './error'
|
import RPCError from './error.js'
|
||||||
import retry from 'async-retry'
|
import retry from 'async-retry'
|
||||||
|
|
||||||
|
export { RPCError }
|
||||||
|
|
||||||
export type RPCResponse = {
|
export type RPCResponse = {
|
||||||
response?: mixed,
|
response?: mixed,
|
||||||
hash?: string,
|
hash?: string,
|
||||||
|
|
11
packages/roleypoly-rpc-server/.babelrc
Normal file
11
packages/roleypoly-rpc-server/.babelrc
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"presets": [ ["@babel/preset-env", { "targets": {"node": "current"} }], "@babel/preset-flow" ],
|
||||||
|
"plugins": [
|
||||||
|
"@babel/plugin-syntax-dynamic-import",
|
||||||
|
"@babel/plugin-proposal-class-properties",
|
||||||
|
"@babel/plugin-proposal-optional-chaining",
|
||||||
|
"@babel/plugin-proposal-export-namespace-from",
|
||||||
|
["@babel/plugin-transform-runtime",
|
||||||
|
{ "helpers": false }]
|
||||||
|
]
|
||||||
|
}
|
24
packages/roleypoly-rpc-server/package.json
Normal file
24
packages/roleypoly-rpc-server/package.json
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"name": "@roleypoly/rpc-server",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"build": "babel -d ./lib ./src",
|
||||||
|
"dev": "yarn build --watch",
|
||||||
|
"postinstall": "test -d lib || npm run build"
|
||||||
|
},
|
||||||
|
"types": "src/index.js",
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"files": [
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"async-retry": "^1.2.3",
|
||||||
|
"glob": "^7.1.3",
|
||||||
|
"nats": "^1.2.10"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/cli": "^7.4.3",
|
||||||
|
"@babel/plugin-proposal-export-namespace-from": "^7.2.0"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,22 +1,21 @@
|
||||||
// @flow
|
// @flow
|
||||||
import logger from '../logger'
|
import logger from './logger'
|
||||||
import glob from 'glob'
|
import glob from 'glob'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { type AppContext } from '../Roleypoly'
|
|
||||||
|
|
||||||
const log = logger(__filename)
|
const log = logger(__filename)
|
||||||
const PROD: boolean = process.env.NODE_ENV === 'production'
|
const PROD: boolean = process.env.NODE_ENV === 'production'
|
||||||
|
|
||||||
export default (ctx: AppContext, forceClear: ?boolean = false): {
|
export default (globString: string, ctx: any, forceClear: ?boolean = false): {
|
||||||
[rpc: string]: Function
|
[rpc: string]: Function
|
||||||
} => {
|
} => {
|
||||||
let map = {}
|
let map = {}
|
||||||
const apis = glob.sync(`${__dirname}/**/!(index).js`).map(v => v.replace(__dirname, '.'))
|
const apis = glob.sync(globString)
|
||||||
log.debug('found rpcs', apis)
|
log.debug('found rpcs', apis)
|
||||||
|
|
||||||
for (let a of apis) {
|
for (let a of apis) {
|
||||||
const filename = path.basename(a)
|
const filename = path.basename(a)
|
||||||
const dirname = path.dirname(a)
|
// const dirname = path.dirname(a)
|
||||||
|
|
||||||
const pathname = a
|
const pathname = a
|
||||||
delete require.cache[require.resolve(pathname)]
|
delete require.cache[require.resolve(pathname)]
|
||||||
|
@ -27,11 +26,6 @@ export default (ctx: AppContext, forceClear: ?boolean = false): {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dirname === 'client') {
|
|
||||||
log.debug(`skipping ${a}`)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// testing only
|
// testing only
|
||||||
if (filename.endsWith('_test.js') && PROD) {
|
if (filename.endsWith('_test.js') && PROD) {
|
||||||
log.debug(`skipping ${a}`)
|
log.debug(`skipping ${a}`)
|
|
@ -1,9 +1,10 @@
|
||||||
// @flow
|
// @flow
|
||||||
import fnv from 'fnv-plus'
|
import fnv from 'fnv-plus'
|
||||||
import autoloader from './_autoloader'
|
import autoloader from './autoloader'
|
||||||
import RPCError from '@roleypoly/rpc-client/error'
|
import { RPCError } from '@roleypoly/rpc-client'
|
||||||
import type Roleypoly, { Router } from '../Roleypoly'
|
import type Roleypoly, { Router } from '@roleypoly/server/Roleypoly'
|
||||||
import type { Context } from 'koa'
|
import type { Context } from 'koa'
|
||||||
|
export * as secureAs from './security'
|
||||||
// import logger from '../logger'
|
// import logger from '../logger'
|
||||||
// const log = logger(__filename)
|
// const log = logger(__filename)
|
||||||
|
|
||||||
|
@ -68,7 +69,7 @@ export default class RPCServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if RPC exists
|
// check if RPC exists
|
||||||
const { fn, args } = (ctx.request.body: RPCIncoming)
|
const { fn, args } = ((ctx.request.body: any): RPCIncoming)
|
||||||
|
|
||||||
if (!(fn in this.rpcMap)) {
|
if (!(fn in this.rpcMap)) {
|
||||||
return this.rpcError(ctx, null, new RPCError(`RPC call ${fn}(...) not found.`, 404))
|
return this.rpcError(ctx, null, new RPCError(`RPC call ${fn}(...) not found.`, 404))
|
70
packages/roleypoly-rpc-server/src/logger.js
Normal file
70
packages/roleypoly-rpc-server/src/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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc (call: string, ...data: any) {
|
||||||
|
console.log(chalk.redBright.bold`RPC` + chalk.redBright(` ${call}():`), 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)
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { type AppContext } from '../Roleypoly'
|
import { type AppContext } from '@roleypoly/server/Roleypoly'
|
||||||
import { type Context } from 'koa'
|
import { type Context } from 'koa'
|
||||||
import RPCError from '@roleypoly/rpc-client/error'
|
import { RPCError } from '@roleypoly/rpc-client'
|
||||||
|
|
||||||
import logger from '../logger'
|
import logger from '../../roleypoly-server/logger'
|
||||||
const log = logger(__filename)
|
const log = logger(__filename)
|
||||||
|
|
||||||
const PermissionError = new RPCError('User does not have permission to call this RPC.', 403)
|
const PermissionError = new RPCError('User does not have permission to call this RPC.', 403)
|
|
@ -10,7 +10,7 @@ import DiscordService from './services/discord'
|
||||||
import SessionService from './services/sessions'
|
import SessionService from './services/sessions'
|
||||||
import AuthService from './services/auth'
|
import AuthService from './services/auth'
|
||||||
import PresentationService from './services/presentation'
|
import PresentationService from './services/presentation'
|
||||||
import RPCServer from './rpc'
|
import RPCServer from '@roleypoly/rpc-server'
|
||||||
import fetchModels, { type Models } from './models'
|
import fetchModels, { type Models } from './models'
|
||||||
import fetchApis from './api'
|
import fetchApis from './api'
|
||||||
import retry from 'async-retry'
|
import retry from 'async-retry'
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/uws": "^11.149.1",
|
"@discordjs/uws": "^11.149.1",
|
||||||
"@roleypoly/types": "^2.0.0",
|
"@roleypoly/types": "^2.0.0",
|
||||||
|
"@roleypoly/rpc-server": "^2.0.0",
|
||||||
"@roleypoly/ui": "^2.0.0",
|
"@roleypoly/ui": "^2.0.0",
|
||||||
"async-retry": "^1.2.3",
|
"async-retry": "^1.2.3",
|
||||||
"bufferutil": "^4.0.1",
|
"bufferutil": "^4.0.1",
|
||||||
|
|
|
@ -2,18 +2,18 @@
|
||||||
import { type AppContext } from '../Roleypoly'
|
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 { secureAs } from '@roleypoly/rpc-server'
|
||||||
import RPCError from '@roleypoly/rpc-client/error'
|
import { RPCError } from '@roleypoly/rpc-client'
|
||||||
|
|
||||||
export default ($: AppContext) => ({
|
export default ($: AppContext) => ({
|
||||||
|
|
||||||
rootGetAllServers: secureAs.root($, (ctx: Context) => {
|
rootGetAllServers: secureAs.root($, (ctx: Context) => {
|
||||||
return $.discord.client.guilds.map<{
|
return $.discord.guilds.valueSeq().map<{
|
||||||
url: string,
|
url: string,
|
||||||
name: string,
|
name: string,
|
||||||
members: number,
|
members: number,
|
||||||
roles: number
|
roles: number
|
||||||
}>((g: Guild) => ({ url: `${$.config.appUrl}/s/${g.id}`, name: g.name, members: g.memberCount, roles: g.roles.size }))
|
}>((g: Guild) => ({ url: `${$.config.appUrl}/s/${g.id}`, name: g.name, members: g.members.size, roles: g.roles.size })).toJS()
|
||||||
}),
|
}),
|
||||||
|
|
||||||
getServerSlug (ctx: Context, id: string) {
|
getServerSlug (ctx: Context, id: string) {
|
||||||
|
@ -40,5 +40,18 @@ export default ($: AppContext) => ({
|
||||||
}
|
}
|
||||||
|
|
||||||
return $.P.presentableServer(srv, gm)
|
return $.P.presentableServer(srv, gm)
|
||||||
|
}),
|
||||||
|
|
||||||
|
listOwnServers: secureAs.authed($, async (ctx: Context, id: string) => {
|
||||||
|
const { userId } = (ctx.session: { userId: string })
|
||||||
|
const srv = $.discord.getRelevantServers(userId)
|
||||||
|
return $.P.presentableServers(srv, userId)
|
||||||
|
}),
|
||||||
|
|
||||||
|
syncGuild: secureAs.bot($, async (ctx: Context, type: string, guildId: string) => {
|
||||||
|
const g = await $.discord.guild(guildId, true)
|
||||||
|
if (g != null && type === 'guildCreate') {
|
||||||
|
$.server.ensure(g)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -4,7 +4,7 @@ import type { AppContext } from '../Roleypoly'
|
||||||
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
|
||||||
import { OrderedSet } from 'immutable'
|
import { OrderedSet, OrderedMap } 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'
|
||||||
|
@ -54,6 +54,8 @@ export type MemberExt = Member & {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class DiscordService extends Service {
|
export default class DiscordService extends Service {
|
||||||
|
static _guildExpiration = +(process.env.GUILD_INVALIDATION_TIME || 36e5)
|
||||||
|
|
||||||
ctx: AppContext
|
ctx: AppContext
|
||||||
client: Eris
|
client: Eris
|
||||||
|
|
||||||
|
@ -67,6 +69,8 @@ export default class DiscordService extends Service {
|
||||||
|
|
||||||
fetcher: IFetcher
|
fetcher: IFetcher
|
||||||
|
|
||||||
|
guilds: OrderedMap<Guild> = OrderedMap<Guild>()
|
||||||
|
_lastGuildFetch: number
|
||||||
constructor (ctx: AppContext) {
|
constructor (ctx: AppContext) {
|
||||||
super(ctx)
|
super(ctx)
|
||||||
this.ctx = ctx
|
this.ctx = ctx
|
||||||
|
@ -88,14 +92,15 @@ export default class DiscordService extends Service {
|
||||||
})
|
})
|
||||||
|
|
||||||
this.fetcher = new RestFetcher(this)
|
this.fetcher = new RestFetcher(this)
|
||||||
|
this.fetchGuilds(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
isRoot (id: string): boolean {
|
isRoot (id: string): boolean {
|
||||||
return this.cfg.rootUsers.has(id)
|
return this.cfg.rootUsers.has(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
getRelevantServers (user: string) {
|
getRelevantServers (user: string): OrderedSet<Guild> {
|
||||||
return this.client.guilds.filter(guild => guild.members.has(user))
|
return this.guilds.filter(guild => guild.members.has(user))
|
||||||
}
|
}
|
||||||
|
|
||||||
async gm (serverId: string, userId: string, { canFake = false }: { canFake: boolean } = {}): Promise<?MemberExt> {
|
async gm (serverId: string, userId: string, { canFake = false }: { canFake: boolean } = {}): Promise<?MemberExt> {
|
||||||
|
@ -280,6 +285,36 @@ export default class DiscordService extends Service {
|
||||||
return `https://discordapp.com/oauth2/authorize?client_id=${this.cfg.clientId}&scope=bot&permissions=268435456`
|
return `https://discordapp.com/oauth2/authorize?client_id=${this.cfg.clientId}&scope=bot&permissions=268435456`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fetchGuilds (force: boolean = false) {
|
||||||
|
if (
|
||||||
|
force ||
|
||||||
|
this.guilds.isEmpty() ||
|
||||||
|
this._lastGuildFetch + DiscordService._guildExpiration < Date.now()
|
||||||
|
) {
|
||||||
|
const g = await this.fetcher.getGuilds()
|
||||||
|
this.guilds = OrderedMap(g.reduce((acc, g) => ({ ...acc, [g.id]: g }), {}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async guild (id: string, invalidate: boolean = false): Promise<?Guild> {
|
||||||
|
// fetch if needed
|
||||||
|
await this.fetchGuilds()
|
||||||
|
|
||||||
|
// do we know about it?
|
||||||
|
// (also don't get this if we're invalidating)
|
||||||
|
if (invalidate === false && this.guilds.has(id)) {
|
||||||
|
return this.guilds.get(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// else let's fetch and cache.
|
||||||
|
const g = await this.fetcher.getGuild(id)
|
||||||
|
if (g != null) {
|
||||||
|
this.guilds = this.guilds.set(g.id, g)
|
||||||
|
}
|
||||||
|
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
async issueChallenge (author: string) {
|
async issueChallenge (author: string) {
|
||||||
// Create a challenge
|
// Create a challenge
|
||||||
const chall = await this.ctx.auth.createDMChallenge(author)
|
const chall = await this.ctx.auth.createDMChallenge(author)
|
||||||
|
|
|
@ -4,6 +4,8 @@ import type DiscordSvc from '../discord'
|
||||||
import type ErisClient, { User, Member, Guild } from 'eris'
|
import type ErisClient, { User, Member, Guild } from 'eris'
|
||||||
import LRU from 'lru-cache'
|
import LRU from 'lru-cache'
|
||||||
import logger from '../../logger'
|
import logger from '../../logger'
|
||||||
|
// $FlowFixMe
|
||||||
|
import { OrderedSet } from 'immutable'
|
||||||
const log = logger(__filename)
|
const log = logger(__filename)
|
||||||
|
|
||||||
export default class BotFetcher implements IFetcher {
|
export default class BotFetcher implements IFetcher {
|
||||||
|
@ -71,4 +73,31 @@ export default class BotFetcher implements IFetcher {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getGuilds = async (): Promise<Guild[]> => {
|
||||||
|
const last: ?string = undefined
|
||||||
|
const limit: number = 100
|
||||||
|
let out = OrderedSet<Guild>()
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
// $FlowFixMe -- last is optional, but typedef isn't.
|
||||||
|
const gl = await this.client.getRESTGuilds(limit, last)
|
||||||
|
|
||||||
|
out = out.union(gl)
|
||||||
|
if (gl.length !== limit) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
log.error('getAllGuilds failed', e)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.toArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidateGuild (id: string) {
|
||||||
|
this.cache.del(`G:${id}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,4 +11,6 @@ export interface IFetcher {
|
||||||
getGuild: (id: string) => Promise<?Guild>;
|
getGuild: (id: string) => Promise<?Guild>;
|
||||||
|
|
||||||
getMember: (server: string, user: string) => Promise<?Member>;
|
getMember: (server: string, user: string) => Promise<?Member>;
|
||||||
|
|
||||||
|
getGuilds: () => Promise<Guild[]>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import { type AppContext } from '../Roleypoly'
|
||||||
import { type Models } from '../models'
|
import { type Models } from '../models'
|
||||||
import { type ServerModel } from '../models/Server'
|
import { type ServerModel } from '../models/Server'
|
||||||
import type DiscordService from './discord'
|
import type DiscordService from './discord'
|
||||||
|
// $FlowFixMe
|
||||||
|
import type { Sequence } from 'immutable'
|
||||||
import {
|
import {
|
||||||
type Guild,
|
type Guild,
|
||||||
type Collection
|
type Collection
|
||||||
|
@ -38,7 +40,7 @@ class PresentationService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
presentableServers (collection: Collection<Guild>, userId: string) {
|
presentableServers (collection: Collection<Guild> | Sequence<Guild>, userId: string): Promise<PresentableServer[]> {
|
||||||
return areduce(Array.from(collection.values()), async (acc, server) => {
|
return areduce(Array.from(collection.values()), async (acc, server) => {
|
||||||
const gm = server.members.get(userId)
|
const gm = server.members.get(userId)
|
||||||
if (gm == null) {
|
if (gm == null) {
|
||||||
|
|
|
@ -5,10 +5,10 @@ import type PresentationService from './presentation'
|
||||||
import {
|
import {
|
||||||
type Guild
|
type Guild
|
||||||
} from 'eris'
|
} from 'eris'
|
||||||
import { type ServerModel, type Category } from '../models/Server'
|
import { type ServerModel, type Category } from '@roleypoly/types'
|
||||||
|
|
||||||
export default class ServerService extends Service {
|
export default class ServerService extends Service {
|
||||||
Server: any // Model<ServerModel> but flowtype is bugged
|
Server: * // Model<ServerModel> but flowtype is bugged
|
||||||
P: PresentationService
|
P: PresentationService
|
||||||
constructor (ctx: AppContext) {
|
constructor (ctx: AppContext) {
|
||||||
super(ctx)
|
super(ctx)
|
||||||
|
|
|
@ -1,16 +1,29 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { namespaceConfig } from 'fast-redux'
|
import { namespaceConfig } from 'fast-redux'
|
||||||
|
import RPC from '../config/rpc'
|
||||||
// import { Map } from 'immutable'
|
// import { Map } from 'immutable'
|
||||||
|
import type { PresentableServer as Server } from '@roleypoly/types'
|
||||||
|
|
||||||
const DEFAULT_STATE = {}
|
export type ServersState = {
|
||||||
|
[id: string]: Server
|
||||||
|
}
|
||||||
|
|
||||||
export type ServersState = typeof DEFAULT_STATE
|
const DEFAULT_STATE: ServersState = {}
|
||||||
|
|
||||||
export const { action, getState: getServerState } = namespaceConfig('servers', DEFAULT_STATE)
|
export const { action, getState: getServerState } = namespaceConfig('servers', DEFAULT_STATE)
|
||||||
|
|
||||||
export const updateServers = action('updateServers', (state: ServersState, serverData) => ({
|
export const updateServers = action('updateServers', (state: ServersState, serverData: Server[]) => ({
|
||||||
...state,
|
...state,
|
||||||
servers: serverData
|
...serverData.reduce((acc, s) => ({ ...acc, [s.id]: s }), {})
|
||||||
}))
|
}))
|
||||||
|
|
||||||
export const updateSingleServer = action('updateSingleServer', (state, data, server) => ({ ...state, [server]: data }))
|
export const updateSingleServer = action('updateSingleServer', (state, data, server) => ({ ...state, [server]: data }))
|
||||||
|
|
||||||
|
export const fetchServerList = (rpc?: typeof RPC) => async (dispatch: *) => {
|
||||||
|
if (rpc == null) {
|
||||||
|
rpc = RPC
|
||||||
|
}
|
||||||
|
|
||||||
|
const servers: Server[] = await rpc.listOwnServers()
|
||||||
|
dispatch(updateServers(servers))
|
||||||
|
}
|
||||||
|
|
37
yarn.lock
37
yarn.lock
|
@ -368,6 +368,14 @@
|
||||||
"@babel/helper-create-class-features-plugin" "^7.4.0"
|
"@babel/helper-create-class-features-plugin" "^7.4.0"
|
||||||
"@babel/helper-plugin-utils" "^7.0.0"
|
"@babel/helper-plugin-utils" "^7.0.0"
|
||||||
|
|
||||||
|
"@babel/plugin-proposal-export-namespace-from@^7.2.0":
|
||||||
|
version "7.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.2.0.tgz#308fd4d04ff257fc3e4be090550840eeabad5dd9"
|
||||||
|
integrity sha512-DZUxbHYxQ5fUFIkMEnh75ogEdBLPfL+mQUqrO2hNY2LGm+tqFnxE924+mhAcCOh/8za8AaZsWHbq6bBoS3TAzA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-plugin-utils" "^7.0.0"
|
||||||
|
"@babel/plugin-syntax-export-namespace-from" "^7.2.0"
|
||||||
|
|
||||||
"@babel/plugin-proposal-json-strings@^7.0.0", "@babel/plugin-proposal-json-strings@^7.2.0":
|
"@babel/plugin-proposal-json-strings@^7.0.0", "@babel/plugin-proposal-json-strings@^7.2.0":
|
||||||
version "7.2.0"
|
version "7.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz#568ecc446c6148ae6b267f02551130891e29f317"
|
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz#568ecc446c6148ae6b267f02551130891e29f317"
|
||||||
|
@ -453,6 +461,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-plugin-utils" "^7.0.0"
|
"@babel/helper-plugin-utils" "^7.0.0"
|
||||||
|
|
||||||
|
"@babel/plugin-syntax-export-namespace-from@^7.2.0":
|
||||||
|
version "7.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.2.0.tgz#8d257838c6b3b779db52c0224443459bd27fb039"
|
||||||
|
integrity sha512-1zGA3UNch6A+A11nIzBVEaE3DDJbjfB+eLIcf0GGOh/BJr/8NxL3546MGhV/r0RhH4xADFIEso39TKCfEMlsGA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-plugin-utils" "^7.0.0"
|
||||||
|
|
||||||
"@babel/plugin-syntax-flow@^7.2.0":
|
"@babel/plugin-syntax-flow@^7.2.0":
|
||||||
version "7.2.0"
|
version "7.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.2.0.tgz#a765f061f803bc48f240c26f8747faf97c26bf7c"
|
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.2.0.tgz#a765f061f803bc48f240c26f8747faf97c26bf7c"
|
||||||
|
@ -8173,6 +8188,14 @@ nanomatch@^1.2.9:
|
||||||
snapdragon "^0.8.1"
|
snapdragon "^0.8.1"
|
||||||
to-regex "^3.0.1"
|
to-regex "^3.0.1"
|
||||||
|
|
||||||
|
nats@^1.2.10:
|
||||||
|
version "1.2.10"
|
||||||
|
resolved "https://registry.yarnpkg.com/nats/-/nats-1.2.10.tgz#3f673e80d3a513f7802b0a5c1f227127a3d1d780"
|
||||||
|
integrity sha512-0FQMINZbyRkFMRbrpc6+IkKMQ+Zi2Ibr4YPhoEBlbP0Gw3ta23e/GB+LvXNqnV3htOPJNJ54+ToMI43BCYATGQ==
|
||||||
|
dependencies:
|
||||||
|
nuid "^1.0.0"
|
||||||
|
ts-nkeys "^1.0.8"
|
||||||
|
|
||||||
natural-compare@^1.4.0:
|
natural-compare@^1.4.0:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||||
|
@ -8553,6 +8576,11 @@ nth-check@~1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
boolbase "~1.0.0"
|
boolbase "~1.0.0"
|
||||||
|
|
||||||
|
nuid@^1.0.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/nuid/-/nuid-1.1.0.tgz#e0c5746350a25562f58283197f34c50861f44675"
|
||||||
|
integrity sha512-C/JdZ6PtCqKsCEs4ni76nhBsdmuQgLAT/CTLNprkcLViDAnkk7qx5sSA8PVC2vmSsdBlSsFuGb52v6pwn1oaeg==
|
||||||
|
|
||||||
num2fraction@^1.2.2:
|
num2fraction@^1.2.2:
|
||||||
version "1.2.2"
|
version "1.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
|
resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
|
||||||
|
@ -11600,6 +11628,13 @@ trough@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.3.tgz#e29bd1614c6458d44869fc28b255ab7857ef7c24"
|
resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.3.tgz#e29bd1614c6458d44869fc28b255ab7857ef7c24"
|
||||||
integrity sha512-fwkLWH+DimvA4YCy+/nvJd61nWQQ2liO/nF/RjkTpiOGi+zxZzVkhb1mvbHIIW4b/8nDsYI8uTmAlc0nNkRMOw==
|
integrity sha512-fwkLWH+DimvA4YCy+/nvJd61nWQQ2liO/nF/RjkTpiOGi+zxZzVkhb1mvbHIIW4b/8nDsYI8uTmAlc0nNkRMOw==
|
||||||
|
|
||||||
|
ts-nkeys@^1.0.8:
|
||||||
|
version "1.0.12"
|
||||||
|
resolved "https://registry.yarnpkg.com/ts-nkeys/-/ts-nkeys-1.0.12.tgz#cda47f4842fe2c4f88b1303817050673e16acb89"
|
||||||
|
integrity sha512-5TgA+wbfxTy/9pdSuAhvneuL65KKoI7phonzNQH2UhnorAQAWehUwHNLEuli596wu/Fxh0SAhMeKZVLNx4s7Ow==
|
||||||
|
dependencies:
|
||||||
|
tweetnacl "^1.0.1"
|
||||||
|
|
||||||
tslib@^1.9.0:
|
tslib@^1.9.0:
|
||||||
version "1.9.3"
|
version "1.9.3"
|
||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
|
||||||
|
@ -11629,7 +11664,7 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
||||||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
||||||
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
|
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
|
||||||
|
|
||||||
tweetnacl@^1.0.0:
|
tweetnacl@^1.0.0, tweetnacl@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.1.tgz#2594d42da73cd036bd0d2a54683dd35a6b55ca17"
|
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.1.tgz#2594d42da73cd036bd0d2a54683dd35a6b55ca17"
|
||||||
integrity sha512-kcoMoKTPYnoeS50tzoqjPY3Uv9axeuuFAZY9M/9zFnhoVvRfxz9K29IMPD7jGmt2c8SW7i3gT9WqDl2+nV7p4A==
|
integrity sha512-kcoMoKTPYnoeS50tzoqjPY3Uv9axeuuFAZY9M/9zFnhoVvRfxz9K29IMPD7jGmt2c8SW7i3gT9WqDl2+nV7p4A==
|
||||||
|
|
Loading…
Add table
Reference in a new issue