Move status refresh intervals to App component (resolves #107).

This commit is contained in:
Daniel Scalzi 2020-09-13 18:43:01 -04:00
parent 67e42ead78
commit 0cbd39b79c
No known key found for this signature in database
GPG Key ID: D18EA3FB4B142A57
10 changed files with 1911 additions and 816 deletions

2344
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -31,14 +31,14 @@
"dependencies": { "dependencies": {
"adm-zip": "^0.4.16", "adm-zip": "^0.4.16",
"async": "^3.2.0", "async": "^3.2.0",
"discord-rpc": "^3.1.3", "discord-rpc": "^3.1.4",
"electron-updater": "^4.3.4", "electron-updater": "^4.3.4",
"fs-extra": "^9.0.1", "fs-extra": "^9.0.1",
"github-syntax-dark": "^0.5.0", "github-syntax-dark": "^0.5.0",
"got": "^11.6.0", "got": "^11.6.2",
"jquery": "^3.5.1", "jquery": "^3.5.1",
"lodash": "^4.17.20", "lodash": "^4.17.20",
"moment": "^2.27.0", "moment": "^2.28.0",
"request": "^2.88.2", "request": "^2.88.2",
"semver": "^7.3.2", "semver": "^7.3.2",
"tar-fs": "^2.1.0", "tar-fs": "^2.1.0",
@ -58,7 +58,7 @@
"@types/jquery": "^3.5.1", "@types/jquery": "^3.5.1",
"@types/lodash": "^4.14.161", "@types/lodash": "^4.14.161",
"@types/mocha": "^8.0.3", "@types/mocha": "^8.0.3",
"@types/node": "^12.12.55", "@types/node": "^12.12.58",
"@types/react": "^16.9.49", "@types/react": "^16.9.49",
"@types/react-dom": "^16.9.8", "@types/react-dom": "^16.9.8",
"@types/react-redux": "^7.1.9", "@types/react-redux": "^7.1.9",
@ -67,19 +67,19 @@
"@types/tar-fs": "^2.0.0", "@types/tar-fs": "^2.0.0",
"@types/triple-beam": "^1.3.2", "@types/triple-beam": "^1.3.2",
"@types/winreg": "^1.2.30", "@types/winreg": "^1.2.30",
"@typescript-eslint/eslint-plugin": "^3.10.1", "@typescript-eslint/eslint-plugin": "^4.1.0",
"@typescript-eslint/parser": "^3.10.1", "@typescript-eslint/parser": "^4.1.0",
"chai": "^4.2.0", "chai": "^4.2.0",
"chai-as-promised": "^7.1.1", "chai-as-promised": "^7.1.1",
"cross-env": "^7.0.2", "cross-env": "^7.0.2",
"electron": "^9.2.1", "electron": "^9.3.0",
"electron-builder": "^22.8.0", "electron-builder": "^22.8.0",
"electron-devtools-installer": "^3.1.1", "electron-devtools-installer": "^3.1.1",
"electron-webpack": "^2.8.2", "electron-webpack": "^2.8.2",
"electron-webpack-ts": "^4.0.1", "electron-webpack-ts": "^4.0.1",
"eslint": "^7.8.1", "eslint": "^7.9.0",
"eslint-plugin-react": "^7.20.6", "eslint-plugin-react": "^7.20.6",
"helios-distribution-types": "1.0.0-pre.1", "helios-distribution-types": "1.0.0-rc.1",
"mocha": "^8.1.3", "mocha": "^8.1.3",
"nock": "^13.0.4", "nock": "^13.0.4",
"react": "^16.13.0", "react": "^16.13.0",

View File

@ -29,6 +29,7 @@ export interface ServerStatus {
version: string version: string
}[] }[]
} }
retrievedAt: number // Internal tracking
} }
/** /**
@ -77,6 +78,7 @@ function unifyStatusResponse(resp: ServerStatus): ServerStatus {
text: resp.description text: resp.description
} }
} }
resp.retrievedAt = (new Date()).getTime()
return resp return resp
} }

View File

@ -30,44 +30,48 @@ export class MojangRestAPI {
version: 1 version: 1
} }
protected static statuses: MojangStatus[] = [ protected static statuses: MojangStatus[] = MojangRestAPI.getDefaultStatuses()
{
service: 'sessionserver.mojang.com', public static getDefaultStatuses(): MojangStatus[] {
status: MojangStatusColor.GREY, return [
name: 'Multiplayer Session Service', {
essential: true service: 'sessionserver.mojang.com',
}, status: MojangStatusColor.GREY,
{ name: 'Multiplayer Session Service',
service: 'authserver.mojang.com', essential: true
status: MojangStatusColor.GREY, },
name: 'Authentication Service', {
essential: true service: 'authserver.mojang.com',
}, status: MojangStatusColor.GREY,
{ name: 'Authentication Service',
service: 'textures.minecraft.net', essential: true
status: MojangStatusColor.GREY, },
name: 'Minecraft Skins', {
essential: false service: 'textures.minecraft.net',
}, status: MojangStatusColor.GREY,
{ name: 'Minecraft Skins',
service: 'api.mojang.com', essential: false
status: MojangStatusColor.GREY, },
name: 'Public API', {
essential: false service: 'api.mojang.com',
}, status: MojangStatusColor.GREY,
{ name: 'Public API',
service: 'minecraft.net', essential: false
status: MojangStatusColor.GREY, },
name: 'Minecraft.net', {
essential: false service: 'minecraft.net',
}, status: MojangStatusColor.GREY,
{ name: 'Minecraft.net',
service: 'account.mojang.com', essential: false
status: MojangStatusColor.GREY, },
name: 'Mojang Accounts Website', {
essential: false service: 'account.mojang.com',
} status: MojangStatusColor.GREY,
] name: 'Mojang Accounts Website',
essential: false
}
]
}
/** /**
* Converts a Mojang status color to a hex value. Valid statuses * Converts a Mojang status color to a hex value. Valid statuses

View File

@ -24,6 +24,10 @@ import { DistributionAPI } from 'common/distribution/DistributionAPI'
import { getServerStatus, ServerStatus } from 'common/mojang/net/ServerStatusAPI' import { getServerStatus, ServerStatus } from 'common/mojang/net/ServerStatusAPI'
import { Distribution } from 'helios-distribution-types' import { Distribution } from 'helios-distribution-types'
import { HeliosDistribution, HeliosServer } from 'common/distribution/DistributionFactory' import { HeliosDistribution, HeliosServer } from 'common/distribution/DistributionFactory'
import { MojangResponse } from 'common/mojang/rest/internal/MojangResponse'
import { MojangStatus, MojangStatusColor } from 'common/mojang/rest/internal/MojangStatus'
import { MojangRestAPI } from 'common/mojang/rest/MojangRestAPI'
import { RestResponseStatus } from 'common/got/RestResponse'
import './Application.css' import './Application.css'
@ -39,8 +43,9 @@ interface ApplicationProps {
currentView: View currentView: View
overlayQueue: OverlayPushAction<unknown>[] overlayQueue: OverlayPushAction<unknown>[]
distribution: HeliosDistribution distribution: HeliosDistribution
selectedServer: HeliosServer selectedServer?: HeliosServer
selectedServerStatus: ServerStatus selectedServerStatus?: ServerStatus
mojangStatuses: MojangStatus[]
} }
interface ApplicationState { interface ApplicationState {
@ -54,8 +59,9 @@ const mapState = (state: StoreType): Partial<ApplicationProps> => {
return { return {
currentView: state.currentView, currentView: state.currentView,
overlayQueue: state.overlayQueue, overlayQueue: state.overlayQueue,
distribution: state.app.distribution!, distribution: state.app.distribution,
selectedServer: state.app.selectedServer! selectedServer: state.app.selectedServer,
mojangStatuses: state.app.mojangStatuses
} }
} }
const mapDispatch = { const mapDispatch = {
@ -64,13 +70,18 @@ const mapDispatch = {
...OverlayActionDispatch ...OverlayActionDispatch
} }
class Application extends React.Component<ApplicationProps & typeof mapDispatch, ApplicationState> { type InternalApplicationProps = ApplicationProps & typeof mapDispatch
class Application extends React.Component<InternalApplicationProps, ApplicationState> {
private static readonly logger = LoggerUtil.getLogger('ApplicationTSX') private static readonly logger = LoggerUtil.getLogger('ApplicationTSX')
private mojangStatusInterval!: NodeJS.Timeout
private serverStatusInterval!: NodeJS.Timeout
private bkid!: number private bkid!: number
constructor(props: ApplicationProps & typeof mapDispatch) { constructor(props: InternalApplicationProps) {
super(props) super(props)
this.state = { this.state = {
loading: true, loading: true,
@ -80,6 +91,83 @@ class Application extends React.Component<ApplicationProps & typeof mapDispatch,
} }
} }
async componentDidMount(): Promise<void> {
this.mojangStatusInterval = setInterval(async () => {
Application.logger.info('Refreshing Mojang Statuses..')
await this.loadMojangStatuses()
}, 300000)
this.serverStatusInterval = setInterval(async () => {
Application.logger.info('Refreshing selected server status..')
await this.syncServerStatus()
}, 300000)
}
componentWillUnmount(): void {
// Clean up intervals.
clearInterval(this.mojangStatusInterval)
clearInterval(this.serverStatusInterval)
}
async componentDidUpdate(prevProps: InternalApplicationProps): Promise<void> {
if(this.props.selectedServer?.rawServer.id !== prevProps.selectedServer?.rawServer.id) {
await this.syncServerStatus()
}
}
/**
* Load the mojang statuses and add them to the global store.
*/
private loadMojangStatuses = async (): Promise<void> => {
const response: MojangResponse<MojangStatus[]> = await MojangRestAPI.status()
if(response.responseStatus !== RestResponseStatus.SUCCESS) {
Application.logger.warn('Failed to retrieve Mojang Statuses.')
}
// TODO Temp workaround because their status checker always shows
// this as red. https://bugs.mojang.com/browse/WEB-2303
const statuses = response.data
for(const status of statuses) {
if(status.service === 'sessionserver.mojang.com' || status.service === 'minecraft.net') {
status.status = MojangStatusColor.GREEN
}
}
this.props.setMojangStatuses(response.data)
}
/**
* Fetch the status of the selected server and store it in the global store.
*/
private syncServerStatus = async (): Promise<void> => {
let serverStatus: ServerStatus | undefined
if(this.props.selectedServer != null) {
const { hostname, port } = this.props.selectedServer
try {
serverStatus = await getServerStatus(
47,
hostname,
port
)
} catch(err) {
Application.logger.error('Error while refreshing server status', err)
}
} else {
serverStatus = undefined
}
this.props.setSelectedServerStatus(serverStatus)
}
private getViewElement = (): JSX.Element => { private getViewElement = (): JSX.Element => {
// TODO debug remove // TODO debug remove
console.log('loading', this.props.currentView, this.state.workingView) console.log('loading', this.props.currentView, this.state.workingView)
@ -94,6 +182,7 @@ class Application extends React.Component<ApplicationProps & typeof mapDispatch,
distribution={this.props.distribution} distribution={this.props.distribution}
selectedServer={this.props.selectedServer} selectedServer={this.props.selectedServer}
selectedServerStatus={this.props.selectedServerStatus} selectedServerStatus={this.props.selectedServerStatus}
mojangStatuses={this.props.mojangStatuses}
/> />
</> </>
case View.LOGIN: case View.LOGIN:
@ -184,6 +273,10 @@ class Application extends React.Component<ApplicationProps & typeof mapDispatch,
this.props.setSelectedServerStatus(selectedServerStatus) this.props.setSelectedServerStatus(selectedServerStatus)
} }
// Load initial mojang statuses.
Application.logger.info('Loading mojang statuses..')
await this.loadMojangStatuses()
// TODO Setup hook for distro refresh every ~ 5 mins. // TODO Setup hook for distro refresh every ~ 5 mins.
// Pick a background id. // Pick a background id.

