Skip to content

Commit

Permalink
refactor service -> monitor
Browse files Browse the repository at this point in the history
  • Loading branch information
arily committed Aug 24, 2023
1 parent 1688794 commit 9c9652d
Show file tree
Hide file tree
Showing 27 changed files with 140 additions and 67 deletions.
4 changes: 4 additions & 0 deletions src/common/utils/locales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ export function ruleset(ruleset: Ruleset) {
export function rankingSystem(rs: Rank) {
return `rank.${rs}`
}

export function service(srv: string) {
return `service.${srv}`
}
2 changes: 1 addition & 1 deletion src/composables/autoLocale.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IntlPicker } from '~/server/backend/$base/intl-picker'
import { IntlPicker } from '$base/intl-picker'
import { useClientDynamicSettings } from '~/store/dynamic-settings'

export function autoLocale(meta: {
Expand Down
3 changes: 3 additions & 0 deletions src/locales/@types.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

import type { LocaleMessageValue, VueMessageType } from '@nuxtjs/i18n/dist/runtime/composables'
import type { Scope, UserPrivilege } from '~/def/user'
import type { Rank } from '~/def'
Expand Down Expand Up @@ -41,5 +42,7 @@ export interface GlobalI18n extends Record<string, LocaleMessageValue<VueMessage
string
>
global: Record<KGlobal, string>

service: Record<string, string>
}

5 changes: 5 additions & 0 deletions src/locales/en-GB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,9 @@ export default {
[Scope.Friends]: 'Friends',
[Scope.Public]: 'Everyone',
},
service: {
logs: 'Logs',
ranks: 'Leaderboard',
sessions: 'Web Login',
},
} satisfies GlobalI18n as GlobalI18n
5 changes: 5 additions & 0 deletions src/locales/zh-CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,9 @@ export default {
[Scope.Friends]: '仅好友',
[Scope.Public]: '公开',
},
service: {
logs: '日志系统',
ranks: '排名系统',
sessions: '网站登录',
},
} satisfies GlobalI18n as GlobalI18n
22 changes: 19 additions & 3 deletions src/pages/status.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// @ts-expect-error we don't have to know
import { JsonViewer } from 'vue3-json-viewer'
import 'vue3-json-viewer/dist/index.css'
import { ServiceStatus } from '../server/backend/$base/server/@extends'
import { Monitored } from '$base/server/@extends'
import { useSession } from '~/store/session'
import { UserPrivilege } from '~/def/user'
Expand Down Expand Up @@ -94,8 +94,23 @@ zh-CN:
<div class="text-xl">
Services
</div>
<div v-for="(service, key) in publicData" :key="key">
{{ key }}: {{ ServiceStatus[service[0]] }}{{ service[1] ? `, ${service[1]}` : '' }}
<div class="grid gap-2 grid-flow-row md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<div
v-for="(service, key) in publicData"
:key="key"
class="bg-gray-100 flex-grow text-black border-l-8 rounded-md px-3 py-2 w-full"
:class="{
'border-green-500': service[0] === Monitored.Status.Up,
'border-orange-500': service[0] === Monitored.Status.Degraded,
'border-red-500': service[0] === Monitored.Status.Down,
'border-gray-200': service[0] === Monitored.Status.Unknown,
}"
>
{{ t(localeKey.service(key as string)) }}
<div class="text-gray-500 font-thin text-sm pt-1">
<span>{{ service[1] }}</span>
</div>
</div>
</div>
</div>
<div v-if="adminData?.metrics" class="container mx-auto custom-container font-mono">
Expand Down Expand Up @@ -225,3 +240,4 @@ zh-CN:
}
}
</style>
$base/server/@traits
5 changes: 0 additions & 5 deletions src/server/backend/$base/locales/@types.d.ts

This file was deleted.

8 changes: 2 additions & 6 deletions src/server/backend/$base/locales/en-GB.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import type { ServerLocale } from './@types'

