cve-connector
Version:
UE Web 开发套件
326 lines (267 loc) • 7.47 kB
Markdown
# 代码重构日志
## 240619
获取云渲染实例的方法 getPixelStreamingInstance
### Before
```ts
import axios from 'axios'
import type { AxiosResponse } from 'axios'
type PixelStreamingCode = '0' | '1' | '2' | '3'
interface PixelStreamingData {
Code: PixelStreamingCode
Data: string | null
Result: string
}
interface PixelStreamingQuery {
ApplicationName: string
}
export function getPixelStreamingInstance(url: string): PixelStreamingPromise {
return new Promise((resolve, reject) => {
axios(url)
.then((res: AxiosResponse<PixelStreamingData, PixelStreamingQuery>) => {
const data: PixelStreamingData = res.data
switch (data.Code) {
case '0': {
if (data.Data) {
resolve(data.Data)
} else {
reject('Get Pixel Streaming Instance Failed!')
}
break
}
case '3': {
reject(data)
break
}
default: {
setTimeout(() => {
resolve(getPixelStreamingInstance(url))
}, 1000)
}
}
})
.catch((error: unknown) => {
reject(error)
})
})
}
```
### Step 1 减少依赖
插件中仅此处使用 axios 插件,决定改用 fetch 发送请求,减少依赖项。
```ts
import axios from 'axios'
import type { AxiosResponse } from 'axios'
interface PixelStreamingQuery {
ApplicationName: string
}
axios(url)
.then((res: AxiosResponse<PixelStreamingData, PixelStreamingQuery>) => {
const data: PixelStreamingData = res.data
// ...
})
.catch((error: unknown) => {
reject(error)
})
```
以上代码改为:
```ts
fetch(url)
.then(async (response: Response) => response.json())
.then((data: PixelStreamingData) => {
// ...
})
.catch((error: unknown) => {
reject(error)
})
```
### Step 2 异步编程
基于异步函数改造代码,减少 Promise 链式调用。
```ts
export function getPixelStreamingInstance(url: string): PixelStreamingPromise {
return new Promise((resolve, reject) => {
fetch(url)
.then(async (response: Response) => response.json())
.then((data: PixelStreamingData) => {
switch (data.Code) {
case '0': {
if (data.Data) {
resolve(data.Data)
} else {
reject('Get Pixel Streaming Instance Failed!')
}
break
}
case '3': {
reject(data)
break
}
default: {
setTimeout(() => {
resolve(getPixelStreamingInstance(url))
}, 1000)
}
}
})
.catch((error: unknown) => {
reject(error)
})
})
}
```
- 将 resolve 改为 return data
- 将 reject 改写为 throw error
以上代码逻辑改写为:
```ts
export async function getPixelStreamingInstance(url: string): PixelStreamingPromise {
const response = await fetch(url)
const data: PixelStreamingData = await response.json()
switch (data.Code) {
case '0': {
if (data.Data) {
return data.Data
} else {
throw new Error('Get Pixel Streaming Instance Failed!')
}
}
case '3': {
throw new Error(data.Data)
}
default: {
setTimeout(() => {
return getPixelStreamingInstance(url)
}, 1000)
}
}
}
```
### Step 3 分支拆解
弃用 switch 分支,减少缩进和嵌套。
```ts
switch (data.Code) {
case '0': {
if (data.Data) {
return data.Data
} else {
throw new Error('Get Pixel Streaming Instance Failed!')
}
}
case '3': {
throw new Error(data.Data)
}
default: {
setTimeout(() => {
return getPixelStreamingInstance(url)
}, 1000)
}
}
```
- 将异常检测的逻辑提前
- 简化计时器代码
- 将 return 后置,保证方法一定有返回值
将代码改为:
```ts
if (!data.Data) {
throw new Error('Get Pixel Streaming Instance Failed!')
}
if (data.Code === '3') {
throw new Error(data.Data)
}
if (data.Code !== '0') {
setTimeout(() => getPixelStreamingInstance(url), 1000)
}
return data.Data
```
### Step 4 入参拆解
url 参数一般为 'http://127.0.0.1:8080/GetPixelStreamingInstance?ApplicationName=CveTemplate',格式其实是固定的,将参数拆解到最小单位,只需要传入 origin 及 name,并补充异常检测。
```ts
export async function getPixelStreamingInstance(url: string): PixelStreamingPromise {
const response = await fetch(url)
const data: PixelStreamingData = await response.json()
// ...
if (data.Code !== '0') {
setTimeout(() => getPixelStreamingInstance(url), 1000)
}
return data.Data
}
```
以上代码改为:
```ts
export async function requestInstance(url: string): PixelStreamingPromise {
origin = origin.replace(/\/$/, '')
if (!name || !origin) {
throw new Error('Invalid Match Maker Origin Or Appilication Name')
}
const url = `${origin}/GetPixelStreamingInstance?ApplicationName=${name}`
const response = await fetch(url)
const data: PixelStreamingData = await response.json()
// ...
if (data.Code !== '0') {
setTimeout(() => requestInstance(origin, name), 1000)
}
return data.Data
}
```
### Step 5 漏洞修复
经调试,data.Code 为 1 和 2 时 data.Data 为 null,逻辑需要调整。
```ts
if (!data.Data) {
throw new Error('Get Pixel Streaming Instance Failed!')
}
// ...
if (data.Code !== '0') {
setTimeout(() => requestInstance(origin, name), 1000)
}
```
- 检测 data.Code 为 1 和 2 的逻辑前置
- 计时器部分(延迟轮询)补充返回值
以上代码改为:
```ts
if (data.Code === '1' || data.Code === '2') {
return await requestInstanceLater(origin, name)
}
if (!data.Data) {
throw new Error('Get Pixel Streaming Instance Failed!')
}
// ...
function requestInstanceLater(origin: string, name: string) {
return new Promise((resolve, reject) => {
setTimeout(() => {
requestInstance(origin, name).then(resolve).catch(reject)
}, 1000)
})
}
```
### After
```ts
type PixelStreamingCode = '0' | '1' | '2' | '3'
interface PixelStreamingData {
Code: PixelStreamingCode
Data: string | null
Result: string
}
export async function requestInstance(origin: string, name: string) {
origin = origin.replace(/\/$/, '')
if (!name || !origin) {
throw new Error('Invalid Match Maker Origin Or Appilication Name')
}
const url = `${origin}/GetPixelStreamingInstance?ApplicationName=${name}`
const response = await fetch(url)
const data: PixelStreamingData = await response.json()
if (data.Code === '1' || data.Code === '2') {
return await requestInstanceLater(origin, name)
}
if (!data.Data) {
throw new Error('Get Pixel Streaming Instance Failed!')
}
if (data.Code === '3') {
throw new Error(data.Data)
}
return data.Data
}
export function requestInstanceLater(origin: string, name: string) {
return new Promise((resolve: (value: string) => void) => {
setTimeout(() => {
requestInstance(origin, name).then(resolve)
}, 1000)
})
}
```