filecache
This commit is contained in:
@@ -0,0 +1,412 @@
|
||||
import {
|
||||
RequestOptions,
|
||||
RequestTask,
|
||||
UploadTask,
|
||||
UploadFileOptions,
|
||||
OnProgressUpdateResult,
|
||||
UploadFileProgressUpdateCallback,
|
||||
OnProgressDownloadResult,
|
||||
DownloadTask,
|
||||
DownloadFileOptions,
|
||||
DownloadFileProgressUpdateCallback,
|
||||
RequestTaskOnHeadersReceivedCallback,
|
||||
RequestTaskOnHeadersReceivedListenerResult,
|
||||
RequestTaskOnChunkReceivedCallback,
|
||||
RequestTaskOnChunkReceivedListenerResult
|
||||
}
|
||||
from '../../interface.uts';
|
||||
import { UTSiOS } from "DCloudUTSFoundation";
|
||||
import { NSNumber, URLSessionDataDelegate, URL, CharacterSet, URLSession, URLSessionConfiguration, OperationQueue, URLSessionTask, URLResponse, URLSessionDataTask, URLAuthenticationChallengeSender, URLAuthenticationChallenge, URLCredential, URLSessionTaskMetrics, Data, HTTPURLResponse, NSError, URLRequest, ComparisonResult } from 'Foundation';
|
||||
import { UploadController } from './upload/UploadController.uts';
|
||||
import { DownloadController } from './download/DownloadController.uts';
|
||||
import { Int } from 'Swift';
|
||||
import { NetworkUtil } from './utils/NetworkUtil.uts';
|
||||
|
||||
class NetworkRequestListener {
|
||||
@UTSiOS.keyword("weak")
|
||||
public task: AnyObject | null = null;
|
||||
|
||||
public onStart() : void { }
|
||||
|
||||
public onHeadersReceived(statusCode : number, headers : Map<string, any>) : void { }
|
||||
|
||||
public onDataReceived(data : Data) : void { }
|
||||
|
||||
public onFinished(response : HTTPURLResponse) : void { }
|
||||
|
||||
public onFail(error : NSError) : void { }
|
||||
}
|
||||
|
||||
class NetworkUploadFileListener {
|
||||
@UTSiOS.keyword("weak")
|
||||
public task: AnyObject | null = null;
|
||||
public progressListeners : Array<UploadFileProgressUpdateCallback> = new Array<UploadFileProgressUpdateCallback>();
|
||||
public onProgress(progressUpdate : OnProgressUpdateResult) : void { };
|
||||
public onDataReceived(data : Data) : void { };
|
||||
public onFinished(response : HTTPURLResponse) : void { };
|
||||
public onFail(error : NSError) : void { };
|
||||
}
|
||||
|
||||
class NetworkDownloadFileListener {
|
||||
@UTSiOS.keyword("weak")
|
||||
public task: AnyObject | null = null;
|
||||
public options : DownloadFileOptions | null = null;
|
||||
public progressListeners : Array<DownloadFileProgressUpdateCallback> = new Array<DownloadFileProgressUpdateCallback>();
|
||||
public onProgress(progressUpdate : OnProgressDownloadResult) : void { };
|
||||
public onFinished(response : HTTPURLResponse, filePath : string) : void { };
|
||||
public onFail(error : NSError) : void { };
|
||||
}
|
||||
|
||||
|
||||
class NetworkRequestTaskImpl implements RequestTask {
|
||||
public headersReceivedListeners = new Map<number, RequestTaskOnHeadersReceivedCallback>()
|
||||
public chunkReceivedListeners = new Map<number, RequestTaskOnChunkReceivedCallback>()
|
||||
|
||||
private requestTaskOnHeadersReceivedCallbackCount: number = 0
|
||||
private requestTaskOnChunkReceivedCallbackCount: number = 0
|
||||
private semaphore = DispatchSemaphore(value = 1)
|
||||
|
||||
private task : URLSessionDataTask | null = null;
|
||||
constructor(task : URLSessionDataTask | null) {
|
||||
this.task = task;
|
||||
super();
|
||||
}
|
||||
|
||||
public abort() {
|
||||
this.task?.cancel()
|
||||
UTSiOS.destroyInstance(this)
|
||||
}
|
||||
|
||||
public onHeadersReceived(listener: RequestTaskOnHeadersReceivedCallback): number {
|
||||
this.semaphore.wait()
|
||||
this.requestTaskOnHeadersReceivedCallbackCount += 1
|
||||
this.semaphore.signal()
|
||||
this.headersReceivedListeners.set(this.requestTaskOnHeadersReceivedCallbackCount, listener)
|
||||
return this.requestTaskOnHeadersReceivedCallbackCount
|
||||
}
|
||||
|
||||
public offHeadersReceived(listener ?: number | RequestTaskOnHeadersReceivedCallback | null): void {
|
||||
if (listener != null && typeof listener! == "number") {
|
||||
const id = listener as number
|
||||
this.headersReceivedListeners.delete(id)
|
||||
} else {
|
||||
this.headersReceivedListeners.clear()
|
||||
}
|
||||
}
|
||||
|
||||
public onChunkReceived(listener: RequestTaskOnChunkReceivedCallback): number {
|
||||
this.semaphore.wait()
|
||||
this.requestTaskOnChunkReceivedCallbackCount += 1
|
||||
this.semaphore.signal()
|
||||
this.chunkReceivedListeners.set(this.requestTaskOnChunkReceivedCallbackCount, listener)
|
||||
return this.requestTaskOnChunkReceivedCallbackCount
|
||||
}
|
||||
|
||||
public offChunkReceived(listener ?: number | RequestTaskOnChunkReceivedCallback | null): void {
|
||||
if (listener != null && typeof listener! == "number") {
|
||||
const id = listener as number
|
||||
this.chunkReceivedListeners.delete(id)
|
||||
} else {
|
||||
this.chunkReceivedListeners.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NetworkManager implements URLSessionDataDelegate {
|
||||
private static instance : NetworkManager | null = null;
|
||||
private enableChunked: boolean = false;
|
||||
private session : URLSession | null = null;
|
||||
|
||||
private taskMap : Map<URLSessionTask, NetworkRequestListener> = new Map<URLSessionDataTask, NetworkRequestListener>();
|
||||
|
||||
public static getInstance() : NetworkManager {
|
||||
if (this.instance == null) {
|
||||
this.instance = new NetworkManager();
|
||||
}
|
||||
return this.instance!;
|
||||
}
|
||||
|
||||
|
||||
public request<T>(param : RequestOptions<T>, listener : NetworkRequestListener) : RequestTask {
|
||||
let request = this.createRequest(param);
|
||||
this.enableChunked = param.enableChunked ?? false
|
||||
if (request == null) {
|
||||
let error = new NSError(domain = "invalid URL", code = 600009);
|
||||
listener.onFail(error);
|
||||
let task = new NetworkRequestTaskImpl(null);
|
||||
listener.task = task;
|
||||
return task;
|
||||
}
|
||||
|
||||
if (this.session == null) {
|
||||
let urlSessionConfig = URLSessionConfiguration.default;
|
||||
|
||||
this.session = new URLSession(configuration = urlSessionConfig, delegate = this, delegateQueue = OperationQueue.current);
|
||||
}
|
||||
let task = this.session?.dataTask(with = request!);
|
||||
task?.resume();
|
||||
if (task != null) {
|
||||
this.taskMap.set(task!, listener);
|
||||
}
|
||||
let requestTask = new NetworkRequestTaskImpl(task);
|
||||
listener.task = requestTask;
|
||||
return requestTask;
|
||||
}
|
||||
|
||||
public uploadFile(options : UploadFileOptions, listener : NetworkUploadFileListener) : UploadTask {
|
||||
return UploadController.getInstance().uploadFile(options, listener);
|
||||
}
|
||||
|
||||
public downloadFile(options : DownloadFileOptions, listener : NetworkDownloadFileListener) : DownloadTask {
|
||||
return DownloadController.getInstance().downloadFile(options, listener);
|
||||
}
|
||||
|
||||
|
||||
public createRequest<T>(param : RequestOptions<T>) : URLRequest | null {
|
||||
const encodeUrl = this.percentEscapedString(param.url)
|
||||
let url = new URL(string = encodeUrl);
|
||||
if (url == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
let timeout = param.timeout == null ? 120000 : param.timeout;
|
||||
let timeoutInterval = new Double(timeout!) / 1000;
|
||||
let request = new URLRequest(url = url!, cachePolicy = URLRequest.CachePolicy.useProtocolCachePolicy, timeoutInterval = timeoutInterval);
|
||||
request.httpShouldHandleCookies = true;
|
||||
let method = param.method;
|
||||
if (method == null || method!.trimmingCharacters(in = CharacterSet.whitespacesAndNewlines).count == 0) {
|
||||
method = "GET";
|
||||
}
|
||||
request.httpMethod = method!;
|
||||
|
||||
let ua = UTSiOS.getUserAgent();
|
||||
request.setValue(ua, forHTTPHeaderField = "User-Agent");
|
||||
|
||||
if (param.header == null) {
|
||||
param.header = {}
|
||||
}
|
||||
|
||||
|
||||
let headers = param.header?.toMap();
|
||||
let hasContentType = false;
|
||||
if (headers != null) {
|
||||
for (entry in headers!) {
|
||||
let key = entry.key;
|
||||
let value = entry.value;
|
||||
if (key.caseInsensitiveCompare("Content-Type") == ComparisonResult.orderedSame) {
|
||||
hasContentType = true;
|
||||
}
|
||||
let valueStr = "";
|
||||
if (value instanceof UTSJSONObject) {
|
||||
valueStr = JSON.stringify(value) ?? ""
|
||||
} else if (value instanceof Map<string, any>) {
|
||||
valueStr = JSON.stringify(new UTSJSONObject(value)) ?? ""
|
||||
} else {
|
||||
valueStr = `${value}`
|
||||
}
|
||||
request.setValue(valueStr, forHTTPHeaderField = key);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasContentType) {
|
||||
if ("GET" != method) {
|
||||
request.setValue("application/json", forHTTPHeaderField = "Content-Type");
|
||||
}
|
||||
}
|
||||
if ("GET" == method) {
|
||||
const data = param.data;
|
||||
if (data != null) {
|
||||
let json : UTSJSONObject | null = null;
|
||||
if (typeof (data) == 'string') {
|
||||
json = JSON.parseObject(data as string);
|
||||
} else if (data instanceof UTSJSONObject) {
|
||||
json = data as UTSJSONObject;
|
||||
} else if (data instanceof Map<string, any>) {
|
||||
json = new UTSJSONObject(data!)
|
||||
}
|
||||
if (json != null) {
|
||||
let urlWithQuery = this.stringifyQuery(encodeUrl, json!)
|
||||
let url = new URL(string = urlWithQuery);
|
||||
request.url = url;
|
||||
}
|
||||
}
|
||||
} else if (param.data != null) {
|
||||
let bodyData : Data | null = null;
|
||||
if (typeof (param.data) == 'string') {
|
||||
bodyData = (param.data as string).data(using = String.Encoding.utf8);
|
||||
} else if (param.data instanceof Map<string, any>) {
|
||||
let body : string | null = "";
|
||||
const contentType = request.value(forHTTPHeaderField = "Content-Type")
|
||||
const data = new UTSJSONObject(param.data!);
|
||||
if (contentType != null) {
|
||||
if (contentType!.indexOf("application/x-www-form-urlencoded") == 0) {
|
||||
const map : Map<string, any | null> = data.toMap();
|
||||
const bodyArray = new Array<string>();
|
||||
map.forEach((value, key) => {
|
||||
bodyArray.push(key + "=" + `${value ?? "null"}`);
|
||||
})
|
||||
body = bodyArray.join("&");
|
||||
} else {
|
||||
body = JSON.stringify(data);
|
||||
}
|
||||
bodyData = body?.data(using = String.Encoding.utf8);
|
||||
}
|
||||
} else if (param.data instanceof ArrayBuffer) {
|
||||
const arrayBuffer = param.data as ArrayBuffer
|
||||
bodyData = arrayBuffer.toData()
|
||||
} else if (param.data instanceof UTSJSONObject) {
|
||||
let body : string | null = "";
|
||||
const contentType = request.value(forHTTPHeaderField = "Content-Type")
|
||||
if (contentType != null) {
|
||||
if (contentType!.indexOf("application/x-www-form-urlencoded") == 0) {
|
||||
const data = param.data as UTSJSONObject;
|
||||
const map : Map<string, any | null> = data.toMap();
|
||||
const bodyArray = new Array<string>();
|
||||
map.forEach((value, key) => {
|
||||
bodyArray.push(key + "=" + `${value ?? "null"}`);
|
||||
})
|
||||
body = bodyArray.join("&");
|
||||
} else {
|
||||
body = JSON.stringify(param.data);
|
||||
}
|
||||
bodyData = body?.data(using = String.Encoding.utf8);
|
||||
}
|
||||
}
|
||||
if (bodyData == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
request.httpBody = bodyData;
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* data拼接到url上
|
||||
*/
|
||||
private stringifyQuery(url : string, data : UTSJSONObject) : string {
|
||||
let newUrl = url;
|
||||
//http:xxx/xxx?a=b&c=d#123
|
||||
let str = url.split('#')
|
||||
let hash = ''
|
||||
if (str.length > 1) {
|
||||
hash = str[1] //123
|
||||
}
|
||||
str = str[0].split('?')
|
||||
let query = ''
|
||||
if (str.length > 1) {
|
||||
query = str[1] //a=b&c=d
|
||||
}
|
||||
newUrl = str[0] // http:xxx/xxx
|
||||
const pairs = query.split('&')
|
||||
const queryMap = new Map<string, string>();
|
||||
pairs.forEach((item : string, index : number) => {
|
||||
const temp = item.split('=')
|
||||
if (temp.length > 1) {
|
||||
queryMap[temp[0]] = temp[1]
|
||||
}
|
||||
});
|
||||
const dataMap : Map<string, any | null> = data.toMap();
|
||||
dataMap.forEach((value, key) => {
|
||||
if (value == null) {
|
||||
value = "";
|
||||
}
|
||||
let encodeKey = encodeURIComponent(key)!
|
||||
if (value instanceof UTSJSONObject || value instanceof Array<any | null>) {
|
||||
queryMap[encodeKey] = encodeURIComponent(JSON.stringify(value)!)!
|
||||
} else if (value instanceof Map<string, any>) {
|
||||
queryMap[encodeKey] = encodeURIComponent(JSON.stringify(new UTSJSONObject(value))!)!
|
||||
} else {
|
||||
queryMap[encodeKey] = encodeURIComponent(`${value!}`)!;
|
||||
}
|
||||
})
|
||||
let queryStr = "";
|
||||
queryMap.forEach((value, key) => {
|
||||
queryStr += key + "=" + value + "&"
|
||||
});
|
||||
|
||||
queryStr = queryStr.slice(0, -1);
|
||||
if (queryStr.length > 0) {
|
||||
newUrl += "?" + queryStr;
|
||||
}
|
||||
if (hash.length > 0) {
|
||||
newUrl += "#" + hash;
|
||||
}
|
||||
return newUrl;
|
||||
}
|
||||
|
||||
private percentEscapedString(str : string) : string {
|
||||
//如果url已经有部分经过encode,那么需要先decode再encode。
|
||||
return str.removingPercentEncoding?.addingPercentEncoding(withAllowedCharacters = CharacterSet.urlQueryAllowed) ?? str
|
||||
}
|
||||
|
||||
|
||||
//mark --- URLSessionDataDelegate
|
||||
|
||||
urlSession(session : URLSession, @argumentLabel("") task : URLSessionTask, @argumentLabel("didSendBodyData") bytesSent : Int64, @argumentLabel("") totalBytesSent : Int64, @argumentLabel("") totalBytesExpectedToSend : Int64) {
|
||||
//todo 原生的onDataSent貌似没实现 ,考虑删掉这个回调。
|
||||
}
|
||||
urlSession(session : URLSession, @argumentLabel("") dataTask : URLSessionDataTask, @argumentLabel("didReceive") response : URLResponse, @argumentLabel("") @escaping completionHandler : (dis : URLSession.ResponseDisposition) => void) {
|
||||
// response开始的时候的header回调
|
||||
let listener = this.taskMap.get(dataTask);
|
||||
if (listener != null) {
|
||||
let httpResponse : HTTPURLResponse = response as HTTPURLResponse;
|
||||
let statusCode = new NSNumber(value = httpResponse.statusCode);
|
||||
listener?.onHeadersReceived(statusCode, httpResponse.allHeaderFields as Map<string, any>);
|
||||
|
||||
const headers = NetworkUtil.convertHeaders(httpResponse.allHeaderFields as Map<string, any>))
|
||||
if (listener!.task != null && listener!.task instanceof NetworkRequestTaskImpl) {
|
||||
const task = listener!.task! as NetworkRequestTaskImpl
|
||||
task.headersReceivedListeners.forEach((value : RequestTaskOnHeadersReceivedCallback, key : number) => {
|
||||
const result: RequestTaskOnHeadersReceivedListenerResult = {
|
||||
cookies: NetworkUtil.parseCookie(headers),
|
||||
header: headers,
|
||||
statusCode: statusCode
|
||||
}
|
||||
value(result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
completionHandler(URLSession.ResponseDisposition.allow);
|
||||
}
|
||||
|
||||
urlSession(session : URLSession, @argumentLabel("") dataTask : URLSessionDataTask, @argumentLabel("didReceive") data : Data) {
|
||||
let listener = this.taskMap.get(dataTask);
|
||||
listener?.onDataReceived(data);
|
||||
if (this.enableChunked && listener != null) {
|
||||
const task = listener!.task! as NetworkRequestTaskImpl
|
||||
task.chunkReceivedListeners.forEach((value : RequestTaskOnChunkReceivedCallback, key : number) => {
|
||||
const result : RequestTaskOnChunkReceivedListenerResult = {
|
||||
data: ArrayBuffer.fromData(data)
|
||||
}
|
||||
value(result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
urlSession(session : URLSession, @argumentLabel("") task : URLSessionTask, @argumentLabel("didCompleteWithError") error : NSError | null) {
|
||||
let listener = this.taskMap.get(task);
|
||||
|
||||
if (error != null) {
|
||||
listener?.onFail(error as NSError);
|
||||
} else {
|
||||
listener?.onFinished(task.response as HTTPURLResponse);
|
||||
}
|
||||
this.taskMap.delete(task);
|
||||
}
|
||||
//todo 暂时证书验证先不实现。
|
||||
// urlSession( session: URLSession, @argumentLabel("didReceive") challenge: URLAuthenticationChallenge, @escaping completionHandler:(dis:URLSession.AuthChallengeDisposition, credentiual:URLCredential)=>void) {
|
||||
// console.log("didReceivechallenge");
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
export {
|
||||
NetworkManager,
|
||||
NetworkRequestListener,
|
||||
NetworkUploadFileListener,
|
||||
NetworkDownloadFileListener
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
|
||||
|
||||
|
||||
class StatusCode {
|
||||
private static statusCodeMap : Map<string, string> | null = null;
|
||||
|
||||
private static initStatusCodeMap() {
|
||||
let map = new Map<string, string>();
|
||||
map.set('100', "Continue");
|
||||
map.set('101', "Switching Protocol");
|
||||
map.set('200', "OK");
|
||||
map.set('201', "Created");
|
||||
map.set('202', "Accepted");
|
||||
map.set('203', "Non-Authoritative Information");
|
||||
map.set('204', "No Content");
|
||||
map.set('205', "Reset Content");
|
||||
map.set('206', "Partial Content");
|
||||
map.set('300', "Multiple Choice");
|
||||
map.set('301', "Moved Permanently");
|
||||
map.set('302', "Found");
|
||||
map.set('303', "See Other");
|
||||
map.set('304', "Not Modified");
|
||||
map.set('305', "Use Proxy");
|
||||
map.set('306', "unused");
|
||||
map.set('307', "Temporary Redirect");
|
||||
map.set('308', "Permanent Redirect");
|
||||
map.set('400', "Bad Request");
|
||||
map.set('401', "Unauthorized");
|
||||
map.set('402', "Payment Required");
|
||||
map.set('403', "Forbidden");
|
||||
map.set('404', "Not Found");
|
||||
map.set('405', "Method Not Allowed");
|
||||
map.set('406', "Not Acceptable");
|
||||
map.set('407', "Proxy Authentication Required");
|
||||
map.set('408', "Request Timeout");
|
||||
map.set('409', "Conflict");
|
||||
map.set('410', "Gone");
|
||||
map.set('411', "Length Required");
|
||||
map.set('412', "Precondition Failed");
|
||||
map.set('413', "Payload Too Large");
|
||||
map.set('414', "URI Too Long");
|
||||
map.set('415', "Unsupported Media Type");
|
||||
map.set('416', "Requested Range Not Satisfiable");
|
||||
map.set('417', "Expectation Failed");
|
||||
map.set('418', "I'm a teapot");
|
||||
map.set('421', "Misdirected Request");
|
||||
map.set('426', "Upgrade Required");
|
||||
map.set('428', "Precondition Required");
|
||||
map.set('429', "Too Many Requests");
|
||||
map.set('431', "Request Header Fields Too Large");
|
||||
map.set('500', "Internal Server Error");
|
||||
map.set('501', "Not Implemented");
|
||||
map.set('502', "Bad Gateway");
|
||||
map.set('503', "Service Unavailable");
|
||||
map.set('504', "Gateway Timeout");
|
||||
map.set('505', "HTTP Version Not Supported");
|
||||
map.set('506', "Variant Also Negotiates");
|
||||
map.set('507', "Variant Also Negotiates");
|
||||
map.set('511', "Network Authentication Required");
|
||||
this.statusCodeMap = map;
|
||||
}
|
||||
|
||||
public static getStatus(code : string) : string {
|
||||
let map = this.statusCodeMap;
|
||||
if (map == null) {
|
||||
this.initStatusCodeMap();
|
||||
}
|
||||
let tmp = this.statusCodeMap!;
|
||||
|
||||
if (!(tmp.has(code))) {
|
||||
return 'unknown status';
|
||||
} else {
|
||||
return tmp.get(code)! as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export {
|
||||
StatusCode
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
|
||||
/**
|
||||
* 弱引用的包装类
|
||||
*/
|
||||
export class WeakRef<T extends Any>{
|
||||
|
||||
@UTSiOS.keyword("weak")
|
||||
private value: T | null = null
|
||||
|
||||
constructor(value: T | null){
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
public get(): T | null{
|
||||
return this.value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
import { DownloadFileOptions, DownloadTask, DownloadFileProgressUpdateCallback, OnProgressDownloadResult } from '../../../interface.uts';
|
||||
import { NetworkDownloadFileListener } from '../NetworkManager.uts';
|
||||
import { UUID, Data, URL, URLResourceKey, URLSessionDataTask, URLSessionTask, URLSession, URLSessionConfiguration, OperationQueue, URLSessionDataDelegate, URLSessionDownloadTask, NSError, URLSessionDownloadDelegate, URLRequest, FileManager, NSString, NSTemporaryDirectory, NSHomeDirectory , CharacterSet , HTTPURLResponse } from 'Foundation';
|
||||
import { } from 'CommonCrypto';
|
||||
import { Int, UnsafeBufferPointer, UnsafeRawBufferPointer } from 'Swift';
|
||||
import { ObjCBool } from "ObjectiveC";
|
||||
|
||||
class NetworkDownloadTaskImpl implements DownloadTask {
|
||||
private task : URLSessionDownloadTask | null = null;
|
||||
private listener : NetworkDownloadFileListener | null = null;
|
||||
constructor(task : URLSessionDownloadTask | null, listener : NetworkDownloadFileListener) {
|
||||
this.task = task;
|
||||
this.listener = listener;
|
||||
super();
|
||||
}
|
||||
|
||||
public abort() {
|
||||
this.task?.cancel()
|
||||
UTSiOS.destroyInstance(this)
|
||||
}
|
||||
|
||||
public onProgressUpdate(option : DownloadFileProgressUpdateCallback) {
|
||||
const kListener = this.listener;
|
||||
if (kListener != null) {
|
||||
kListener!.progressListeners.add(option);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export class DownloadController implements URLSessionDownloadDelegate {
|
||||
private static instance : DownloadController | null = null
|
||||
|
||||
private session : URLSession | null = null;
|
||||
|
||||
private taskMap : Map<URLSessionTask, NetworkDownloadFileListener> = new Map<URLSessionTask, NetworkDownloadFileListener>();
|
||||
|
||||
public static getInstance() : DownloadController {
|
||||
if (this.instance == null) {
|
||||
this.instance = new DownloadController();
|
||||
}
|
||||
return this.instance!;
|
||||
}
|
||||
|
||||
public downloadFile(options : DownloadFileOptions, listener : NetworkDownloadFileListener) : DownloadTask {
|
||||
let request = this.createDownloadRequest(options, listener);
|
||||
if (request == null) {
|
||||
const task = new NetworkDownloadTaskImpl(null, listener)
|
||||
listener.task = task;
|
||||
return task;
|
||||
}
|
||||
|
||||
if (this.session == null) {
|
||||
let urlSessionConfig = URLSessionConfiguration.default;
|
||||
|
||||
this.session = new URLSession(configuration = urlSessionConfig, delegate = this, delegateQueue = OperationQueue.current);
|
||||
}
|
||||
|
||||
let task = this.session?.downloadTask(with = request!);
|
||||
task?.resume();
|
||||
|
||||
if (task != null) {
|
||||
this.taskMap.set(task!, listener);
|
||||
}
|
||||
let requestTask = new NetworkDownloadTaskImpl(task, listener);
|
||||
listener.task = requestTask
|
||||
return requestTask;
|
||||
}
|
||||
|
||||
private createDownloadRequest(options : DownloadFileOptions, listener : NetworkDownloadFileListener) : URLRequest | null {
|
||||
const encodeUrl = this.percentEscapedString(options.url)
|
||||
let url = new URL(string = encodeUrl);
|
||||
if (url == null) {
|
||||
let error = new NSError(domain = "invalid URL", code = 600009);
|
||||
listener.onFail(error);
|
||||
return null
|
||||
}
|
||||
|
||||
let timeout = options.timeout == null ? 120000 : options.timeout;
|
||||
let timeoutInterval = new Double(timeout!) / 1000;
|
||||
let request = new URLRequest(url = url!, cachePolicy = URLRequest.CachePolicy.useProtocolCachePolicy, timeoutInterval = timeoutInterval);
|
||||
request.httpShouldHandleCookies = true;
|
||||
request.httpMethod = "GET";
|
||||
|
||||
let ua = UTSiOS.getUserAgent();
|
||||
request.setValue(ua, forHTTPHeaderField = "User-Agent");
|
||||
|
||||
let headers = options.header?.toMap();
|
||||
if (headers != null) {
|
||||
for (entry in headers!) {
|
||||
let key = entry.key;
|
||||
let value = entry.value;
|
||||
let valueStr = "";
|
||||
if (value instanceof UTSJSONObject) {
|
||||
valueStr = JSON.stringify(value) ?? ""
|
||||
}else if(value instanceof Map<string, any>){
|
||||
valueStr = JSON.stringify(new UTSJSONObject(value)) ?? ""
|
||||
}else{
|
||||
valueStr = `${value}`
|
||||
}
|
||||
request.setValue(valueStr, forHTTPHeaderField = key);
|
||||
}
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
private percentEscapedString(str: string): string {
|
||||
//如果url已经有部分经过encode,那么需要先decode再encode。
|
||||
return str.removingPercentEncoding?.addingPercentEncoding(withAllowedCharacters= CharacterSet.urlQueryAllowed) ?? str
|
||||
}
|
||||
|
||||
private convertToMD5(param : string) : string {
|
||||
const strData = param.data(using = String.Encoding.utf8)!
|
||||
let digest = new Array<UInt8>(repeating = 0, count = new Int(CC_MD5_DIGEST_LENGTH))
|
||||
strData.withUnsafeBytes((body : UnsafeRawBufferPointer) => {
|
||||
CC_MD5(body.baseAddress, new UInt32(strData.count), UTSiOS.getPointer(digest))
|
||||
})
|
||||
let md5String = ""
|
||||
digest.forEach((byte : UInt8) => {
|
||||
md5String += new String(format = "%02x", new UInt8(byte))
|
||||
})
|
||||
|
||||
return md5String
|
||||
}
|
||||
|
||||
|
||||
private isSandBoxPath(path : string) : boolean {
|
||||
return path.startsWith(NSHomeDirectory())
|
||||
}
|
||||
|
||||
private getTempPath() : string {
|
||||
let cacheDirectory = FileManager.default.urls(for = FileManager.SearchPathDirectory.cachesDirectory, in = FileManager.SearchPathDomainMask.userDomainMask).first!
|
||||
return cacheDirectory.path
|
||||
}
|
||||
|
||||
private getRealPath() : string {
|
||||
return this.getTempPath() + "/uni-download/"
|
||||
}
|
||||
|
||||
|
||||
private getTargetPath(options : DownloadFileOptions | null, fileName : string, listener : NetworkDownloadFileListener | null) : string | null {
|
||||
let targetPath = ""
|
||||
let specifyPath = options?.filePath ?? ""
|
||||
if(specifyPath.startsWith("unifile://")){
|
||||
specifyPath = UTSiOS.getResourceAbsolutePath(specifyPath, null);
|
||||
}
|
||||
let hasFileName = false;
|
||||
if (specifyPath != "") {
|
||||
const pos = specifyPath.lastIndexOf("/")
|
||||
if (pos == specifyPath.length - 1) {
|
||||
//如果filePath是目录
|
||||
if (this.isSandBoxPath(specifyPath)) {
|
||||
targetPath = specifyPath
|
||||
} else {
|
||||
targetPath = this.getTempPath() + "/" + specifyPath
|
||||
}
|
||||
} else {
|
||||
let path = "";
|
||||
if (this.isSandBoxPath(specifyPath)) {
|
||||
path = specifyPath;
|
||||
} else {
|
||||
path = this.getTempPath() + "/" + specifyPath
|
||||
}
|
||||
let fileManager = FileManager.default
|
||||
var isDirectory : ObjCBool = false
|
||||
if (fileManager.fileExists(atPath = path, isDirectory = UTSiOS.getPointer(isDirectory))) {
|
||||
if (isDirectory.boolValue) {
|
||||
let error = new NSError(domain = "The target file path is already a directory file, and file creation failed.", code = 602001);
|
||||
listener?.onFail(error);
|
||||
return null
|
||||
}
|
||||
}
|
||||
targetPath = path
|
||||
hasFileName = true
|
||||
}
|
||||
} else {
|
||||
targetPath = this.getRealPath()
|
||||
}
|
||||
if(!hasFileName){
|
||||
targetPath += fileName
|
||||
}
|
||||
let fileManager = FileManager.default
|
||||
if (fileManager.fileExists(atPath = targetPath)) {
|
||||
const index = targetPath.lastIndexOf(".");
|
||||
let tFileName = targetPath;
|
||||
let tFileType = "";
|
||||
if (index >= 0) {
|
||||
tFileName = targetPath.substring(0, index as Int)
|
||||
tFileType = targetPath.substring(index as Int)
|
||||
}
|
||||
|
||||
var number = 1
|
||||
while (fileManager.fileExists(atPath = targetPath)) {
|
||||
targetPath = tFileName + `(${number})` + tFileType;
|
||||
number++
|
||||
}
|
||||
}
|
||||
|
||||
return targetPath
|
||||
}
|
||||
|
||||
private getFileName(fileName : string, url : URL | null) : string {
|
||||
var suggestedFilename = fileName
|
||||
|
||||
if (suggestedFilename != "") {
|
||||
let cString = suggestedFilename.cString(using = String.Encoding.isoLatin1)
|
||||
if (cString != null) {
|
||||
suggestedFilename = new String(cString = cString!, encoding = String.Encoding.utf8) ?? suggestedFilename
|
||||
}
|
||||
|
||||
let cleanUri = suggestedFilename.removingPercentEncoding
|
||||
if (cleanUri != null && cleanUri!.length > 0) {
|
||||
suggestedFilename = cleanUri!
|
||||
}
|
||||
|
||||
suggestedFilename = suggestedFilename.replacingOccurrences(of = "/", with = "")
|
||||
suggestedFilename = suggestedFilename.replacingOccurrences(of = "\\", with = "")
|
||||
} else {
|
||||
if (url == null) {
|
||||
suggestedFilename = ""
|
||||
} else {
|
||||
suggestedFilename = this.convertToMD5(url!.absoluteString)
|
||||
}
|
||||
}
|
||||
|
||||
if (suggestedFilename.length > 255) {
|
||||
let extensionType = (suggestedFilename as NSString).pathExtension
|
||||
suggestedFilename = this.convertToMD5((suggestedFilename as NSString).deletingPathExtension)
|
||||
if (extensionType != "") {
|
||||
suggestedFilename = (suggestedFilename as NSString).appendingPathExtension(extensionType) ?? suggestedFilename
|
||||
}
|
||||
}
|
||||
|
||||
return suggestedFilename
|
||||
}
|
||||
|
||||
|
||||
//mark --- URLSessionDownloadDelegate
|
||||
|
||||
urlSession(session : URLSession, @argumentLabel("") downloadTask : URLSessionDownloadTask, @argumentLabel("didWriteData") bytesWritten : Int64, @argumentLabel("") totalBytesWritten : Int64, @argumentLabel("") totalBytesExpectedToWrite : Int64) {
|
||||
let listener = this.taskMap.get(downloadTask);
|
||||
const progress = (Number.from(totalBytesWritten) / totalBytesExpectedToWrite) * 100
|
||||
const progressUpdate : OnProgressDownloadResult = {
|
||||
progress: progress.toInt(),
|
||||
totalBytesWritten: totalBytesWritten,
|
||||
totalBytesExpectedToWrite: totalBytesExpectedToWrite
|
||||
}
|
||||
listener?.onProgress(progressUpdate)
|
||||
}
|
||||
|
||||
urlSession(session : URLSession, @argumentLabel("") downloadTask : URLSessionDownloadTask, @argumentLabel("didFinishDownloadingTo") location : URL) {
|
||||
let listener = this.taskMap.get(downloadTask);
|
||||
let suggestedFilename = downloadTask.response?.suggestedFilename
|
||||
const statusCode = (downloadTask.response as HTTPURLResponse).statusCode
|
||||
if(statusCode - 200 < 100 && statusCode - 200 >= 0) {
|
||||
const fileName = this.getFileName(suggestedFilename ?? "", downloadTask.response?.url)
|
||||
let destPath = this.getTargetPath(listener?.options, fileName, listener);
|
||||
if (destPath != null) {
|
||||
let fileManager = FileManager.default
|
||||
try {
|
||||
let directoryPath = (destPath as NSString).deletingLastPathComponent
|
||||
if (!fileManager.fileExists(atPath = directoryPath)) {
|
||||
UTSiOS.try(fileManager.createDirectory(atPath = directoryPath, withIntermediateDirectories = true, attributes = null), "?")
|
||||
}
|
||||
UTSiOS.try(fileManager.moveItem(atPath = location.path, toPath = destPath!), "?")
|
||||
listener?.onFinished(downloadTask.response as HTTPURLResponse, destPath!);
|
||||
} catch {
|
||||
let error = new NSError(domain = "file move fail", code = 602001);
|
||||
listener?.onFail(error);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let error = new NSError(domain = "request fail", code = statusCode);
|
||||
listener?.onFail(error);
|
||||
}
|
||||
this.taskMap.delete(downloadTask);
|
||||
}
|
||||
|
||||
urlSession(session : URLSession, @argumentLabel("") task : URLSessionTask, @argumentLabel("didCompleteWithError") error : NSError | null) {
|
||||
if(error != null){
|
||||
let listener = this.taskMap.get(task);
|
||||
listener?.onFail(error as NSError);
|
||||
this.taskMap.delete(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
import { UploadFileOptions, UploadTask, UploadFileProgressUpdateCallback, UploadFileOptionFiles, OnProgressUpdateResult } from '../../../interface.uts';
|
||||
import { NetworkUploadFileListener } from '../NetworkManager.uts'
|
||||
import { CharacterSet, HTTPURLResponse, UUID, Data, URL, URLResourceKey, URLSessionDataTask, URLSessionTask, URLSession, URLSessionConfiguration, OperationQueue, URLSessionDataDelegate, URLSessionUploadTask, NSError , NSMutableData , NSMutableSet , URLRequest} from 'Foundation';
|
||||
import { UTTypeCreatePreferredIdentifierForTag, UTTypeCopyPreferredTagWithClass, kUTTagClassFilenameExtension, kUTTagClassMIMEType } from 'MobileCoreServices';
|
||||
import { CFString } from 'CoreFoundation';
|
||||
|
||||
class NetworkUploadTaskImpl implements UploadTask {
|
||||
private task : URLSessionDataTask | null = null;
|
||||
private listener : NetworkUploadFileListener | null = null;
|
||||
constructor(task : URLSessionDataTask | null, listener : NetworkUploadFileListener) {
|
||||
this.task = task;
|
||||
this.listener = listener;
|
||||
super();
|
||||
}
|
||||
|
||||
public abort() {
|
||||
this.task?.cancel()
|
||||
UTSiOS.destroyInstance(this)
|
||||
}
|
||||
|
||||
public onProgressUpdate(option : UploadFileProgressUpdateCallback) {
|
||||
const kListener = this.listener;
|
||||
if (kListener != null) {
|
||||
kListener!.progressListeners.add(option);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UploadController implements URLSessionDataDelegate {
|
||||
private static instance : UploadController | null = null
|
||||
|
||||
private session : URLSession | null = null;
|
||||
|
||||
private taskMap : Map<URLSessionTask, NetworkUploadFileListener> = new Map<URLSessionTask, NetworkUploadFileListener>();
|
||||
|
||||
public static getInstance() : UploadController {
|
||||
if (this.instance == null) {
|
||||
this.instance = new UploadController();
|
||||
}
|
||||
return this.instance!;
|
||||
}
|
||||
|
||||
|
||||
public uploadFile(options : UploadFileOptions, listener : NetworkUploadFileListener) : UploadTask {
|
||||
let boundary = `----${new UUID().uuidString}`
|
||||
let request = this.createRequest(options, listener, boundary);
|
||||
if (request == null) {
|
||||
const task = new NetworkUploadTaskImpl(null, listener)
|
||||
listener.task = task
|
||||
return task;
|
||||
}
|
||||
|
||||
if (this.session == null) {
|
||||
let urlSessionConfig = URLSessionConfiguration.default;
|
||||
|
||||
this.session = new URLSession(configuration = urlSessionConfig, delegate = this, delegateQueue = OperationQueue.current);
|
||||
}
|
||||
|
||||
const bodyData = this.createBody(boundary, options, listener);
|
||||
if (bodyData == null) {
|
||||
const task = new NetworkUploadTaskImpl(null, listener);
|
||||
listener.task = task
|
||||
return task
|
||||
}
|
||||
let task = this.session?.uploadTask(with = request!, from = bodyData!);
|
||||
task?.resume();
|
||||
if (task != null) {
|
||||
this.taskMap.set(task!, listener);
|
||||
}
|
||||
let requestTask = new NetworkUploadTaskImpl(task, listener);
|
||||
listener.task = requestTask
|
||||
return requestTask;
|
||||
}
|
||||
|
||||
|
||||
private createRequest(param : UploadFileOptions, listener : NetworkUploadFileListener, boundary : string) : URLRequest | null {
|
||||
const encodeUrl = this.percentEscapedString(param.url)
|
||||
let url = new URL(string = encodeUrl);
|
||||
if (url == null) {
|
||||
let error = new NSError(domain = "invalid URL", code = 600009);
|
||||
listener.onFail(error);
|
||||
return null
|
||||
}
|
||||
|
||||
let timeout = param.timeout == null ? 120000 : param.timeout;
|
||||
let timeoutInterval = new Double(timeout!) / 1000;
|
||||
let request = new URLRequest(url = url!, cachePolicy = URLRequest.CachePolicy.useProtocolCachePolicy, timeoutInterval = timeoutInterval);
|
||||
request.httpShouldHandleCookies = true;
|
||||
|
||||
request.httpMethod = "POST";
|
||||
|
||||
request.setValue(`multipart/form-data; boundary=${boundary}`, forHTTPHeaderField = "Content-Type");
|
||||
|
||||
let ua = UTSiOS.getUserAgent();
|
||||
request.setValue(ua, forHTTPHeaderField = "User-Agent");
|
||||
|
||||
|
||||
let headers = param.header?.toMap();
|
||||
if (headers != null) {
|
||||
for (entry in headers!) {
|
||||
let key = entry.key;
|
||||
let value = entry.value;
|
||||
let valueStr = "";
|
||||
if (value instanceof UTSJSONObject) {
|
||||
valueStr = JSON.stringify(value) ?? ""
|
||||
}else if(value instanceof Map<string, any>){
|
||||
valueStr = JSON.stringify(new UTSJSONObject(value)) ?? ""
|
||||
}else{
|
||||
valueStr = `${value}`
|
||||
}
|
||||
request.setValue(valueStr, forHTTPHeaderField = key);
|
||||
}
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
private createBody(boundary : string, options : UploadFileOptions, listener : NetworkUploadFileListener) : Data | null {
|
||||
let body = new NSMutableData();
|
||||
let formData = options.formData?.toMap();
|
||||
if (formData != null) {
|
||||
for (entry in formData!) {
|
||||
const key = entry.key;
|
||||
const value = entry.value;
|
||||
if (value != null && typeof (key) == 'string') {
|
||||
if (value instanceof UTSJSONObject) {
|
||||
let valueStr = JSON.stringify(value)
|
||||
if (valueStr != null) {
|
||||
this.fillTextPart(body, boundary, key, valueStr as string)
|
||||
}
|
||||
}else if(value instanceof Map<string, any>){
|
||||
let valueStr = JSON.stringify(new UTSJSONObject(value))
|
||||
if (valueStr != null) {
|
||||
this.fillTextPart(body, boundary, key, valueStr as string)
|
||||
}
|
||||
}else{
|
||||
this.fillTextPart(body, boundary, key, `${value}`)
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const tempFiles = options.files;
|
||||
if (tempFiles != null && tempFiles!.length > 0) {
|
||||
const files : UploadFileOptionFiles[] = tempFiles!;
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const item = files[i]
|
||||
const filePath = item.uri;
|
||||
const name = item.name ?? "file";
|
||||
if (!this.fillFilePart(body, boundary, name, filePath!, listener)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const filePath = options.filePath;
|
||||
const name = options.name ?? "file";
|
||||
if (filePath == null) {
|
||||
let error = new NSError(domain = "filePath is null", code = -1);
|
||||
listener.onFail(error)
|
||||
return null;
|
||||
}
|
||||
if (!this.fillFilePart(body, boundary, name, filePath!, listener)) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
body.append(`--${boundary}--\r\n`.data(using = String.Encoding.utf8)!)
|
||||
|
||||
return body.copy() as Data;
|
||||
}
|
||||
|
||||
|
||||
private percentEscapedString(str: string): string {
|
||||
//如果url已经有部分经过encode,那么需要先decode再encode。
|
||||
return str.removingPercentEncoding?.addingPercentEncoding(withAllowedCharacters= CharacterSet.urlQueryAllowed) ?? str
|
||||
}
|
||||
|
||||
|
||||
private fillTextPart(body : NSMutableData, boundary : string, key : string, value : string) {
|
||||
body.append(`--${boundary}\r\n`.data(using = String.Encoding.utf8)!)
|
||||
body.append(`Content-Disposition: form-data; name=\"${key}\"\r\n`.data(using = String.Encoding.utf8)!)
|
||||
body.append("\r\n".data(using = String.Encoding.utf8)!)
|
||||
body.append(value.data(using = String.Encoding.utf8)!)
|
||||
body.append("\r\n".data(using = String.Encoding.utf8)!)
|
||||
}
|
||||
|
||||
private fillFilePart(body : NSMutableData, boundary : string, name : string, filePath : string, listener : NetworkUploadFileListener) : boolean {
|
||||
const absolutePath = new URL(fileURLWithPath = UTSiOS.getResourceAbsolutePath(filePath, null))
|
||||
const fileData = UTSiOS.try(new Data(contentsOf = absolutePath), "?")
|
||||
if (fileData == null) {
|
||||
let error = new NSError(domain = "Illegal file", code = -1);
|
||||
listener.onFail(error)
|
||||
return false
|
||||
}
|
||||
const mimeType = this.getMimeType(absolutePath)
|
||||
const fileName = absolutePath.lastPathComponent
|
||||
|
||||
const keys = new Swift.Set([URLResourceKey.fileSizeKey])
|
||||
const resourceValue = UTSiOS.try(absolutePath.resourceValues(forKeys = keys), "?")
|
||||
const fileSize = resourceValue?.fileSize
|
||||
body.append(`--${boundary}\r\n`.data(using = String.Encoding.utf8)!)
|
||||
body.append(`Content-Disposition: form-data; name=\"${name}\"; filename=\"${fileName}\"\r\n`.data(using = String.Encoding.utf8)!)
|
||||
body.append(`Content-Type: ${mimeType}\r\n`.data(using = String.Encoding.utf8)!)
|
||||
if (fileSize != null) {
|
||||
body.append(`Content-Length: ${fileSize!}\r\n`.data(using = String.Encoding.utf8)!)
|
||||
}
|
||||
body.append("\r\n".data(using = String.Encoding.utf8)!)
|
||||
body.append(fileData!)
|
||||
body.append("\r\n".data(using = String.Encoding.utf8)!)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
private getMimeType(url : URL) : string {
|
||||
let pathExtension = url.pathExtension
|
||||
|
||||
const uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as CFString, null)?.takeRetainedValue()
|
||||
if (uti != null) {
|
||||
let mimetype = UTTypeCopyPreferredTagWithClass(uti!, kUTTagClassMIMEType)?.takeRetainedValue()
|
||||
if (mimetype != null) {
|
||||
return mimetype as string;
|
||||
}
|
||||
}
|
||||
return "application/octet-stream"
|
||||
}
|
||||
|
||||
//mark --- URLSessionDataDelegate
|
||||
urlSession(session : URLSession, @argumentLabel("") task : URLSessionTask, @argumentLabel("didSendBodyData") bytesSent : Int64, @argumentLabel("") totalBytesSent : Int64, @argumentLabel("") totalBytesExpectedToSend : Int64) {
|
||||
|
||||
let listener = this.taskMap.get(task);
|
||||
const progress = (Number.from(totalBytesSent) / totalBytesExpectedToSend) * 100
|
||||
const progressUpdate : OnProgressUpdateResult = {
|
||||
progress: progress.toInt(),
|
||||
totalBytesSent: totalBytesSent,
|
||||
totalBytesExpectedToSend: totalBytesExpectedToSend
|
||||
}
|
||||
listener?.onProgress(progressUpdate)
|
||||
}
|
||||
|
||||
urlSession(session : URLSession, @argumentLabel("") dataTask : URLSessionDataTask, @argumentLabel("didReceive") data : Data) {
|
||||
let listener = this.taskMap.get(dataTask);
|
||||
listener?.onDataReceived(data);
|
||||
}
|
||||
|
||||
urlSession(session : URLSession, @argumentLabel("") task : URLSessionTask, @argumentLabel("didCompleteWithError") error : NSError | null) {
|
||||
let listener = this.taskMap.get(task);
|
||||
|
||||
if (error != null) {
|
||||
listener?.onFail(error as NSError);
|
||||
} else {
|
||||
listener?.onFinished(task.response as HTTPURLResponse);
|
||||
}
|
||||
this.taskMap.delete(task);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export {
|
||||
UploadController
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
export class NetworkUtil {
|
||||
public static convertHeaders(headers: Map<string, any> | null): UTSJSONObject {
|
||||
|
||||
let simpleHeaders = new UTSJSONObject()
|
||||
if (headers != null) {
|
||||
headers!.forEach((value: any | null, key: string) => {
|
||||
if (value == null) {
|
||||
simpleHeaders.set(key, '')
|
||||
} else {
|
||||
simpleHeaders.set(key, value)
|
||||
}
|
||||
})
|
||||
}
|
||||
return simpleHeaders;
|
||||
}
|
||||
|
||||
public static parseCookie(header : UTSJSONObject | null) : string[] {
|
||||
if (header == null) {
|
||||
return []
|
||||
}
|
||||
let cookiesStr = header!.getString('Set-Cookie') as string | null
|
||||
if (cookiesStr == null) {
|
||||
cookiesStr = header!.getString('set-cookie') as string | null
|
||||
}
|
||||
if (cookiesStr == null) {
|
||||
return []
|
||||
}
|
||||
let cookiesArr = new Array<string>()
|
||||
if (cookiesStr!.charAt(0) == "[" && cookiesStr!.charAt(cookiesStr!.length - 1) == "]") {
|
||||
cookiesStr = cookiesStr!.slice(1, -1)
|
||||
}
|
||||
|
||||
const handleCookiesArr = cookiesStr!.split(';')
|
||||
for (let i = 0; i < handleCookiesArr.length; i++) {
|
||||
if (handleCookiesArr[i].indexOf('Expires=') != -1 || handleCookiesArr[i].indexOf('expires=') != -1) {
|
||||
cookiesArr.push(handleCookiesArr[i].replace(',', ''))
|
||||
} else {
|
||||
cookiesArr.push(handleCookiesArr[i])
|
||||
}
|
||||
}
|
||||
cookiesArr = cookiesArr.join(';').split(',')
|
||||
|
||||
return cookiesArr
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user