├── .gitignore ├── Cartfile ├── Cartfile.private ├── Cartfile.resolved ├── CoreHTTP.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── CoreHTTP.xcscmblueprint └── xcshareddata │ └── xcschemes │ └── CoreHTTP (iOS).xcscheme ├── Library ├── ArgoDecoding.swift ├── ArgoDecodingUtility.swift ├── ArgoParsing.swift ├── Bundle+Additions.swift ├── CoreHTTP.h ├── HTTPAuthenticationType.swift ├── HTTPHost.swift ├── HTTPHostRegistry.swift ├── HTTPMethod.swift ├── HTTPRequest.swift ├── HTTPResource.swift ├── HTTPResourceRequestable.swift ├── HTTPResponse.swift ├── HTTPResponseError.swift ├── HTTPResult.swift ├── HTTPStatusCodes.swift ├── Info.plist ├── Int+Additions.swift ├── JSONSerialization.swift ├── Logging.swift ├── Support.swift └── Support │ ├── iOS │ ├── CoreHTTP-iOS.h │ └── Info.plist │ └── macOS │ ├── CoreHTTP-Mac.h │ └── Info.plist ├── README.md ├── Sample └── NASA Photo of the Day │ ├── NASA Photo of the Day.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── NASA Photo of the Day │ ├── AppDelegate.swift │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ ├── NASAPhoto.swift │ ├── NASAPhotoOfTheDay.swift │ └── ViewController.swift └── Tests ├── CoreHTTPTests.swift └── Support └── Info.plist /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | 30 | ## Playgrounds 31 | timeline.xctimeline 32 | playground.xcworkspace 33 | 34 | # Swift Package Manager 35 | # 36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 37 | # Packages/ 38 | .build/ 39 | 40 | # CocoaPods 41 | # 42 | # We recommend against adding the Pods directory to your .gitignore. However 43 | # you should judge for yourself, the pros and cons are mentioned at: 44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 45 | # 46 | # Pods/ 47 | 48 | # Carthage 49 | # 50 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 51 | # Carthage/Checkouts 52 | 53 | Carthage/ 54 | 55 | # fastlane 56 | # 57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 58 | # screenshots whenever they are needed. 59 | # For more information about the recommended setup visit: 60 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 61 | 62 | fastlane/report.xml 63 | fastlane/Preview.html 64 | fastlane/screenshots 65 | fastlane/test_output 66 | -------------------------------------------------------------------------------- /Cartfile: -------------------------------------------------------------------------------- 1 | github "antitypical/Result" 2 | github "thoughtbot/Curry" ~> 3.0 3 | github "thoughtbot/Argo" ~> 4.0 4 | 5 | -------------------------------------------------------------------------------- /Cartfile.private: -------------------------------------------------------------------------------- 1 | github "Quick/Quick" 2 | github "Quick/Nimble" 3 | -------------------------------------------------------------------------------- /Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "thoughtbot/Curry" "v3.0.0" 2 | github "Quick/Nimble" "v5.1.0" 3 | github "Quick/Quick" "v0.10.0" 4 | github "antitypical/Result" "3.0.0" 5 | github "thoughtbot/Runes" "v4.0.0" 6 | github "thoughtbot/Argo" "v4.0.0" 7 | -------------------------------------------------------------------------------- /CoreHTTP.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C71A7F791D87A4BD00F2C879 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = C71A7F781D87A4BD00F2C879 /* Logging.swift */; }; 11 | C71A7F7B1D87A4E200F2C879 /* Int+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C71A7F7A1D87A4E200F2C879 /* Int+Additions.swift */; }; 12 | C759F9221D2263D60081C915 /* HTTPResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = C759F9211D2263D60081C915 /* HTTPResponse.swift */; }; 13 | C759F9241D226C150081C915 /* HTTPStatusCodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C759F9231D226C150081C915 /* HTTPStatusCodes.swift */; }; 14 | C7A82DC51DC1EA09007B1270 /* CoreHTTP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C7C669171D223181007ECF77 /* CoreHTTP.framework */; }; 15 | C7C669251D2231F5007ECF77 /* CoreHTTP.h in Headers */ = {isa = PBXBuildFile; fileRef = C7C669231D2231D4007ECF77 /* CoreHTTP.h */; settings = {ATTRIBUTES = (Public, ); }; }; 16 | C7C6692F1D223207007ECF77 /* HTTPHost.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C669261D223207007ECF77 /* HTTPHost.swift */; }; 17 | C7C669301D223207007ECF77 /* HTTPResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C669271D223207007ECF77 /* HTTPResource.swift */; }; 18 | C7C669311D223207007ECF77 /* HTTPRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C669281D223207007ECF77 /* HTTPRequest.swift */; }; 19 | C7C669321D223207007ECF77 /* HTTPResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C669291D223207007ECF77 /* HTTPResponseError.swift */; }; 20 | C7C669331D223207007ECF77 /* HTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C6692A1D223207007ECF77 /* HTTPMethod.swift */; }; 21 | C7C669341D223207007ECF77 /* HTTPHostRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C6692B1D223207007ECF77 /* HTTPHostRegistry.swift */; }; 22 | C7C669351D223207007ECF77 /* ArgoDecoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C6692C1D223207007ECF77 /* ArgoDecoding.swift */; }; 23 | C7C669361D223207007ECF77 /* ArgoDecodingUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C6692D1D223207007ECF77 /* ArgoDecodingUtility.swift */; }; 24 | C7C669371D223207007ECF77 /* ArgoParsing.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C6692E1D223207007ECF77 /* ArgoParsing.swift */; }; 25 | C7C6693F1D223374007ECF77 /* Argo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C7C6693C1D223374007ECF77 /* Argo.framework */; }; 26 | C7C669401D223374007ECF77 /* Curry.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C7C6693D1D223374007ECF77 /* Curry.framework */; }; 27 | C7C669411D223374007ECF77 /* Runes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C7C6693E1D223374007ECF77 /* Runes.framework */; }; 28 | C7C669431D22344B007ECF77 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C7C669421D22344B007ECF77 /* Result.framework */; }; 29 | C7DB9B451DC3066B0092EFE6 /* JSONSerialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7DB9B441DC3066B0092EFE6 /* JSONSerialization.swift */; }; 30 | C7E14CBB1DDEEC0B0088AB27 /* HTTPAuthenticationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7E14CBA1DDEEC0B0088AB27 /* HTTPAuthenticationType.swift */; }; 31 | C7E14CBD1DE2A7F30088AB27 /* HTTPResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7E14CBC1DE2A7F30088AB27 /* HTTPResult.swift */; }; 32 | C7E14CD11DE5541C0088AB27 /* HTTPResourceRequestable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7E14CD01DE5541C0088AB27 /* HTTPResourceRequestable.swift */; }; 33 | C7E1B3B51D26402900C22DC2 /* Bundle+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7E1B3B41D26402900C22DC2 /* Bundle+Additions.swift */; }; 34 | C7E1B3B71D2640B200C22DC2 /* Support.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7E1B3B61D2640B200C22DC2 /* Support.swift */; }; 35 | /* End PBXBuildFile section */ 36 | 37 | /* Begin PBXContainerItemProxy section */ 38 | C7A82DC61DC1EA09007B1270 /* PBXContainerItemProxy */ = { 39 | isa = PBXContainerItemProxy; 40 | containerPortal = C7C6690E1D223181007ECF77 /* Project object */; 41 | proxyType = 1; 42 | remoteGlobalIDString = C7C669161D223181007ECF77; 43 | remoteInfo = "CoreHTTP-iOS"; 44 | }; 45 | /* End PBXContainerItemProxy section */ 46 | 47 | /* Begin PBXFileReference section */ 48 | C71A7F781D87A4BD00F2C879 /* Logging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = ""; }; 49 | C71A7F7A1D87A4E200F2C879 /* Int+Additions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Int+Additions.swift"; sourceTree = ""; }; 50 | C759F9211D2263D60081C915 /* HTTPResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPResponse.swift; sourceTree = ""; }; 51 | C759F9231D226C150081C915 /* HTTPStatusCodes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPStatusCodes.swift; sourceTree = ""; }; 52 | C7A82DC01DC1EA09007B1270 /* CoreHTTPTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreHTTPTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | C7A82DCC1DC1EA48007B1270 /* CoreHTTPTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreHTTPTests.swift; sourceTree = ""; }; 54 | C7A82DCE1DC1EA48007B1270 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 55 | C7A82DCF1DC1EA61007B1270 /* Cartfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile; sourceTree = SOURCE_ROOT; }; 56 | C7A82DD01DC1EA7E007B1270 /* Cartfile.private */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Cartfile.private; path = ../Cartfile.private; sourceTree = ""; }; 57 | C7C669171D223181007ECF77 /* CoreHTTP.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CoreHTTP.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | C7C669231D2231D4007ECF77 /* CoreHTTP.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CoreHTTP.h; sourceTree = ""; }; 59 | C7C669241D2231D4007ECF77 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 60 | C7C669261D223207007ECF77 /* HTTPHost.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPHost.swift; sourceTree = ""; }; 61 | C7C669271D223207007ECF77 /* HTTPResource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPResource.swift; sourceTree = ""; }; 62 | C7C669281D223207007ECF77 /* HTTPRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPRequest.swift; sourceTree = ""; }; 63 | C7C669291D223207007ECF77 /* HTTPResponseError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPResponseError.swift; sourceTree = ""; }; 64 | C7C6692A1D223207007ECF77 /* HTTPMethod.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPMethod.swift; sourceTree = ""; }; 65 | C7C6692B1D223207007ECF77 /* HTTPHostRegistry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPHostRegistry.swift; sourceTree = ""; }; 66 | C7C6692C1D223207007ECF77 /* ArgoDecoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArgoDecoding.swift; sourceTree = ""; }; 67 | C7C6692D1D223207007ECF77 /* ArgoDecodingUtility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArgoDecodingUtility.swift; sourceTree = ""; }; 68 | C7C6692E1D223207007ECF77 /* ArgoParsing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArgoParsing.swift; sourceTree = ""; }; 69 | C7C6693C1D223374007ECF77 /* Argo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Argo.framework; path = Carthage/Build/iOS/Argo.framework; sourceTree = SOURCE_ROOT; }; 70 | C7C6693D1D223374007ECF77 /* Curry.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Curry.framework; path = Carthage/Build/iOS/Curry.framework; sourceTree = SOURCE_ROOT; }; 71 | C7C6693E1D223374007ECF77 /* Runes.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Runes.framework; path = Carthage/Build/iOS/Runes.framework; sourceTree = SOURCE_ROOT; }; 72 | C7C669421D22344B007ECF77 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/iOS/Result.framework; sourceTree = SOURCE_ROOT; }; 73 | C7DB9B441DC3066B0092EFE6 /* JSONSerialization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONSerialization.swift; sourceTree = ""; }; 74 | C7E14CBA1DDEEC0B0088AB27 /* HTTPAuthenticationType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPAuthenticationType.swift; sourceTree = ""; }; 75 | C7E14CBC1DE2A7F30088AB27 /* HTTPResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPResult.swift; sourceTree = ""; }; 76 | C7E14CD01DE5541C0088AB27 /* HTTPResourceRequestable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPResourceRequestable.swift; sourceTree = ""; }; 77 | C7E1B3B41D26402900C22DC2 /* Bundle+Additions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Bundle+Additions.swift"; sourceTree = ""; }; 78 | C7E1B3B61D2640B200C22DC2 /* Support.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Support.swift; sourceTree = ""; }; 79 | /* End PBXFileReference section */ 80 | 81 | /* Begin PBXFrameworksBuildPhase section */ 82 | C7A82DBD1DC1EA09007B1270 /* Frameworks */ = { 83 | isa = PBXFrameworksBuildPhase; 84 | buildActionMask = 2147483647; 85 | files = ( 86 | C7A82DC51DC1EA09007B1270 /* CoreHTTP.framework in Frameworks */, 87 | ); 88 | runOnlyForDeploymentPostprocessing = 0; 89 | }; 90 | C7C669131D223181007ECF77 /* Frameworks */ = { 91 | isa = PBXFrameworksBuildPhase; 92 | buildActionMask = 2147483647; 93 | files = ( 94 | C7C669401D223374007ECF77 /* Curry.framework in Frameworks */, 95 | C7C669411D223374007ECF77 /* Runes.framework in Frameworks */, 96 | C7C6693F1D223374007ECF77 /* Argo.framework in Frameworks */, 97 | C7C669431D22344B007ECF77 /* Result.framework in Frameworks */, 98 | ); 99 | runOnlyForDeploymentPostprocessing = 0; 100 | }; 101 | /* End PBXFrameworksBuildPhase section */ 102 | 103 | /* Begin PBXGroup section */ 104 | C7A82DCB1DC1EA48007B1270 /* Tests */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | C7A82DCC1DC1EA48007B1270 /* CoreHTTPTests.swift */, 108 | C7A82DCD1DC1EA48007B1270 /* Support */, 109 | ); 110 | path = Tests; 111 | sourceTree = ""; 112 | }; 113 | C7A82DCD1DC1EA48007B1270 /* Support */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | C7A82DCE1DC1EA48007B1270 /* Info.plist */, 117 | ); 118 | path = Support; 119 | sourceTree = ""; 120 | }; 121 | C7C6690D1D223181007ECF77 = { 122 | isa = PBXGroup; 123 | children = ( 124 | C7C669221D2231D4007ECF77 /* Library */, 125 | C7C669391D22325E007ECF77 /* Resources */, 126 | C7A82DCB1DC1EA48007B1270 /* Tests */, 127 | C7C669181D223181007ECF77 /* Products */, 128 | ); 129 | sourceTree = ""; 130 | }; 131 | C7C669181D223181007ECF77 /* Products */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | C7C669171D223181007ECF77 /* CoreHTTP.framework */, 135 | C7A82DC01DC1EA09007B1270 /* CoreHTTPTests.xctest */, 136 | ); 137 | name = Products; 138 | sourceTree = ""; 139 | }; 140 | C7C669221D2231D4007ECF77 /* Library */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | C7C669381D22320D007ECF77 /* Support */, 144 | C7C669261D223207007ECF77 /* HTTPHost.swift */, 145 | C7E14CBA1DDEEC0B0088AB27 /* HTTPAuthenticationType.swift */, 146 | C7C6692A1D223207007ECF77 /* HTTPMethod.swift */, 147 | C7C669271D223207007ECF77 /* HTTPResource.swift */, 148 | C7E14CD01DE5541C0088AB27 /* HTTPResourceRequestable.swift */, 149 | C7C669281D223207007ECF77 /* HTTPRequest.swift */, 150 | C759F9211D2263D60081C915 /* HTTPResponse.swift */, 151 | C7E14CBC1DE2A7F30088AB27 /* HTTPResult.swift */, 152 | C7C669291D223207007ECF77 /* HTTPResponseError.swift */, 153 | C759F9231D226C150081C915 /* HTTPStatusCodes.swift */, 154 | C7C6692B1D223207007ECF77 /* HTTPHostRegistry.swift */, 155 | C7DB9B431DC3064B0092EFE6 /* Argo */, 156 | C71A7F781D87A4BD00F2C879 /* Logging.swift */, 157 | C7DB9B441DC3066B0092EFE6 /* JSONSerialization.swift */, 158 | C71A7F7A1D87A4E200F2C879 /* Int+Additions.swift */, 159 | C7E1B3B41D26402900C22DC2 /* Bundle+Additions.swift */, 160 | C7E1B3B61D2640B200C22DC2 /* Support.swift */, 161 | ); 162 | path = Library; 163 | sourceTree = ""; 164 | }; 165 | C7C669381D22320D007ECF77 /* Support */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | C7A82DCF1DC1EA61007B1270 /* Cartfile */, 169 | C7A82DD01DC1EA7E007B1270 /* Cartfile.private */, 170 | C7C669231D2231D4007ECF77 /* CoreHTTP.h */, 171 | C7C669241D2231D4007ECF77 /* Info.plist */, 172 | ); 173 | name = Support; 174 | sourceTree = ""; 175 | }; 176 | C7C669391D22325E007ECF77 /* Resources */ = { 177 | isa = PBXGroup; 178 | children = ( 179 | C7C669421D22344B007ECF77 /* Result.framework */, 180 | C7C6693C1D223374007ECF77 /* Argo.framework */, 181 | C7C6693D1D223374007ECF77 /* Curry.framework */, 182 | C7C6693E1D223374007ECF77 /* Runes.framework */, 183 | ); 184 | name = Resources; 185 | path = Library; 186 | sourceTree = ""; 187 | }; 188 | C7DB9B431DC3064B0092EFE6 /* Argo */ = { 189 | isa = PBXGroup; 190 | children = ( 191 | C7C6692E1D223207007ECF77 /* ArgoParsing.swift */, 192 | C7C6692C1D223207007ECF77 /* ArgoDecoding.swift */, 193 | C7C6692D1D223207007ECF77 /* ArgoDecodingUtility.swift */, 194 | ); 195 | name = Argo; 196 | sourceTree = ""; 197 | }; 198 | /* End PBXGroup section */ 199 | 200 | /* Begin PBXHeadersBuildPhase section */ 201 | C7C669141D223181007ECF77 /* Headers */ = { 202 | isa = PBXHeadersBuildPhase; 203 | buildActionMask = 2147483647; 204 | files = ( 205 | C7C669251D2231F5007ECF77 /* CoreHTTP.h in Headers */, 206 | ); 207 | runOnlyForDeploymentPostprocessing = 0; 208 | }; 209 | /* End PBXHeadersBuildPhase section */ 210 | 211 | /* Begin PBXNativeTarget section */ 212 | C7A82DBF1DC1EA09007B1270 /* CoreHTTPTests */ = { 213 | isa = PBXNativeTarget; 214 | buildConfigurationList = C7A82DCA1DC1EA09007B1270 /* Build configuration list for PBXNativeTarget "CoreHTTPTests" */; 215 | buildPhases = ( 216 | C7A82DBC1DC1EA09007B1270 /* Sources */, 217 | C7A82DBD1DC1EA09007B1270 /* Frameworks */, 218 | C7A82DBE1DC1EA09007B1270 /* Resources */, 219 | ); 220 | buildRules = ( 221 | ); 222 | dependencies = ( 223 | C7A82DC71DC1EA09007B1270 /* PBXTargetDependency */, 224 | ); 225 | name = CoreHTTPTests; 226 | productName = CoreHTTPTests; 227 | productReference = C7A82DC01DC1EA09007B1270 /* CoreHTTPTests.xctest */; 228 | productType = "com.apple.product-type.bundle.unit-test"; 229 | }; 230 | C7C669161D223181007ECF77 /* CoreHTTP-iOS */ = { 231 | isa = PBXNativeTarget; 232 | buildConfigurationList = C7C6691F1D223181007ECF77 /* Build configuration list for PBXNativeTarget "CoreHTTP-iOS" */; 233 | buildPhases = ( 234 | C7C669121D223181007ECF77 /* Sources */, 235 | C7C669131D223181007ECF77 /* Frameworks */, 236 | C7C669141D223181007ECF77 /* Headers */, 237 | C7C669151D223181007ECF77 /* Resources */, 238 | ); 239 | buildRules = ( 240 | ); 241 | dependencies = ( 242 | ); 243 | name = "CoreHTTP-iOS"; 244 | productName = CoreHTTP; 245 | productReference = C7C669171D223181007ECF77 /* CoreHTTP.framework */; 246 | productType = "com.apple.product-type.framework"; 247 | }; 248 | /* End PBXNativeTarget section */ 249 | 250 | /* Begin PBXProject section */ 251 | C7C6690E1D223181007ECF77 /* Project object */ = { 252 | isa = PBXProject; 253 | attributes = { 254 | LastSwiftUpdateCheck = 0810; 255 | LastUpgradeCheck = 0810; 256 | ORGANIZATIONNAME = "Magical Panda Software"; 257 | TargetAttributes = { 258 | C7A82DBF1DC1EA09007B1270 = { 259 | CreatedOnToolsVersion = 8.1; 260 | ProvisioningStyle = Automatic; 261 | }; 262 | C7C669161D223181007ECF77 = { 263 | CreatedOnToolsVersion = 8.0; 264 | DevelopmentTeam = HG57592ZYS; 265 | DevelopmentTeamName = "Magical Panda Software, LLC"; 266 | LastSwiftMigration = 0800; 267 | ProvisioningStyle = Automatic; 268 | }; 269 | }; 270 | }; 271 | buildConfigurationList = C7C669111D223181007ECF77 /* Build configuration list for PBXProject "CoreHTTP" */; 272 | compatibilityVersion = "Xcode 3.2"; 273 | developmentRegion = English; 274 | hasScannedForEncodings = 0; 275 | knownRegions = ( 276 | en, 277 | ); 278 | mainGroup = C7C6690D1D223181007ECF77; 279 | productRefGroup = C7C669181D223181007ECF77 /* Products */; 280 | projectDirPath = ""; 281 | projectRoot = ""; 282 | targets = ( 283 | C7C669161D223181007ECF77 /* CoreHTTP-iOS */, 284 | C7A82DBF1DC1EA09007B1270 /* CoreHTTPTests */, 285 | ); 286 | }; 287 | /* End PBXProject section */ 288 | 289 | /* Begin PBXResourcesBuildPhase section */ 290 | C7A82DBE1DC1EA09007B1270 /* Resources */ = { 291 | isa = PBXResourcesBuildPhase; 292 | buildActionMask = 2147483647; 293 | files = ( 294 | ); 295 | runOnlyForDeploymentPostprocessing = 0; 296 | }; 297 | C7C669151D223181007ECF77 /* Resources */ = { 298 | isa = PBXResourcesBuildPhase; 299 | buildActionMask = 2147483647; 300 | files = ( 301 | ); 302 | runOnlyForDeploymentPostprocessing = 0; 303 | }; 304 | /* End PBXResourcesBuildPhase section */ 305 | 306 | /* Begin PBXSourcesBuildPhase section */ 307 | C7A82DBC1DC1EA09007B1270 /* Sources */ = { 308 | isa = PBXSourcesBuildPhase; 309 | buildActionMask = 2147483647; 310 | files = ( 311 | ); 312 | runOnlyForDeploymentPostprocessing = 0; 313 | }; 314 | C7C669121D223181007ECF77 /* Sources */ = { 315 | isa = PBXSourcesBuildPhase; 316 | buildActionMask = 2147483647; 317 | files = ( 318 | C7C6692F1D223207007ECF77 /* HTTPHost.swift in Sources */, 319 | C7E14CD11DE5541C0088AB27 /* HTTPResourceRequestable.swift in Sources */, 320 | C7C669371D223207007ECF77 /* ArgoParsing.swift in Sources */, 321 | C7E1B3B51D26402900C22DC2 /* Bundle+Additions.swift in Sources */, 322 | C71A7F791D87A4BD00F2C879 /* Logging.swift in Sources */, 323 | C759F9221D2263D60081C915 /* HTTPResponse.swift in Sources */, 324 | C7C669361D223207007ECF77 /* ArgoDecodingUtility.swift in Sources */, 325 | C7E14CBD1DE2A7F30088AB27 /* HTTPResult.swift in Sources */, 326 | C7E14CBB1DDEEC0B0088AB27 /* HTTPAuthenticationType.swift in Sources */, 327 | C7C669321D223207007ECF77 /* HTTPResponseError.swift in Sources */, 328 | C7C669301D223207007ECF77 /* HTTPResource.swift in Sources */, 329 | C7C669331D223207007ECF77 /* HTTPMethod.swift in Sources */, 330 | C7C669341D223207007ECF77 /* HTTPHostRegistry.swift in Sources */, 331 | C7DB9B451DC3066B0092EFE6 /* JSONSerialization.swift in Sources */, 332 | C7E1B3B71D2640B200C22DC2 /* Support.swift in Sources */, 333 | C759F9241D226C150081C915 /* HTTPStatusCodes.swift in Sources */, 334 | C71A7F7B1D87A4E200F2C879 /* Int+Additions.swift in Sources */, 335 | C7C669311D223207007ECF77 /* HTTPRequest.swift in Sources */, 336 | C7C669351D223207007ECF77 /* ArgoDecoding.swift in Sources */, 337 | ); 338 | runOnlyForDeploymentPostprocessing = 0; 339 | }; 340 | /* End PBXSourcesBuildPhase section */ 341 | 342 | /* Begin PBXTargetDependency section */ 343 | C7A82DC71DC1EA09007B1270 /* PBXTargetDependency */ = { 344 | isa = PBXTargetDependency; 345 | target = C7C669161D223181007ECF77 /* CoreHTTP-iOS */; 346 | targetProxy = C7A82DC61DC1EA09007B1270 /* PBXContainerItemProxy */; 347 | }; 348 | /* End PBXTargetDependency section */ 349 | 350 | /* Begin XCBuildConfiguration section */ 351 | C7A82DC81DC1EA09007B1270 /* Debug */ = { 352 | isa = XCBuildConfiguration; 353 | buildSettings = { 354 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 355 | INFOPLIST_FILE = CoreHTTPTests/Info.plist; 356 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 357 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 358 | PRODUCT_BUNDLE_IDENTIFIER = com.magicalpanda.CoreHTTPTests; 359 | PRODUCT_NAME = "$(TARGET_NAME)"; 360 | SWIFT_VERSION = 3.0; 361 | }; 362 | name = Debug; 363 | }; 364 | C7A82DC91DC1EA09007B1270 /* Release */ = { 365 | isa = XCBuildConfiguration; 366 | buildSettings = { 367 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 368 | INFOPLIST_FILE = CoreHTTPTests/Info.plist; 369 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 370 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 371 | PRODUCT_BUNDLE_IDENTIFIER = com.magicalpanda.CoreHTTPTests; 372 | PRODUCT_NAME = "$(TARGET_NAME)"; 373 | SWIFT_VERSION = 3.0; 374 | }; 375 | name = Release; 376 | }; 377 | C7C6691D1D223181007ECF77 /* Debug */ = { 378 | isa = XCBuildConfiguration; 379 | buildSettings = { 380 | ALWAYS_SEARCH_USER_PATHS = NO; 381 | CLANG_ANALYZER_NONNULL = YES; 382 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 383 | CLANG_CXX_LIBRARY = "libc++"; 384 | CLANG_ENABLE_MODULES = YES; 385 | CLANG_ENABLE_OBJC_ARC = YES; 386 | CLANG_WARN_BOOL_CONVERSION = YES; 387 | CLANG_WARN_CONSTANT_CONVERSION = YES; 388 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 389 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 390 | CLANG_WARN_EMPTY_BODY = YES; 391 | CLANG_WARN_ENUM_CONVERSION = YES; 392 | CLANG_WARN_INFINITE_RECURSION = YES; 393 | CLANG_WARN_INT_CONVERSION = YES; 394 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 395 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 396 | CLANG_WARN_UNREACHABLE_CODE = YES; 397 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 398 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 399 | COPY_PHASE_STRIP = NO; 400 | CURRENT_PROJECT_VERSION = 1; 401 | DEBUG_INFORMATION_FORMAT = dwarf; 402 | ENABLE_STRICT_OBJC_MSGSEND = YES; 403 | ENABLE_TESTABILITY = YES; 404 | GCC_C_LANGUAGE_STANDARD = gnu99; 405 | GCC_DYNAMIC_NO_PIC = NO; 406 | GCC_NO_COMMON_BLOCKS = YES; 407 | GCC_OPTIMIZATION_LEVEL = 0; 408 | GCC_PREPROCESSOR_DEFINITIONS = ( 409 | "DEBUG=1", 410 | "$(inherited)", 411 | ); 412 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 413 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 414 | GCC_WARN_UNDECLARED_SELECTOR = YES; 415 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 416 | GCC_WARN_UNUSED_FUNCTION = YES; 417 | GCC_WARN_UNUSED_VARIABLE = YES; 418 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 419 | MTL_ENABLE_DEBUG_INFO = YES; 420 | ONLY_ACTIVE_ARCH = YES; 421 | SDKROOT = iphoneos; 422 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 423 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 424 | TARGETED_DEVICE_FAMILY = "1,2"; 425 | VERSIONING_SYSTEM = "apple-generic"; 426 | VERSION_INFO_PREFIX = ""; 427 | }; 428 | name = Debug; 429 | }; 430 | C7C6691E1D223181007ECF77 /* Release */ = { 431 | isa = XCBuildConfiguration; 432 | buildSettings = { 433 | ALWAYS_SEARCH_USER_PATHS = NO; 434 | CLANG_ANALYZER_NONNULL = YES; 435 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 436 | CLANG_CXX_LIBRARY = "libc++"; 437 | CLANG_ENABLE_MODULES = YES; 438 | CLANG_ENABLE_OBJC_ARC = YES; 439 | CLANG_WARN_BOOL_CONVERSION = YES; 440 | CLANG_WARN_CONSTANT_CONVERSION = YES; 441 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 442 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 443 | CLANG_WARN_EMPTY_BODY = YES; 444 | CLANG_WARN_ENUM_CONVERSION = YES; 445 | CLANG_WARN_INFINITE_RECURSION = YES; 446 | CLANG_WARN_INT_CONVERSION = YES; 447 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 448 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 449 | CLANG_WARN_UNREACHABLE_CODE = YES; 450 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 451 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 452 | COPY_PHASE_STRIP = NO; 453 | CURRENT_PROJECT_VERSION = 1; 454 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 455 | ENABLE_NS_ASSERTIONS = NO; 456 | ENABLE_STRICT_OBJC_MSGSEND = YES; 457 | GCC_C_LANGUAGE_STANDARD = gnu99; 458 | GCC_NO_COMMON_BLOCKS = YES; 459 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 460 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 461 | GCC_WARN_UNDECLARED_SELECTOR = YES; 462 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 463 | GCC_WARN_UNUSED_FUNCTION = YES; 464 | GCC_WARN_UNUSED_VARIABLE = YES; 465 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 466 | MTL_ENABLE_DEBUG_INFO = NO; 467 | SDKROOT = iphoneos; 468 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 469 | TARGETED_DEVICE_FAMILY = "1,2"; 470 | VALIDATE_PRODUCT = YES; 471 | VERSIONING_SYSTEM = "apple-generic"; 472 | VERSION_INFO_PREFIX = ""; 473 | }; 474 | name = Release; 475 | }; 476 | C7C669201D223181007ECF77 /* Debug */ = { 477 | isa = XCBuildConfiguration; 478 | buildSettings = { 479 | CLANG_ENABLE_MODULES = YES; 480 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 481 | DEFINES_MODULE = YES; 482 | DYLIB_COMPATIBILITY_VERSION = 1; 483 | DYLIB_CURRENT_VERSION = 1; 484 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 485 | FRAMEWORK_SEARCH_PATHS = ( 486 | "$(inherited)", 487 | "$(PROJECT_DIR)/Carthage/Build/iOS", 488 | ); 489 | INFOPLIST_FILE = Library/Info.plist; 490 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 491 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 492 | PRODUCT_BUNDLE_IDENTIFIER = com.magicalpanda.CoreHTTP; 493 | PRODUCT_NAME = CoreHTTP; 494 | SKIP_INSTALL = YES; 495 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 496 | SWIFT_VERSION = 3.0; 497 | }; 498 | name = Debug; 499 | }; 500 | C7C669211D223181007ECF77 /* Release */ = { 501 | isa = XCBuildConfiguration; 502 | buildSettings = { 503 | CLANG_ENABLE_MODULES = YES; 504 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 505 | DEFINES_MODULE = YES; 506 | DYLIB_COMPATIBILITY_VERSION = 1; 507 | DYLIB_CURRENT_VERSION = 1; 508 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 509 | FRAMEWORK_SEARCH_PATHS = ( 510 | "$(inherited)", 511 | "$(PROJECT_DIR)/Carthage/Build/iOS", 512 | ); 513 | INFOPLIST_FILE = Library/Info.plist; 514 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 515 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 516 | PRODUCT_BUNDLE_IDENTIFIER = com.magicalpanda.CoreHTTP; 517 | PRODUCT_NAME = CoreHTTP; 518 | SKIP_INSTALL = YES; 519 | SWIFT_VERSION = 3.0; 520 | }; 521 | name = Release; 522 | }; 523 | /* End XCBuildConfiguration section */ 524 | 525 | /* Begin XCConfigurationList section */ 526 | C7A82DCA1DC1EA09007B1270 /* Build configuration list for PBXNativeTarget "CoreHTTPTests" */ = { 527 | isa = XCConfigurationList; 528 | buildConfigurations = ( 529 | C7A82DC81DC1EA09007B1270 /* Debug */, 530 | C7A82DC91DC1EA09007B1270 /* Release */, 531 | ); 532 | defaultConfigurationIsVisible = 0; 533 | defaultConfigurationName = Release; 534 | }; 535 | C7C669111D223181007ECF77 /* Build configuration list for PBXProject "CoreHTTP" */ = { 536 | isa = XCConfigurationList; 537 | buildConfigurations = ( 538 | C7C6691D1D223181007ECF77 /* Debug */, 539 | C7C6691E1D223181007ECF77 /* Release */, 540 | ); 541 | defaultConfigurationIsVisible = 0; 542 | defaultConfigurationName = Release; 543 | }; 544 | C7C6691F1D223181007ECF77 /* Build configuration list for PBXNativeTarget "CoreHTTP-iOS" */ = { 545 | isa = XCConfigurationList; 546 | buildConfigurations = ( 547 | C7C669201D223181007ECF77 /* Debug */, 548 | C7C669211D223181007ECF77 /* Release */, 549 | ); 550 | defaultConfigurationIsVisible = 0; 551 | defaultConfigurationName = Release; 552 | }; 553 | /* End XCConfigurationList section */ 554 | }; 555 | rootObject = C7C6690E1D223181007ECF77 /* Project object */; 556 | } 557 | -------------------------------------------------------------------------------- /CoreHTTP.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CoreHTTP.xcodeproj/project.xcworkspace/xcshareddata/CoreHTTP.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "6B45497ABA8393E2DC9E80A6AF0081D366C274C5", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | 5 | }, 6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 7 | "6B45497ABA8393E2DC9E80A6AF0081D366C274C5" : 9223372036854775807, 8 | "0A5C3A6DB1EA9211CEFA5384E9882B4D710699A4" : 9223372036854775807, 9 | "956D2B21DD155C49504BB67697A67F7C5351A353" : 9223372036854775807 10 | }, 11 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "C604F87D-685B-4CE3-8353-A79EF376AEF7", 12 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 13 | "6B45497ABA8393E2DC9E80A6AF0081D366C274C5" : "CoreHTTP\/", 14 | "0A5C3A6DB1EA9211CEFA5384E9882B4D710699A4" : "Experiments\/Runes\/", 15 | "956D2B21DD155C49504BB67697A67F7C5351A353" : "Experiments\/Result\/" 16 | }, 17 | "DVTSourceControlWorkspaceBlueprintNameKey" : "CoreHTTP", 18 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 19 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CoreHTTP.xcodeproj", 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 21 | { 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:casademora\/Runes.git", 23 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 24 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "0A5C3A6DB1EA9211CEFA5384E9882B4D710699A4" 25 | }, 26 | { 27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:casademora\/CoreHTTP.git", 28 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 29 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "6B45497ABA8393E2DC9E80A6AF0081D366C274C5" 30 | }, 31 | { 32 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:casademora\/Result.git", 33 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 34 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "956D2B21DD155C49504BB67697A67F7C5351A353" 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /CoreHTTP.xcodeproj/xcshareddata/xcschemes/CoreHTTP (iOS).xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /Library/ArgoDecoding.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Decoding.swift 3 | // GaugesAPI 4 | // 5 | // Created by Saul Mora on 6/26/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | import Runes 10 | import Argo 11 | import Result 12 | 13 | func decode(rootKey: String) -> (Any) -> Result where T == T.DecodedType 14 | { 15 | return { objectData in 16 | guard let decodable = objectData as? [String : Any] else { return Result(error: .invalidResponseType) } 17 | let result: Decoded = decode(decodable, rootKey: rootKey) 18 | 19 | return (transform <^> objectData <*> result) 20 | ?? Result(error: .deserializationFailure(message: "Object Data \(objectData), rootKey: \(rootKey)")) 21 | } 22 | } 23 | 24 | func decode(objectData: Any) -> Result where T == T.DecodedType 25 | { 26 | let result: Decoded = decode(objectData) 27 | 28 | return (transform <^> objectData <*> result) 29 | ?? Result(error: .deserializationFailure(message: "Object Data \(objectData)")) 30 | } 31 | 32 | func decode(rootKey: String) -> (Any) -> Result<[T], HTTPResponseError> where T == T.DecodedType 33 | { 34 | return { objectData in 35 | guard let decodable = objectData as? [String : Any] else { return Result(error: .invalidResponseType) } 36 | let result: Decoded<[T]> = decode(decodable, rootKey: rootKey) 37 | 38 | return (transform <^> objectData <*> result) 39 | ?? Result(error: .deserializationFailure(message: "Object Data \(objectData), rootKey: \(rootKey)")) 40 | } 41 | } 42 | 43 | func decode(objectData: Any) -> Result<[T], HTTPResponseError> where T == T.DecodedType 44 | { 45 | let result: Decoded<[T]> = decode(objectData) 46 | return (transform <^> objectData <*> result) 47 | ?? Result(error: .deserializationFailure(message: "Object Data: \(objectData)")) 48 | } 49 | 50 | fileprivate func transform(objectData: Any) -> (Decoded) -> Result where T == T.DecodedType 51 | { 52 | return { result in 53 | switch result { 54 | case .success(let value): 55 | return Result(value) 56 | case .failure(let error): 57 | let description = error.description 58 | return Result(error: .decodingFailure(description: description, source: sourceStringFrom(object: objectData))) 59 | } 60 | } 61 | } 62 | 63 | fileprivate func transform(objectData: Any) -> (Decoded<[T]>) -> Result<[T], HTTPResponseError> where T == T.DecodedType 64 | { 65 | return { result in 66 | switch result { 67 | case .success(let value): 68 | return Result(value) 69 | case .failure(let error): 70 | let description = error.description 71 | return Result(error: .decodingFailure(description: description, source: sourceStringFrom(object: objectData))) 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Library/ArgoDecodingUtility.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DecodingUtility.swift 3 | // GaugesAPI 4 | // 5 | // Created by Saul Mora on 6/26/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | import Argo 10 | 11 | extension URL: Decodable 12 | { 13 | public static func decode(_ json: JSON) -> Decoded 14 | { 15 | if case .string(let value) = json, let url = URL(string: value) 16 | { 17 | return .success(url) 18 | } 19 | else 20 | { 21 | return .failure(.typeMismatch(expected: "URL", actual: json.description)) 22 | } 23 | } 24 | } 25 | 26 | public func dateFrom(_ format: String) -> (String) -> Decoded 27 | { 28 | let formatter = DateFormatter() 29 | formatter.dateFormat = format 30 | return { dateToFormat in 31 | if let date = formatter.date(from: dateToFormat) 32 | { 33 | return .success(date) 34 | } 35 | else 36 | { 37 | return .failure(.typeMismatch(expected: "Date", actual: dateToFormat)) 38 | } 39 | } 40 | } 41 | 42 | public func stringFrom(_ date: Date, format: String) -> String 43 | { 44 | let formatter = DateFormatter() 45 | formatter.dateFormat = format 46 | return formatter.string(from: date) 47 | } 48 | 49 | public func stringFrom(format: String) -> (Date) -> String 50 | { 51 | let formatter = DateFormatter() 52 | formatter.dateFormat = format 53 | 54 | return { date in 55 | formatter.string(from: date) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Library/ArgoParsing.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Parsing.swift 3 | // GaugesAPI 4 | // 5 | // Created by Saul Mora on 6/19/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | import Result 10 | import Argo 11 | 12 | public func parse(data: Data) -> Result where T == T.DecodedType 13 | { 14 | let result = deserializeJSON(data: data) 15 | return result >>- decode 16 | } 17 | 18 | public func parse(rootKey: String) -> (Data) -> Result where T == T.DecodedType 19 | { 20 | return { data in 21 | let result = deserializeJSON(data: data) 22 | return result >>- decode(rootKey: rootKey) 23 | } 24 | } 25 | 26 | public func parse(data: Data) -> Result<[T], HTTPResponseError> where T == T.DecodedType 27 | { 28 | return deserializeJSON(data: data) 29 | >>- decode 30 | } 31 | 32 | public func parse(rootKey: String) -> (Data) -> Result<[T], HTTPResponseError> where T == T.DecodedType 33 | { 34 | return { data in 35 | return deserializeJSON(data: data) 36 | >>- decode(rootKey: rootKey) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Library/Bundle+Additions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSBundle+Additions.swift 3 | // 4 | // 5 | // Created by Saul Mora on 6/26/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Runes 11 | 12 | extension Bundle 13 | { 14 | var executableName: String 15 | { 16 | let bundleExecutableKey = kCFBundleExecutableKey as String 17 | let bundleIdentifierKey = kCFBundleIdentifierKey as String 18 | 19 | let executableName = 20 | (infoDictionary >>- { $0[bundleExecutableKey] }) 21 | ?? (infoDictionary >>- { $0[bundleIdentifierKey] }) 22 | return executableName as? String ?? "Unable to Determine Executable Name" 23 | } 24 | 25 | var bundleVersion: String 26 | { 27 | let bundleVersionKey = kCFBundleVersionKey as String 28 | let bundleShortVersionkey = "CFBundleShortVersionString" 29 | 30 | let version = (infoDictionary >>- { $0[bundleVersionKey] }) 31 | ?? (infoDictionary >>- { $0[bundleShortVersionkey] }) 32 | 33 | return version as? String ?? "0.0.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Library/CoreHTTP.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoreHTTP.h 3 | // CoreHTTP 4 | // 5 | // Created by Saul Mora on 6/28/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for CoreHTTP. 12 | FOUNDATION_EXPORT double CoreHTTPVersionNumber; 13 | 14 | //! Project version string for CoreHTTP. 15 | FOUNDATION_EXPORT const unsigned char CoreHTTPVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Library/HTTPAuthenticationType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPAuthenticationType.swift 3 | // CoreHTTP 4 | // 5 | // Created by Saul Mora on 11/18/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public typealias AuthenticationToken = String 12 | public enum HTTPAuthenticationType 13 | { 14 | case none 15 | case queryParameters(String, AuthenticationToken) 16 | case basic(AuthenticationToken) 17 | case oauth(AuthenticationToken) 18 | 19 | var authenticationHeaderValue: String 20 | { 21 | switch self 22 | { 23 | case .basic(let token): 24 | return "Basic \(token)" 25 | case .oauth(let token): 26 | return "Bearer \(token)" 27 | default: 28 | return "" 29 | } 30 | } 31 | 32 | var isStaticHeaderAuthentication: Bool 33 | { 34 | switch self 35 | { 36 | case .basic, .oauth: return true 37 | default: return false 38 | } 39 | } 40 | 41 | private func authentication() -> (URLRequest) -> URLRequest 42 | { 43 | switch self 44 | { 45 | case .queryParameters: 46 | return authenticateQuery 47 | case .basic, .oauth: 48 | return authenticateHeader 49 | case .none: 50 | return noAuthentication 51 | } 52 | } 53 | 54 | func authenticate(request: URLRequest) -> URLRequest 55 | { 56 | let function = authentication() 57 | return function(request) 58 | } 59 | 60 | private func noAuthentication(request: URLRequest) -> URLRequest 61 | { 62 | return request 63 | } 64 | 65 | private func authenticateHeader(request: URLRequest) -> URLRequest 66 | { 67 | var authenticatedRequest = request 68 | authenticatedRequest.setValue(authenticationHeaderValue, forHTTPHeaderField: "Authorization") 69 | return authenticatedRequest 70 | } 71 | 72 | private func authenticateQuery(request: URLRequest) -> URLRequest 73 | { 74 | guard 75 | let url = request.url, 76 | var components = URLComponents(url: url, resolvingAgainstBaseURL: false), 77 | case let .queryParameters(key, value) = self 78 | else { return request } 79 | 80 | var queryItems = components.queryItems ?? [] 81 | queryItems.append(URLQueryItem(name: key, value: value)) 82 | components.queryItems = queryItems 83 | 84 | var authenticatedRequest = request 85 | authenticatedRequest.url = components.url 86 | return authenticatedRequest 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Library/HTTPHost.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPAPIHost.swift 3 | // GaugesAPI 4 | // 5 | // Created by Saul Mora on 6/19/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | import Result 10 | 11 | public typealias ResponseValidationFunction = (Data?) -> (HTTPURLResponse) -> Result 12 | public typealias AuthenticateURLRequestFunction = (_ request: URLRequest) -> (URLRequest) 13 | public typealias PreprocessRequestFunction = (URLRequest) -> URLRequest 14 | public typealias GenerateAuthenticationCredentialsFunction = (Void) -> (HTTPAuthenticationType) 15 | 16 | public protocol HTTPHostProtocol: Hashable, HTTPResourceRequestable 17 | { 18 | var baseURLString: String { get } 19 | var baseURL: URL { get } 20 | 21 | var session: URLSession { get } 22 | 23 | var validate: ResponseValidationFunction { get } 24 | var authentication: GenerateAuthenticationCredentialsFunction { get } 25 | } 26 | 27 | open class HTTPHost: HTTPHostProtocol 28 | { 29 | public let baseURLString: String 30 | 31 | public let preprocessRequest: PreprocessRequestFunction? 32 | public let validate: ResponseValidationFunction 33 | public var authentication: GenerateAuthenticationCredentialsFunction 34 | { 35 | didSet 36 | { 37 | rebuildSession() 38 | } 39 | } 40 | public private(set) lazy var session: URLSession = self.buildSession() 41 | 42 | private let configuration: URLSessionConfiguration 43 | 44 | public init(baseURLString: String, 45 | configuration: URLSessionConfiguration = .default, 46 | preprocessRequests: PreprocessRequestFunction? = nil, 47 | validate: @escaping ResponseValidationFunction = defaultValidation, 48 | authentication: @escaping GenerateAuthenticationCredentialsFunction = defaultAuthentication) 49 | { 50 | self.baseURLString = baseURLString 51 | self.configuration = configuration 52 | self.preprocessRequest = preprocessRequests 53 | self.validate = validate 54 | self.authentication = authentication 55 | } 56 | 57 | func setAuthentication(type: HTTPAuthenticationType) 58 | { 59 | authentication = { type } 60 | } 61 | 62 | private func rebuildSession() 63 | { 64 | session = buildSession() 65 | } 66 | 67 | private func buildSession() -> URLSession 68 | { 69 | let configuration = self.configuration 70 | self.applyAdditionalConfiguration(configuration) 71 | return URLSession(configuration: configuration, delegate: nil, delegateQueue: nil) 72 | } 73 | 74 | open func applyAdditionalConfiguration(_ configuration: URLSessionConfiguration) 75 | { 76 | var addtionalHeaders: [String: Any] = [:] 77 | addtionalHeaders["User-Agent"] = buildUserAgent() 78 | 79 | let authType = authentication() 80 | if authType.isStaticHeaderAuthentication 81 | { 82 | addtionalHeaders["Authorization"] = authType.authenticationHeaderValue 83 | } 84 | configuration.httpAdditionalHeaders = addtionalHeaders 85 | } 86 | } 87 | 88 | extension HTTPHost: Hashable 89 | { 90 | public var baseURL: URL 91 | { 92 | return URL(string: baseURLString) ?? URL(fileURLWithPath: "/") 93 | } 94 | 95 | public var hashValue: Int 96 | { 97 | return baseURLString.hashValue 98 | } 99 | } 100 | 101 | public func ==(lhs: H, rhs: H) -> Bool 102 | { 103 | return lhs.baseURLString == rhs.baseURLString 104 | } 105 | 106 | fileprivate func defaultValidation(data: Data?) -> (HTTPURLResponse) -> Result 107 | { 108 | return { response in 109 | response.isSuccess ? 110 | Result(data, failWith: .responseFailure(response)) : 111 | Result(error: .responseFailure(response)) 112 | } 113 | } 114 | 115 | fileprivate func defaultAuthentication() -> HTTPAuthenticationType 116 | { 117 | return .none 118 | } 119 | 120 | private func buildUserAgent() -> String 121 | { 122 | let bundle = Bundle.main 123 | let device = UIDevice.current 124 | let screen = UIScreen.main 125 | 126 | return "\(bundle.executableName))/\(bundle.bundleVersion) (\(device.model); \(device.systemName) \(device.systemVersion); Scale/\(screen.scale))" 127 | } 128 | -------------------------------------------------------------------------------- /Library/HTTPHostRegistry.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPUtility.swift 3 | // GaugesAPI 4 | // 5 | // Created by Saul Mora on 6/19/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | struct HostRegistry 12 | { 13 | private var collection: Set = Set() 14 | 15 | fileprivate init() {} 16 | 17 | func hostFor(_ resource: R) -> HTTPHost? 18 | where R: HTTPResourceProtocol & HostedResource 19 | { 20 | return collection.filter { $0.canRequestResource(resource: resource) }.first 21 | } 22 | 23 | mutating func register(_ host: Host) 24 | { 25 | collection.insert(host) 26 | } 27 | 28 | mutating func unregister(_ host: Host) 29 | { 30 | collection.remove(host) 31 | } 32 | } 33 | 34 | private(set) var defaultHostRegistry = HostRegistry() 35 | 36 | public func register(host: H) 37 | { 38 | defaultHostRegistry.register(host) 39 | } 40 | 41 | public func unregister(host: H) 42 | { 43 | defaultHostRegistry.unregister(host) 44 | } 45 | 46 | public protocol HostedResource 47 | { 48 | var hostType: AnyClass { get } 49 | } 50 | 51 | extension UIApplication 52 | { 53 | var hostRegistry: HostRegistry 54 | { 55 | return defaultHostRegistry 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /Library/HTTPMethod.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPMethod.swift 3 | // GaugesAPI 4 | // 5 | // Created by Saul Mora on 6/19/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | public protocol HTTPMethodProtocol: RawRepresentable 10 | { 11 | var value: String { get } 12 | } 13 | 14 | extension HTTPMethodProtocol where RawValue == String 15 | { 16 | public var value: String { return rawValue } 17 | } 18 | 19 | public enum AnyHTTPMethod: String, HTTPMethodProtocol 20 | { 21 | case unknown 22 | case GET 23 | case HEAD 24 | case OPTIONS 25 | case TRACE 26 | case CONNECT 27 | case POST 28 | case PUT 29 | case DELETE 30 | } 31 | 32 | public enum QueriableHTTPMethod: String, HTTPMethodProtocol 33 | { 34 | case unknown 35 | case GET 36 | case HEAD 37 | case OPTIONS 38 | case TRACE 39 | case CONNECT 40 | } 41 | 42 | public enum UpdatableHTTPMethod: String, HTTPMethodProtocol 43 | { 44 | case unknown 45 | case POST 46 | case PUT 47 | case DELETE 48 | } 49 | 50 | -------------------------------------------------------------------------------- /Library/HTTPRequest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPResourceRequest.swift 3 | // CoreHTTP 4 | // 5 | // Created by Saul Mora on 6/25/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | import Result 10 | 11 | let defaultCachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy 12 | let defaultTimeout: TimeInterval = 30.seconds 13 | 14 | func buildRequest( 15 | for resource: R, 16 | host: H, 17 | cachePolicy: URLRequest.CachePolicy, 18 | requestTimeout: TimeInterval) 19 | -> Result 20 | where 21 | H: HTTPHostProtocol, 22 | R: HTTPResourceProtocol, 23 | R.ErrorType == HTTPResponseError 24 | { 25 | let path = resource.path 26 | let requestedURL = host.baseURL.appendingPathComponent(path) 27 | guard var components = URLComponents(url: requestedURL, resolvingAgainstBaseURL: false) 28 | else { return Result(error: .hostBaseURLInvalid) } 29 | 30 | components.queryItems = convertToQueryItems(source: resource.queryParameters) 31 | 32 | guard let requestURL = components.url 33 | else { return Result(error: .unableToBuildRequest(path: resource.path, queryParameters: resource.queryParameters)) } 34 | 35 | var request = URLRequest(url: requestURL, cachePolicy: cachePolicy, timeoutInterval: requestTimeout) 36 | request.httpMethod = resource.method.value 37 | 38 | return Result(request) 39 | } 40 | 41 | 42 | @discardableResult public func request 43 | ( 44 | resource: R, 45 | from host: HTTPHost? = nil, 46 | cacheWith cachePolicy: URLRequest.CachePolicy = defaultCachePolicy, 47 | timeoutAfter requestTimeout: TimeInterval = defaultTimeout, 48 | completion: @escaping (Result) -> Void 49 | ) 50 | -> HTTPResponse 51 | where R: HTTPResourceProtocol & HostedResource, 52 | R.ErrorType == HTTPResponseError 53 | { 54 | guard let hostToQuery = host ?? defaultHostRegistry.hostFor(resource) else { 55 | let response = HTTPResponse(result: Result(error: .hostNotSpecified)) 56 | completion(response.result) 57 | return response 58 | } 59 | 60 | return hostToQuery.request(resource: resource, cacheWith: cachePolicy, timeoutAfter: requestTimeout, completion: completion) 61 | } 62 | 63 | 64 | /// Utilities 65 | 66 | func convertToQueryItems(source: [String: String]) -> [URLQueryItem] 67 | { 68 | guard !source.isEmpty else { return [] } 69 | 70 | return source.flatMap { URLQueryItem(name: $0, value: $1) } 71 | } 72 | -------------------------------------------------------------------------------- /Library/HTTPResource.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPResource.swift 3 | // GaugesAPI 4 | // 5 | // Created by Saul Mora on 6/19/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | import Argo 10 | import Runes 11 | import Result 12 | import Foundation 13 | 14 | public typealias ResourceParseResult = Result 15 | public typealias ResourceParseFunction = (Data) -> ResourceParseResult 16 | 17 | public protocol HTTPResourceProtocol 18 | { 19 | associatedtype ResourceType 20 | associatedtype ErrorType: HTTPResourceError 21 | associatedtype HTTPMethod: HTTPMethodProtocol 22 | 23 | var path: String { get } 24 | var method: HTTPMethod { get } 25 | var queryParameters: [String: String] { get } 26 | var parse: (Data) -> ResourceParseResult { get } 27 | } 28 | 29 | open class HTTPResource: HTTPResourceProtocol 30 | { 31 | public typealias ErrorType = HTTPResponseError 32 | 33 | public let path: String 34 | public let method: HTTPMethod 35 | public let queryParameters: [String : String] 36 | public let parse: ResourceParseFunction 37 | 38 | public init(path: String, method: HTTPMethod, queryParameters: [String: String] = [:], parse: @escaping ResourceParseFunction) 39 | { 40 | self.path = path 41 | self.method = method 42 | self.queryParameters = queryParameters 43 | self.parse = parse 44 | } 45 | } 46 | 47 | open class QueriableHTTPResource: HTTPResource 48 | { 49 | public override init(path: String, method: QueriableHTTPMethod = .GET, queryParameters: [String: String] = [:], parse: @escaping ResourceParseFunction) 50 | { 51 | super.init(path: path, method: method, queryParameters: queryParameters, parse: parse) 52 | } 53 | } 54 | 55 | open class UpdatableHTTPResource: HTTPResource 56 | { 57 | public override init(path: String, method: UpdatableHTTPMethod = .POST, queryParameters: [String: String] = [:], parse: @escaping ResourceParseFunction) 58 | { 59 | super.init(path: path, method: method, queryParameters: queryParameters, parse: parse) 60 | } 61 | } 62 | 63 | open class DownloadableHTTPResource: QueriableHTTPResource 64 | { 65 | 66 | } 67 | -------------------------------------------------------------------------------- /Library/HTTPResourceRequestable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPResourceRequestable.swift 3 | // CoreHTTP 4 | // 5 | // Created by Saul Mora on 11/23/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | import Result 10 | 11 | public protocol HTTPResourceRequestable 12 | { 13 | func canRequestResource(resource: R) -> Bool 14 | where R: HTTPResourceProtocol & HostedResource 15 | 16 | @discardableResult func request 17 | ( 18 | resource: R, 19 | cacheWith cachePolicy: URLRequest.CachePolicy, 20 | timeoutAfter requestTimeout: TimeInterval, 21 | completion: @escaping (Result) -> Void 22 | ) -> HTTPResponse 23 | where R: HostedResource & HTTPResourceProtocol, 24 | R.ErrorType == HTTPResponseError 25 | } 26 | 27 | 28 | extension HTTPResourceRequestable where Self: HTTPHostProtocol 29 | { 30 | public func canRequestResource(resource: R) -> Bool 31 | where R: HTTPResourceProtocol & HostedResource 32 | { 33 | let resourceIsCompatible: Bool = type(of: resource.hostType) == type(of: self) 34 | return resourceIsCompatible 35 | } 36 | 37 | private func buildDataTask(for resource: R, with completion: @escaping (Result) -> Void) -> (URLRequest) -> URLSessionTask 38 | where R: HTTPResourceProtocol, 39 | R.ErrorType == HTTPResponseError 40 | { 41 | let responseValidation = validate 42 | let session = self.session 43 | return { request in 44 | let completionHandler = completionHandlerForRequest(resource: resource, validate: responseValidation, completion: completion) 45 | return session.dataTask(with: request, completionHandler: completionHandler) 46 | } 47 | } 48 | 49 | private func beginTask(task: URLSessionTask) -> URLSessionTask 50 | { 51 | log(level: .Debug, message: "Sending Request: \(task.currentRequest?.url)") 52 | task.resume() 53 | return task 54 | } 55 | 56 | @discardableResult 57 | public func request 58 | ( 59 | resource: R, 60 | cacheWith cachePolicy: URLRequest.CachePolicy = defaultCachePolicy, 61 | timeoutAfter requestTimeout: TimeInterval = defaultTimeout, 62 | completion: @escaping (Result) -> Void 63 | ) -> HTTPResponse 64 | where R: HTTPResourceProtocol & HostedResource, 65 | R.ErrorType == HTTPResponseError 66 | { 67 | let request = buildRequest(for: resource, host: self, cachePolicy: cachePolicy, requestTimeout: requestTimeout) 68 | 69 | let sessionTask = request 70 | .map (authentication().authenticate) 71 | .map (buildDataTask(for: resource, with: completion)) 72 | .map (beginTask) 73 | 74 | return HTTPResponse(task: sessionTask.value!) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Library/HTTPResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPResponse.swift 3 | // CoreHTTP 4 | // 5 | // Created by Saul Mora on 6/28/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | import Result 10 | 11 | func validateResponse(_ error: Error?) -> (HTTPURLResponse) -> Result 12 | { 13 | return { httpResponse in 14 | 15 | log(level: .Debug, message: "Received Response: \(httpResponse.statusCode) - \(httpResponse.url) - \(httpResponse.allHeaderFields)") 16 | 17 | func transform(error: Error) -> Result 18 | { 19 | return Result(error: error._code == NSURLErrorCancelled ? .cancelled : .responseFailure(httpResponse)) 20 | } 21 | 22 | return error.flatMap(transform) ?? Result(httpResponse) 23 | } 24 | } 25 | 26 | func completionHandlerForRequest 27 | ( 28 | resource: R, 29 | validate: @escaping ResponseValidationFunction, 30 | completion: @escaping (Result) -> Void 31 | ) 32 | -> (Data?, URLResponse?, Error?) -> Void 33 | where R.ErrorType == HTTPResponseError 34 | { 35 | return { (data, response, error) in 36 | 37 | let responseValue = Result(response as? HTTPURLResponse, failWith: .invalidResponseType) 38 | >>- validateResponse(error) 39 | >>- validate(data) 40 | >>- resource.parse 41 | 42 | completion(responseValue) 43 | } 44 | } 45 | 46 | func completionHandlerForRequest 47 | ( 48 | resource: R, 49 | validate: @escaping ResponseValidationFunction, 50 | completion: @escaping (Result) -> Void 51 | ) -> (Data?, URLResponse?, Error?) -> Void 52 | where R.ErrorType == HTTPRequestError 53 | { 54 | return { (data, response, error) in 55 | completion(.failure(.unknown)) 56 | } 57 | } 58 | 59 | public protocol HTTPProgressMonitorable 60 | { 61 | var progress: Progress { get } 62 | } 63 | 64 | public protocol HTTPResponseProtocol 65 | { 66 | associatedtype ResponseType 67 | associatedtype ErrorType = HTTPResponseError 68 | } 69 | 70 | public class HTTPResponse: HTTPResponseProtocol 71 | { 72 | public typealias ResponseType = R.ResourceType 73 | 74 | var result: Result 75 | public let progress: Progress? 76 | let task: URLSessionTask? 77 | 78 | init(task: URLSessionTask? = nil, result: Result = .failure(.unknown)) 79 | { 80 | self.task = task 81 | self.progress = nil 82 | self.result = result 83 | } 84 | 85 | // func download(f: (R.ResourceType) -> T) -> T 86 | // { 87 | // return result.map(f) 88 | ////wait for response to complete 89 | ////kick off download 90 | //// return f(self) 91 | // } 92 | } 93 | 94 | -------------------------------------------------------------------------------- /Library/HTTPResponseError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPAPIError.swift 3 | // CoreHTTP 4 | // 5 | // Created by Saul Mora on 6/19/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | public protocol HTTPResourceError: Error 10 | { 11 | } 12 | 13 | public enum HTTPRequestError: HTTPResourceError 14 | { 15 | case unknown 16 | case hostForRequestNotFound 17 | case hostNotSpecified 18 | case hostBaseURLInvalid 19 | 20 | case unableToBuildRequest(path: String, queryParameters: [String: String]) 21 | } 22 | 23 | public enum HTTPResponseError: HTTPResourceError 24 | { 25 | case unknown 26 | case cancelled 27 | case noResponse 28 | 29 | case invalidResponseType 30 | case hostNotSpecified 31 | case hostBaseURLInvalid 32 | case resourceRequestAgainstIncorrectHost(resourceType: String, hostType: String) 33 | case unableToBuildRequest(path: String, queryParameters: [String: String]) 34 | 35 | case unexpectedHTTPStatus(statusCode: HTTPStatusCode, description: String) 36 | 37 | case decodingFailure(description: String, source: String) 38 | case deserializationFailure(message: String) 39 | 40 | static func responseFailure(_ response: HTTPURLResponse) -> HTTPResponseError 41 | { 42 | let statusCode = response.httpStatusCode 43 | return .unexpectedHTTPStatus(statusCode: statusCode, description: statusCode.localizedDescription) 44 | } 45 | } 46 | 47 | //public enum HTTPResponseParseError: HTTPResourceError 48 | //{ 49 | // case invalidResponseType 50 | // case decodingFailure(description: String, source: String) 51 | // case deserializationFailure(message: String) 52 | //} 53 | // 54 | 55 | -------------------------------------------------------------------------------- /Library/HTTPResult.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPResult.swift 3 | // CoreHTTP 4 | // 5 | // Created by Saul Mora on 11/21/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | import Result 10 | 11 | enum HTTPResult 12 | { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Library/HTTPStatusCodes.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPStatusCodes.swift 3 | // CoreHTTP 4 | // 5 | // Created by Saul Mora on 6/28/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | //https://en.wikipedia.org/wiki/List_of_HTTP_status_codes 10 | 11 | public protocol HTTPStatusCodeProtocol: RawRepresentable, ExpressibleByIntegerLiteral 12 | { 13 | var code: Int { get } 14 | var localizedDescription: String { get } 15 | } 16 | 17 | extension HTTPStatusCodeProtocol where RawValue == Int 18 | { 19 | public var code: Int 20 | { 21 | return rawValue 22 | } 23 | 24 | public var localizedDescription: String 25 | { 26 | return HTTPURLResponse.localizedString(forStatusCode: code) 27 | } 28 | } 29 | 30 | 31 | extension HTTPURLResponse 32 | { 33 | var httpStatusCode: HTTPStatusCode 34 | { 35 | return HTTPStatusCode.statusFor(code: statusCode) 36 | } 37 | 38 | var isSuccess: Bool 39 | { 40 | return httpStatusCode.isSuccess 41 | } 42 | 43 | var isInformational: Bool 44 | { 45 | return httpStatusCode.isInformational 46 | } 47 | 48 | var isRedirection: Bool 49 | { 50 | return httpStatusCode.isRedirection 51 | } 52 | 53 | var isClientError: Bool 54 | { 55 | return httpStatusCode.isClientError 56 | } 57 | 58 | var isServerError: Bool 59 | { 60 | return httpStatusCode.isServerError 61 | } 62 | } 63 | 64 | public enum HTTPStatusCode: Int, HTTPStatusCodeProtocol 65 | { 66 | public init(integerLiteral value: Int) 67 | { 68 | self = HTTPStatusCode.statusFor(code: value) 69 | } 70 | 71 | static func statusFor(code: Int) -> HTTPStatusCode 72 | { 73 | return HTTPStatusCode(rawValue: code) ?? .Unknown 74 | } 75 | 76 | case Unknown = 0 77 | 78 | //informational 79 | case Continue = 100 80 | case SwitchingProtocols = 101 81 | case Processing = 102 82 | 83 | fileprivate static let informationalStatusCodes: [HTTPStatusCode] = [.Continue, .SwitchingProtocols, .Processing] 84 | public var isInformational: Bool 85 | { 86 | return HTTPStatusCode.informationalStatusCodes.contains(self) 87 | } 88 | 89 | //success 90 | case ok = 200 91 | case created = 201 92 | case accepted = 202 93 | case nonAuthoratativeInformation = 203 94 | case noContent = 204 95 | case resetContent = 205 96 | case partialContent = 206 97 | case multiStatus = 207 98 | case alreadyReported = 208 99 | case imUsed = 226 100 | 101 | fileprivate static let successStatusCodes: [HTTPStatusCode] = [.ok, .created, .accepted, .nonAuthoratativeInformation, .noContent, .resetContent, .partialContent, .multiStatus, .alreadyReported, .imUsed] 102 | public var isSuccess: Bool 103 | { 104 | return HTTPStatusCode.successStatusCodes.contains(self) 105 | } 106 | 107 | //redirection 108 | case multipleChoices = 300 109 | case movedPermanently = 301 110 | case found = 302 111 | case seeOther = 303 112 | case notModified = 304 113 | case useProxy = 305 114 | case switchProxy = 306 115 | case temporaryRedirect = 307 116 | case permanentRedirect = 308 117 | 118 | fileprivate static let redirectionStatusCodes: [HTTPStatusCode] = [.multipleChoices, .movedPermanently, .found, .seeOther, .notModified, .useProxy, .switchProxy, .temporaryRedirect, .permanentRedirect] 119 | public var isRedirection: Bool 120 | { 121 | return HTTPStatusCode.redirectionStatusCodes.contains(self) 122 | } 123 | 124 | //client error 125 | case badRequest = 400 126 | case unauthorized = 401 127 | case paymentRequired = 402 128 | case forbidden = 403 129 | case notFound = 404 130 | case methodNotAllowed = 405 131 | case notAcceptable = 406 132 | case proxyAuthenticationRequired = 407 133 | case requestTimeout = 408 134 | case conflict = 409 135 | case gone = 410 136 | case lengthRequired = 411 137 | case preconditionFailed = 412 138 | case payloadTooLarge = 413 139 | case uriTooLong = 414 140 | case unsupportedMediaType = 415 141 | case rangeNotStatisfiable = 416 142 | case expectationFailed = 417 143 | case imATeapot = 418 144 | case misdirectedRequest = 421 145 | case unprocessableEntity = 422 146 | case locked = 423 147 | case failedDependency = 424 148 | case upgradeRequired = 426 149 | case preconditionRequired = 428 150 | case tooManyRequests = 429 151 | case requestHeaderFieldsTooLarge = 431 152 | case unavailableForLegalReasons = 451 153 | 154 | private static let clientErrorStatusCodes: [HTTPStatusCode] = [.badRequest, .unauthorized, .paymentRequired, .forbidden, .notFound, .methodNotAllowed, .notAcceptable, .proxyAuthenticationRequired, .requestTimeout, .conflict, .gone, .lengthRequired, .preconditionFailed, .payloadTooLarge, .uriTooLong, .unsupportedMediaType, .rangeNotStatisfiable, .imATeapot, .misdirectedRequest, .unprocessableEntity, .locked, .failedDependency, .upgradeRequired, .preconditionRequired, .tooManyRequests, .requestHeaderFieldsTooLarge, .unavailableForLegalReasons] 155 | public var isClientError: Bool 156 | { 157 | return HTTPStatusCode.clientErrorStatusCodes.contains(self) 158 | } 159 | 160 | //server error 161 | case internalServerError = 500 162 | case notImplemented = 501 163 | case badGateway = 502 164 | case serviceUnavailable = 503 165 | case gatewayTimeout = 504 166 | case HTTPVersionNotSupported = 505 167 | case variantAlsoNegatiates = 506 168 | case insufficientStorage = 507 169 | case loopDetected = 508 170 | case notExtended = 510 171 | case networkAuthenticationRequired = 511 172 | 173 | fileprivate static let serverErrorStatusCodes: [HTTPStatusCode] = [.internalServerError, .notImplemented, .badGateway, .serviceUnavailable, .gatewayTimeout, .HTTPVersionNotSupported, .variantAlsoNegatiates, .insufficientStorage, .loopDetected, .notExtended, .networkAuthenticationRequired] 174 | public var isServerError: Bool 175 | { 176 | return HTTPStatusCode.serverErrorStatusCodes.contains(self) 177 | } 178 | } 179 | 180 | enum UnofficialStatusCode: Int, HTTPStatusCodeProtocol 181 | { 182 | init(integerLiteral value: Int) 183 | { 184 | self = UnofficialStatusCode(rawValue: value) ?? .unknown 185 | } 186 | 187 | case unknown = 0 188 | case checkpoint = 103 189 | case enhaceYourCalm = 420 190 | case blockedByWindowsParentalControls = 450 191 | case invalidToken_Ersi = 498 192 | case tokenRequired_Ersi = 499 193 | // case RequestHasBeenForbiddenByAntivirus = 499 194 | case bandwidthLimitExceeded = 509 195 | case siteIsFrozen = 530 196 | 197 | fileprivate static let allStatusCodes: [UnofficialStatusCode] = [.checkpoint, .enhaceYourCalm, .blockedByWindowsParentalControls, .invalidToken_Ersi, .tokenRequired_Ersi, .bandwidthLimitExceeded, .siteIsFrozen] 198 | } 199 | 200 | extension HTTPStatusCode 201 | { 202 | public static func isUnofficial(statusCode: Int) -> Bool 203 | { 204 | return UnofficialStatusCode.allStatusCodes.map { $0.code }.contains(statusCode) 205 | } 206 | } 207 | 208 | enum InternetInformationServicesStatusCode: Int, HTTPStatusCodeProtocol 209 | { 210 | init(integerLiteral value: Int) 211 | { 212 | self = InternetInformationServicesStatusCode(rawValue: value) ?? .unknown 213 | } 214 | 215 | case unknown = 0 216 | case loginTimeout = 440 217 | case retryWith = 449 218 | case redirect = 451 219 | 220 | fileprivate static let allStatusCodes: [InternetInformationServicesStatusCode] = [.loginTimeout, .retryWith, .redirect] 221 | } 222 | 223 | extension HTTPStatusCode 224 | { 225 | public static func isInternetInformationServices(statusCode: Int) -> Bool 226 | { 227 | return InternetInformationServicesStatusCode.allStatusCodes.map { $0.code }.contains(statusCode) 228 | } 229 | } 230 | 231 | enum NGinxStatusCode: Int, HTTPStatusCodeProtocol 232 | { 233 | init(integerLiteral value: Int) 234 | { 235 | self = NGinxStatusCode(rawValue: value) ?? .unknown 236 | } 237 | 238 | case unknown = 0 239 | case noResponse = 444 240 | case SSLCertificateError = 495 241 | case SSLCertificateRequired = 496 242 | case HTTPRequestSentToHTTPSPort = 497 243 | case clientClosedRequest = 499 244 | 245 | fileprivate static let allStatusCodes: [NGinxStatusCode] = [.noResponse, .SSLCertificateError, .SSLCertificateRequired, .HTTPRequestSentToHTTPSPort, .clientClosedRequest] 246 | } 247 | 248 | extension HTTPStatusCode 249 | { 250 | public static func isNGinx(statusCode: Int) -> Bool 251 | { 252 | return NGinxStatusCode.allStatusCodes.map { $0.code }.contains(statusCode) 253 | } 254 | } 255 | 256 | enum CloudFlareStatusCode: Int, HTTPStatusCodeProtocol 257 | { 258 | init(integerLiteral value: Int) 259 | { 260 | self = CloudFlareStatusCode(rawValue: value) ?? .unknown 261 | } 262 | 263 | case unknown = 0 264 | case unknownError = 520 265 | case webServerIsDown = 521 266 | case connectionTimedOut = 522 267 | case originIsUnreachable = 523 268 | case aTimeoutOccured = 524 269 | case SSLHandshakeFailed = 525 270 | case invalidSSLCertificate = 526 271 | 272 | fileprivate static let allStatusCodes: [CloudFlareStatusCode] = [.unknownError, .webServerIsDown, .connectionTimedOut, .originIsUnreachable, .aTimeoutOccured, .SSLHandshakeFailed, .invalidSSLCertificate] 273 | } 274 | 275 | extension HTTPStatusCode 276 | { 277 | public static func isCloudFlare(statusCode: Int) -> Bool 278 | { 279 | return CloudFlareStatusCode.allStatusCodes.map { $0.code }.contains(statusCode) 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /Library/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Library/Int+Additions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Int+Additions.swift 3 | // CoreHTTP 4 | // 5 | // Created by Saul Mora on 9/13/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension Int 12 | { 13 | var seconds: TimeInterval 14 | { 15 | return TimeInterval(self) 16 | } 17 | 18 | var minutes: TimeInterval 19 | { 20 | return TimeInterval(self * 60) 21 | } 22 | 23 | var hours: TimeInterval 24 | { 25 | return minutes * 60 26 | } 27 | 28 | var days: TimeInterval 29 | { 30 | return hours * 24 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Library/JSONSerialization.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JSONSerialization.swift 3 | // CoreHTTP 4 | // 5 | // Created by Saul Mora on 10/28/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | import Result 10 | 11 | func deserializeJSON(data: Data) -> Result 12 | { 13 | do { 14 | let result = try JSONSerialization.jsonObject(with: data, options: .init(rawValue: 0)) 15 | return Result(result) 16 | } 17 | catch 18 | { 19 | log(level: .Error, message: "Unable to deserialize JSON: \(error)") 20 | return Result(error: .deserializationFailure(message: error.localizedDescription)) 21 | } 22 | } 23 | 24 | func serializeJSON(object: Any) -> Result 25 | { 26 | do { 27 | let result = try JSONSerialization.data(withJSONObject: object, options: .init(rawValue: 0)) 28 | return Result(result) 29 | } 30 | catch 31 | { 32 | log(level: .Error, message: "Unable to serialize JSON: \(error)") 33 | return Result(error: .deserializationFailure(message: error.localizedDescription)) 34 | } 35 | } 36 | 37 | fileprivate let unableToReadSourceMessage = "<>" 38 | 39 | func sourceStringFrom(data: Data) -> String 40 | { 41 | let source = String(data: data, encoding: String.Encoding.utf8) ?? unableToReadSourceMessage 42 | return source 43 | } 44 | 45 | func sourceStringFrom(object: Any) -> String 46 | { 47 | if let source = object as? CustomStringConvertible 48 | { 49 | return source.description 50 | } 51 | return unableToReadSourceMessage 52 | } 53 | -------------------------------------------------------------------------------- /Library/Logging.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Logging.swift 3 | // CoreHTTP 4 | // 5 | // Created by Saul Mora on 9/13/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum LogLevel: Int 12 | { 13 | case Debug 14 | case Info 15 | case Warn 16 | case Error 17 | case Fatal 18 | 19 | public static func <(left: LogLevel, right: LogLevel) -> Bool 20 | { 21 | return left.rawValue < right.rawValue 22 | } 23 | 24 | public static func <=(left: LogLevel, right: LogLevel) -> Bool 25 | { 26 | return left.rawValue <= right.rawValue 27 | } 28 | 29 | public static func >(left: LogLevel, right: LogLevel) -> Bool 30 | { 31 | return left.rawValue > right.rawValue 32 | } 33 | } 34 | 35 | public protocol Logger 36 | { 37 | func log(level: LogLevel, message: String) 38 | } 39 | 40 | extension Logger 41 | { 42 | func log(level: LogLevel = .Debug, message: String) 43 | { 44 | guard level < currentLogLevel else { return } 45 | print(message) 46 | } 47 | } 48 | 49 | public var currentLogLevel: LogLevel = .Debug 50 | public var currentLogger: Logger? = ConsoleLogger() 51 | 52 | func log(level: LogLevel = .Debug, message: String) 53 | { 54 | currentLogger?.log(level: level, message: message) 55 | } 56 | 57 | 58 | struct ConsoleLogger: Logger 59 | { 60 | } 61 | -------------------------------------------------------------------------------- /Library/Support.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Support.swift 3 | // CoreHTTP 4 | // 5 | // Created by Saul Mora on 7/1/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | let bundleIndentifier = "com.magicalpanda.CoreHTTP" 10 | let frameworkBundle = Bundle(identifier: bundleIndentifier)! 11 | -------------------------------------------------------------------------------- /Library/Support/iOS/CoreHTTP-iOS.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoreHTTP.h 3 | // CoreHTTP 4 | // 5 | // Created by Saul Mora on 6/28/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for CoreHTTP. 12 | FOUNDATION_EXPORT double CoreHTTPVersionNumber; 13 | 14 | //! Project version string for CoreHTTP. 15 | FOUNDATION_EXPORT const unsigned char CoreHTTPVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Library/Support/iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Library/Support/macOS/CoreHTTP-Mac.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoreHTTP-Mac.h 3 | // CoreHTTP-Mac 4 | // 5 | // Created by Saul Mora on 8/18/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for CoreHTTP-Mac. 12 | FOUNDATION_EXPORT double CoreHTTP_MacVersionNumber; 13 | 14 | //! Project version string for CoreHTTP-Mac. 15 | FOUNDATION_EXPORT const unsigned char CoreHTTP_MacVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Library/Support/macOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSHumanReadableCopyright 22 | Copyright © 2016 Magical Panda Software. All rights reserved. 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CoreHTTP 2 | Swift based Light HTTP library 3 | -------------------------------------------------------------------------------- /Sample/NASA Photo of the Day/NASA Photo of the Day.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C799FAB21DC20BA200FAC0B7 /* NASAPhotoOfTheDay.swift in Sources */ = {isa = PBXBuildFile; fileRef = C799FAB11DC20BA200FAC0B7 /* NASAPhotoOfTheDay.swift */; }; 11 | C799FAB51DC20BB900FAC0B7 /* NASAPhoto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C799FAB41DC20BB900FAC0B7 /* NASAPhoto.swift */; }; 12 | C7A82DDF1DC1EBBE007B1270 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7A82DDE1DC1EBBE007B1270 /* AppDelegate.swift */; }; 13 | C7A82DE11DC1EBBE007B1270 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7A82DE01DC1EBBE007B1270 /* ViewController.swift */; }; 14 | C7A82DE41DC1EBBE007B1270 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C7A82DE21DC1EBBE007B1270 /* Main.storyboard */; }; 15 | C7A82DE61DC1EBBE007B1270 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C7A82DE51DC1EBBE007B1270 /* Assets.xcassets */; }; 16 | C7A82DE91DC1EBBE007B1270 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C7A82DE71DC1EBBE007B1270 /* LaunchScreen.storyboard */; }; 17 | C7A82DFB1DC1EC2F007B1270 /* CoreHTTP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C7A82DF61DC1EC19007B1270 /* CoreHTTP.framework */; }; 18 | C7A82DFD1DC1EC46007B1270 /* CoreHTTP.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = C7A82DF61DC1EC19007B1270 /* CoreHTTP.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 19 | C7A82E021DC1ED21007B1270 /* Result.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = C7A82DFE1DC1ED21007B1270 /* Result.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 20 | C7A82E031DC1ED21007B1270 /* Argo.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = C7A82DFF1DC1ED21007B1270 /* Argo.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 21 | C7A82E041DC1ED21007B1270 /* Curry.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = C7A82E001DC1ED21007B1270 /* Curry.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 22 | C7A82E051DC1ED21007B1270 /* Runes.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = C7A82E011DC1ED21007B1270 /* Runes.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 23 | C7A82E071DC1F039007B1270 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C7A82DFE1DC1ED21007B1270 /* Result.framework */; }; 24 | C7A82E081DC1F039007B1270 /* Argo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C7A82DFF1DC1ED21007B1270 /* Argo.framework */; }; 25 | C7A82E091DC1F039007B1270 /* Curry.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C7A82E001DC1ED21007B1270 /* Curry.framework */; }; 26 | C7A82E0A1DC1F039007B1270 /* Runes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C7A82E011DC1ED21007B1270 /* Runes.framework */; }; 27 | C7E14CCC1DE5459D0088AB27 /* then.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C7E14CCB1DE5459D0088AB27 /* then.framework */; }; 28 | C7E14CCD1DE545A10088AB27 /* then.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C7E14CCB1DE5459D0088AB27 /* then.framework */; }; 29 | C7E14CCE1DE545A10088AB27 /* then.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = C7E14CCB1DE5459D0088AB27 /* then.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 30 | /* End PBXBuildFile section */ 31 | 32 | /* Begin PBXContainerItemProxy section */ 33 | C7A82DF51DC1EC19007B1270 /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = C7A82DF01DC1EC19007B1270 /* CoreHTTP.xcodeproj */; 36 | proxyType = 2; 37 | remoteGlobalIDString = C7C669171D223181007ECF77; 38 | remoteInfo = "CoreHTTP-iOS"; 39 | }; 40 | C7A82DF71DC1EC19007B1270 /* PBXContainerItemProxy */ = { 41 | isa = PBXContainerItemProxy; 42 | containerPortal = C7A82DF01DC1EC19007B1270 /* CoreHTTP.xcodeproj */; 43 | proxyType = 2; 44 | remoteGlobalIDString = C7A82DC01DC1EA09007B1270; 45 | remoteInfo = CoreHTTPTests; 46 | }; 47 | C7A82DF91DC1EC28007B1270 /* PBXContainerItemProxy */ = { 48 | isa = PBXContainerItemProxy; 49 | containerPortal = C7A82DF01DC1EC19007B1270 /* CoreHTTP.xcodeproj */; 50 | proxyType = 1; 51 | remoteGlobalIDString = C7C669161D223181007ECF77; 52 | remoteInfo = "CoreHTTP-iOS"; 53 | }; 54 | /* End PBXContainerItemProxy section */ 55 | 56 | /* Begin PBXCopyFilesBuildPhase section */ 57 | C7A82DFC1DC1EC37007B1270 /* CopyFiles */ = { 58 | isa = PBXCopyFilesBuildPhase; 59 | buildActionMask = 2147483647; 60 | dstPath = ""; 61 | dstSubfolderSpec = 10; 62 | files = ( 63 | C7A82DFD1DC1EC46007B1270 /* CoreHTTP.framework in CopyFiles */, 64 | C7A82E021DC1ED21007B1270 /* Result.framework in CopyFiles */, 65 | C7A82E031DC1ED21007B1270 /* Argo.framework in CopyFiles */, 66 | C7A82E041DC1ED21007B1270 /* Curry.framework in CopyFiles */, 67 | C7A82E051DC1ED21007B1270 /* Runes.framework in CopyFiles */, 68 | C7E14CCE1DE545A10088AB27 /* then.framework in CopyFiles */, 69 | ); 70 | runOnlyForDeploymentPostprocessing = 0; 71 | }; 72 | /* End PBXCopyFilesBuildPhase section */ 73 | 74 | /* Begin PBXFileReference section */ 75 | C799FAB11DC20BA200FAC0B7 /* NASAPhotoOfTheDay.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NASAPhotoOfTheDay.swift; sourceTree = ""; }; 76 | C799FAB41DC20BB900FAC0B7 /* NASAPhoto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NASAPhoto.swift; sourceTree = ""; }; 77 | C7A82DDB1DC1EBBE007B1270 /* NASA Photo of the Day.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "NASA Photo of the Day.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 78 | C7A82DDE1DC1EBBE007B1270 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 79 | C7A82DE01DC1EBBE007B1270 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 80 | C7A82DE31DC1EBBE007B1270 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 81 | C7A82DE51DC1EBBE007B1270 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 82 | C7A82DE81DC1EBBE007B1270 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 83 | C7A82DEA1DC1EBBE007B1270 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 84 | C7A82DF01DC1EC19007B1270 /* CoreHTTP.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CoreHTTP.xcodeproj; path = ../../CoreHTTP.xcodeproj; sourceTree = ""; }; 85 | C7A82DFE1DC1ED21007B1270 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = ../../Carthage/Build/iOS/Result.framework; sourceTree = ""; }; 86 | C7A82DFF1DC1ED21007B1270 /* Argo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Argo.framework; path = ../../Carthage/Build/iOS/Argo.framework; sourceTree = ""; }; 87 | C7A82E001DC1ED21007B1270 /* Curry.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Curry.framework; path = ../../Carthage/Build/iOS/Curry.framework; sourceTree = ""; }; 88 | C7A82E011DC1ED21007B1270 /* Runes.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Runes.framework; path = ../../Carthage/Build/iOS/Runes.framework; sourceTree = ""; }; 89 | C7E14CCB1DE5459D0088AB27 /* then.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = then.framework; path = ../../Carthage/Build/iOS/then.framework; sourceTree = ""; }; 90 | /* End PBXFileReference section */ 91 | 92 | /* Begin PBXFrameworksBuildPhase section */ 93 | C7A82DD81DC1EBBE007B1270 /* Frameworks */ = { 94 | isa = PBXFrameworksBuildPhase; 95 | buildActionMask = 2147483647; 96 | files = ( 97 | C7A82DFB1DC1EC2F007B1270 /* CoreHTTP.framework in Frameworks */, 98 | C7A82E071DC1F039007B1270 /* Result.framework in Frameworks */, 99 | C7E14CCD1DE545A10088AB27 /* then.framework in Frameworks */, 100 | C7A82E081DC1F039007B1270 /* Argo.framework in Frameworks */, 101 | C7A82E091DC1F039007B1270 /* Curry.framework in Frameworks */, 102 | C7A82E0A1DC1F039007B1270 /* Runes.framework in Frameworks */, 103 | C7E14CCC1DE5459D0088AB27 /* then.framework in Frameworks */, 104 | ); 105 | runOnlyForDeploymentPostprocessing = 0; 106 | }; 107 | /* End PBXFrameworksBuildPhase section */ 108 | 109 | /* Begin PBXGroup section */ 110 | C7A82DD21DC1EBBE007B1270 = { 111 | isa = PBXGroup; 112 | children = ( 113 | C7A82DF01DC1EC19007B1270 /* CoreHTTP.xcodeproj */, 114 | C7A82DDD1DC1EBBE007B1270 /* NASA Photo of the Day */, 115 | C7A82E061DC1ED27007B1270 /* Frameworks */, 116 | C7A82DDC1DC1EBBE007B1270 /* Products */, 117 | ); 118 | sourceTree = ""; 119 | }; 120 | C7A82DDC1DC1EBBE007B1270 /* Products */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | C7A82DDB1DC1EBBE007B1270 /* NASA Photo of the Day.app */, 124 | ); 125 | name = Products; 126 | sourceTree = ""; 127 | }; 128 | C7A82DDD1DC1EBBE007B1270 /* NASA Photo of the Day */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | C7A82DDE1DC1EBBE007B1270 /* AppDelegate.swift */, 132 | C7A82DE01DC1EBBE007B1270 /* ViewController.swift */, 133 | C799FAB11DC20BA200FAC0B7 /* NASAPhotoOfTheDay.swift */, 134 | C799FAB41DC20BB900FAC0B7 /* NASAPhoto.swift */, 135 | C7A82DE21DC1EBBE007B1270 /* Main.storyboard */, 136 | C7A82DE51DC1EBBE007B1270 /* Assets.xcassets */, 137 | C7A82DE71DC1EBBE007B1270 /* LaunchScreen.storyboard */, 138 | C7A82DEA1DC1EBBE007B1270 /* Info.plist */, 139 | ); 140 | path = "NASA Photo of the Day"; 141 | sourceTree = ""; 142 | }; 143 | C7A82DF11DC1EC19007B1270 /* Products */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | C7A82DF61DC1EC19007B1270 /* CoreHTTP.framework */, 147 | C7A82DF81DC1EC19007B1270 /* CoreHTTPTests.xctest */, 148 | ); 149 | name = Products; 150 | sourceTree = ""; 151 | }; 152 | C7A82E061DC1ED27007B1270 /* Frameworks */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | C7E14CCB1DE5459D0088AB27 /* then.framework */, 156 | C7A82DFE1DC1ED21007B1270 /* Result.framework */, 157 | C7A82DFF1DC1ED21007B1270 /* Argo.framework */, 158 | C7A82E001DC1ED21007B1270 /* Curry.framework */, 159 | C7A82E011DC1ED21007B1270 /* Runes.framework */, 160 | ); 161 | name = Frameworks; 162 | sourceTree = ""; 163 | }; 164 | /* End PBXGroup section */ 165 | 166 | /* Begin PBXNativeTarget section */ 167 | C7A82DDA1DC1EBBE007B1270 /* NASA Photo of the Day */ = { 168 | isa = PBXNativeTarget; 169 | buildConfigurationList = C7A82DED1DC1EBBE007B1270 /* Build configuration list for PBXNativeTarget "NASA Photo of the Day" */; 170 | buildPhases = ( 171 | C7A82DD71DC1EBBE007B1270 /* Sources */, 172 | C7A82DD81DC1EBBE007B1270 /* Frameworks */, 173 | C7A82DD91DC1EBBE007B1270 /* Resources */, 174 | C7A82DFC1DC1EC37007B1270 /* CopyFiles */, 175 | ); 176 | buildRules = ( 177 | ); 178 | dependencies = ( 179 | C7A82DFA1DC1EC28007B1270 /* PBXTargetDependency */, 180 | ); 181 | name = "NASA Photo of the Day"; 182 | productName = "NASA Photo of the Day"; 183 | productReference = C7A82DDB1DC1EBBE007B1270 /* NASA Photo of the Day.app */; 184 | productType = "com.apple.product-type.application"; 185 | }; 186 | /* End PBXNativeTarget section */ 187 | 188 | /* Begin PBXProject section */ 189 | C7A82DD31DC1EBBE007B1270 /* Project object */ = { 190 | isa = PBXProject; 191 | attributes = { 192 | LastSwiftUpdateCheck = 0810; 193 | LastUpgradeCheck = 0820; 194 | ORGANIZATIONNAME = "Magical Panda, LLC"; 195 | TargetAttributes = { 196 | C7A82DDA1DC1EBBE007B1270 = { 197 | CreatedOnToolsVersion = 8.1; 198 | ProvisioningStyle = Automatic; 199 | }; 200 | }; 201 | }; 202 | buildConfigurationList = C7A82DD61DC1EBBE007B1270 /* Build configuration list for PBXProject "NASA Photo of the Day" */; 203 | compatibilityVersion = "Xcode 3.2"; 204 | developmentRegion = English; 205 | hasScannedForEncodings = 0; 206 | knownRegions = ( 207 | en, 208 | Base, 209 | ); 210 | mainGroup = C7A82DD21DC1EBBE007B1270; 211 | productRefGroup = C7A82DDC1DC1EBBE007B1270 /* Products */; 212 | projectDirPath = ""; 213 | projectReferences = ( 214 | { 215 | ProductGroup = C7A82DF11DC1EC19007B1270 /* Products */; 216 | ProjectRef = C7A82DF01DC1EC19007B1270 /* CoreHTTP.xcodeproj */; 217 | }, 218 | ); 219 | projectRoot = ""; 220 | targets = ( 221 | C7A82DDA1DC1EBBE007B1270 /* NASA Photo of the Day */, 222 | ); 223 | }; 224 | /* End PBXProject section */ 225 | 226 | /* Begin PBXReferenceProxy section */ 227 | C7A82DF61DC1EC19007B1270 /* CoreHTTP.framework */ = { 228 | isa = PBXReferenceProxy; 229 | fileType = wrapper.framework; 230 | path = CoreHTTP.framework; 231 | remoteRef = C7A82DF51DC1EC19007B1270 /* PBXContainerItemProxy */; 232 | sourceTree = BUILT_PRODUCTS_DIR; 233 | }; 234 | C7A82DF81DC1EC19007B1270 /* CoreHTTPTests.xctest */ = { 235 | isa = PBXReferenceProxy; 236 | fileType = wrapper.cfbundle; 237 | path = CoreHTTPTests.xctest; 238 | remoteRef = C7A82DF71DC1EC19007B1270 /* PBXContainerItemProxy */; 239 | sourceTree = BUILT_PRODUCTS_DIR; 240 | }; 241 | /* End PBXReferenceProxy section */ 242 | 243 | /* Begin PBXResourcesBuildPhase section */ 244 | C7A82DD91DC1EBBE007B1270 /* Resources */ = { 245 | isa = PBXResourcesBuildPhase; 246 | buildActionMask = 2147483647; 247 | files = ( 248 | C7A82DE91DC1EBBE007B1270 /* LaunchScreen.storyboard in Resources */, 249 | C7A82DE61DC1EBBE007B1270 /* Assets.xcassets in Resources */, 250 | C7A82DE41DC1EBBE007B1270 /* Main.storyboard in Resources */, 251 | ); 252 | runOnlyForDeploymentPostprocessing = 0; 253 | }; 254 | /* End PBXResourcesBuildPhase section */ 255 | 256 | /* Begin PBXSourcesBuildPhase section */ 257 | C7A82DD71DC1EBBE007B1270 /* Sources */ = { 258 | isa = PBXSourcesBuildPhase; 259 | buildActionMask = 2147483647; 260 | files = ( 261 | C7A82DE11DC1EBBE007B1270 /* ViewController.swift in Sources */, 262 | C7A82DDF1DC1EBBE007B1270 /* AppDelegate.swift in Sources */, 263 | C799FAB21DC20BA200FAC0B7 /* NASAPhotoOfTheDay.swift in Sources */, 264 | C799FAB51DC20BB900FAC0B7 /* NASAPhoto.swift in Sources */, 265 | ); 266 | runOnlyForDeploymentPostprocessing = 0; 267 | }; 268 | /* End PBXSourcesBuildPhase section */ 269 | 270 | /* Begin PBXTargetDependency section */ 271 | C7A82DFA1DC1EC28007B1270 /* PBXTargetDependency */ = { 272 | isa = PBXTargetDependency; 273 | name = "CoreHTTP-iOS"; 274 | targetProxy = C7A82DF91DC1EC28007B1270 /* PBXContainerItemProxy */; 275 | }; 276 | /* End PBXTargetDependency section */ 277 | 278 | /* Begin PBXVariantGroup section */ 279 | C7A82DE21DC1EBBE007B1270 /* Main.storyboard */ = { 280 | isa = PBXVariantGroup; 281 | children = ( 282 | C7A82DE31DC1EBBE007B1270 /* Base */, 283 | ); 284 | name = Main.storyboard; 285 | sourceTree = ""; 286 | }; 287 | C7A82DE71DC1EBBE007B1270 /* LaunchScreen.storyboard */ = { 288 | isa = PBXVariantGroup; 289 | children = ( 290 | C7A82DE81DC1EBBE007B1270 /* Base */, 291 | ); 292 | name = LaunchScreen.storyboard; 293 | sourceTree = ""; 294 | }; 295 | /* End PBXVariantGroup section */ 296 | 297 | /* Begin XCBuildConfiguration section */ 298 | C7A82DEB1DC1EBBE007B1270 /* Debug */ = { 299 | isa = XCBuildConfiguration; 300 | buildSettings = { 301 | ALWAYS_SEARCH_USER_PATHS = NO; 302 | CLANG_ANALYZER_NONNULL = YES; 303 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 304 | CLANG_CXX_LIBRARY = "libc++"; 305 | CLANG_ENABLE_MODULES = YES; 306 | CLANG_ENABLE_OBJC_ARC = YES; 307 | CLANG_WARN_BOOL_CONVERSION = YES; 308 | CLANG_WARN_CONSTANT_CONVERSION = YES; 309 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 310 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 311 | CLANG_WARN_EMPTY_BODY = YES; 312 | CLANG_WARN_ENUM_CONVERSION = YES; 313 | CLANG_WARN_INFINITE_RECURSION = YES; 314 | CLANG_WARN_INT_CONVERSION = YES; 315 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 316 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 317 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 318 | CLANG_WARN_UNREACHABLE_CODE = YES; 319 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 320 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 321 | COPY_PHASE_STRIP = NO; 322 | DEBUG_INFORMATION_FORMAT = dwarf; 323 | ENABLE_STRICT_OBJC_MSGSEND = YES; 324 | ENABLE_TESTABILITY = YES; 325 | GCC_C_LANGUAGE_STANDARD = gnu99; 326 | GCC_DYNAMIC_NO_PIC = NO; 327 | GCC_NO_COMMON_BLOCKS = YES; 328 | GCC_OPTIMIZATION_LEVEL = 0; 329 | GCC_PREPROCESSOR_DEFINITIONS = ( 330 | "DEBUG=1", 331 | "$(inherited)", 332 | ); 333 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 334 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 335 | GCC_WARN_UNDECLARED_SELECTOR = YES; 336 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 337 | GCC_WARN_UNUSED_FUNCTION = YES; 338 | GCC_WARN_UNUSED_VARIABLE = YES; 339 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 340 | MTL_ENABLE_DEBUG_INFO = YES; 341 | ONLY_ACTIVE_ARCH = YES; 342 | SDKROOT = iphoneos; 343 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 344 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 345 | TARGETED_DEVICE_FAMILY = "1,2"; 346 | }; 347 | name = Debug; 348 | }; 349 | C7A82DEC1DC1EBBE007B1270 /* Release */ = { 350 | isa = XCBuildConfiguration; 351 | buildSettings = { 352 | ALWAYS_SEARCH_USER_PATHS = NO; 353 | CLANG_ANALYZER_NONNULL = YES; 354 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 355 | CLANG_CXX_LIBRARY = "libc++"; 356 | CLANG_ENABLE_MODULES = YES; 357 | CLANG_ENABLE_OBJC_ARC = YES; 358 | CLANG_WARN_BOOL_CONVERSION = YES; 359 | CLANG_WARN_CONSTANT_CONVERSION = YES; 360 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 361 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 362 | CLANG_WARN_EMPTY_BODY = YES; 363 | CLANG_WARN_ENUM_CONVERSION = YES; 364 | CLANG_WARN_INFINITE_RECURSION = YES; 365 | CLANG_WARN_INT_CONVERSION = YES; 366 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 367 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 368 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 369 | CLANG_WARN_UNREACHABLE_CODE = YES; 370 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 371 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 372 | COPY_PHASE_STRIP = NO; 373 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 374 | ENABLE_NS_ASSERTIONS = NO; 375 | ENABLE_STRICT_OBJC_MSGSEND = YES; 376 | GCC_C_LANGUAGE_STANDARD = gnu99; 377 | GCC_NO_COMMON_BLOCKS = YES; 378 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 379 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 380 | GCC_WARN_UNDECLARED_SELECTOR = YES; 381 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 382 | GCC_WARN_UNUSED_FUNCTION = YES; 383 | GCC_WARN_UNUSED_VARIABLE = YES; 384 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 385 | MTL_ENABLE_DEBUG_INFO = NO; 386 | SDKROOT = iphoneos; 387 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 388 | TARGETED_DEVICE_FAMILY = "1,2"; 389 | VALIDATE_PRODUCT = YES; 390 | }; 391 | name = Release; 392 | }; 393 | C7A82DEE1DC1EBBE007B1270 /* Debug */ = { 394 | isa = XCBuildConfiguration; 395 | buildSettings = { 396 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 397 | FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/../../Carthage/Build/iOS"; 398 | INFOPLIST_FILE = "NASA Photo of the Day/Info.plist"; 399 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 400 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 401 | PRODUCT_BUNDLE_IDENTIFIER = "com.magicalpanda.NASA-Photo-of-the-Day"; 402 | PRODUCT_NAME = "$(TARGET_NAME)"; 403 | SWIFT_VERSION = 3.0; 404 | }; 405 | name = Debug; 406 | }; 407 | C7A82DEF1DC1EBBE007B1270 /* Release */ = { 408 | isa = XCBuildConfiguration; 409 | buildSettings = { 410 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 411 | FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/../../Carthage/Build/iOS"; 412 | INFOPLIST_FILE = "NASA Photo of the Day/Info.plist"; 413 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 414 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 415 | PRODUCT_BUNDLE_IDENTIFIER = "com.magicalpanda.NASA-Photo-of-the-Day"; 416 | PRODUCT_NAME = "$(TARGET_NAME)"; 417 | SWIFT_VERSION = 3.0; 418 | }; 419 | name = Release; 420 | }; 421 | /* End XCBuildConfiguration section */ 422 | 423 | /* Begin XCConfigurationList section */ 424 | C7A82DD61DC1EBBE007B1270 /* Build configuration list for PBXProject "NASA Photo of the Day" */ = { 425 | isa = XCConfigurationList; 426 | buildConfigurations = ( 427 | C7A82DEB1DC1EBBE007B1270 /* Debug */, 428 | C7A82DEC1DC1EBBE007B1270 /* Release */, 429 | ); 430 | defaultConfigurationIsVisible = 0; 431 | defaultConfigurationName = Release; 432 | }; 433 | C7A82DED1DC1EBBE007B1270 /* Build configuration list for PBXNativeTarget "NASA Photo of the Day" */ = { 434 | isa = XCConfigurationList; 435 | buildConfigurations = ( 436 | C7A82DEE1DC1EBBE007B1270 /* Debug */, 437 | C7A82DEF1DC1EBBE007B1270 /* Release */, 438 | ); 439 | defaultConfigurationIsVisible = 0; 440 | defaultConfigurationName = Release; 441 | }; 442 | /* End XCConfigurationList section */ 443 | }; 444 | rootObject = C7A82DD31DC1EBBE007B1270 /* Project object */; 445 | } 446 | -------------------------------------------------------------------------------- /Sample/NASA Photo of the Day/NASA Photo of the Day.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sample/NASA Photo of the Day/NASA Photo of the Day/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // NASA Photo of the Day 4 | // 5 | // Created by Saul Mora on 10/27/16. 6 | // Copyright © 2016 Magical Panda, LLC. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import CoreHTTP 11 | 12 | @UIApplicationMain 13 | class AppDelegate: UIResponder, UIApplicationDelegate { 14 | 15 | var window: UIWindow? 16 | 17 | 18 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool 19 | { 20 | return true 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /Sample/NASA Photo of the Day/NASA Photo of the Day/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /Sample/NASA Photo of the Day/NASA Photo of the Day/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Sample/NASA Photo of the Day/NASA Photo of the Day/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 35 | 38 | 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 | -------------------------------------------------------------------------------- /Sample/NASA Photo of the Day/NASA Photo of the Day/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSAppTransportSecurity 24 | 25 | NSAllowsArbitraryLoads 26 | 27 | 28 | UILaunchStoryboardName 29 | LaunchScreen 30 | UIMainStoryboardFile 31 | Main 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UISupportedInterfaceOrientations~ipad 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationPortraitUpsideDown 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Sample/NASA Photo of the Day/NASA Photo of the Day/NASAPhoto.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NASAPhoto.swift 3 | // NASA Photo of the Day 4 | // 5 | // Created by Saul Mora on 10/27/16. 6 | // Copyright © 2016 Magical Panda, LLC. All rights reserved. 7 | // 8 | 9 | import Argo 10 | import Curry 11 | import Runes 12 | import CoreHTTP 13 | 14 | struct Photo 15 | { 16 | let title: String 17 | let explanation: String 18 | 19 | let copyright: String 20 | 21 | let hdURLString: String 22 | let URLString: String 23 | 24 | var url: URL? 25 | { 26 | return URL(string: URLString) 27 | } 28 | 29 | var hdURL: URL? 30 | { 31 | return URL(string: hdURLString) 32 | } 33 | 34 | let serviceVersion: String 35 | 36 | let mediaType: MediaType 37 | let date: Date 38 | 39 | enum MediaType: String 40 | { 41 | case unknown 42 | case image 43 | } 44 | } 45 | 46 | extension Photo: Decodable 47 | { 48 | static func decode(_ json: JSON) -> Decoded 49 | { 50 | let f = curry(Photo.init) 51 | <^> json <| "title" 52 | <*> json <| "explanation" 53 | <*> json <| "copyright" 54 | <*> json <| "hdurl" 55 | <*> json <| "url" 56 | return f 57 | <*> json <| "service_version" 58 | <*> json <| "media_type" 59 | <*> (json <| "date" >>- dateFrom("yyyy-mm-dd")) 60 | } 61 | } 62 | 63 | extension Photo.MediaType: Decodable 64 | { 65 | static func decode(_ json: JSON) -> Decoded 66 | { 67 | switch json { 68 | case .string(let value): 69 | if let mediaType = Photo.MediaType(rawValue: value) 70 | { 71 | return .success(mediaType) 72 | } 73 | fallthrough 74 | default: 75 | return .failure(.custom("Unable to decode MediaType")) 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Sample/NASA Photo of the Day/NASA Photo of the Day/NASAPhotoOfTheDay.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NASAPhotoOfTheDay.swift 3 | // NASA Photo of the Day 4 | // 5 | // Created by Saul Mora on 10/27/16. 6 | // Copyright © 2016 Magical Panda, LLC. All rights reserved. 7 | // 8 | 9 | import CoreHTTP 10 | import Runes 11 | 12 | class NASAAPODHost: HTTPHost 13 | { 14 | init(apiKey: String) 15 | { 16 | let generateCredentials: GenerateAuthenticationCredentialsFunction = { .queryParameters("api_key", apiKey) } 17 | super.init(baseURLString: "https://api.nasa.gov/planetary", configuration: .default, authentication: generateCredentials) 18 | } 19 | } 20 | 21 | class NASAAPODHTTPResource: HTTPResource, HostedResource 22 | { 23 | let hostType: AnyClass = NASAAPODHost.self 24 | } 25 | 26 | 27 | func astronomyPhotoOfTheDay(date: Date? = nil, includeHDPhoto: Bool = false) -> NASAAPODHTTPResource 28 | { 29 | var queryParameters: [String: String] = [:] 30 | queryParameters["date"] = date >>- stringFrom(format: "yyyy-mm-dd") 31 | queryParameters["hd"] = String(includeHDPhoto) 32 | return NASAAPODHTTPResource(path: "apod", method: .GET, queryParameters: queryParameters, parse: parse) 33 | } 34 | 35 | 36 | -------------------------------------------------------------------------------- /Sample/NASA Photo of the Day/NASA Photo of the Day/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // NASA Photo of the Day 4 | // 5 | // Created by Saul Mora on 10/27/16. 6 | // Copyright © 2016 Magical Panda, LLC. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import CoreHTTP 11 | 12 | class ViewController: UIViewController 13 | { 14 | @IBOutlet var progressView: UIProgressView! 15 | @IBOutlet var imageView: UIImageView! 16 | @IBOutlet var spinner: UIActivityIndicatorView! 17 | @IBOutlet var button: UIButton! 18 | 19 | private lazy var host = NASAAPODHost(apiKey: "NNKOjkoul8n1CH18TWA9gwngW1s1SmjESPjNoUFo") 20 | 21 | private func resetUI() 22 | { 23 | DispatchQueue.main.async { 24 | self.button.isEnabled = true 25 | self.progressView.isHidden = true 26 | self.spinner.stopAnimating() 27 | } 28 | } 29 | 30 | private func blockUI() 31 | { 32 | DispatchQueue.main.async { 33 | self.spinner.startAnimating() 34 | self.button.isEnabled = false 35 | self.progressView?.isHidden = false 36 | } 37 | } 38 | 39 | private func displayImage(photo: Photo) -> Photo 40 | { 41 | guard let imageURL = photo.url else { return photo } 42 | 43 | print("Loading image at: \(imageURL)") 44 | 45 | let imageData = try! Data(contentsOf: imageURL) 46 | print("Loaded photo of the day") 47 | 48 | DispatchQueue.main.async { 49 | self.imageView.image = UIImage(data: imageData) 50 | } 51 | return photo 52 | } 53 | 54 | private func displayError(error: HTTPResponseError) -> HTTPResponseError 55 | { 56 | let alert = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert) 57 | alert.addAction(UIAlertAction(title: "Darn!", style: .default, handler: nil)) 58 | present(alert, animated: UIView.areAnimationsEnabled, completion: nil) 59 | 60 | print("Error Loading image \(error)") 61 | return error 62 | } 63 | 64 | @IBAction func reloadImage(button: UIButton) 65 | { 66 | print("Starting request for photo") 67 | blockUI() 68 | 69 | let response = host.request(resource: astronomyPhotoOfTheDay()) { result in 70 | 71 | print("Photo request completed") 72 | defer { self.resetUI() } 73 | 74 | _ = result 75 | .map(self.displayImage) 76 | .mapError(self.displayError) 77 | } 78 | progressView.observedProgress = response.progress 79 | 80 | //TODO: Make this API happen 81 | // host.request(resource: astronomyPhotoOfTheDay()) 82 | // .download { photoData -> URL in $0.url } 83 | // .progress { value in print("Download ") } 84 | // .trackProgress { self.progressView.observedProgress = $0 } 85 | // .then(self.displayImage) 86 | // .finally(resetUI) 87 | } 88 | 89 | } 90 | 91 | 92 | -------------------------------------------------------------------------------- /Tests/CoreHTTPTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CoreHTTPTests.swift 3 | // CoreHTTPTests 4 | // 5 | // Created by Saul Mora on 10/27/16. 6 | // Copyright © 2016 Magical Panda Software. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class CoreHTTPTests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | super.tearDown() 21 | } 22 | 23 | func testExample() { 24 | // This is an example of a functional test case. 25 | // Use XCTAssert and related functions to verify your tests produce the correct results. 26 | } 27 | 28 | func testPerformanceExample() { 29 | // This is an example of a performance test case. 30 | self.measure { 31 | // Put the code you want to measure the time of here. 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /Tests/Support/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | --------------------------------------------------------------------------------