export default {
landing: {
content: `We are an osu! private server built from the ground up with many unique features not seen elsewhere!
- for more information, check out bancho.py and Guccho on GitHub
- we're fully open source!`,
content: 'We are an osu! private server built from the ground up with many unique features not seen elsewhere!',
},
} satisfies ServerLocale as ServerLocale
} as const
8 changes: 2 additions & 6 deletions src/server/backend/$base/locales/zh-CN.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import type { ServerLocale } from './@types'

export default {
landing: {
content: `这里是一个面向全模式的osu!私服。有则最先进的RX、AP算法,同时为全模式提供PP计算支持。拥有全图排行榜,以及无限次数的改名机会。
- 如果有更多疑问,可以访问gulag和Guccho的Github仓库。
- 我们的项目完全开源!`,
content: '这里是一个面向全模式的osu!私服。有则最先进的RX、AP算法,同时为全模式提供PP计算支持。拥有全图排行榜,以及无限次数的改名机会。',
},
} satisfies ServerLocale as ServerLocale
} as const
19 changes: 11 additions & 8 deletions src/server/backend/$base/server/@extends.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ export abstract class ScoreIdTransformable {
static stringToScoreId: typeof stringToScoreId
}

export enum ServiceStatus {
Unknown,
Down,
Degraded,
Up,
export namespace Monitored {
export enum Status {
Unknown,
Down,
Degraded,
Up,
}
export const status = Symbol('status')
export type Report = [Monitored.Status] | [Monitored.Status, string]
}
export const status = Symbol('status')

export abstract class Status {
[status]: [ServiceStatus] | [ServiceStatus, string] = [ServiceStatus.Unknown, 'No metrics']
export interface Monitored {
[Monitored.status]: Monitored.Report
}
2 changes: 1 addition & 1 deletion src/server/backend/$base/server/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export * from './rank'
export * from './map'
export * from './score'
export * from './service-status'
export * from './monitor'
export * from './user'
export * from './user-relation'
export * from './article'
13 changes: 5 additions & 8 deletions src/server/backend/$base/server/log.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import { access } from 'node:fs/promises'
import fs from 'node:fs'
import winston from 'winston'
import { ServiceStatus, Status, status } from './@extends'
import { Monitored } from './@extends'
import { observe } from '$base/logger'

export class LogProvider extends Status {
export class LogProvider implements Monitored {
static combined = '.logs/combined.log'
static error = '.logs/error.log'
static error = '.logs/error.log';

constructor() {
super()
this[status] = [ServiceStatus.Up]
}
[Monitored.status]: Monitored[typeof Monitored.status] = [Monitored.Status.Up]

async get(last: number) {
try {
Expand All @@ -35,7 +32,7 @@ export class LogProvider extends Status {
}[]>
}
catch (e) {
this.status = [ServiceStatus.Degraded]
this[Monitored.status] = [Monitored.Status.Degraded]
throw e
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { cpus } from 'node:os'
import { memoryUsage } from 'node:process'
import { currentLoad, mem } from 'systeminformation'

import { ServiceStatus, status } from './@extends'
import { Monitored } from './@extends'
import * as services from '~/server/singleton/service'

export class ServiceStatusProvider {
export class MonitorProvider {
static lastTime = process.hrtime()
static lastUsage = process.cpuUsage()
static interval = 2000
Expand All @@ -25,7 +25,7 @@ export class ServiceStatusProvider {
}

static async metrics() {
const [load, memory] = await Promise.all([ServiceStatusProvider.load(), ServiceStatusProvider.memory()])
const [load, memory] = await Promise.all([MonitorProvider.load(), MonitorProvider.memory()])
return {
load,
memory,
Expand All @@ -36,7 +36,7 @@ export class ServiceStatusProvider {
const load = await currentLoad()
return {
app: {
web: ServiceStatusProvider.processUsage,
web: MonitorProvider.processUsage,
},
system: {
avg: load.avgLoad,
Expand All @@ -51,15 +51,15 @@ export class ServiceStatusProvider {
}

static collectLoad() {
const durationUsage = process.cpuUsage(ServiceStatusProvider.lastUsage)
const duration = process.hrtime(ServiceStatusProvider.lastTime)
const durationUsage = process.cpuUsage(MonitorProvider.lastUsage)
const duration = process.hrtime(MonitorProvider.lastTime)

ServiceStatusProvider.lastTime = process.hrtime()
ServiceStatusProvider.lastUsage = process.cpuUsage()
MonitorProvider.lastTime = process.hrtime()
MonitorProvider.lastUsage = process.cpuUsage()

const calc = (a: number, b: [number, number]) => ServiceStatusProvider.#calcPercentageLoad(a, b) / cpus().length
const calc = (a: number, b: [number, number]) => MonitorProvider.#calcPercentageLoad(a, b) / cpus().length

ServiceStatusProvider.processUsage = {
MonitorProvider.processUsage = {
user: calc(durationUsage.user, duration) * 10000,
system: calc(durationUsage.system, duration) * 10000,
get current() {
Expand Down Expand Up @@ -87,9 +87,9 @@ export class ServiceStatusProvider {
return memoryUsage()
}

static async reportStatus() {
const ret = Object.fromEntries(Object.keys(services).map((key) => {
return [key, (services[key as keyof typeof services] as any)[status] || [ServiceStatus.Unknown]]
async reportStatus() {
const ret = Object.fromEntries(Object.keys(services).filter(key => (services[key as keyof typeof services] as any)[Monitored.status]).map((key) => {
return [key, (services[key as keyof typeof services] as Monitored)[Monitored.status]]
}))
return ret
}
Expand Down Expand Up @@ -134,4 +134,4 @@ export class ServiceStatusProvider {
}
}
}
setInterval(ServiceStatusProvider.collectLoad, ServiceStatusProvider.interval)
setInterval(MonitorProvider.collectLoad, MonitorProvider.interval)
6 changes: 5 additions & 1 deletion src/server/backend/$base/server/session/session-store.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { match } from 'switch-pattern'
import { Monitored } from '../@extends'
import type { Session } from '.'
import { logger } from '.'

export const sessionConfig = {
expire: 1000 * 60 * 60 * 24, // 1D
}

export abstract class SessionStore<TSessionId extends string, TSession extends Session<string>> {
export abstract class SessionStore<TSessionId extends string, TSession extends Session<string>> implements Monitored {
abstract [Monitored.status]: Monitored[typeof Monitored.status]
abstract get(key: TSessionId): PromiseLike<TSession | undefined>
abstract set(key: TSessionId, value: TSession): PromiseLike<TSessionId>
abstract destroy(key: TSessionId): PromiseLike<boolean>
Expand Down Expand Up @@ -42,6 +44,8 @@ export abstract class HouseKeeperSession<TSessionId extends string, TSession ext
export class MemorySessionStore<TSessionId extends string, TSession extends Session<string>> extends HouseKeeperSession<TSessionId, TSession> implements HouseKeeperSession<TSessionId, TSession> {
private store: Map<TSessionId, TSession>

[Monitored.status]: Monitored[typeof Monitored.status] = [Monitored.Status.Up, 'Memory Session driver']

constructor() {
super()
logger.warn('Warn: You are using memory session store.')
Expand Down
13 changes: 13 additions & 0 deletions src/server/backend/bancho.py/locales/en-GB.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { DeepPartial } from '@trpc/server'

import type { GlobalI18n } from '~/locales/@types'

export default {
landing: {
content: `We are an osu! private server built from the ground up with many unique features not seen elsewhere!
- for more information, check out bancho.py and Guccho on GitHub
- we're fully open source!`,
},
service: {
},
} as const satisfies DeepPartial<GlobalI18n>
9 changes: 8 additions & 1 deletion src/server/backend/bancho.py/locales/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
export * from '$base/locales'
import enGB from './en-GB'
import zhCN from './zh-CN'
import { Lang } from '~/def'

export const locales = {
[Lang.enGB]: enGB,
[Lang.zhCN]: zhCN,
} as const
12 changes: 12 additions & 0 deletions src/server/backend/bancho.py/locales/zh-CN.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { DeepPartial } from '@trpc/server'
import type { GlobalI18n } from '~/locales/@types'

export default {
landing: {
content: `这里是一个面向全模式的osu!私服。有则最先进的RX、AP算法,同时为全模式提供PP计算支持。拥有全图排行榜,以及无限次数的改名机会。
- 如果有更多疑问,可以访问gulag和Guccho的Github仓库。
- 我们的项目完全开源!`,
},
service: {
},
} as const satisfies DeepPartial<GlobalI18n>
2 changes: 1 addition & 1 deletion src/server/backend/bancho.py/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export { ArticleProvider } from './article'
export { RankProvider } from './rank'
export { MapProvider } from './map'
export { ScoreProvider } from './score'
export { ServiceStatusProvider } from './service-status'
export { MonitorProivider } from './monitor'
export { UserProvider } from './user'
export { UserRelationProvider } from './user-relations'
export { SessionProvider } from './session'
Expand Down
3 changes: 3 additions & 0 deletions src/server/backend/bancho.py/server/monitor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { MonitorProvider as Base } from '$base/server'

export class MonitorProivider extends Base {}
8 changes: 7 additions & 1 deletion src/server/backend/bancho.py/server/rank.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import type {
} from '~/def/common'
import type { RankProvider as Base } from '$base/server'
import type { CountryCode } from '~/def/country-code'
import { Monitored } from '$base/server/@extends'

const logger = Logger.child({ label: 'leaderboard', backend: 'bancho.py' })

Expand All @@ -50,6 +51,7 @@ const leaderboardFields = {
export class DatabaseRankProvider implements Base<Id> {
static stringToId = stringToId
static idToString = idToString

db = getPrismaClient()

config = config
Expand Down Expand Up @@ -235,11 +237,15 @@ export class DatabaseRankProvider implements Base<Id> {
}
}

export class RedisRankProvider extends DatabaseRankProvider {
export class RedisRankProvider extends DatabaseRankProvider implements Monitored {
static RedisNoDataError = class RedisNoDataError extends Error { name = 'RedisNoDataError' }

redisClient = redisClient()

get [Monitored.status](): Monitored[typeof Monitored.status] {
return this.redisClient?.isReady ? [Monitored.Status.Up, 'Providing Realtime data 🔥'] : [Monitored.Status.Degraded, 'Leaderboards may differ from real results.']
}

async getPPv2LiveLeaderboard(
banchoPyMode: number,
start: number,
Expand Down
3 changes: 0 additions & 3 deletions src/server/backend/bancho.py/server/service-status.ts

This file was deleted.

5 changes: 5 additions & 0 deletions src/server/backend/bancho.py/server/session/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ import { config } from '../../env'
import { RedisSessionStore } from './redis-session-store'
import type { Session } from '$base/server/session'
import { SessionProvider as Base, MemorySessionProvider } from '$base/server/session'
import { Monitored } from '$base/server/@extends'

const s = lazySingleton(<TSession extends Session>() => new RedisSessionStore<TSession>())

export class RedisSessionProvider extends Base<Session> implements Base<Session> {
get [Monitored.status]() {
return this.store[Monitored.status]
}

prepare() {
return s<Session>()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ import { match } from 'switch-pattern'
import { client as getRedis } from '../source/redis'
import type { Session } from '$base/server/session'
import { SessionStore, sessionConfig } from '$base/server/session/session-store'
import { Monitored } from '$base/server/@extends'

type Key = string & { __brand: 'key' }
export class RedisSessionStore<TDoc extends Document & Session<any>> extends SessionStore<string, TDoc> implements SessionStore<string, TDoc> {
get [Monitored.status](): Monitored[typeof Monitored.status] {
return this.#redis?.isReady ? [Monitored.Status.Up] : [Monitored.Status.Down, 'failed to connect to session server']
}

static REDIS_SESSION_PREFIX = 'session:guccho:'
#redis: ReturnType<typeof createClient>

Expand Down
Loading

0 comments on commit 9c9652d

Please sign in to comment.