From b47b6e0e5b7fb19b201c104aa57001f6478b30e8 Mon Sep 17 00:00:00 2001 From: jas0ncn Date: Tue, 11 Sep 2018 00:54:22 +0800 Subject: [PATCH] Add: add mobx for state management --- src/lib/createStore.ts | 14 ++++++ src/lib/helper.ts | 24 ++++++++++ src/models/BaseProps.ts | 17 +++++++ src/models/Config.ts | 35 ++++++++++++++ src/models/Proxy.ts | 93 ++++++++++++++++++++++++++++++++++++ src/models/Rule.ts | 11 +++++ src/models/index.ts | 4 ++ src/render.tsx | 30 +++++++----- src/stores/ConfigStore.ts | 38 +++++++++++++++ src/stores/RouterStore.ts | 14 ++++++ src/stores/index.ts | 2 + src/views/Overview/index.tsx | 13 ++++- tsconfig.json | 2 + 13 files changed, 283 insertions(+), 14 deletions(-) create mode 100644 src/lib/createStore.ts create mode 100644 src/lib/helper.ts create mode 100644 src/models/BaseProps.ts create mode 100644 src/models/Config.ts create mode 100644 src/models/Proxy.ts create mode 100644 src/models/Rule.ts create mode 100644 src/models/index.ts create mode 100644 src/stores/ConfigStore.ts create mode 100644 src/stores/RouterStore.ts create mode 100644 src/stores/index.ts diff --git a/src/lib/createStore.ts b/src/lib/createStore.ts new file mode 100644 index 0000000..d89506b --- /dev/null +++ b/src/lib/createStore.ts @@ -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) diff --git a/src/lib/helper.ts b/src/lib/helper.ts new file mode 100644 index 0000000..66dc344 --- /dev/null +++ b/src/lib/helper.ts @@ -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} promise + */ +export async function to (promise: any): Promise<[T, E]> { + try { + const ret = await promise + return [ret, null as E] + } catch (e) { + return [null as T, e] + } +} diff --git a/src/models/BaseProps.ts b/src/models/BaseProps.ts new file mode 100644 index 0000000..13cbaa1 --- /dev/null +++ b/src/models/BaseProps.ts @@ -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, BaseProps {} + +/** + * use when component is inject by mobx + */ +export interface BaseProps { + styles?: any + router?: RouterStore + config?: ConfigStore +} diff --git a/src/models/Config.ts b/src/models/Config.ts new file mode 100644 index 0000000..d07af58 --- /dev/null +++ b/src/models/Config.ts @@ -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[] + +} diff --git a/src/models/Proxy.ts b/src/models/Proxy.ts new file mode 100644 index 0000000..6aa2885 --- /dev/null +++ b/src/models/Proxy.ts @@ -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 + +} diff --git a/src/models/Rule.ts b/src/models/Rule.ts new file mode 100644 index 0000000..61d57cd --- /dev/null +++ b/src/models/Rule.ts @@ -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 + +} diff --git a/src/models/index.ts b/src/models/index.ts new file mode 100644 index 0000000..d6cff1e --- /dev/null +++ b/src/models/index.ts @@ -0,0 +1,4 @@ +export * from './BaseProps' +export * from './Config' +export * from './Proxy' +export * from './Rule' diff --git a/src/render.tsx b/src/render.tsx index 30a9d56..22b8fe8 100644 --- a/src/render.tsx +++ b/src/render.tsx @@ -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( - - - - - + + + + + + + , rootEl ) @@ -30,11 +32,13 @@ export default function renderApp () { const NewApp = require('./views/App').default render( - - - - - + + + + + + + , rootEl ) diff --git a/src/stores/ConfigStore.ts b/src/stores/ConfigStore.ts new file mode 100644 index 0000000..a162887 --- /dev/null +++ b/src/stores/ConfigStore.ts @@ -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' + }) + } + +} diff --git a/src/stores/RouterStore.ts b/src/stores/RouterStore.ts new file mode 100644 index 0000000..465ff1b --- /dev/null +++ b/src/stores/RouterStore.ts @@ -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 diff --git a/src/stores/index.ts b/src/stores/index.ts new file mode 100644 index 0000000..3e89db5 --- /dev/null +++ b/src/stores/index.ts @@ -0,0 +1,2 @@ +export * from './ConfigStore' +export * from './RouterStore' diff --git a/src/views/Overview/index.tsx b/src/views/Overview/index.tsx index 255f133..9f832d6 100644 --- a/src/views/Overview/index.tsx +++ b/src/views/Overview/index.tsx @@ -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 { + + componentDidMount () { + // here can access stores + console.log(this.props) + } -export default class Overview extends React.Component<{}, {}> { render () { return 'Overview' } diff --git a/tsconfig.json b/tsconfig.json index bd9b91f..f4924d2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -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/*"] }