@wutiange/log-listener-plugin 2.0.1-alpha.3 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -201
- package/README.md +163 -163
- package/dist/src/HTTPInterceptor.js +2 -1
- package/dist/src/HTTPInterceptor.js.map +1 -1
- package/dist/src/__tests__/Server.test.js +4 -4
- package/dist/src/__tests__/Server.test.js.map +1 -1
- package/dist/src/__tests__/console.test.d.ts +1 -0
- package/dist/src/__tests__/console.test.js +29 -0
- package/dist/src/__tests__/console.test.js.map +1 -0
- package/dist/src/__tests__/utils.test.js +5 -1
- package/dist/src/__tests__/utils.test.js.map +1 -1
- package/dist/src/common.d.ts +1 -7
- package/dist/src/common.js +2 -14
- package/dist/src/common.js.map +1 -1
- package/dist/src/logPlugin.js +22 -17
- package/dist/src/logPlugin.js.map +1 -1
- package/dist/src/server.d.ts +21 -0
- package/dist/src/{Server.js → server.js} +47 -31
- package/dist/src/server.js.map +1 -0
- package/dist/src/utils.js +4 -4
- package/dist/src/utils.js.map +1 -1
- package/index.ts +3 -3
- package/package.json +59 -59
- package/src/HTTPInterceptor.ts +340 -339
- package/src/Server.ts +178 -167
- package/src/__mocks__/react-native/Libraries/Blob/FileReader.js +44 -44
- package/src/__mocks__/react-native/Libraries/Network/XHRInterceptor.js +39 -39
- package/src/__tests__/HTTPInterceptor.test.ts +322 -322
- package/src/__tests__/Server.test.ts +149 -149
- package/src/__tests__/utils.test.ts +113 -112
- package/src/common.ts +57 -70
- package/src/logPlugin.ts +231 -224
- package/src/logger.ts +14 -14
- package/src/utils.ts +112 -112
- package/tsconfig.json +26 -26
- package/dist/src/Server.d.ts +0 -20
- package/dist/src/Server.js.map +0 -1
package/src/Server.ts
CHANGED
@@ -1,167 +1,178 @@
|
|
1
|
-
import { hasPort, sleep } from "./utils";
|
2
|
-
import Zeroconf from "react-native-zeroconf";
|
3
|
-
import { getBaseData,
|
4
|
-
import logger from "./logger";
|
5
|
-
import md5 from 'crypto-js/md5';
|
6
|
-
|
7
|
-
|
8
|
-
const DEFAULT_PORT = 27751;
|
9
|
-
class Server {
|
10
|
-
private
|
11
|
-
private
|
12
|
-
private
|
13
|
-
private
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
this.
|
22
|
-
}
|
23
|
-
|
24
|
-
|
25
|
-
this.
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
}
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
}
|
103
|
-
|
104
|
-
private send = async (
|
105
|
-
path: string,
|
106
|
-
data: Record<string, any>
|
107
|
-
): Promise<void> => {
|
108
|
-
const request = async (url: string, _data: Record<string, any>) => {
|
109
|
-
await Promise.race([
|
110
|
-
fetch(`${url}/${path}`, {
|
111
|
-
method: "POST",
|
112
|
-
headers: {
|
113
|
-
"Content-Type": "application/json;charset=utf-8",
|
114
|
-
},
|
115
|
-
body: JSON.stringify(
|
116
|
-
{ ...this.innerBaseData, ...this.baseData, ..._data },
|
117
|
-
(_, val) => {
|
118
|
-
if (val instanceof Error) {
|
119
|
-
return val.toString();
|
120
|
-
}
|
121
|
-
return val;
|
122
|
-
}
|
123
|
-
),
|
124
|
-
}),
|
125
|
-
sleep(this.timeout, true),
|
126
|
-
]);
|
127
|
-
};
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
this.
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
}
|
166
|
-
|
167
|
-
|
1
|
+
import { hasPort, sleep } from "./utils";
|
2
|
+
import Zeroconf from "react-native-zeroconf";
|
3
|
+
import { getBaseData, LOG_KEY } from "./common";
|
4
|
+
import logger from "./logger";
|
5
|
+
import md5 from 'crypto-js/md5';
|
6
|
+
|
7
|
+
|
8
|
+
const DEFAULT_PORT = 27751;
|
9
|
+
class Server {
|
10
|
+
private baseUrlArr: Set<string> = new Set();
|
11
|
+
private urlsObj: Map<string, string> = new Map();
|
12
|
+
private timeout: number;
|
13
|
+
private baseData: Record<string, any> = {};
|
14
|
+
private urlsListener: (urls: Set<string>) => void;
|
15
|
+
private innerBaseData: Record<string, string> = {};
|
16
|
+
|
17
|
+
constructor(url?: string | Set<string>, timeout: number = 30000) {
|
18
|
+
if (typeof url === "string") {
|
19
|
+
this.updateUrl(url);
|
20
|
+
} else {
|
21
|
+
this.setBaseUrlArr(url ?? new Set());
|
22
|
+
}
|
23
|
+
this.timeout = timeout;
|
24
|
+
this.innerBaseData = getBaseData();
|
25
|
+
this.handleZeroConf();
|
26
|
+
}
|
27
|
+
|
28
|
+
addUrlsListener = (
|
29
|
+
onNewUrlCallback: (urls: Set<string>) => void
|
30
|
+
) => {
|
31
|
+
this.urlsListener = onNewUrlCallback;
|
32
|
+
};
|
33
|
+
|
34
|
+
private requestJoin = async (url: string, token: string) => {
|
35
|
+
const response = await fetch(url, {
|
36
|
+
method: "POST",
|
37
|
+
headers: {
|
38
|
+
"Content-Type": "application/json;charset=utf-8",
|
39
|
+
},
|
40
|
+
body: JSON.stringify({
|
41
|
+
token,
|
42
|
+
model: this.innerBaseData.Model ?? `${this.innerBaseData.systemName}v${this.innerBaseData.osVersion}`,
|
43
|
+
id: md5(JSON.stringify(this.innerBaseData)).toString(),
|
44
|
+
}),
|
45
|
+
});
|
46
|
+
if (response.status !== 200) {
|
47
|
+
return false;
|
48
|
+
}
|
49
|
+
const json = await response.json();
|
50
|
+
if (json.code !== 0) {
|
51
|
+
return false;
|
52
|
+
}
|
53
|
+
return true
|
54
|
+
}
|
55
|
+
|
56
|
+
private async handleZeroConf() {
|
57
|
+
try {
|
58
|
+
const Zeroconf = require("react-native-zeroconf")?.default;
|
59
|
+
if (!Zeroconf) {
|
60
|
+
return;
|
61
|
+
}
|
62
|
+
// @ts-ignore
|
63
|
+
const zeroconf: Zeroconf = new Zeroconf();
|
64
|
+
zeroconf.on("resolved", async (service) => {
|
65
|
+
try {
|
66
|
+
const { path, token } = service.txt ?? {};
|
67
|
+
const url = `http://${service.host}:${service.port}`;
|
68
|
+
if (!(path && token) || this.baseUrlArr.has(url)) {
|
69
|
+
return;
|
70
|
+
}
|
71
|
+
if (!(await this.requestJoin(`${url}${path}`, token))) {
|
72
|
+
return;
|
73
|
+
}
|
74
|
+
this.baseUrlArr.add(url);
|
75
|
+
this.urlsObj.set(service.name, url)
|
76
|
+
if (this.urlsListener) {
|
77
|
+
this.urlsListener(this.baseUrlArr);
|
78
|
+
}
|
79
|
+
} catch (error) {
|
80
|
+
logger.warn(LOG_KEY, "加入日志系统失败---", error);
|
81
|
+
}
|
82
|
+
});
|
83
|
+
zeroconf.on("remove", (name) => {
|
84
|
+
const currentUrl = this.urlsObj.get(name);
|
85
|
+
this.baseUrlArr.delete(currentUrl)
|
86
|
+
this.urlsObj.delete(name)
|
87
|
+
if (this.urlsListener) {
|
88
|
+
this.urlsListener(this.baseUrlArr);
|
89
|
+
}
|
90
|
+
});
|
91
|
+
zeroconf.on("error", (err) => {
|
92
|
+
logger.warn(LOG_KEY, "zeroconf出现错误", err);
|
93
|
+
})
|
94
|
+
zeroconf.scan("http", "tcp");
|
95
|
+
} catch (error: any) {
|
96
|
+
logger.warn(LOG_KEY, "zeroconf扫描或处理相关逻辑失败或者您根本就没有安装 react-native-zeroconf ,如果您没有安装,那么您将无法使用发现功能", error);
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
updateTimeout(timeout = 3000) {
|
101
|
+
this.timeout = timeout;
|
102
|
+
}
|
103
|
+
|
104
|
+
private send = async (
|
105
|
+
path: string,
|
106
|
+
data: Record<string, any>
|
107
|
+
): Promise<void> => {
|
108
|
+
const request = async (url: string, _data: Record<string, any>) => {
|
109
|
+
await Promise.race([
|
110
|
+
fetch(`${url}/${path}`, {
|
111
|
+
method: "POST",
|
112
|
+
headers: {
|
113
|
+
"Content-Type": "application/json;charset=utf-8",
|
114
|
+
},
|
115
|
+
body: JSON.stringify(
|
116
|
+
{ ...this.innerBaseData, ...this.baseData, ..._data },
|
117
|
+
(_, val) => {
|
118
|
+
if (val instanceof Error) {
|
119
|
+
return val.toString();
|
120
|
+
}
|
121
|
+
return val;
|
122
|
+
}
|
123
|
+
),
|
124
|
+
}),
|
125
|
+
sleep(this.timeout, true),
|
126
|
+
]);
|
127
|
+
};
|
128
|
+
if (this.baseUrlArr.size === 0) {
|
129
|
+
return;
|
130
|
+
}
|
131
|
+
this.baseUrlArr.forEach(async (e) => {
|
132
|
+
try {
|
133
|
+
await request(e, data)
|
134
|
+
} catch (error: any) {
|
135
|
+
if (error?.message?.includes("Network request failed") || error?.message?.includes("Timeout")) {
|
136
|
+
return
|
137
|
+
}
|
138
|
+
logger.warn(LOG_KEY, "上报日志失败", error)
|
139
|
+
}
|
140
|
+
})
|
141
|
+
};
|
142
|
+
|
143
|
+
updateUrl(url: string = '') {
|
144
|
+
const tempUrl = url.includes("http") ? url : `http://${url}`;
|
145
|
+
if (!url) {
|
146
|
+
const currentUrl = this.urlsObj.get("Default");
|
147
|
+
this.baseUrlArr.delete(currentUrl);
|
148
|
+
this.urlsObj.delete("Default");
|
149
|
+
} else if (!hasPort(tempUrl)) {
|
150
|
+
this.updateUrl(`${tempUrl}:${DEFAULT_PORT}`);
|
151
|
+
} else {
|
152
|
+
this.baseUrlArr.add(tempUrl);
|
153
|
+
this.urlsObj.set("Default", tempUrl);
|
154
|
+
}
|
155
|
+
}
|
156
|
+
|
157
|
+
setBaseUrlArr(urlArr: Set<string> = new Set()) {
|
158
|
+
this.baseUrlArr = urlArr;
|
159
|
+
}
|
160
|
+
|
161
|
+
getBaseUrlArr() {
|
162
|
+
return this.baseUrlArr;
|
163
|
+
}
|
164
|
+
|
165
|
+
updateBaseData(data: Record<string, any> = {}) {
|
166
|
+
this.baseData = data;
|
167
|
+
}
|
168
|
+
|
169
|
+
log = async (data: Record<string, any>) => {
|
170
|
+
return this.send("log", data);
|
171
|
+
};
|
172
|
+
|
173
|
+
network = async (data: Record<string, any>) => {
|
174
|
+
return this.send("network", data);
|
175
|
+
};
|
176
|
+
}
|
177
|
+
|
178
|
+
export default Server;
|
@@ -1,45 +1,45 @@
|
|
1
|
-
class FileReader {
|
2
|
-
constructor() {
|
3
|
-
this.result = null;
|
4
|
-
this.error = null;
|
5
|
-
this.readyState = FileReader.EMPTY;
|
6
|
-
}
|
7
|
-
|
8
|
-
static EMPTY = 0;
|
9
|
-
static LOADING = 1;
|
10
|
-
static DONE = 2;
|
11
|
-
|
12
|
-
addEventListener(event, callback) {
|
13
|
-
this[`on${event}`] = callback;
|
14
|
-
}
|
15
|
-
|
16
|
-
removeEventListener(event, callback) {
|
17
|
-
if (this[`on${event}`] === callback) {
|
18
|
-
this[`on${event}`] = null;
|
19
|
-
}
|
20
|
-
}
|
21
|
-
|
22
|
-
readAsText(blob) {
|
23
|
-
this._read(blob, 'text');
|
24
|
-
}
|
25
|
-
|
26
|
-
readAsArrayBuffer(blob) {
|
27
|
-
this._read(blob, 'arraybuffer');
|
28
|
-
}
|
29
|
-
|
30
|
-
_read(blob, resultType) {
|
31
|
-
this.readyState = FileReader.LOADING;
|
32
|
-
setTimeout(() => {
|
33
|
-
this.readyState = FileReader.DONE;
|
34
|
-
if (resultType === 'text') {
|
35
|
-
this.result = blob.text();
|
36
|
-
} else if (resultType === 'arraybuffer') {
|
37
|
-
// 这里我们简单地返回一个空的 ArrayBuffer
|
38
|
-
this.result = new ArrayBuffer(0);
|
39
|
-
}
|
40
|
-
if (this.onload) this.onload({target: this});
|
41
|
-
}, 0);
|
42
|
-
}
|
43
|
-
}
|
44
|
-
|
1
|
+
class FileReader {
|
2
|
+
constructor() {
|
3
|
+
this.result = null;
|
4
|
+
this.error = null;
|
5
|
+
this.readyState = FileReader.EMPTY;
|
6
|
+
}
|
7
|
+
|
8
|
+
static EMPTY = 0;
|
9
|
+
static LOADING = 1;
|
10
|
+
static DONE = 2;
|
11
|
+
|
12
|
+
addEventListener(event, callback) {
|
13
|
+
this[`on${event}`] = callback;
|
14
|
+
}
|
15
|
+
|
16
|
+
removeEventListener(event, callback) {
|
17
|
+
if (this[`on${event}`] === callback) {
|
18
|
+
this[`on${event}`] = null;
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
readAsText(blob) {
|
23
|
+
this._read(blob, 'text');
|
24
|
+
}
|
25
|
+
|
26
|
+
readAsArrayBuffer(blob) {
|
27
|
+
this._read(blob, 'arraybuffer');
|
28
|
+
}
|
29
|
+
|
30
|
+
_read(blob, resultType) {
|
31
|
+
this.readyState = FileReader.LOADING;
|
32
|
+
setTimeout(() => {
|
33
|
+
this.readyState = FileReader.DONE;
|
34
|
+
if (resultType === 'text') {
|
35
|
+
this.result = blob.text();
|
36
|
+
} else if (resultType === 'arraybuffer') {
|
37
|
+
// 这里我们简单地返回一个空的 ArrayBuffer
|
38
|
+
this.result = new ArrayBuffer(0);
|
39
|
+
}
|
40
|
+
if (this.onload) this.onload({target: this});
|
41
|
+
}, 0);
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
45
|
module.exports = FileReader;
|
@@ -1,39 +1,39 @@
|
|
1
|
-
// __mocks__/react-native/Libraries/XHRInterceptor.js
|
2
|
-
|
3
|
-
class XHRInterceptor {
|
4
|
-
static _isInterceptorEnabled = false
|
5
|
-
static openCallback = null
|
6
|
-
static requestHeaderCallback = null
|
7
|
-
static headerReceivedCallback = null
|
8
|
-
static sendCallback = null
|
9
|
-
static responseCallback = null
|
10
|
-
|
11
|
-
static setOpenCallback = jest.fn((callback) => {
|
12
|
-
XHRInterceptor.openCallback = callback;
|
13
|
-
})
|
14
|
-
static setRequestHeaderCallback = jest.fn((callback) => {
|
15
|
-
XHRInterceptor.requestHeaderCallback = callback;
|
16
|
-
})
|
17
|
-
static setHeaderReceivedCallback = jest.fn((callback) => {
|
18
|
-
XHRInterceptor.headerReceivedCallback = callback;
|
19
|
-
})
|
20
|
-
static setSendCallback = jest.fn((callback) => {
|
21
|
-
XHRInterceptor.sendCallback = callback;
|
22
|
-
})
|
23
|
-
static setResponseCallback = jest.fn((callback) => {
|
24
|
-
XHRInterceptor.responseCallback = callback;
|
25
|
-
})
|
26
|
-
|
27
|
-
static enableInterception = jest.fn(() => {
|
28
|
-
XHRInterceptor._isInterceptorEnabled = true;
|
29
|
-
})
|
30
|
-
|
31
|
-
static disableInterception = jest.fn(() => {
|
32
|
-
XHRInterceptor._isInterceptorEnabled = false;
|
33
|
-
})
|
34
|
-
|
35
|
-
static isInterceptorEnabled = jest.fn(() => XHRInterceptor._isInterceptorEnabled)
|
36
|
-
};
|
37
|
-
|
38
|
-
module.exports = XHRInterceptor;
|
39
|
-
|
1
|
+
// __mocks__/react-native/Libraries/XHRInterceptor.js
|
2
|
+
|
3
|
+
class XHRInterceptor {
|
4
|
+
static _isInterceptorEnabled = false
|
5
|
+
static openCallback = null
|
6
|
+
static requestHeaderCallback = null
|
7
|
+
static headerReceivedCallback = null
|
8
|
+
static sendCallback = null
|
9
|
+
static responseCallback = null
|
10
|
+
|
11
|
+
static setOpenCallback = jest.fn((callback) => {
|
12
|
+
XHRInterceptor.openCallback = callback;
|
13
|
+
})
|
14
|
+
static setRequestHeaderCallback = jest.fn((callback) => {
|
15
|
+
XHRInterceptor.requestHeaderCallback = callback;
|
16
|
+
})
|
17
|
+
static setHeaderReceivedCallback = jest.fn((callback) => {
|
18
|
+
XHRInterceptor.headerReceivedCallback = callback;
|
19
|
+
})
|
20
|
+
static setSendCallback = jest.fn((callback) => {
|
21
|
+
XHRInterceptor.sendCallback = callback;
|
22
|
+
})
|
23
|
+
static setResponseCallback = jest.fn((callback) => {
|
24
|
+
XHRInterceptor.responseCallback = callback;
|
25
|
+
})
|
26
|
+
|
27
|
+
static enableInterception = jest.fn(() => {
|
28
|
+
XHRInterceptor._isInterceptorEnabled = true;
|
29
|
+
})
|
30
|
+
|
31
|
+
static disableInterception = jest.fn(() => {
|
32
|
+
XHRInterceptor._isInterceptorEnabled = false;
|
33
|
+
})
|
34
|
+
|
35
|
+
static isInterceptorEnabled = jest.fn(() => XHRInterceptor._isInterceptorEnabled)
|
36
|
+
};
|
37
|
+
|
38
|
+
module.exports = XHRInterceptor;
|
39
|
+
|