mirror of
https://github.com/woodchen-ink/clash-and-dashboard.git
synced 2025-07-18 05:51:56 +08:00
Add: add mobx for state management
This commit is contained in:
parent
8f97504649
commit
b47b6e0e5b
14
src/lib/createStore.ts
Normal file
14
src/lib/createStore.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { createHashHistory } from 'history'
|
||||
import { configure } from 'mobx'
|
||||
import { RouterStore, ConfigStore } from '@stores'
|
||||
|
||||
// prepare MobX stores
|
||||
configure({ enforceActions: 'observed' })
|
||||
const history = createHashHistory()
|
||||
|
||||
export const rootStores = {
|
||||
router: new RouterStore(history),
|
||||
config: new ConfigStore()
|
||||
}
|
||||
|
||||
export const storeKeys = Object.keys(rootStores)
|
24
src/lib/helper.ts
Normal file
24
src/lib/helper.ts
Normal file
@ -0,0 +1,24 @@
|
||||
export function getLocalStorageItem (key: string) {
|
||||
return window.localStorage.getItem(key)
|
||||
}
|
||||
|
||||
export function setLocalStorageItem (key: string, value: string) {
|
||||
return window.localStorage.setItem(key, value)
|
||||
}
|
||||
|
||||
export function removeLocalStorageItem (key: string) {
|
||||
return window.localStorage.removeItem(key)
|
||||
}
|
||||
|
||||
/**
|
||||
* to return Promise<[T, Error]>
|
||||
* @param {Promise<T>} promise
|
||||
*/
|
||||
export async function to <T, E = Error> (promise: any): Promise<[T, E]> {
|
||||
try {
|
||||
const ret = await promise
|
||||
return [ret, null as E]
|
||||
} catch (e) {
|
||||
return [null as T, e]
|
||||
}
|
||||
}
|
17
src/models/BaseProps.ts
Normal file
17
src/models/BaseProps.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { RouteComponentProps } from 'react-router'
|
||||
import { RouterStore, ConfigStore } from '@stores'
|
||||
|
||||
/**
|
||||
* expose base router component props
|
||||
* and mobx store to props
|
||||
*/
|
||||
export interface BaseRouterProps extends RouteComponentProps<any>, BaseProps {}
|
||||
|
||||
/**
|
||||
* use when component is inject by mobx
|
||||
*/
|
||||
export interface BaseProps {
|
||||
styles?: any
|
||||
router?: RouterStore
|
||||
config?: ConfigStore
|
||||
}
|
35
src/models/Config.ts
Normal file
35
src/models/Config.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { Proxy, ProxyGroup } from './Proxy'
|
||||
import { Rule } from './Rule'
|
||||
|
||||
/**
|
||||
* clash config
|
||||
* @see https://github.com/Dreamacro/clash#config
|
||||
*/
|
||||
export interface Config {
|
||||
|
||||
general?: {
|
||||
|
||||
/**
|
||||
* http proxy port
|
||||
*/
|
||||
port?: number
|
||||
|
||||
/**
|
||||
* socks proxy port
|
||||
*/
|
||||
socksPort?: number
|
||||
|
||||
/**
|
||||
* controller port
|
||||
*/
|
||||
externalController: number
|
||||
|
||||
}
|
||||
|
||||
proxy?: Proxy[]
|
||||
|
||||
proxyGroup?: ProxyGroup[]
|
||||
|
||||
rules?: Rule[]
|
||||
|
||||
}
|
93
src/models/Proxy.ts
Normal file
93
src/models/Proxy.ts
Normal file
@ -0,0 +1,93 @@
|
||||
/**
|
||||
* proxy config interface
|
||||
*/
|
||||
export interface Proxy {
|
||||
|
||||
/**
|
||||
* proxy name
|
||||
*/
|
||||
name?: string
|
||||
|
||||
/**
|
||||
* configs of proxy server
|
||||
* now support shadowsocks, v2ray and socks5
|
||||
*/
|
||||
config?: ShadowsocksProxy | VmessProxy | Socks5Proxy
|
||||
}
|
||||
|
||||
export interface ShadowsocksProxy {
|
||||
|
||||
type?: 'ss'
|
||||
|
||||
server?: string
|
||||
|
||||
port?: number
|
||||
|
||||
cipter?: string
|
||||
|
||||
password?: string
|
||||
|
||||
}
|
||||
|
||||
export interface VmessProxy {
|
||||
|
||||
type?: 'vmess'
|
||||
|
||||
server?: string
|
||||
|
||||
port?: number
|
||||
|
||||
uuid?: string
|
||||
|
||||
alterid?: number
|
||||
|
||||
cipter?: string
|
||||
|
||||
tls?: boolean
|
||||
|
||||
}
|
||||
|
||||
export interface Socks5Proxy {
|
||||
|
||||
type?: 'socks5'
|
||||
|
||||
server?: string
|
||||
|
||||
port?: number
|
||||
|
||||
}
|
||||
|
||||
export interface ProxyGroup {
|
||||
|
||||
/**
|
||||
* proxy group name
|
||||
*/
|
||||
name?: string
|
||||
|
||||
/**
|
||||
* configs of proxy server
|
||||
* now support select and url-test
|
||||
*/
|
||||
config?: SelectProxyGroup | UrlTestProxyGroup
|
||||
|
||||
}
|
||||
|
||||
export interface SelectProxyGroup {
|
||||
|
||||
type?: 'select'
|
||||
|
||||
proxies?: Proxy[]
|
||||
|
||||
}
|
||||
|
||||
export interface UrlTestProxyGroup {
|
||||
|
||||
type?: 'url-test'
|
||||
|
||||
proxies?: Proxy[]
|
||||
|
||||
url?: string
|
||||
|
||||
interval?: number // second
|
||||
|
||||
}
|
11
src/models/Rule.ts
Normal file
11
src/models/Rule.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Proxy } from './Proxy'
|
||||
|
||||
export interface Rule {
|
||||
|
||||
type?: 'DOMAIN' | 'DOMAIN-SUFFIX' | 'DOMAIN-KEYWORD' | 'DOMAIN-SUFFIX' | 'GEOIP' | 'FINAL'
|
||||
|
||||
value?: string
|
||||
|
||||
use?: Proxy
|
||||
|
||||
}
|
4
src/models/index.ts
Normal file
4
src/models/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './BaseProps'
|
||||
export * from './Config'
|
||||
export * from './Proxy'
|
||||
export * from './Rule'
|
@ -1,14 +1,14 @@
|
||||
import * as React from 'react'
|
||||
import { render } from 'react-dom'
|
||||
import { HashRouter, BrowserRouter } from 'react-router-dom'
|
||||
import { Provider } from 'mobx-react'
|
||||
import { HashRouter } from 'react-router-dom'
|
||||
import { I18nextProvider } from 'react-i18next'
|
||||
import { AppContainer } from 'react-hot-loader'
|
||||
import { isClashX } from '@lib/jsBridge'
|
||||
import { rootStores } from '@lib/createStore'
|
||||
import App from '@views/App'
|
||||
import i18n from '@i18n'
|
||||
|
||||
const rootEl = document.getElementById('root')
|
||||
const Router = isClashX() ? HashRouter : BrowserRouter
|
||||
|
||||
// Hot Module Replacement API
|
||||
declare let module: { hot: any }
|
||||
@ -16,11 +16,13 @@ declare let module: { hot: any }
|
||||
export default function renderApp () {
|
||||
render(
|
||||
<AppContainer>
|
||||
<Router>
|
||||
<I18nextProvider i18n={ i18n }>
|
||||
<App />
|
||||
</I18nextProvider>
|
||||
</Router>
|
||||
<Provider {...rootStores}>
|
||||
<HashRouter>
|
||||
<I18nextProvider i18n={ i18n }>
|
||||
<App />
|
||||
</I18nextProvider>
|
||||
</HashRouter>
|
||||
</Provider>
|
||||
</AppContainer>,
|
||||
rootEl
|
||||
)
|
||||
@ -30,11 +32,13 @@ export default function renderApp () {
|
||||
const NewApp = require('./views/App').default
|
||||
render(
|
||||
<AppContainer>
|
||||
<Router>
|
||||
<I18nextProvider i18n={ i18n }>
|
||||
<NewApp />
|
||||
</I18nextProvider>
|
||||
</Router>
|
||||
<Provider {...rootStores}>
|
||||
<HashRouter>
|
||||
<I18nextProvider i18n={ i18n }>
|
||||
<NewApp />
|
||||
</I18nextProvider>
|
||||
</HashRouter>
|
||||
</Provider>
|
||||
</AppContainer>,
|
||||
rootEl
|
||||
)
|
||||
|
38
src/stores/ConfigStore.ts
Normal file
38
src/stores/ConfigStore.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { observable, action, runInAction } from 'mobx'
|
||||
import { parse } from 'ini'
|
||||
import { Config } from '@models'
|
||||
import { jsBridge } from '@lib/jsBridge'
|
||||
|
||||
export class ConfigStore {
|
||||
|
||||
@observable
|
||||
config: Config = {}
|
||||
|
||||
@observable
|
||||
public state: 'pending' | 'ok' | 'error' = 'pending'
|
||||
|
||||
@action
|
||||
async fetchAndParseConfig () {
|
||||
this.state = 'pending'
|
||||
|
||||
const rawConfig = await jsBridge.readConfigString()
|
||||
|
||||
runInAction(() => {
|
||||
// emit error when config is empty
|
||||
// because read config might be error
|
||||
if (!rawConfig) {
|
||||
this.state = 'error'
|
||||
return
|
||||
}
|
||||
|
||||
// otherwise parse ini
|
||||
const config = parse(rawConfig)
|
||||
|
||||
console.log(config)
|
||||
|
||||
this.config = config
|
||||
this.state = 'ok'
|
||||
})
|
||||
}
|
||||
|
||||
}
|
14
src/stores/RouterStore.ts
Normal file
14
src/stores/RouterStore.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { History } from 'history'
|
||||
import { RouterStore as BaseRouterStore, syncHistoryWithStore } from 'mobx-react-router'
|
||||
|
||||
export class RouterStore extends BaseRouterStore {
|
||||
constructor (history?: History) {
|
||||
super()
|
||||
|
||||
if (history) {
|
||||
this.history = syncHistoryWithStore(history, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default RouterStore
|
2
src/stores/index.ts
Normal file
2
src/stores/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './ConfigStore'
|
||||
export * from './RouterStore'
|
@ -1,6 +1,17 @@
|
||||
import * as React from 'react'
|
||||
import { inject, observer } from 'mobx-react'
|
||||
import { storeKeys } from '@lib/createStore'
|
||||
import { BaseRouterProps } from '@models'
|
||||
|
||||
@inject(...storeKeys)
|
||||
@observer
|
||||
export default class Overview extends React.Component<BaseRouterProps, {}> {
|
||||
|
||||
componentDidMount () {
|
||||
// here can access stores
|
||||
console.log(this.props)
|
||||
}
|
||||
|
||||
export default class Overview extends React.Component<{}, {}> {
|
||||
render () {
|
||||
return 'Overview'
|
||||
}
|
||||
|
@ -25,6 +25,8 @@
|
||||
"@i18n/*": ["src/i18n/*"],
|
||||
"@stores": ["src/stores"],
|
||||
"@stores/*": ["src/stores/*"],
|
||||
"@models": ["src/models"],
|
||||
"@models/*": ["src/models/*"],
|
||||
"@styles": ["src/styles"],
|
||||
"@styles/*": ["src/styles/*"]
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user