|
@@ -10,12 +10,23 @@ const UtilName = "heanup RcpSocket"
|
|
|
|
|
|
|
|
export class RcpSocket {
|
|
export class RcpSocket {
|
|
|
private static instance: RcpSocket;
|
|
private static instance: RcpSocket;
|
|
|
- private backgroundManager = BackgroundManager.getInstance()
|
|
|
|
|
public ErrorMessage: string | BusinessError = ''
|
|
public ErrorMessage: string | BusinessError = ''
|
|
|
public filesInfo: FileInfo[] = []
|
|
public filesInfo: FileInfo[] = []
|
|
|
|
|
+ private backgroundManager = BackgroundManager.getInstance()
|
|
|
|
|
|
|
|
//private rcpSession : rcp.Session | null = null
|
|
//private rcpSession : rcp.Session | null = null
|
|
|
|
|
|
|
|
|
|
+ constructor() {
|
|
|
|
|
+ console.info(UtilName, 'testTag', 'RcpSocketUtil单例已创建')
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ static getInstance(): RcpSocket {
|
|
|
|
|
+ if (!RcpSocket.instance) {
|
|
|
|
|
+ RcpSocket.instance = new RcpSocket();
|
|
|
|
|
+ }
|
|
|
|
|
+ return RcpSocket.instance;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
public RcpSendHead(host: string, port: number, account: string, password: string, path: string,
|
|
public RcpSendHead(host: string, port: number, account: string, password: string, path: string,
|
|
|
enableHttps: boolean): Promise<number> {
|
|
enableHttps: boolean): Promise<number> {
|
|
|
return new Promise<number>((resolve, reject) => {
|
|
return new Promise<number>((resolve, reject) => {
|
|
@@ -159,7 +170,6 @@ export class RcpSocket {
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
public RcpSendMove(host: string, port: number, account: string, password: string, path: string, enableHttps: boolean,
|
|
public RcpSendMove(host: string, port: number, account: string, password: string, path: string, enableHttps: boolean,
|
|
|
newPath: string): Promise<void> {
|
|
newPath: string): Promise<void> {
|
|
|
return new Promise<void>((resolve, reject) => {
|
|
return new Promise<void>((resolve, reject) => {
|
|
@@ -225,7 +235,6 @@ export class RcpSocket {
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
// rcp方法
|
|
// rcp方法
|
|
|
public async RcpSendPropFind(
|
|
public async RcpSendPropFind(
|
|
|
host: string,
|
|
host: string,
|
|
@@ -300,7 +309,7 @@ export class RcpSocket {
|
|
|
const encodedCredentials = buffer
|
|
const encodedCredentials = buffer
|
|
|
.from(`${account}:${password}`)
|
|
.from(`${account}:${password}`)
|
|
|
.toString("base64");
|
|
.toString("base64");
|
|
|
- console.info(UtilName,'testTag',account,password)
|
|
|
|
|
|
|
+ console.info(UtilName, 'testTag', account, password)
|
|
|
|
|
|
|
|
|
|
|
|
|
const headers: rcp.RequestHeaders = {
|
|
const headers: rcp.RequestHeaders = {
|
|
@@ -319,7 +328,7 @@ export class RcpSocket {
|
|
|
console.info(UtilName, 'testTag', 'PROPFIND执行完毕')
|
|
console.info(UtilName, 'testTag', 'PROPFIND执行完毕')
|
|
|
if (response != '') {
|
|
if (response != '') {
|
|
|
// 提取文件信息
|
|
// 提取文件信息
|
|
|
- const filesInfo = this.extractHrefContents(response, path,url);
|
|
|
|
|
|
|
+ const filesInfo = this.extractHrefContents(response, path, url);
|
|
|
if (filesInfo.length !== 0) {
|
|
if (filesInfo.length !== 0) {
|
|
|
console.info(UtilName, 'testTag', '请求成功')
|
|
console.info(UtilName, 'testTag', '请求成功')
|
|
|
rcpSession.close()
|
|
rcpSession.close()
|
|
@@ -349,7 +358,6 @@ export class RcpSocket {
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
// PROPFIND递归方法
|
|
// PROPFIND递归方法
|
|
|
public async RcpSendPropFindInfinity(
|
|
public async RcpSendPropFindInfinity(
|
|
|
host: string,
|
|
host: string,
|
|
@@ -454,20 +462,20 @@ export class RcpSocket {
|
|
|
};
|
|
};
|
|
|
let sendSinglePropfind = async (url: string, root: string): Promise<FileInfo[]> => {
|
|
let sendSinglePropfind = async (url: string, root: string): Promise<FileInfo[]> => {
|
|
|
return new Promise<FileInfo[]>(async (resolve, reject) => {
|
|
return new Promise<FileInfo[]>(async (resolve, reject) => {
|
|
|
- if(root.includes('%23recycle')){
|
|
|
|
|
|
|
+ if (root.includes('%23recycle')) {
|
|
|
resolve([])
|
|
resolve([])
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
// 发起请求
|
|
// 发起请求
|
|
|
try {
|
|
try {
|
|
|
- AppStorage.setOrCreate('CurrentPropfindInfinityRoot',root)
|
|
|
|
|
|
|
+ AppStorage.setOrCreate('CurrentPropfindInfinityRoot', root)
|
|
|
response = ''
|
|
response = ''
|
|
|
const req = new rcp.Request(url, "PROPFIND", headers, requestBody)
|
|
const req = new rcp.Request(url, "PROPFIND", headers, requestBody)
|
|
|
await rcpSession.fetch(req)
|
|
await rcpSession.fetch(req)
|
|
|
.finally(async () => {
|
|
.finally(async () => {
|
|
|
if (response != '') {
|
|
if (response != '') {
|
|
|
// 提取文件信息
|
|
// 提取文件信息
|
|
|
- let filesInfo = this.extractHrefContents(response, root,url);
|
|
|
|
|
|
|
+ let filesInfo = this.extractHrefContents(response, root, url);
|
|
|
let folderInfos: FileInfo[] = []
|
|
let folderInfos: FileInfo[] = []
|
|
|
for (const info of filesInfo) {
|
|
for (const info of filesInfo) {
|
|
|
if (this.isFileFolder(info.name)) {
|
|
if (this.isFileFolder(info.name)) {
|
|
@@ -517,23 +525,14 @@ export class RcpSocket {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
resolve(filesInfo)
|
|
resolve(filesInfo)
|
|
|
- }).
|
|
|
|
|
- catch((err: BusinessError) => {
|
|
|
|
|
|
|
+ }).catch((err: BusinessError) => {
|
|
|
rcpSession?.close()
|
|
rcpSession?.close()
|
|
|
- console.error(UtilName,'testTag','PROPFIND目录递归失败',JSON.stringify(err))
|
|
|
|
|
|
|
+ console.error(UtilName, 'testTag', 'PROPFIND目录递归失败', JSON.stringify(err))
|
|
|
reject(err)
|
|
reject(err)
|
|
|
})
|
|
})
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 判断文件是否属于文件夹
|
|
|
|
|
- private isFileFolder(filename: string):boolean{
|
|
|
|
|
- return filename.toLowerCase().endsWith('/')
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
//ArrayBuffer转utf8字符串
|
|
//ArrayBuffer转utf8字符串
|
|
|
buf2String(buf: ArrayBuffer) {
|
|
buf2String(buf: ArrayBuffer) {
|
|
|
let msgArray = new Uint8Array(buf);
|
|
let msgArray = new Uint8Array(buf);
|
|
@@ -551,41 +550,15 @@ export class RcpSocket {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
stringToNumber(str: string): number {
|
|
stringToNumber(str: string): number {
|
|
|
- let result:number = 0;
|
|
|
|
|
|
|
+ let result: number = 0;
|
|
|
for (let i = 0; i < str.length; i++) {
|
|
for (let i = 0; i < str.length; i++) {
|
|
|
result += str.charCodeAt(i);
|
|
result += str.charCodeAt(i);
|
|
|
}
|
|
}
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 将 HTTP 日期字符串转换为 Unix 时间戳
|
|
|
|
|
- private convertToUnixTimestamp(dateString: string): number {
|
|
|
|
|
- const date = new Date(dateString);
|
|
|
|
|
- if (isNaN(date.getTime())) {
|
|
|
|
|
- console.error(UtilName,'testTag',"非法日期字符串:", dateString);
|
|
|
|
|
- return 0;
|
|
|
|
|
- }
|
|
|
|
|
- return Math.floor(date.getTime() / 1000);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private decodeXMLEntities(str: string): string {
|
|
|
|
|
- const entityMap: HashMap<string,string> = new HashMap()
|
|
|
|
|
- entityMap.set('&', '&')
|
|
|
|
|
- entityMap.set('<', '<')
|
|
|
|
|
- entityMap.set('>','>')
|
|
|
|
|
- entityMap.set('"', '"')
|
|
|
|
|
- entityMap.set(''', "'")
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- // 正则匹配替换
|
|
|
|
|
- return str.replace(/&(amp|lt|gt|quot|apos);/g, (match:string, entity:string) => {
|
|
|
|
|
- const decoded = entityMap.get(`&${entity};`);
|
|
|
|
|
- return decoded ? decoded : match;
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
// 使用正则表达式提取所有 <D:href> 标签的内容
|
|
// 使用正则表达式提取所有 <D:href> 标签的内容
|
|
|
- extractHrefContents(xmlContent: string,rootpath: string,url: string): FileInfo[] {
|
|
|
|
|
|
|
+ extractHrefContents(xmlContent: string, rootpath: string, url: string): FileInfo[] {
|
|
|
const filesInfo: FileInfo[] = [];
|
|
const filesInfo: FileInfo[] = [];
|
|
|
// 匹配每个 <D:response>
|
|
// 匹配每个 <D:response>
|
|
|
const responseRegex = /<D:response\b[^>]*>([\s\S]*?)<\/D:response>/gi;
|
|
const responseRegex = /<D:response\b[^>]*>([\s\S]*?)<\/D:response>/gi;
|
|
@@ -597,7 +570,9 @@ export class RcpSocket {
|
|
|
|
|
|
|
|
// 提取 <D:href> 内容
|
|
// 提取 <D:href> 内容
|
|
|
const hrefMatch = responseBlock.match(/<D:href>(.*?)<\/D:href>/i);
|
|
const hrefMatch = responseBlock.match(/<D:href>(.*?)<\/D:href>/i);
|
|
|
- if (!hrefMatch) continue;
|
|
|
|
|
|
|
+ if (!hrefMatch) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// 获取完整的href路径
|
|
// 获取完整的href路径
|
|
|
const fullHref = this.decodeXMLEntities(decodeURI(hrefMatch[1]));
|
|
const fullHref = this.decodeXMLEntities(decodeURI(hrefMatch[1]));
|
|
@@ -629,7 +604,7 @@ export class RcpSocket {
|
|
|
|
|
|
|
|
// 提取<D:getlastmodified> 内容
|
|
// 提取<D:getlastmodified> 内容
|
|
|
let lastModifiedMatch = responseBlock.match(/<D:getlastmodified>(.*?)<\/D:getlastmodified>/i);
|
|
let lastModifiedMatch = responseBlock.match(/<D:getlastmodified>(.*?)<\/D:getlastmodified>/i);
|
|
|
- if(!lastModifiedMatch){
|
|
|
|
|
|
|
+ if (!lastModifiedMatch) {
|
|
|
lastModifiedMatch = responseBlock.match(/<lp1:getlastmodified>(.*?)<\/lp1:getlastmodified>/i);
|
|
lastModifiedMatch = responseBlock.match(/<lp1:getlastmodified>(.*?)<\/lp1:getlastmodified>/i);
|
|
|
}
|
|
}
|
|
|
const lastModified = lastModifiedMatch ? this.convertToUnixTimestamp(lastModifiedMatch[1]) : 0;
|
|
const lastModified = lastModifiedMatch ? this.convertToUnixTimestamp(lastModifiedMatch[1]) : 0;
|
|
@@ -646,11 +621,18 @@ export class RcpSocket {
|
|
|
return filesInfo;
|
|
return filesInfo;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- constructor() {
|
|
|
|
|
- console.info(UtilName,'testTag','RcpSocketUtil单例已创建')
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 获取文件列表(简化版包装方法)
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取文件列表
|
|
|
|
|
+ * @param host 主机名
|
|
|
|
|
+ * @param localHost 本地主机名
|
|
|
|
|
+ * @param isUseLocalHost 是否使用本地主机名
|
|
|
|
|
+ * @param port 端口号
|
|
|
|
|
+ * @param path 路径
|
|
|
|
|
+ * @param account 用户名
|
|
|
|
|
+ * @param password 密码
|
|
|
|
|
+ * @param enableHttps 是否启用HTTPS
|
|
|
|
|
+ * @returns
|
|
|
|
|
+ */
|
|
|
public async getFileList(
|
|
public async getFileList(
|
|
|
host: string,
|
|
host: string,
|
|
|
localHost: string,
|
|
localHost: string,
|
|
@@ -671,10 +653,41 @@ export class RcpSocket {
|
|
|
console.info(UtilName, 'testTag', '订阅HTTP数据传输事件(占位)');
|
|
console.info(UtilName, 'testTag', '订阅HTTP数据传输事件(占位)');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- static getInstance(): RcpSocket {
|
|
|
|
|
- if (!RcpSocket.instance) {
|
|
|
|
|
- RcpSocket.instance = new RcpSocket();
|
|
|
|
|
|
|
+ // 获取文件列表(简化版包装方法)
|
|
|
|
|
+
|
|
|
|
|
+ // 判断文件是否属于文件夹
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 判断文件是否属于文件夹
|
|
|
|
|
+ * @param filename 文件名
|
|
|
|
|
+ * @returns
|
|
|
|
|
+ */
|
|
|
|
|
+ private isFileFolder(filename: string): boolean {
|
|
|
|
|
+ return filename.toLowerCase().endsWith('/')
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 将 HTTP 日期字符串转换为 Unix 时间戳
|
|
|
|
|
+ private convertToUnixTimestamp(dateString: string): number {
|
|
|
|
|
+ const date = new Date(dateString);
|
|
|
|
|
+ if (isNaN(date.getTime())) {
|
|
|
|
|
+ console.error(UtilName, 'testTag', "非法日期字符串:", dateString);
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
- return RcpSocket.instance;
|
|
|
|
|
|
|
+ return Math.floor(date.getTime() / 1000);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private decodeXMLEntities(str: string): string {
|
|
|
|
|
+ const entityMap: HashMap<string, string> = new HashMap()
|
|
|
|
|
+ entityMap.set('&', '&')
|
|
|
|
|
+ entityMap.set('<', '<')
|
|
|
|
|
+ entityMap.set('>', '>')
|
|
|
|
|
+ entityMap.set('"', '"')
|
|
|
|
|
+ entityMap.set(''', "'")
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // 正则匹配替换
|
|
|
|
|
+ return str.replace(/&(amp|lt|gt|quot|apos);/g, (match: string, entity: string) => {
|
|
|
|
|
+ const decoded = entityMap.get(`&${entity};`);
|
|
|
|
|
+ return decoded ? decoded : match;
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|