mirror of
https://github.com/woodchen-ink/clash-and-dashboard.git
synced 2025-07-18 14:01:56 +08:00
Add: API request lib
This commit is contained in:
parent
fc4c58ae92
commit
b60ebfe75f
1221
package-lock.json
generated
1221
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
31
package.json
31
package.json
@ -26,19 +26,20 @@
|
|||||||
"start-dev": "webpack-dev-server --config=configs/webpack/dev.js"
|
"start-dev": "webpack-dev-server --config=configs/webpack/dev.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "^7.1.0",
|
"@babel/cli": "^7.1.2",
|
||||||
"@babel/core": "^7.1.0",
|
"@babel/core": "^7.1.2",
|
||||||
"@babel/preset-env": "^7.1.0",
|
"@babel/preset-env": "^7.1.0",
|
||||||
"@babel/preset-react": "^7.0.0",
|
"@babel/preset-react": "^7.0.0",
|
||||||
"@types/node": "^10.10.3",
|
"@types/node": "^10.11.4",
|
||||||
"@types/react": "^16.4.14",
|
"@types/react": "^16.4.15",
|
||||||
"@types/react-dom": "^16.0.7",
|
"@types/react-dom": "^16.0.8",
|
||||||
"@types/react-i18next": "^7.8.2",
|
"@types/react-i18next": "^7.8.2",
|
||||||
"@types/react-router-dom": "^4.3.1",
|
"@types/react-router-dom": "^4.3.1",
|
||||||
"@types/react-sortable-hoc": "^0.6.4",
|
"@types/react-sortable-hoc": "^0.6.4",
|
||||||
|
"@types/yaml": "^1.0.0",
|
||||||
"autoprefixer": "^9.1.5",
|
"autoprefixer": "^9.1.5",
|
||||||
"awesome-typescript-loader": "^5.2.1",
|
"awesome-typescript-loader": "^5.2.1",
|
||||||
"babel-loader": "^8.0.2",
|
"babel-loader": "^8.0.4",
|
||||||
"css-loader": "^1.0.0",
|
"css-loader": "^1.0.0",
|
||||||
"file-loader": "^2.0.0",
|
"file-loader": "^2.0.0",
|
||||||
"html-webpack-plugin": "^3.2.0",
|
"html-webpack-plugin": "^3.2.0",
|
||||||
@ -49,28 +50,29 @@
|
|||||||
"react-hot-loader": "^4.3.11",
|
"react-hot-loader": "^4.3.11",
|
||||||
"sass-loader": "^7.1.0",
|
"sass-loader": "^7.1.0",
|
||||||
"style-loader": "^0.23.0",
|
"style-loader": "^0.23.0",
|
||||||
"stylelint": "^9.5.0",
|
"stylelint": "^9.6.0",
|
||||||
"stylelint-config-standard": "^18.2.0",
|
"stylelint-config-standard": "^18.2.0",
|
||||||
"stylelint-webpack-plugin": "^0.10.5",
|
"stylelint-webpack-plugin": "^0.10.5",
|
||||||
"tslint": "^5.11.0",
|
"tslint": "^5.11.0",
|
||||||
"tslint-config-standard": "^8.0.1",
|
"tslint-config-standard": "^8.0.1",
|
||||||
"tslint-loader": "^3.6.0",
|
"tslint-loader": "^3.6.0",
|
||||||
"uglifyjs-webpack-plugin": "^2.0.1",
|
"uglifyjs-webpack-plugin": "^2.0.1",
|
||||||
"webpack": "^4.19.1",
|
"webpack": "^4.20.2",
|
||||||
"webpack-cli": "^3.1.1",
|
"webpack-cli": "^3.1.2",
|
||||||
"webpack-dev-middleware": "^3.3.0",
|
"webpack-dev-middleware": "^3.4.0",
|
||||||
"webpack-dev-server": "^3.1.8",
|
"webpack-dev-server": "^3.1.9",
|
||||||
"webpack-merge": "^4.1.4",
|
"webpack-merge": "^4.1.4",
|
||||||
"webpack-pwa-manifest": "^3.7.1"
|
"webpack-pwa-manifest": "^3.7.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"axios": "^0.18.0",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"dayjs": "^1.7.5",
|
"dayjs": "^1.7.7",
|
||||||
"i18next": "^11.9.0",
|
"i18next": "^11.9.0",
|
||||||
"i18next-browser-languagedetector": "^2.2.3",
|
"i18next-browser-languagedetector": "^2.2.3",
|
||||||
"immer": "^1.7.2",
|
"immer": "^1.7.2",
|
||||||
"ini": "^1.3.5",
|
"ini": "^1.3.5",
|
||||||
"mobx": "^5.1.2",
|
"mobx": "^5.5.0",
|
||||||
"mobx-react": "^5.2.8",
|
"mobx-react": "^5.2.8",
|
||||||
"mobx-react-router": "^4.0.5",
|
"mobx-react-router": "^4.0.5",
|
||||||
"node-sass": "^4.9.3",
|
"node-sass": "^4.9.3",
|
||||||
@ -79,6 +81,7 @@
|
|||||||
"react-i18next": "^7.12.0",
|
"react-i18next": "^7.12.0",
|
||||||
"react-router-dom": "^4.3.1",
|
"react-router-dom": "^4.3.1",
|
||||||
"react-sortable-hoc": "^0.8.3",
|
"react-sortable-hoc": "^0.8.3",
|
||||||
"typescript": "^3.0.3"
|
"typescript": "^3.1.1",
|
||||||
|
"yaml": "^1.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export function getLocalStorageItem (key: string) {
|
export function getLocalStorageItem (key: string, defaultValue = '') {
|
||||||
return window.localStorage.getItem(key)
|
return window.localStorage.getItem(key) || defaultValue
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setLocalStorageItem (key: string, value: string) {
|
export function setLocalStorageItem (key: string, value: string) {
|
||||||
@ -22,3 +22,5 @@ export async function to <T, E = Error> (promise: any): Promise<[T, E]> {
|
|||||||
return [null as T, e]
|
return [null as T, e]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type Partial<T> = { [P in keyof T]?: T[P] }
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
const sectionExpr = /^\[(.*)\]/
|
|
||||||
const lineBreak = /\r?\n/g
|
|
||||||
|
|
||||||
const isSectionLine = (line: string) => sectionExpr.test(line)
|
|
||||||
const formatSection = (text: string) =>
|
|
||||||
text.split(lineBreak)
|
|
||||||
.map(t => t.trim())
|
|
||||||
.filter(t => t && t[0] !== ';')
|
|
||||||
.map(t => t.split('=', 2))
|
|
||||||
.filter(pair => pair.length === 2)
|
|
||||||
.reduce((map, [key, value]) => map.set(key.trim(), value.trim()), new Map<string, string>())
|
|
||||||
|
|
||||||
const iniParser = (text = '') => {
|
|
||||||
const section = new Map<string, string>()
|
|
||||||
if (text.length === 0) return
|
|
||||||
const lines = text.split(lineBreak)
|
|
||||||
let content: string[] = []
|
|
||||||
let sectionName = ''
|
|
||||||
for (const line of lines) {
|
|
||||||
if (isSectionLine(line)) {
|
|
||||||
if (sectionName !== '') {
|
|
||||||
section.set(sectionName, content.join('\n'))
|
|
||||||
}
|
|
||||||
content = []
|
|
||||||
const match = line.match(sectionExpr)
|
|
||||||
sectionName = match && match[1]
|
|
||||||
} else {
|
|
||||||
content.push(line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sectionName !== '') {
|
|
||||||
section.set(sectionName, content.join('\n'))
|
|
||||||
}
|
|
||||||
return section
|
|
||||||
}
|
|
@ -25,7 +25,7 @@ export interface JsBridgeAPI {
|
|||||||
/**
|
/**
|
||||||
* Call a native handle
|
* Call a native handle
|
||||||
*/
|
*/
|
||||||
callHandler: (handleName: string, data?: any, responseCallback?: (responseData: any) => void) => void
|
callHandler: <T>(handleName: string, data?: any, responseCallback?: (responseData: T) => void) => void
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Who knows
|
* Who knows
|
||||||
@ -115,8 +115,8 @@ export class JsBridge {
|
|||||||
setTimeout(() => document.documentElement.removeChild(WVJBIframe), 0)
|
setTimeout(() => document.documentElement.removeChild(WVJBIframe), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
public callHandler (handleName: string, data?: any) {
|
public callHandler<T> (handleName: string, data?: any) {
|
||||||
return new Promise(resolve => {
|
return new Promise<T>((resolve) => {
|
||||||
this.instance.callHandler(
|
this.instance.callHandler(
|
||||||
handleName,
|
handleName,
|
||||||
data || undefined,
|
data || undefined,
|
||||||
@ -130,11 +130,11 @@ export class JsBridge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public readConfigString () {
|
public readConfigString () {
|
||||||
return this.callHandler('readConfigString')
|
return this.callHandler<string>('readConfigString')
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPasteboard () {
|
public getPasteboard () {
|
||||||
return this.callHandler('getPasteboard')
|
return this.callHandler<string>('getPasteboard')
|
||||||
}
|
}
|
||||||
|
|
||||||
public setPasteboard (data: string) {
|
public setPasteboard (data: string) {
|
||||||
|
99
src/lib/request.ts
Normal file
99
src/lib/request.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import axios, { AxiosInstance } from 'axios'
|
||||||
|
import { Partial, getLocalStorageItem } from '@lib/helper'
|
||||||
|
import { isClashX } from '@lib/jsBridge'
|
||||||
|
import { rootStores } from '@lib/createStore'
|
||||||
|
|
||||||
|
let instance: Request
|
||||||
|
|
||||||
|
export interface Config {
|
||||||
|
port: number
|
||||||
|
'socket-port': number
|
||||||
|
'redir-port': number
|
||||||
|
'allow-lan': boolean
|
||||||
|
mode: string
|
||||||
|
'log-level': string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Rules {
|
||||||
|
rules: { name: string, payload: string }[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Proxies {
|
||||||
|
proxies: {
|
||||||
|
[key: string]: Proxy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Proxy {
|
||||||
|
type: 'Direct' | 'Selector' | 'Reject' | 'URLTest' | 'Shadowsocks' | 'Vmess' | 'Socks' | 'Fallback'
|
||||||
|
now?: string
|
||||||
|
all?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Request {
|
||||||
|
protected instance: AxiosInstance
|
||||||
|
|
||||||
|
constructor (host: string, secret?: string) {
|
||||||
|
this.instance = axios.create({
|
||||||
|
baseURL: host,
|
||||||
|
headers: secret ? { Authorization: `Bearer ${secret}` } : {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfig () {
|
||||||
|
return this.instance.get<Config>('configs')
|
||||||
|
}
|
||||||
|
|
||||||
|
updateConfig (config: Partial<Config>) {
|
||||||
|
return this.instance.put<void>('configs', config)
|
||||||
|
}
|
||||||
|
|
||||||
|
getRules () {
|
||||||
|
return this.instance.get<Rules>('rules')
|
||||||
|
}
|
||||||
|
|
||||||
|
updateRules () {
|
||||||
|
return this.instance.put<void>('rules')
|
||||||
|
}
|
||||||
|
|
||||||
|
getProxies () {
|
||||||
|
return this.instance.get<Proxies>('proxies')
|
||||||
|
}
|
||||||
|
|
||||||
|
getProxy (name: string) {
|
||||||
|
return this.instance.get<Proxy>('proxies/:name', { params: { name } })
|
||||||
|
}
|
||||||
|
|
||||||
|
getProxyDelay (name: string) {
|
||||||
|
return this.instance.get<{ delay: number }>('proxies/:name/delay', { params: { name } })
|
||||||
|
}
|
||||||
|
|
||||||
|
changeProxySelected (name: string, select: string) {
|
||||||
|
return this.instance.get<void>('proxies/:name', { params: { name }, data: { name: select } })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function Instance () {
|
||||||
|
if (instance) {
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isClashX()) {
|
||||||
|
await rootStores.config.fetchAndParseConfig()
|
||||||
|
const general = rootStores.config.config.general
|
||||||
|
instance = new Request(
|
||||||
|
`http://${general.externalControllerAddr}:${general.externalControllerPort}`,
|
||||||
|
general.secret
|
||||||
|
)
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
|
||||||
|
const hostname = getLocalStorageItem('externalControllerAddr', '')
|
||||||
|
const port = getLocalStorageItem('externalControllerPort', '')
|
||||||
|
const secret = getLocalStorageItem('secret', '')
|
||||||
|
if (!hostname || !port) {
|
||||||
|
throw new Error('can\'t get hostname or port')
|
||||||
|
}
|
||||||
|
instance = new Request(`http://${hostname}:${port}`, secret)
|
||||||
|
return instance
|
||||||
|
}
|
@ -19,11 +19,40 @@ export interface Config {
|
|||||||
*/
|
*/
|
||||||
socksPort?: number
|
socksPort?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* redir proxy port
|
||||||
|
*/
|
||||||
|
redirPort?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* proxy is allow lan
|
||||||
|
*/
|
||||||
|
allowLan?: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* controller port
|
* controller port
|
||||||
*/
|
*/
|
||||||
externalController: number
|
externalControllerPort?: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* controller address
|
||||||
|
*/
|
||||||
|
externalControllerAddr?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* controller secret
|
||||||
|
*/
|
||||||
|
secret?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clash proxy mode
|
||||||
|
*/
|
||||||
|
mode?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clash tty log level
|
||||||
|
*/
|
||||||
|
logLevel?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
proxy?: Proxy[]
|
proxy?: Proxy[]
|
||||||
|
@ -30,10 +30,14 @@ export interface ShadowsocksProxy {
|
|||||||
|
|
||||||
port?: number
|
port?: number
|
||||||
|
|
||||||
cipter?: string
|
cipher?: string
|
||||||
|
|
||||||
password?: string
|
password?: string
|
||||||
|
|
||||||
|
obfs?: string
|
||||||
|
|
||||||
|
'obfs-host'?: string
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VmessProxy {
|
export interface VmessProxy {
|
||||||
@ -48,7 +52,7 @@ export interface VmessProxy {
|
|||||||
|
|
||||||
alterid?: number
|
alterid?: number
|
||||||
|
|
||||||
cipter?: string
|
cipher?: string
|
||||||
|
|
||||||
tls?: boolean
|
tls?: boolean
|
||||||
|
|
||||||
@ -75,7 +79,7 @@ export interface ProxyGroup {
|
|||||||
* configs of proxy server
|
* configs of proxy server
|
||||||
* now support select and url-test
|
* now support select and url-test
|
||||||
*/
|
*/
|
||||||
config?: SelectProxyGroup | UrlTestProxyGroup
|
config?: SelectProxyGroup | UrlTestProxyGroup | FallbackProxyGroup
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,6 +91,18 @@ export interface SelectProxyGroup {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FallbackProxyGroup {
|
||||||
|
|
||||||
|
type?: 'fallback'
|
||||||
|
|
||||||
|
proxies?: string[] // proxy names
|
||||||
|
|
||||||
|
url?: string
|
||||||
|
|
||||||
|
interval?: number // second
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export interface UrlTestProxyGroup {
|
export interface UrlTestProxyGroup {
|
||||||
|
|
||||||
type?: 'url-test'
|
type?: 'url-test'
|
||||||
|
@ -2,9 +2,9 @@ export interface Rule {
|
|||||||
|
|
||||||
type?: RuleType
|
type?: RuleType
|
||||||
|
|
||||||
value?: string
|
payload?: string
|
||||||
|
|
||||||
use?: string // proxy or proxy group name
|
proxy?: string // proxy or proxy group name
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { observable, action, runInAction } from 'mobx'
|
import { observable, action, runInAction } from 'mobx'
|
||||||
import { parse } from 'ini'
|
import * as yaml from 'yaml'
|
||||||
import { Config } from '@models'
|
import * as Models from '@models'
|
||||||
import { jsBridge } from '@lib/jsBridge'
|
import { jsBridge } from '@lib/jsBridge'
|
||||||
|
|
||||||
export class ConfigStore {
|
export class ConfigStore {
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
config: Config = {}
|
config: Models.Config = {}
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
public state: 'pending' | 'ok' | 'error' = 'pending'
|
public state: 'pending' | 'ok' | 'error' = 'pending'
|
||||||
@ -26,11 +26,37 @@ export class ConfigStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// otherwise parse ini
|
// otherwise parse ini
|
||||||
const config = parse(rawConfig)
|
const config = yaml.parse(rawConfig)
|
||||||
|
|
||||||
console.log(config)
|
const externalController = config['external-controller'] as string || ''
|
||||||
|
const host = externalController.split(':')
|
||||||
|
|
||||||
this.config = config
|
const proxies = config.Proxy as any[] || []
|
||||||
|
const proxy: Models.Proxy[] = proxies
|
||||||
|
.filter(p => ['vmess', 'ss', 'socks5'].includes(p.type))
|
||||||
|
.map(p => ({ name: p.name, config: p }))
|
||||||
|
|
||||||
|
const proxyGroups = config['Proxy Group'] as any[] || []
|
||||||
|
const proxyGroup: Models.ProxyGroup[] = proxyGroups
|
||||||
|
.filter(p => ['url-test', 'select', 'fallback'].includes(p.type))
|
||||||
|
.map(p => ({ name: p.name, config: p }))
|
||||||
|
|
||||||
|
this.config = {
|
||||||
|
general: {
|
||||||
|
port: config.port || 0,
|
||||||
|
socksPort: config['socks-port'] || 0,
|
||||||
|
redirPort: config['redir-port'] || 0,
|
||||||
|
allowLan: config['allow-lan'] || false,
|
||||||
|
externalControllerAddr: host[0] || '',
|
||||||
|
externalControllerPort: parseInt(host[1], 10) || 0,
|
||||||
|
secret: config.secret || '',
|
||||||
|
logLevel: config['log-level'] || 'info',
|
||||||
|
mode: config.mode || 'Rule'
|
||||||
|
},
|
||||||
|
proxy,
|
||||||
|
proxyGroup,
|
||||||
|
rules: config['Rule'] || []
|
||||||
|
}
|
||||||
this.state = 'ok'
|
this.state = 'ok'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"lib": ["es5", "es6", "dom"],
|
"lib": ["es5", "es6", "dom", "es2017"],
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"downlevelIteration": true,
|
"downlevelIteration": true,
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user