diff --git a/MisskeyKit/APIs/Wrapper/HTTP/Drive.swift b/MisskeyKit/APIs/Wrapper/HTTP/Drive.swift index 57ce06b..3f7c0bf 100644 --- a/MisskeyKit/APIs/Wrapper/HTTP/Drive.swift +++ b/MisskeyKit/APIs/Wrapper/HTTP/Drive.swift @@ -117,7 +117,7 @@ extension MisskeyKit { //MARK: Control Files - public func createFile(name: String, isSensitive: Bool = false, force: Bool = false, folderId: String = "", result callback: @escaping (DriveFileModel?, MisskeyKitError?)->()) { + public func createFile(fileData: Data, fileType: String, name: String, isSensitive: Bool = false, force: Bool = false, folderId: String = "", result callback: @escaping (DriveFileModel?, MisskeyKitError?)->()) { var params = ["name":name, "isSensitive":isSensitive, @@ -125,7 +125,7 @@ extension MisskeyKit { "force":force] as [String : Any] params = params.removeRedundant() - MisskeyKit.handleAPI(needApiKey: true, api: "drive/files/create", params: params, type: DriveFileModel.self) { info, error in + MisskeyKit.handleAPI(needApiKey: true, api: "drive/files/create", params: params, data: fileData, fileType: fileType, type: DriveFileModel.self) { info, error in if let error = error { callback(nil, error); return } guard let info = info else { callback(nil, error); return } diff --git a/MisskeyKit/APIs/Wrapper/HTTP/MisskeyKit.swift b/MisskeyKit/APIs/Wrapper/HTTP/MisskeyKit.swift index 96aaa21..24c0120 100644 --- a/MisskeyKit/APIs/Wrapper/HTTP/MisskeyKit.swift +++ b/MisskeyKit/APIs/Wrapper/HTTP/MisskeyKit.swift @@ -28,77 +28,47 @@ open class MisskeyKit { Api.instance = instance } - //MARK:- Internal Methods - internal static func handleAPI(needApiKey: Bool = false, api: String, params: [String: Any], type: T.Type, missingCount: Int? = nil, callback: @escaping (T?, MisskeyKitError?)->Void) where T : Decodable { - if let missingCount = missingCount - { - guard missingCount < 4 else { - return callback(nil, .FailedToCommunicateWithServer) - } - } - - var params = params - if needApiKey { - params["i"] = auth.getAPIKey() - } - - guard let rawJson = params.toRawJson() else { - callback(nil, .FailedToDecodeJson) - return - } - - - Requestor.post(url: Api.fullUrl(api), rawJson: rawJson) { (response: HTTPURLResponse?, resultRawJson: String?, error: MisskeyKitError?) in - guard let resultRawJson = resultRawJson else { - if let missingCount = missingCount { - self.handleAPI(needApiKey: needApiKey, - api: api, - params: params, - type: type, - missingCount: missingCount + 1, - callback: callback) - } - - // If being initial error... - self.handleAPI(needApiKey: needApiKey, - api: api, - params: params, - type: type, - missingCount: 1, - callback: callback) - - return - } - - let resultJson = arrayReactions(rawJson: resultRawJson) // Changes a form of reactions to array. - - if let response = response, response.statusCode == 200, resultJson.count == 0 { - callback(nil, nil) - return - } - - guard let json = resultJson.decodeJSON(type) else { - if resultJson.count == 0 { - guard String(reflecting: T.self) == "Swift.Bool" else { - callback(nil, .ResponseIsNull) - return - } - - callback(nil, nil) - return - } - - //guard上のifでnilチェックできているので強制アンラップでOK - let error = ApiError.checkNative(rawJson: resultJson, response!.statusCode) - callback(nil, error) - return - } - - callback(json, nil) + //MARK:- Internal Methods + internal static func handleAPI(needApiKey: Bool = false, api: String, params: [String: Any], data: Data? = nil, fileType: String? = nil, type: T.Type, missingCount: Int? = nil, callback: @escaping (T?, MisskeyKitError?)->Void) where T : Decodable { + let hasAttachment = data != nil + + if hasAttachment && fileType == nil { return } // If fileType being nil ... + + if let missingCount = missingCount, missingCount >= 4 { return callback(nil, .FailedToCommunicateWithServer) } + + var params = params + if needApiKey { + params["i"] = auth.getAPIKey() + } + + let completion = { (response: HTTPURLResponse?, resultRawJson: String?, error: MisskeyKitError?) in + self.handleResponse(response: response, + resultRawJson: resultRawJson, + error: error, + needApiKey: needApiKey, + api: api, + params: params, + data: data, + fileType: fileType, + type: T.self, + missingCount: missingCount, + callback: callback) + } + + + + + if !hasAttachment { + guard let rawJson = params.toRawJson() else { callback(nil, .FailedToDecodeJson); return } + Requestor.post(url: Api.fullUrl(api), rawJson: rawJson, completion: completion) + } + else { + Requestor.post(url: Api.fullUrl(api), paramsDic: params, data: data, fileType: fileType, completion: completion) } } + // ** 参考 ** //reactionsのkeyは無数に存在するため、codableでのパースは難しい。 //そこで、生のjsonを直接弄り、reactionsを配列型に変更する。 @@ -119,7 +89,7 @@ open class MisskeyKit { replaceList.append(shapedReactions) } - + var replacedRawJson = rawJson for i in 0...reactionsList.count-1 { replacedRawJson = replacedRawJson.replacingOccurrences(of: reactionsList[i][0], with: replaceList[i]) @@ -128,5 +98,58 @@ open class MisskeyKit { return replacedRawJson } + + + + //MARK: Private Methods + private static func handleResponse(response: HTTPURLResponse?, resultRawJson: String?, error: MisskeyKitError?, needApiKey: Bool = false, api: String, params: [String: Any], data: Data? = nil, fileType: String? = nil, type: T.Type, missingCount: Int? = nil, callback: @escaping (T?, MisskeyKitError?)->Void) where T : Decodable { + guard let resultRawJson = resultRawJson else { + if let missingCount = missingCount { + self.handleAPI(needApiKey: needApiKey, + api: api, + params: params, + type: type, + missingCount: missingCount + 1, + callback: callback) + } + + // If being initial error... + self.handleAPI(needApiKey: needApiKey, + api: api, + params: params, + type: type, + missingCount: 1, + callback: callback) + + return + } + + let resultJson = arrayReactions(rawJson: resultRawJson) // Changes a form of reactions to array. + + if let response = response, response.statusCode == 200, resultJson.count == 0 { + callback(nil, nil) + return + } + + guard let json = resultJson.decodeJSON(type) else { + if resultJson.count == 0 { + guard String(reflecting: T.self) == "Swift.Bool" else { + callback(nil, .ResponseIsNull) + return + } + + callback(nil, nil) + return + } + + //guard上のifでnilチェックできているので強制アンラップでOK + let error = ApiError.checkNative(rawJson: resultJson, response!.statusCode) + callback(nil, error) + return + } + + callback(json, nil) + } + } diff --git a/MisskeyKit/Utilities/Requestor.swift b/MisskeyKit/Utilities/Requestor.swift index 3a99ae1..de32a6c 100644 --- a/MisskeyKit/Utilities/Requestor.swift +++ b/MisskeyKit/Utilities/Requestor.swift @@ -12,6 +12,9 @@ import Foundation internal typealias ResponseCallBack = (HTTPURLResponse?, String?, MisskeyKitError?) -> Void internal class Requestor { + private static let boundary = UUID().uuidString + + //MARK: GET static func get(url: String, completion: @escaping ResponseCallBack) { self.get(url: URL(string: url)!, completion: completion) } @@ -36,9 +39,71 @@ internal class Requestor { } + //MARK: POST + + //With Attachment + static func post(url: String, paramsDic: [String: Any], data: Data?, fileType: String?, completion: @escaping ResponseCallBack) { + self.post(url: URL(string: url)!, + paramsDic: paramsDic, + data: data, + fileType: fileType, + completion: completion) + } + + // Generate a "multipart/form-data" request + static func post(url: URL, paramsDic: [String: Any], data: Data?, fileType: String?, completion: @escaping ResponseCallBack) { + guard let data = data, let fileType = fileType else { completion(nil,nil,.FailedToCommunicateWithServer); return } + + var request = URLRequest(url: url) + request.httpMethod = "POST" + + let session = URLSession(configuration: URLSessionConfiguration.default) + let uuid = UUID().uuidString + var bodyData: Data = Data() + + + request.setValue("multipart/form-data; boundary=\(self.boundary)", forHTTPHeaderField: "Content-Type") + + + paramsDic.forEach{ params in + let value = String(describing: params.value) + + bodyData.append("\r\n--\(boundary)\r\n".data(using: .utf8)!) + bodyData.append("Content-Disposition: form-data; name=\"\(params.key)\"\r\n\r\n".data(using: .utf8)!) + bodyData.append(value.data(using: .utf8)!) + } + + bodyData.append("\r\n--\(boundary)\r\n".data(using: .utf8)!) + bodyData.append("Content-Disposition: form-data; name=\"file\"; filename=\"\(uuid)\"\r\n".data(using: .utf8)!) + bodyData.append("Content-Type: \(fileType)\r\n\r\n".data(using: .utf8)!) + bodyData.append(data) + + bodyData.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!) + + request.httpBody = bodyData + + let task = session.dataTask(with: request) { (data, response, error) in + if let _ = error { + completion(nil, nil, .FailedToCommunicateWithServer) + return + } + guard let response = response as? HTTPURLResponse else { + completion(nil, nil, nil) + return + } + + + if let data = data, let dataString = String(data: data, encoding: .utf8) { + completion(response, dataString, nil) + } + + } + task.resume() + } + //Without attachment static func post(url: String, rawJson: String, completion: @escaping ResponseCallBack) { self.post(url: URL(string: url)!, rawJson: rawJson,