Skip to content
This repository was archived by the owner on Jan 28, 2019. It is now read-only.

Commit

Permalink
SwiftLint + gardening
Browse files Browse the repository at this point in the history
  • Loading branch information
Peter Zignego committed Jun 9, 2017
1 parent 5f15ba6 commit dc21b46
Show file tree
Hide file tree
Showing 5 changed files with 822 additions and 314 deletions.
7 changes: 7 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
disabled_rules:
- identifier_name
- function_parameter_count
line_length: 140
excluded: # paths to ignore during linting. Takes precedence over `included`.
- Carthage
- Pods
56 changes: 56 additions & 0 deletions SKWebAPI.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
objects = {

/* Begin PBXBuildFile section */
26A2E62B1EEB26C3005C25AC /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26A2E62A1EEB26C3005C25AC /* Endpoint.swift */; };
26A2E62C1EEB26C3005C25AC /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26A2E62A1EEB26C3005C25AC /* Endpoint.swift */; };
26A2E62D1EEB26C3005C25AC /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26A2E62A1EEB26C3005C25AC /* Endpoint.swift */; };
26D1C4C21EE462DC00C95954 /* SKCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26D1C4C11EE462DC00C95954 /* SKCore.framework */; };
26D1C4C61EE463A600C95954 /* SKCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26D1C4C51EE463A600C95954 /* SKCore.framework */; };
26D1C4C81EE463AD00C95954 /* SKCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26D1C4C71EE463AD00C95954 /* SKCore.framework */; };
Expand All @@ -23,6 +26,7 @@
2684F1E41E95ABD400536DCC /* SKWebAPI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SKWebAPI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
2684F2081E95ABD600536DCC /* SKWebAPI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SKWebAPI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
2684F20D1E95AF8C00536DCC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
26A2E62A1EEB26C3005C25AC /* Endpoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Endpoint.swift; sourceTree = "<group>"; };
26D1C4C11EE462DC00C95954 /* SKCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SKCore.framework; path = Carthage/Build/Mac/SKCore.framework; sourceTree = "<group>"; };
26D1C4C51EE463A600C95954 /* SKCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SKCore.framework; path = Carthage/Build/iOS/SKCore.framework; sourceTree = "<group>"; };
26D1C4C71EE463AD00C95954 /* SKCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SKCore.framework; path = Carthage/Build/tvOS/SKCore.framework; sourceTree = "<group>"; };
Expand Down Expand Up @@ -110,6 +114,7 @@
children = (
26DC0EA51E95BB5D00991BDF /* NetworkInterface.swift */,
26DC0EA61E95BB5D00991BDF /* WebAPI.swift */,
26A2E62A1EEB26C3005C25AC /* Endpoint.swift */,
);
path = Sources;
sourceTree = SOURCE_ROOT;
Expand Down Expand Up @@ -149,6 +154,7 @@
2684F1791E95AA6900536DCC /* Frameworks */,
2684F17A1E95AA6900536DCC /* Headers */,
2684F17B1E95AA6900536DCC /* Resources */,
26A2E62E1EEB27AB005C25AC /* SwiftLint */,
);
buildRules = (
);
Expand All @@ -167,6 +173,7 @@
2684F1DE1E95ABD400536DCC /* Frameworks */,
2684F1DF1E95ABD400536DCC /* Headers */,
2684F1E01E95ABD400536DCC /* Resources */,
26A2E62F1EEB27CB005C25AC /* SwiftLint */,
);
buildRules = (
);
Expand All @@ -185,6 +192,7 @@
2684F2021E95ABD600536DCC /* Frameworks */,
2684F2031E95ABD600536DCC /* Headers */,
2684F2041E95ABD600536DCC /* Resources */,
26A2E6301EEB27D8005C25AC /* SwiftLint */,
);
buildRules = (
);
Expand Down Expand Up @@ -259,12 +267,58 @@
};
/* End PBXResourcesBuildPhase section */