View File

@ -6,11 +6,9 @@ import { StoreType } from '../../redux/store'
import { AppActionDispatch } from '../..//redux/actions/appActions' import { AppActionDispatch } from '../..//redux/actions/appActions'
import { OverlayActionDispatch } from '../../redux/actions/overlayActions' import { OverlayActionDispatch } from '../../redux/actions/overlayActions'
import { HeliosDistribution, HeliosServer } from 'common/distribution/DistributionFactory' import { HeliosDistribution, HeliosServer } from 'common/distribution/DistributionFactory'
import { ServerStatus, getServerStatus } from 'common/mojang/net/ServerStatusAPI' import { ServerStatus } from 'common/mojang/net/ServerStatusAPI'
import { MojangStatus, MojangStatusColor } from 'common/mojang/rest/internal/MojangStatus' import { MojangStatus, MojangStatusColor } from 'common/mojang/rest/internal/MojangStatus'
import { MojangResponse } from 'common/mojang/rest/internal/MojangResponse'
import { MojangRestAPI } from 'common/mojang/rest/MojangRestAPI' import { MojangRestAPI } from 'common/mojang/rest/MojangRestAPI'
import { RestResponseStatus } from 'common/got/RestResponse'
import { LoggerUtil } from 'common/logging/loggerutil' import { LoggerUtil } from 'common/logging/loggerutil'
import News from '../news/News' import News from '../news/News'
@ -19,20 +17,21 @@ import './Landing.css'
interface LandingProps { interface LandingProps {
distribution: HeliosDistribution distribution: HeliosDistribution
selectedServer: HeliosServer selectedServer?: HeliosServer
selectedServerStatus: ServerStatus selectedServerStatus?: ServerStatus
mojangStatuses: MojangStatus[]
} }
interface LandingState { interface LandingState {
mojangStatuses: MojangStatus[] workingServerStatus?: ServerStatus
outdatedServerStatus: boolean
} }
const mapState = (state: StoreType): Partial<LandingProps> => { const mapState = (state: StoreType): Partial<LandingProps> => {
return { return {
distribution: state.app.distribution!, distribution: state.app.distribution!,
selectedServer: state.app.selectedServer!, selectedServer: state.app.selectedServer,
selectedServerStatus: state.app.selectedServerStatus! selectedServerStatus: state.app.selectedServerStatus,
mojangStatuses: state.app.mojangStatuses
} }
} }
const mapDispatch = { const mapDispatch = {
@ -44,102 +43,21 @@ type InternalLandingProps = LandingProps & typeof mapDispatch
class Landing extends React.Component<InternalLandingProps, LandingState> { class Landing extends React.Component<InternalLandingProps, LandingState> {
private static readonly logger = LoggerUtil.getLogger('LandingTSX') private static readonly logger = LoggerUtil.getLogger('Landing')
private mojangStatusInterval!: NodeJS.Timeout
private serverStatusInterval!: NodeJS.Timeout
constructor(props: InternalLandingProps) { constructor(props: InternalLandingProps) {
super(props) super(props)
this.state = { this.state = {
mojangStatuses: [], workingServerStatus: props.selectedServerStatus
outdatedServerStatus: false
} }
} }
async componentDidMount(): Promise<void> { /* Mojang Status Methods */
// Load Mojang statuses and setup refresh interval.
Landing.logger.info('Loading mojang statuses..')
await this.loadMojangStatuses()
this.mojangStatusInterval = setInterval(async () => {
Landing.logger.info('Refreshing Mojang Statuses..')
await this.loadMojangStatuses()
}, 300000)
this.serverStatusInterval = setInterval(async () => {
Landing.logger.info('Refreshing selected server status..')
this.setState({
...this.state,
outdatedServerStatus: true
})
}, 300000)
}
componentWillUnmount(): void {
// Clean up intervals.
clearInterval(this.mojangStatusInterval)
clearInterval(this.serverStatusInterval)
}
private loadMojangStatuses = async (): Promise<void> => {
const response: MojangResponse<MojangStatus[]> = await MojangRestAPI.status()
if(response.responseStatus !== RestResponseStatus.SUCCESS) {
Landing.logger.warn('Failed to retrieve Mojang Statuses.')
}
// TODO Temp workaround because their status checker always shows
// this as red. https://bugs.mojang.com/browse/WEB-2303
const statuses = response.data
for(const status of statuses) {
if(status.service === 'sessionserver.mojang.com' || status.service === 'minecraft.net') {
status.status = MojangStatusColor.GREEN
}
}
this.setState({
...this.state,
mojangStatuses: response.data
})
}
private syncServerStatus = async (): Promise<void> => {
let serverStatus: ServerStatus | undefined
if(this.props.selectedServer != null) {
const { hostname, port } = this.props.selectedServer
try {
serverStatus = await getServerStatus(
47,
hostname,
port
)
} catch(err) {
Landing.logger.error('Error while refreshing server status', err)
}
} else {
serverStatus = undefined
}
this.props.setSelectedServerStatus(serverStatus)
}
private finishServerSync = async (): Promise<void> => {
this.setState({
...this.state,
outdatedServerStatus: false
})
}
private getMainMojangStatusColor = (): string => { private getMainMojangStatusColor = (): string => {
const essential = this.state.mojangStatuses.filter(s => s.essential) const essential = this.props.mojangStatuses.filter(s => s.essential)
if(this.state.mojangStatuses.length === 0) { if(this.props.mojangStatuses.length === 0) {
return MojangRestAPI.statusToHex(MojangStatusColor.GREY) return MojangRestAPI.statusToHex(MojangStatusColor.GREY)
} }
@ -152,11 +70,11 @@ class Landing extends React.Component<InternalLandingProps, LandingState> {
return MojangRestAPI.statusToHex(MojangStatusColor.YELLOW) return MojangRestAPI.statusToHex(MojangStatusColor.YELLOW)
} }
// If any non-essential are not green, return yellow. // If any non-essential are not green, return yellow.
if(this.state.mojangStatuses.filter(s => s.status !== MojangStatusColor.GREEN && s.status !== MojangStatusColor.GREY).length > 0) { if(this.props.mojangStatuses.filter(s => s.status !== MojangStatusColor.GREEN && s.status !== MojangStatusColor.GREY).length > 0) {
return MojangRestAPI.statusToHex(MojangStatusColor.YELLOW) return MojangRestAPI.statusToHex(MojangStatusColor.YELLOW)
} }
// if all are grey, return grey. // if all are grey, return grey.
if(this.state.mojangStatuses.filter(s => s.status === MojangStatusColor.GREY).length === this.state.mojangStatuses.length) { if(this.props.mojangStatuses.filter(s => s.status === MojangStatusColor.GREY).length === this.props.mojangStatuses.length) {
return MojangRestAPI.statusToHex(MojangStatusColor.GREY) return MojangRestAPI.statusToHex(MojangStatusColor.GREY)
} }
@ -166,7 +84,7 @@ class Landing extends React.Component<InternalLandingProps, LandingState> {
private getMojangStatusesAsJSX = (essential: boolean): JSX.Element[] => { private getMojangStatusesAsJSX = (essential: boolean): JSX.Element[] => {
const statuses: JSX.Element[] = [] const statuses: JSX.Element[] = []
for(const status of this.state.mojangStatuses.filter(s => s.essential === essential)) { for(const status of this.props.mojangStatuses.filter(s => s.essential === essential)) {
statuses.push( statuses.push(
<div className="mojangStatusContainer" key={status.service}> <div className="mojangStatusContainer" key={status.service}>
<span className="mojangStatusIcon" style={{color: MojangRestAPI.statusToHex(status.status)}}>&#8226;</span> <span className="mojangStatusIcon" style={{color: MojangRestAPI.statusToHex(status.status)}}>&#8226;</span>
@ -177,18 +95,23 @@ class Landing extends React.Component<InternalLandingProps, LandingState> {
return statuses return statuses
} }
/* Selected Server Methods */
private updateWorkingServerStatus = (): void => {
this.setState({
...this.state,
workingServerStatus: this.props.selectedServerStatus
})
}
private openServerSelect = (): void => { private openServerSelect = (): void => {
this.props.pushServerSelectOverlay({ this.props.pushServerSelectOverlay({
servers: this.props.distribution.servers, servers: this.props.distribution.servers,
selectedId: this.props.selectedServer.rawServer.id, selectedId: this.props.selectedServer?.rawServer.id,
onSelection: async (serverId: string) => { onSelection: async (serverId: string) => {
Landing.logger.info('Server Selection Change:', serverId) Landing.logger.info('Server Selection Change:', serverId)
const next: HeliosServer = this.props.distribution.getServerById(serverId)! const next: HeliosServer = this.props.distribution.getServerById(serverId)!
this.props.setSelectedServer(next) this.props.setSelectedServer(next)
this.setState({
...this.state,
outdatedServerStatus: true
})
} }
}) })
} }
@ -202,18 +125,20 @@ class Landing extends React.Component<InternalLandingProps, LandingState> {
} }
private getSelectedServerStatusText = (): string => { private getSelectedServerStatusText = (): string => {
return this.props.selectedServerStatus != null ? 'PLAYERS' : 'SERVER' return this.state.workingServerStatus != null ? 'PLAYERS' : 'SERVER'
} }
private getSelectedServerCount = (): string => { private getSelectedServerCount = (): string => {
if(this.props.selectedServerStatus != null) { if(this.state.workingServerStatus != null) {
const { online, max } = this.props.selectedServerStatus.players const { online, max } = this.state.workingServerStatus.players
return `${online}/${max}` return `${online}/${max}`
} else { } else {
return 'OFFLINE' return 'OFFLINE'
} }
} }
/* Render */
render(): JSX.Element { render(): JSX.Element {
return <> return <>
@ -316,12 +241,11 @@ class Landing extends React.Component<InternalLandingProps, LandingState> {
<div id="content"> <div id="content">
<CSSTransition <CSSTransition
in={!this.state.outdatedServerStatus} in={this.props.selectedServerStatus?.retrievedAt === this.state.workingServerStatus?.retrievedAt}
timeout={500} timeout={500}
classNames="serverStatusWrapper" classNames="serverStatusWrapper"
unmountOnExit unmountOnExit
onEnter={this.syncServerStatus} onExited={this.updateWorkingServerStatus}
onExited={this.finishServerSync}
> >
<div id="server_status_wrapper"> <div id="server_status_wrapper">
<span className="bot_label" id="landingPlayerLabel">{this.getSelectedServerStatusText()}</span> <span className="bot_label" id="landingPlayerLabel">{this.getSelectedServerStatusText()}</span>

View File

@ -9,7 +9,7 @@ import '../shared-select/SharedSelect.css'
export interface ServerSelectOverlayProps { export interface ServerSelectOverlayProps {
servers: HeliosServer[] servers: HeliosServer[]
selectedId: string selectedId?: string
onSelection: (serverId: string) => Promise<void> onSelection: (serverId: string) => Promise<void>
} }
@ -30,7 +30,7 @@ class ServerSelectOverlay extends React.Component<InternalServerSelectOverlayPro
constructor(props: InternalServerSelectOverlayProps) { constructor(props: InternalServerSelectOverlayProps) {
super(props) super(props)
this.state = { this.state = {
selectedId: props.selectedId selectedId: props.selectedId!
} }
} }

View File

@ -31,6 +31,7 @@ ReactDOM.render(
distribution={store.getState().app.distribution!} distribution={store.getState().app.distribution!}
selectedServer={store.getState().app.selectedServer!} selectedServer={store.getState().app.selectedServer!}
selectedServerStatus={store.getState().app.selectedServerStatus!} selectedServerStatus={store.getState().app.selectedServerStatus!}
mojangStatuses={store.getState().app.mojangStatuses!}
/> />
</Provider> </Provider>
</AppContainer>, </AppContainer>,

View File

@ -1,11 +1,13 @@
import { Action } from 'redux' import { Action } from 'redux'
import { HeliosDistribution, HeliosServer } from 'common/distribution/DistributionFactory' import { HeliosDistribution, HeliosServer } from 'common/distribution/DistributionFactory'
import { ServerStatus } from 'common/mojang/net/ServerStatusAPI' import { ServerStatus } from 'common/mojang/net/ServerStatusAPI'
import { MojangStatus } from 'common/mojang/rest/internal/MojangStatus'
export enum AppActionType { export enum AppActionType {
SetDistribution = 'SET_DISTRIBUTION', SetDistribution = 'SET_DISTRIBUTION',
SetSelectedServer = 'SET_SELECTED_SERVER', SetSelectedServer = 'SET_SELECTED_SERVER',
SetSelectedServerStatus = 'SET_SELECTED_SERVER_STATUS' SetSelectedServerStatus = 'SET_SELECTED_SERVER_STATUS',
SetMojangStatuses = 'SET_MOJANG_STATUSES'
} }
// eslint-disable-next-line @typescript-eslint/no-empty-interface // eslint-disable-next-line @typescript-eslint/no-empty-interface
@ -23,6 +25,10 @@ export interface SetSelectedServerStatusAction extends AppAction {
payload?: ServerStatus payload?: ServerStatus
} }
export interface SetMojangStatusesAction extends AppAction {
payload: MojangStatus[]
}
export function setDistribution(distribution?: HeliosDistribution): SetDistributionAction { export function setDistribution(distribution?: HeliosDistribution): SetDistributionAction {
return { return {
type: AppActionType.SetDistribution, type: AppActionType.SetDistribution,
@ -44,8 +50,16 @@ export function setSelectedServerStatus(serverStatus?: ServerStatus): SetSelecte
} }
} }
export function setMojangStatuses(mojangStatuses: MojangStatus[]): SetMojangStatusesAction {
return {
type: AppActionType.SetMojangStatuses,
payload: mojangStatuses
}
}
export const AppActionDispatch = { export const AppActionDispatch = {
setDistribution: (d?: HeliosDistribution): SetDistributionAction => setDistribution(d), setDistribution: (d?: HeliosDistribution): SetDistributionAction => setDistribution(d),
setSelectedServer: (s?: HeliosServer): SetSelectedServerAction => setSelectedServer(s), setSelectedServer: (s?: HeliosServer): SetSelectedServerAction => setSelectedServer(s),
setSelectedServerStatus: (ss?: ServerStatus): SetSelectedServerStatusAction => setSelectedServerStatus(ss) setSelectedServerStatus: (ss?: ServerStatus): SetSelectedServerStatusAction => setSelectedServerStatus(ss),
setMojangStatuses: (ms: MojangStatus[]): SetMojangStatusesAction => setMojangStatuses(ms)
} }

View File

@ -1,18 +1,22 @@
import { AppActionType, AppAction, SetDistributionAction, SetSelectedServerAction, SetSelectedServerStatusAction } from '../actions/appActions' import { AppActionType, AppAction, SetDistributionAction, SetSelectedServerAction, SetSelectedServerStatusAction, SetMojangStatusesAction } from '../actions/appActions'
import { Reducer } from 'redux' import { Reducer } from 'redux'
import { HeliosDistribution, HeliosServer } from 'common/distribution/DistributionFactory' import { HeliosDistribution, HeliosServer } from 'common/distribution/DistributionFactory'
import { ServerStatus } from 'common/mojang/net/ServerStatusAPI' import { ServerStatus } from 'common/mojang/net/ServerStatusAPI'
import { MojangStatus } from 'common/mojang/rest/internal/MojangStatus'
import { MojangRestAPI } from 'common/mojang/rest/MojangRestAPI'
export interface AppState { export interface AppState {
distribution?: HeliosDistribution distribution?: HeliosDistribution
selectedServer?: HeliosServer selectedServer?: HeliosServer
selectedServerStatus?: ServerStatus selectedServerStatus?: ServerStatus
mojangStatuses: MojangStatus[]
} }
const defaultAppState: AppState = { const defaultAppState: AppState = {
distribution: undefined, distribution: undefined,
selectedServer: undefined, selectedServer: undefined,
selectedServerStatus: undefined selectedServerStatus: undefined,
mojangStatuses: MojangRestAPI.getDefaultStatuses()
} }
const AppReducer: Reducer<AppState, AppAction> = (state = defaultAppState, action) => { const AppReducer: Reducer<AppState, AppAction> = (state = defaultAppState, action) => {
@ -32,6 +36,11 @@ const AppReducer: Reducer<AppState, AppAction> = (state = defaultAppState, actio
...state, ...state,
selectedServerStatus: (action as SetSelectedServerStatusAction).payload selectedServerStatus: (action as SetSelectedServerStatusAction).payload
} }
case AppActionType.SetMojangStatuses:
return {
...state,
mojangStatuses: (action as SetMojangStatusesAction).payload
}
} }
return state return state
} }