/* Begin PBXShellScriptBuildPhase section */
26A2E62E1EEB27AB005C25AC /* SwiftLint */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = SwiftLint;
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
};
26A2E62F1EEB27CB005C25AC /* SwiftLint */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = SwiftLint;
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
};
26A2E6301EEB27D8005C25AC /* SwiftLint */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = SwiftLint;
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
};
/* End PBXShellScriptBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
2684F1781E95AA6900536DCC /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
26DC0EA71E95BB5D00991BDF /* NetworkInterface.swift in Sources */,
26A2E62B1EEB26C3005C25AC /* Endpoint.swift in Sources */,
26DC0EAA1E95BB5D00991BDF /* WebAPI.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -274,6 +328,7 @@
buildActionMask = 2147483647;
files = (
26DC0EA81E95BB5D00991BDF /* NetworkInterface.swift in Sources */,
26A2E62C1EEB26C3005C25AC /* Endpoint.swift in Sources */,
26DC0EAB1E95BB5D00991BDF /* WebAPI.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -283,6 +338,7 @@
buildActionMask = 2147483647;
files = (
26DC0EA91E95BB5D00991BDF /* NetworkInterface.swift in Sources */,
26A2E62D1EEB26C3005C25AC /* Endpoint.swift in Sources */,
26DC0EAC1E95BB5D00991BDF /* WebAPI.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
81 changes: 81 additions & 0 deletions Sources/Endpoint.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//
// WebAPI.swift
//
// Copyright © 2017 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

public enum Endpoint: String {
case apiTest = "api.test"
case authRevoke = "auth.revoke"
case authTest = "auth.test"
case channelsHistory = "channels.history"
case channelsInfo = "channels.info"
case channelsList = "channels.list"
case channelsMark = "channels.mark"
case channelsSetPurpose = "channels.setPurpose"
case channelsSetTopic = "channels.setTopic"
case chatDelete = "chat.delete"
case chatPostMessage = "chat.postMessage"
case chatMeMessage = "chat.meMessage"
case chatUpdate = "chat.update"
case dndInfo = "dnd.info"
case dndTeamInfo = "dnd.teamInfo"
case emojiList = "emoji.list"
case filesCommentsAdd = "files.comments.add"
case filesCommentsEdit = "files.comments.edit"
case filesCommentsDelete = "files.comments.delete"
case filesDelete = "files.delete"
case filesInfo = "files.info"
case filesUpload = "files.upload"
case groupsClose = "groups.close"
case groupsHistory = "groups.history"
case groupsInfo = "groups.info"
case groupsList = "groups.list"
case groupsMark = "groups.mark"
case groupsOpen = "groups.open"
case groupsSetPurpose = "groups.setPurpose"
case groupsSetTopic = "groups.setTopic"
case imClose = "im.close"
case imHistory = "im.history"
case imList = "im.list"
case imMark = "im.mark"
case imOpen = "im.open"
case mpimClose = "mpim.close"
case mpimHistory = "mpim.history"
case mpimList = "mpim.list"
case mpimMark = "mpim.mark"
case mpimOpen = "mpim.open"
case oauthAccess = "oauth.access"
case pinsAdd = "pins.add"
case pinsRemove = "pins.remove"
case reactionsAdd = "reactions.add"
case reactionsGet = "reactions.get"
case reactionsList = "reactions.list"
case reactionsRemove = "reactions.remove"
case rtmStart = "rtm.start"
case starsAdd = "stars.add"
case starsRemove = "stars.remove"
case teamInfo = "team.info"
case usersGetPresence = "users.getPresence"
case usersInfo = "users.info"
case usersList = "users.list"
case usersSetActive = "users.setActive"
case usersSetPresence = "users.setPresence"
}
73 changes: 48 additions & 25 deletions Sources/NetworkInterface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,24 @@
// THE SOFTWARE.

#if os(Linux)
import Dispatch
import Dispatch
#endif
import Foundation
import SKCore

public struct NetworkInterface {

private let apiUrl = "https://slack.com/api/"
private let session = URLSession(configuration: .default)

internal init() {}

internal func request(_ endpoint: Endpoint, parameters: [String: Any?], successClosure: @escaping ([String: Any])->Void, errorClosure: @escaping (SlackError)->Void) {

internal func request(
_ endpoint: Endpoint,
parameters: [String: Any?],
successClosure: @escaping ([String: Any]) -> Void,
errorClosure: @escaping (SlackError) -> Void
) {
var components = URLComponents(string: "\(apiUrl)\(endpoint.rawValue)")
if parameters.count > 0 {
components?.queryItems = filterNilParameters(parameters).map { URLQueryItem(name: $0.0, value: "\($0.1)") }
Expand All @@ -44,7 +49,7 @@ public struct NetworkInterface {
return
}
let request = URLRequest(url: url)

session.dataTask(with: request) {(data, response, publicError) in
do {
successClosure(try NetworkInterface.handleResponse(data, response: response, publicError: publicError))
Expand All @@ -53,7 +58,7 @@ public struct NetworkInterface {
}
}.resume()
}

//Adapted from https://gist.github.com/erica/baa8a187a5b4796dab27
internal func synchronusRequest(_ endpoint: Endpoint, parameters: [String: Any?]) -> [String: Any]? {
var components = URLComponents(string: "\(apiUrl)\(endpoint.rawValue)")
Expand All @@ -78,8 +83,13 @@ public struct NetworkInterface {
_ = semaphore.wait(timeout: DispatchTime.distantFuture)
return try? NetworkInterface.handleResponse(data, response: response, publicError: error)
}

internal func customRequest(_ url: String, data: Data, success: @escaping (Bool)->Void, errorClosure: @escaping (SlackError)->Void) {

internal func customRequest(
_ url: String,
data: Data,
success: @escaping (Bool) -> Void,
errorClosure: @escaping (SlackError) -> Void
) {
guard let string = url.removingPercentEncoding, let url = URL(string: string) else {
errorClosure(SlackError.clientNetworkError)
return
Expand All @@ -89,22 +99,30 @@ public struct NetworkInterface {
let contentType = "application/json"
request.setValue(contentType, forHTTPHeaderField: "Content-Type")
request.httpBody = data
session.dataTask(with: request) {(data, response, publicError) in

session.dataTask(with: request) {(_, _, publicError) in
if publicError == nil {
success(true)
} else {
errorClosure(SlackError.clientNetworkError)
}
}.resume()
}

internal func uploadRequest(data: Data, parameters: [String: Any?], successClosure: @escaping ([String: Any])->Void, errorClosure: @escaping (SlackError)->Void) {

internal func uploadRequest(
data: Data,
parameters: [String: Any?],
successClosure: @escaping ([String: Any]) -> Void, errorClosure: @escaping (SlackError) -> Void
) {
var components = URLComponents(string: "\(apiUrl)\(Endpoint.filesUpload.rawValue)")
if parameters.count > 0 {
components?.queryItems = filterNilParameters(parameters).map { URLQueryItem(name: $0.0, value: "\($0.1)") }
}
guard let url = components?.url, let filename = parameters["filename"] as? String, let filetype = parameters["filetype"] as? String else {
guard
let url = components?.url,
let filename = parameters["filename"] as? String,
let filetype = parameters["filetype"] as? String
else {
errorClosure(SlackError.clientNetworkError)
return
}
Expand All @@ -116,22 +134,27 @@ public struct NetworkInterface {
let boundaryEnd = "--\(boundaryConstant)--\r\n"
let contentDispositionString = "Content-Disposition: form-data; name=\"file\"; filename=\"\(filename)\"\r\n"
let contentTypeString = "Content-Type: \(filetype)\r\n\r\n"

guard let boundaryStartData = boundaryStart.data(using: .utf8), let dispositionData = contentDispositionString.data(using: .utf8), let contentTypeData = contentTypeString.data(using: .utf8), let boundaryEndData = boundaryEnd.data(using: .utf8) else {

guard
let boundaryStartData = boundaryStart.data(using: .utf8),
let dispositionData = contentDispositionString.data(using: .utf8),
let contentTypeData = contentTypeString.data(using: .utf8),
let boundaryEndData = boundaryEnd.data(using: .utf8)
else {
errorClosure(SlackError.clientNetworkError)
return
}

var requestBodyData = Data()
requestBodyData.append(contentsOf: boundaryStartData)
requestBodyData.append(contentsOf: dispositionData)
requestBodyData.append(contentsOf: contentTypeData)
requestBodyData.append(contentsOf: data)
requestBodyData.append(contentsOf: boundaryEndData)

request.setValue(contentType, forHTTPHeaderField: "Content-Type")
request.httpBody = requestBodyData as Data

session.dataTask(with: request) {(data, response, publicError) in
do {
successClosure(try NetworkInterface.handleResponse(data, response: response, publicError: publicError))
Expand All @@ -140,7 +163,7 @@ public struct NetworkInterface {
}
}.resume()
}

internal static func handleResponse(_ data: Data?, response: URLResponse?, publicError: Error?) throws -> [String: Any] {
guard let data = data, let response = response as? HTTPURLResponse else {
throw SlackError.clientNetworkError
Expand All @@ -149,10 +172,10 @@ public struct NetworkInterface {
guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
throw SlackError.clientJSONError
}

switch response.statusCode {
case 200:
if (json["ok"] as! Bool == true) {
if json["ok"] as? Bool == true {
return json
} else {
if let errorString = json["error"] as? String {
Expand All @@ -174,16 +197,16 @@ public struct NetworkInterface {
}
}
}

private func randomBoundary() -> String {
#if os(Linux)
return "slackkit.boundary.\(Int(random()))\(Int(random()))"
#else
return "slackkit.boundary.\(arc4random())\(arc4random())"
#endif
}
//MARK: - Filter Nil Parameters

// MARK: - Filter Nil Parameters
private func filterNilParameters(_ parameters: [String: Any?]) -> [String: Any] {
var finalParameters = [String: Any]()
for (key, value) in parameters {
Expand Down
Loading

0 comments on commit dc21b46

Please sign in to comment.