From 42174d141868657d9f5ded7fdb5ef1d900c5cadf Mon Sep 17 00:00:00 2001 From: Ben Davis Date: Wed, 28 Jun 2017 00:32:39 +0100 Subject: [PATCH] Started announce to tracker --- BitTorrent.xcodeproj/project.pbxproj | 423 +++++++++++++++++- .../contents.xcworkspacedata | 10 + .../HTTP Networking/HTTPConnection.swift | 79 ++++ .../HTTP Networking/HTTPConnectionStub.swift | 38 ++ .../HTTP Networking/HTTPConnectionTests.swift | 82 ++++ .../HTTP Networking/String+URLEncode.swift | 6 +- .../HTTP Networking/URLEncodeTests.swift | 26 ++ BitTorrent/Models/TorrentMetaInfo.swift | 9 +- BitTorrent/Models/TorrentMetaInfoTests.swift | 14 +- BitTorrent/Tracker/TorrentHTTPTracker.swift | 72 +++ .../Tracker/TorrentHTTPTrackerTests.swift | 56 +++ BitTorrentExample/AppDelegate.swift | 43 ++ .../AppIcon.appiconset/Contents.json | 93 ++++ .../Base.lproj/LaunchScreen.storyboard | 27 ++ BitTorrentExample/Info.plist | 43 ++ Podfile | 18 + Podfile.lock | 27 ++ .../Single text file/TestText.torrent | Bin Test Torrents/Single text file/text.txt | 1 + 19 files changed, 1047 insertions(+), 20 deletions(-) create mode 100644 BitTorrent.xcworkspace/contents.xcworkspacedata create mode 100644 BitTorrent/HTTP Networking/HTTPConnection.swift create mode 100644 BitTorrent/HTTP Networking/HTTPConnectionStub.swift create mode 100644 BitTorrent/HTTP Networking/HTTPConnectionTests.swift create mode 100644 BitTorrent/HTTP Networking/URLEncodeTests.swift create mode 100644 BitTorrent/Tracker/TorrentHTTPTracker.swift create mode 100644 BitTorrent/Tracker/TorrentHTTPTrackerTests.swift create mode 100644 BitTorrentExample/AppDelegate.swift create mode 100644 BitTorrentExample/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 BitTorrentExample/Base.lproj/LaunchScreen.storyboard create mode 100644 BitTorrentExample/Info.plist create mode 100644 Podfile create mode 100644 Podfile.lock rename TestText.torrent => Test Torrents/Single text file/TestText.torrent (100%) create mode 100644 Test Torrents/Single text file/text.txt diff --git a/BitTorrent.xcodeproj/project.pbxproj b/BitTorrent.xcodeproj/project.pbxproj index b6c5292..41deff0 100644 --- a/BitTorrent.xcodeproj/project.pbxproj +++ b/BitTorrent.xcodeproj/project.pbxproj @@ -7,20 +7,52 @@ objects = { /* Begin PBXBuildFile section */ + 093BCDB0AFF1213952AF9B78 /* Pods_BitTorrent_BitTorrentExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC831BC41AD3DBDC243F2D31 /* Pods_BitTorrent_BitTorrentExample.framework */; }; + 8214C7DC09DE39DFD4A3A4D4 /* Pods_BitTorrentExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38D46CB7DEC9C9D2E7BFCC79 /* Pods_BitTorrentExample.framework */; }; + 85A4C242C1CF7B2588181C55 /* Pods_BitTorrentTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C9C10DE7DF23AC06671B75B /* Pods_BitTorrentTests.framework */; }; + B537CF061F03148B0084089B /* HTTPConnectionStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = B537CF051F03148B0084089B /* HTTPConnectionStub.swift */; }; + B537CF461F031AD20084089B /* TestText.torrent in Resources */ = {isa = PBXBuildFile; fileRef = B5E9B0E31F02F9E700EF58E3 /* TestText.torrent */; }; + B537CF491F031C3D0084089B /* BEncode.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B54D0C1A1CA53983004343BD /* BEncode.framework */; }; + B537CF4A1F031C3D0084089B /* BEncode.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B54D0C1A1CA53983004343BD /* BEncode.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + B537CF4D1F031C3D0084089B /* BitTorrent.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B585AB741C3833450093FA41 /* BitTorrent.framework */; }; + B537CF4E1F031C3D0084089B /* BitTorrent.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B585AB741C3833450093FA41 /* BitTorrent.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; B54D0C1F1CA53993004343BD /* BEncode.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B54D0C1A1CA53983004343BD /* BEncode.framework */; }; B54D0C271CA56ADB004343BD /* TorrentMetaInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54D0C261CA56ADB004343BD /* TorrentMetaInfoTests.swift */; }; B54D0C761CA58993004343BD /* CommonCrypto.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B54D0C581CA58722004343BD /* CommonCrypto.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; B54D0C7A1CA69FAD004343BD /* TorrentMetaInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54D0C231CA56A22004343BD /* TorrentMetaInfo.swift */; }; B54D0C7B1CA69FD8004343BD /* Data+sha1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54D0C2B1CA5787E004343BD /* Data+sha1.swift */; }; - B55D3FC21CA81372005CBDFF /* TestText.torrent in Resources */ = {isa = PBXBuildFile; fileRef = B55D3FC11CA81372005CBDFF /* TestText.torrent */; }; + B5530DB21F03063300F71CCD /* HTTPConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5530DB11F03063300F71CCD /* HTTPConnection.swift */; }; + B5530DB51F03063E00F71CCD /* HTTPConnectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5530DB41F03063E00F71CCD /* HTTPConnectionTests.swift */; }; + B55317DC1F02FC4D00909ADF /* TorrentHTTPTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B55317DB1F02FC4D00909ADF /* TorrentHTTPTracker.swift */; }; + B55317E01F02FE1500909ADF /* URLEncodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B55317DF1F02FE1500909ADF /* URLEncodeTests.swift */; }; B56A8A071C83539300426AC8 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56A8A061C83539300426AC8 /* TestHelpers.swift */; }; B585AB781C3833450093FA41 /* BitTorrent.h in Headers */ = {isa = PBXBuildFile; fileRef = B585AB771C3833450093FA41 /* BitTorrent.h */; settings = {ATTRIBUTES = (Public, ); }; }; B585AB7F1C3833450093FA41 /* BitTorrent.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B585AB741C3833450093FA41 /* BitTorrent.framework */; }; B585AB841C3833450093FA41 /* BitTorrentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B585AB831C3833450093FA41 /* BitTorrentTests.swift */; }; + B5BD7FD61F03032400621BC2 /* TorrentHTTPTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BD7FD51F03032400621BC2 /* TorrentHTTPTrackerTests.swift */; }; B5E977961CAFB46B0038EBE7 /* String+URLEncode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E977951CAFB46B0038EBE7 /* String+URLEncode.swift */; }; + B5E9B0D81F02E6F800EF58E3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E9B0D71F02E6F800EF58E3 /* AppDelegate.swift */; }; + B5E9B0DA1F02E6F800EF58E3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B5E9B0D91F02E6F800EF58E3 /* Assets.xcassets */; }; + B5E9B0DD1F02E6F800EF58E3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B5E9B0DB1F02E6F800EF58E3 /* LaunchScreen.storyboard */; }; + B5E9B0E51F02FAC600EF58E3 /* TestText.torrent in Resources */ = {isa = PBXBuildFile; fileRef = B5E9B0E31F02F9E700EF58E3 /* TestText.torrent */; }; + F2A74A776590BB3F37116B02 /* Pods_BitTorrent.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B95A5AC293A32B10DB4660E /* Pods_BitTorrent.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + B537CF471F031C2F0084089B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = B585AB6B1C3833450093FA41 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B585AB731C3833450093FA41; + remoteInfo = BitTorrent; + }; + B537CF4B1F031C3D0084089B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = B54D0C141CA53983004343BD /* BEncode.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = B54D0BDA1CA53299004343BD; + remoteInfo = BEncode; + }; B54D0C191CA53983004343BD /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = B54D0C141CA53983004343BD /* BEncode.xcodeproj */; @@ -58,7 +90,31 @@ }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + B537CF4F1F031C3D0084089B /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + B537CF4A1F031C3D0084089B /* BEncode.framework in Embed Frameworks */, + B537CF4E1F031C3D0084089B /* BitTorrent.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ + 38D46CB7DEC9C9D2E7BFCC79 /* Pods_BitTorrentExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BitTorrentExample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B42EF97BEA586F1F3D322AF /* Pods-BitTorrentExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BitTorrentExample.release.xcconfig"; path = "Pods/Target Support Files/Pods-BitTorrentExample/Pods-BitTorrentExample.release.xcconfig"; sourceTree = ""; }; + 4C9C10DE7DF23AC06671B75B /* Pods_BitTorrentTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BitTorrentTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 63B7D3BCB690B552A38F570E /* Pods-BitTorrent-BitTorrentExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BitTorrent-BitTorrentExample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-BitTorrent-BitTorrentExample/Pods-BitTorrent-BitTorrentExample.debug.xcconfig"; sourceTree = ""; }; + 935B3E651D3B45CEBF2BF84C /* Pods-BitTorrent.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BitTorrent.release.xcconfig"; path = "Pods/Target Support Files/Pods-BitTorrent/Pods-BitTorrent.release.xcconfig"; sourceTree = ""; }; + 9B95A5AC293A32B10DB4660E /* Pods_BitTorrent.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BitTorrent.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + A40A9CCBA0D27D6AEF58A344 /* Pods-BitTorrentTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BitTorrentTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-BitTorrentTests/Pods-BitTorrentTests.release.xcconfig"; sourceTree = ""; }; + AB708F970D0B280193A6EB38 /* Pods-BitTorrentTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BitTorrentTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-BitTorrentTests/Pods-BitTorrentTests.debug.xcconfig"; sourceTree = ""; }; + B537CF051F03148B0084089B /* HTTPConnectionStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = HTTPConnectionStub.swift; path = "HTTP Networking/HTTPConnectionStub.swift"; sourceTree = ""; }; B54D0C141CA53983004343BD /* BEncode.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = BEncode.xcodeproj; path = Submodules/BEncodeSwift/BEncode.xcodeproj; sourceTree = ""; }; B54D0C231CA56A22004343BD /* TorrentMetaInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TorrentMetaInfo.swift; path = Models/TorrentMetaInfo.swift; sourceTree = ""; }; B54D0C261CA56ADB004343BD /* TorrentMetaInfoTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TorrentMetaInfoTests.swift; path = Models/TorrentMetaInfoTests.swift; sourceTree = ""; }; @@ -69,7 +125,10 @@ B54D0C721CA5879E004343BD /* iphoneos.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = iphoneos.modulemap; sourceTree = ""; }; B54D0C731CA587A9004343BD /* iphonesimulator.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = iphonesimulator.modulemap; sourceTree = ""; }; B54D0C741CA587B5004343BD /* macosx.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = macosx.modulemap; sourceTree = ""; }; - B55D3FC11CA81372005CBDFF /* TestText.torrent */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestText.torrent; sourceTree = ""; }; + B5530DB11F03063300F71CCD /* HTTPConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = HTTPConnection.swift; path = "HTTP Networking/HTTPConnection.swift"; sourceTree = ""; }; + B5530DB41F03063E00F71CCD /* HTTPConnectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = HTTPConnectionTests.swift; path = "HTTP Networking/HTTPConnectionTests.swift"; sourceTree = ""; }; + B55317DB1F02FC4D00909ADF /* TorrentHTTPTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TorrentHTTPTracker.swift; path = Tracker/TorrentHTTPTracker.swift; sourceTree = ""; }; + B55317DF1F02FE1500909ADF /* URLEncodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = URLEncodeTests.swift; path = "HTTP Networking/URLEncodeTests.swift"; sourceTree = ""; }; B56A8A061C83539300426AC8 /* TestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestHelpers.swift; path = Utilities/TestHelpers.swift; sourceTree = ""; }; B585AB741C3833450093FA41 /* BitTorrent.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BitTorrent.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B585AB771C3833450093FA41 /* BitTorrent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BitTorrent.h; sourceTree = ""; }; @@ -77,7 +136,19 @@ B585AB7E1C3833450093FA41 /* BitTorrentTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BitTorrentTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; B585AB831C3833450093FA41 /* BitTorrentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = BitTorrentTests.swift; path = BitTorrentTests/BitTorrentTests.swift; sourceTree = SOURCE_ROOT; }; B585AB851C3833450093FA41 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B5BD7FD51F03032400621BC2 /* TorrentHTTPTrackerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TorrentHTTPTrackerTests.swift; path = Tracker/TorrentHTTPTrackerTests.swift; sourceTree = ""; }; B5E977951CAFB46B0038EBE7 /* String+URLEncode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "String+URLEncode.swift"; path = "HTTP Networking/String+URLEncode.swift"; sourceTree = ""; }; + B5E9B0D51F02E6F800EF58E3 /* BitTorrentExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BitTorrentExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + B5E9B0D71F02E6F800EF58E3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + B5E9B0D91F02E6F800EF58E3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + B5E9B0DC1F02E6F800EF58E3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + B5E9B0DE1F02E6F800EF58E3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B5E9B0E31F02F9E700EF58E3 /* TestText.torrent */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestText.torrent; sourceTree = ""; }; + B5E9B0E41F02F9E700EF58E3 /* text.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = text.txt; sourceTree = ""; }; + BDA22A3943D47D6B2152CB15 /* Pods-BitTorrent.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BitTorrent.debug.xcconfig"; path = "Pods/Target Support Files/Pods-BitTorrent/Pods-BitTorrent.debug.xcconfig"; sourceTree = ""; }; + BFDACB202E071FF8247EC868 /* Pods-BitTorrentExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BitTorrentExample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-BitTorrentExample/Pods-BitTorrentExample.debug.xcconfig"; sourceTree = ""; }; + C79B494173728B25AA5E2B62 /* Pods-BitTorrent-BitTorrentExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BitTorrent-BitTorrentExample.release.xcconfig"; path = "Pods/Target Support Files/Pods-BitTorrent-BitTorrentExample/Pods-BitTorrent-BitTorrentExample.release.xcconfig"; sourceTree = ""; }; + DC831BC41AD3DBDC243F2D31 /* Pods_BitTorrent_BitTorrentExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BitTorrent_BitTorrentExample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -94,6 +165,7 @@ files = ( B54D0C761CA58993004343BD /* CommonCrypto.framework in Frameworks */, B54D0C1F1CA53993004343BD /* BEncode.framework in Frameworks */, + F2A74A776590BB3F37116B02 /* Pods_BitTorrent.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -102,16 +174,47 @@ buildActionMask = 2147483647; files = ( B585AB7F1C3833450093FA41 /* BitTorrent.framework in Frameworks */, + 85A4C242C1CF7B2588181C55 /* Pods_BitTorrentTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B5E9B0D21F02E6F800EF58E3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8214C7DC09DE39DFD4A3A4D4 /* Pods_BitTorrentExample.framework in Frameworks */, + B537CF491F031C3D0084089B /* BEncode.framework in Frameworks */, + B537CF4D1F031C3D0084089B /* BitTorrent.framework in Frameworks */, + 093BCDB0AFF1213952AF9B78 /* Pods_BitTorrent_BitTorrentExample.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 78A2F0108F1BFA84BB97BD61 /* Pods */ = { + isa = PBXGroup; + children = ( + BDA22A3943D47D6B2152CB15 /* Pods-BitTorrent.debug.xcconfig */, + 935B3E651D3B45CEBF2BF84C /* Pods-BitTorrent.release.xcconfig */, + BFDACB202E071FF8247EC868 /* Pods-BitTorrentExample.debug.xcconfig */, + 4B42EF97BEA586F1F3D322AF /* Pods-BitTorrentExample.release.xcconfig */, + AB708F970D0B280193A6EB38 /* Pods-BitTorrentTests.debug.xcconfig */, + A40A9CCBA0D27D6AEF58A344 /* Pods-BitTorrentTests.release.xcconfig */, + 63B7D3BCB690B552A38F570E /* Pods-BitTorrent-BitTorrentExample.debug.xcconfig */, + C79B494173728B25AA5E2B62 /* Pods-BitTorrent-BitTorrentExample.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; B54D0C131CA53979004343BD /* Frameworks */ = { isa = PBXGroup; children = ( B54D0C141CA53983004343BD /* BEncode.xcodeproj */, + 9B95A5AC293A32B10DB4660E /* Pods_BitTorrent.framework */, + 38D46CB7DEC9C9D2E7BFCC79 /* Pods_BitTorrentExample.framework */, + 4C9C10DE7DF23AC06671B75B /* Pods_BitTorrentTests.framework */, + DC831BC41AD3DBDC243F2D31 /* Pods_BitTorrent_BitTorrentExample.framework */, ); name = Frameworks; sourceTree = ""; @@ -125,12 +228,12 @@ name = Products; sourceTree = ""; }; - B54D0C211CA56619004343BD /* Torrents */ = { + B54D0C211CA56619004343BD /* Test Torrents */ = { isa = PBXGroup; children = ( - B55D3FC11CA81372005CBDFF /* TestText.torrent */, + B5E9B0E21F02F9E700EF58E3 /* Single text file */, ); - name = Torrents; + path = "Test Torrents"; sourceTree = ""; }; B54D0C251CA56A25004343BD /* Models */ = { @@ -162,15 +265,26 @@ path = CommonCrypto; sourceTree = ""; }; + B55317DA1F02FC3000909ADF /* Tracker */ = { + isa = PBXGroup; + children = ( + B55317DB1F02FC4D00909ADF /* TorrentHTTPTracker.swift */, + B5BD7FD51F03032400621BC2 /* TorrentHTTPTrackerTests.swift */, + ); + name = Tracker; + sourceTree = ""; + }; B585AB6A1C3833450093FA41 = { isa = PBXGroup; children = ( - B54D0C211CA56619004343BD /* Torrents */, + B54D0C211CA56619004343BD /* Test Torrents */, + B5E9B0D61F02E6F800EF58E3 /* BitTorrentExample */, B585AB761C3833450093FA41 /* BitTorrent */, B585AB821C3833450093FA41 /* BitTorrentTests */, B54D0C591CA58722004343BD /* CommonCrypto */, B54D0C131CA53979004343BD /* Frameworks */, B585AB751C3833450093FA41 /* Products */, + 78A2F0108F1BFA84BB97BD61 /* Pods */, ); sourceTree = ""; }; @@ -180,6 +294,7 @@ B585AB741C3833450093FA41 /* BitTorrent.framework */, B585AB7E1C3833450093FA41 /* BitTorrentTests.xctest */, B54D0C581CA58722004343BD /* CommonCrypto.framework */, + B5E9B0D51F02E6F800EF58E3 /* BitTorrentExample.app */, ); name = Products; sourceTree = ""; @@ -189,6 +304,7 @@ children = ( B585AB771C3833450093FA41 /* BitTorrent.h */, B585AB831C3833450093FA41 /* BitTorrentTests.swift */, + B55317DA1F02FC3000909ADF /* Tracker */, B54D0C251CA56A25004343BD /* Models */, B54D0C291CA5785F004343BD /* Utilities */, B5E9778F1CAFB2090038EBE7 /* HTTP Networking */, @@ -210,10 +326,34 @@ isa = PBXGroup; children = ( B5E977951CAFB46B0038EBE7 /* String+URLEncode.swift */, + B55317DF1F02FE1500909ADF /* URLEncodeTests.swift */, + B5530DB11F03063300F71CCD /* HTTPConnection.swift */, + B537CF051F03148B0084089B /* HTTPConnectionStub.swift */, + B5530DB41F03063E00F71CCD /* HTTPConnectionTests.swift */, ); name = "HTTP Networking"; sourceTree = ""; }; + B5E9B0D61F02E6F800EF58E3 /* BitTorrentExample */ = { + isa = PBXGroup; + children = ( + B5E9B0D71F02E6F800EF58E3 /* AppDelegate.swift */, + B5E9B0D91F02E6F800EF58E3 /* Assets.xcassets */, + B5E9B0DB1F02E6F800EF58E3 /* LaunchScreen.storyboard */, + B5E9B0DE1F02E6F800EF58E3 /* Info.plist */, + ); + path = BitTorrentExample; + sourceTree = ""; + }; + B5E9B0E21F02F9E700EF58E3 /* Single text file */ = { + isa = PBXGroup; + children = ( + B5E9B0E31F02F9E700EF58E3 /* TestText.torrent */, + B5E9B0E41F02F9E700EF58E3 /* text.txt */, + ); + path = "Single text file"; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -257,10 +397,12 @@ isa = PBXNativeTarget; buildConfigurationList = B585AB881C3833450093FA41 /* Build configuration list for PBXNativeTarget "BitTorrent" */; buildPhases = ( + 12AC90F633781EF3E22E6344 /* [CP] Check Pods Manifest.lock */, B585AB6F1C3833450093FA41 /* Sources */, B585AB701C3833450093FA41 /* Frameworks */, B585AB711C3833450093FA41 /* Headers */, B585AB721C3833450093FA41 /* Resources */, + 675ADD5995C4967B1FDA8F34 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -277,9 +419,12 @@ isa = PBXNativeTarget; buildConfigurationList = B585AB8B1C3833450093FA41 /* Build configuration list for PBXNativeTarget "BitTorrentTests" */; buildPhases = ( + 794AC8207A2F6801357BF21C /* [CP] Check Pods Manifest.lock */, B585AB7A1C3833450093FA41 /* Sources */, B585AB7B1C3833450093FA41 /* Frameworks */, B585AB7C1C3833450093FA41 /* Resources */, + 9AD83819A2F4C07F5CB417AF /* [CP] Embed Pods Frameworks */, + BD00B85F3B0DA72D8440099C /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -291,6 +436,29 @@ productReference = B585AB7E1C3833450093FA41 /* BitTorrentTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + B5E9B0D41F02E6F800EF58E3 /* BitTorrentExample */ = { + isa = PBXNativeTarget; + buildConfigurationList = B5E9B0DF1F02E6F800EF58E3 /* Build configuration list for PBXNativeTarget "BitTorrentExample" */; + buildPhases = ( + 83D69C44459BE9615A543981 /* [CP] Check Pods Manifest.lock */, + B5E9B0D11F02E6F800EF58E3 /* Sources */, + B5E9B0D21F02E6F800EF58E3 /* Frameworks */, + B5E9B0D31F02E6F800EF58E3 /* Resources */, + 452A0C5000B0F3E45AA9DBAD /* [CP] Embed Pods Frameworks */, + 20B0019C02FBFB67DA726A29 /* [CP] Copy Pods Resources */, + B537CF4F1F031C3D0084089B /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B537CF481F031C2F0084089B /* PBXTargetDependency */, + B537CF4C1F031C3D0084089B /* PBXTargetDependency */, + ); + name = BitTorrentExample; + productName = BitTorrentExample; + productReference = B5E9B0D51F02E6F800EF58E3 /* BitTorrentExample.app */; + productType = "com.apple.product-type.application"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -298,7 +466,7 @@ isa = PBXProject; attributes = { LastSwiftMigration = 0720; - LastSwiftUpdateCheck = 0730; + LastSwiftUpdateCheck = 0900; LastUpgradeCheck = 0900; ORGANIZATIONNAME = "Ben Davis"; TargetAttributes = { @@ -307,12 +475,17 @@ }; B585AB731C3833450093FA41 = { CreatedOnToolsVersion = 7.2; + DevelopmentTeam = HT9AS2MWK9; LastSwiftMigration = 0900; }; B585AB7D1C3833450093FA41 = { CreatedOnToolsVersion = 7.2; LastSwiftMigration = 0900; }; + B5E9B0D41F02E6F800EF58E3 = { + CreatedOnToolsVersion = 9.0; + DevelopmentTeam = HT9AS2MWK9; + }; }; }; buildConfigurationList = B585AB6E1C3833450093FA41 /* Build configuration list for PBXProject "BitTorrent" */; @@ -321,6 +494,7 @@ hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = B585AB6A1C3833450093FA41; productRefGroup = B585AB751C3833450093FA41 /* Products */; @@ -333,6 +507,7 @@ ); projectRoot = ""; targets = ( + B5E9B0D41F02E6F800EF58E3 /* BitTorrentExample */, B585AB731C3833450093FA41 /* BitTorrent */, B585AB7D1C3833450093FA41 /* BitTorrentTests */, B54D0C571CA58722004343BD /* CommonCrypto */, @@ -376,12 +551,145 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - B55D3FC21CA81372005CBDFF /* TestText.torrent in Resources */, + B5E9B0E51F02FAC600EF58E3 /* TestText.torrent in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B5E9B0D31F02E6F800EF58E3 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B537CF461F031AD20084089B /* TestText.torrent in Resources */, + B5E9B0DA1F02E6F800EF58E3 /* Assets.xcassets in Resources */, + B5E9B0DD1F02E6F800EF58E3 /* LaunchScreen.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 12AC90F633781EF3E22E6344 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + 20B0019C02FBFB67DA726A29 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-BitTorrent-BitTorrentExample/Pods-BitTorrent-BitTorrentExample-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 452A0C5000B0F3E45AA9DBAD /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-BitTorrent-BitTorrentExample/Pods-BitTorrent-BitTorrentExample-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 675ADD5995C4967B1FDA8F34 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-BitTorrent/Pods-BitTorrent-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 794AC8207A2F6801357BF21C /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + 83D69C44459BE9615A543981 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + 9AD83819A2F4C07F5CB417AF /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-BitTorrentTests/Pods-BitTorrentTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + BD00B85F3B0DA72D8440099C /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-BitTorrentTests/Pods-BitTorrentTests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ B54D0C531CA58722004343BD /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -394,9 +702,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + B55317DC1F02FC4D00909ADF /* TorrentHTTPTracker.swift in Sources */, B5E977961CAFB46B0038EBE7 /* String+URLEncode.swift in Sources */, B54D0C7A1CA69FAD004343BD /* TorrentMetaInfo.swift in Sources */, B54D0C7B1CA69FD8004343BD /* Data+sha1.swift in Sources */, + B5530DB21F03063300F71CCD /* HTTPConnection.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -404,15 +714,37 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + B537CF061F03148B0084089B /* HTTPConnectionStub.swift in Sources */, + B5BD7FD61F03032400621BC2 /* TorrentHTTPTrackerTests.swift in Sources */, + B5530DB51F03063E00F71CCD /* HTTPConnectionTests.swift in Sources */, B56A8A071C83539300426AC8 /* TestHelpers.swift in Sources */, B585AB841C3833450093FA41 /* BitTorrentTests.swift in Sources */, B54D0C271CA56ADB004343BD /* TorrentMetaInfoTests.swift in Sources */, + B55317E01F02FE1500909ADF /* URLEncodeTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B5E9B0D11F02E6F800EF58E3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B5E9B0D81F02E6F800EF58E3 /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + B537CF481F031C2F0084089B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B585AB731C3833450093FA41 /* BitTorrent */; + targetProxy = B537CF471F031C2F0084089B /* PBXContainerItemProxy */; + }; + B537CF4C1F031C3D0084089B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = BEncode; + targetProxy = B537CF4B1F031C3D0084089B /* PBXContainerItemProxy */; + }; B54D0C1E1CA5398F004343BD /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = BEncode; @@ -430,6 +762,17 @@ }; /* End PBXTargetDependency section */ +/* Begin PBXVariantGroup section */ + B5E9B0DB1F02E6F800EF58E3 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + B5E9B0DC1F02E6F800EF58E3 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + /* Begin XCBuildConfiguration section */ B54D0C6A1CA58722004343BD /* Debug */ = { isa = XCBuildConfiguration; @@ -579,11 +922,14 @@ }; B585AB891C3833450093FA41 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = BDA22A3943D47D6B2152CB15 /* Pods-BitTorrent.debug.xcconfig */; buildSettings = { CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = HT9AS2MWK9; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -607,11 +953,14 @@ }; B585AB8A1C3833450093FA41 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 935B3E651D3B45CEBF2BF84C /* Pods-BitTorrent.release.xcconfig */; buildSettings = { CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = HT9AS2MWK9; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -634,6 +983,7 @@ }; B585AB8C1C3833450093FA41 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = AB708F970D0B280193A6EB38 /* Pods-BitTorrentTests.debug.xcconfig */; buildSettings = { INFOPLIST_FILE = BitTorrentTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.3; @@ -648,6 +998,7 @@ }; B585AB8D1C3833450093FA41 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = A40A9CCBA0D27D6AEF58A344 /* Pods-BitTorrentTests.release.xcconfig */; buildSettings = { INFOPLIST_FILE = BitTorrentTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.3; @@ -660,6 +1011,53 @@ }; name = Release; }; + B5E9B0E01F02E6F800EF58E3 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 63B7D3BCB690B552A38F570E /* Pods-BitTorrent-BitTorrentExample.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + DEVELOPMENT_TEAM = HT9AS2MWK9; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = BitTorrentExample/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "uk.co.-bendavisapps.BitTorrentExample"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + B5E9B0E11F02E6F800EF58E3 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C79B494173728B25AA5E2B62 /* Pods-BitTorrent-BitTorrentExample.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "iPhone Developer"; + DEVELOPMENT_TEAM = HT9AS2MWK9; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = BitTorrentExample/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "uk.co.-bendavisapps.BitTorrentExample"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -699,6 +1097,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + B5E9B0DF1F02E6F800EF58E3 /* Build configuration list for PBXNativeTarget "BitTorrentExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B5E9B0E01F02E6F800EF58E3 /* Debug */, + B5E9B0E11F02E6F800EF58E3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = B585AB6B1C3833450093FA41 /* Project object */; diff --git a/BitTorrent.xcworkspace/contents.xcworkspacedata b/BitTorrent.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..5a22413 --- /dev/null +++ b/BitTorrent.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/BitTorrent/HTTP Networking/HTTPConnection.swift b/BitTorrent/HTTP Networking/HTTPConnection.swift new file mode 100644 index 0000000..96e2b04 --- /dev/null +++ b/BitTorrent/HTTP Networking/HTTPConnection.swift @@ -0,0 +1,79 @@ +// +// HTTPConnection.swift +// BitTorrent +// +// Created by Ben Davis on 27/06/2017. +// Copyright © 2017 Ben Davis. All rights reserved. +// + +import Foundation +import Alamofire + +struct HTTPResponse { + let completed: Bool + let responseData: Data? + let statusCode: Int + + init(completed: Bool, responseData: Data? = nil, statusCode: Int = 0) { + self.completed = completed + self.responseData = responseData + self.statusCode = statusCode; + } + + init(response: DataResponse) { + + guard let data = response.data, + let httpResponse = response.response, + response.error == nil else { + + self.init(completed: false) + return + } + + self.init(completed: true, responseData: data, statusCode: httpResponse.statusCode) + } +} + +protocol BasicHTTPConnection { + func makeRequest(url: URL, urlParameters: [String: String]?, completion: @escaping (HTTPResponse)->Void) +} + +class HTTPConnection: BasicHTTPConnection { + + func makeRequest(url: URL, urlParameters: [String: String]? = nil, completion: @escaping (HTTPResponse)->Void) { + + + // TODO: Think of a way to fix this... + class ParameterEncodingFixer: ParameterEncoding { + + func encode(_ requestConvertable: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest { + + let urlEncoding = URLEncoding() + + guard parameters != nil else { + return try urlEncoding.encode(requestConvertable, with: nil) + } + + var newParameters = parameters + newParameters!.removeValue(forKey: "info_hash") + + var result = try urlEncoding.encode(requestConvertable, with: newParameters) + + if let infoHash: String = parameters?["info_hash"] as? String { + let newURL = result.url!.absoluteString + "&info_hash=" + infoHash + result.url = URL(string: newURL) + } + + return result; + } + + } + + let encoding: ParameterEncoding = ParameterEncodingFixer() + + Alamofire.request(url, parameters: urlParameters, encoding: encoding).responseData { response in + completion(HTTPResponse(response: response)) + } + } + +} diff --git a/BitTorrent/HTTP Networking/HTTPConnectionStub.swift b/BitTorrent/HTTP Networking/HTTPConnectionStub.swift new file mode 100644 index 0000000..666cc68 --- /dev/null +++ b/BitTorrent/HTTP Networking/HTTPConnectionStub.swift @@ -0,0 +1,38 @@ +// +// HTTPConnectionStub.swift +// BitTorrentTests +// +// Created by Ben Davis on 27/06/2017. +// Copyright © 2017 Ben Davis. All rights reserved. +// + +import Foundation +@testable import BitTorrent + +struct HTTPConnectionStubRequest { + let url: URL + let urlParameters: [String: String]? + let completion: (HTTPResponse)->Void +} + +class HTTPConnectionStub: BasicHTTPConnection { + + var previousRequests: [HTTPConnectionStubRequest] = [] + + var lastRequest: HTTPConnectionStubRequest { + return previousRequests.last! + } + + func makeRequest(url: URL, urlParameters: [String: String]? = nil, completion: @escaping (HTTPResponse)->Void) { + previousRequests.append(HTTPConnectionStubRequest(url: url, + urlParameters: urlParameters, + completion: completion)) + } + + // MARK: - + + func completeLastRequest(with response: HTTPResponse) { + previousRequests.last!.completion(response) + } + +} diff --git a/BitTorrent/HTTP Networking/HTTPConnectionTests.swift b/BitTorrent/HTTP Networking/HTTPConnectionTests.swift new file mode 100644 index 0000000..5839d2e --- /dev/null +++ b/BitTorrent/HTTP Networking/HTTPConnectionTests.swift @@ -0,0 +1,82 @@ +// +// HTTPConnectionTests.swift +// BitTorrentTests +// +// Created by Ben Davis on 27/06/2017. +// Copyright © 2017 Ben Davis. All rights reserved. +// + +import XCTest +import OHHTTPStubs +@testable import BitTorrent + +class HTTPConnectionTests: XCTestCase { + + let host = "test.com" + let url = URL(string: "https://test.com")! + let urlParameters = ["foo": "bar", "hello": "world!"] + let statusCode: Int32 = 123 + let responseData = Data(bytes: [1,2,3,4]) + + var connection: HTTPConnection! + + override func setUp() { + super.setUp() + + OHHTTPStubs.stubRequests(passingTest: { [weak self] request -> Bool in + + guard let host = self?.host, let urlParameters = self?.urlParameters else { + return false + } + + let components = URLComponents(url: request.url!, resolvingAgainstBaseURL: false)! + let urlParametersInRequest: [String: String] + + if let queryItems = components.queryItems { + let elements = queryItems.map({ ($0.name, $0.value) }) + urlParametersInRequest = Dictionary(uniqueKeysWithValues: elements) as! [String : String] + } else { + urlParametersInRequest = [:] + } + + return (components.host == host && urlParametersInRequest == urlParameters) + + }, withStubResponse: { [weak self] request -> OHHTTPStubsResponse in + + OHHTTPStubsResponse(data: self!.responseData, + statusCode: self!.statusCode, + headers: nil) + }) + + connection = HTTPConnection() + } + + func test_failedRequest() { + + let expectation = self.expectation(description: "Completion closure invoked") + + connection.makeRequest(url: URL(string: "other.com")!) { response in + XCTAssertFalse(response.completed) + XCTAssertNil(response.responseData) + XCTAssertEqual(response.statusCode , 0) + expectation.fulfill() + } + + waitForExpectations(timeout: 0.1) + } + + func test_canMakeRequest() { + + let expectation = self.expectation(description: "Completion closure invoked") + + connection.makeRequest(url: url, urlParameters: urlParameters) { response in + XCTAssert(response.completed) + XCTAssertEqual(response.responseData, self.responseData) + XCTAssertEqual(response.statusCode, Int(self.statusCode)) + expectation.fulfill() + } + + waitForExpectations(timeout: 0.1) + } + +} diff --git a/BitTorrent/HTTP Networking/String+URLEncode.swift b/BitTorrent/HTTP Networking/String+URLEncode.swift index b303718..262ddb9 100644 --- a/BitTorrent/HTTP Networking/String+URLEncode.swift +++ b/BitTorrent/HTTP Networking/String+URLEncode.swift @@ -14,7 +14,11 @@ extension String { static let asciiSpace: UInt8 = 32 static let asciiPercentage: UInt8 = 37 - static func urlEncode(_ data: Data) -> String { + init(urlEncodingData data: Data) { + self = String.urlEncode(data) + } + + private static func urlEncode(_ data: Data) -> String { let allowedCharacters = CharacterSet(charactersIn: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_~") let result = NSMutableString() diff --git a/BitTorrent/HTTP Networking/URLEncodeTests.swift b/BitTorrent/HTTP Networking/URLEncodeTests.swift new file mode 100644 index 0000000..38cf446 --- /dev/null +++ b/BitTorrent/HTTP Networking/URLEncodeTests.swift @@ -0,0 +1,26 @@ +// +// URLEncodeTests.swift +// BitTorrentTests +// +// Created by Ben Davis on 27/06/2017. +// Copyright © 2017 Ben Davis. All rights reserved. +// + +import XCTest +@testable import BitTorrent + +class URLEncodeTests: XCTestCase { + + func test_canEncodeBinaryAsURLEncodedString() { + + let data = Data(bytes: [0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf1, 0x23, 0x45, + 0x67, 0x89, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x9a]) + + let expected = "%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx%9A" + + let result = String(urlEncodingData: data) + + XCTAssertEqual(result, expected) + } + +} diff --git a/BitTorrent/Models/TorrentMetaInfo.swift b/BitTorrent/Models/TorrentMetaInfo.swift index b76c132..10e046a 100644 --- a/BitTorrent/Models/TorrentMetaInfo.swift +++ b/BitTorrent/Models/TorrentMetaInfo.swift @@ -15,12 +15,12 @@ class TorrentMetaInfo { let infoHash : Data // this is the original BEncoded dictionary, hashed let info: TorrentInfoDictionary - let announce: String + let announce: URL let announceList: [[String]]? let creationDate: Date? let comment: String? let createdBy: String? - + init?(data: Data) { let decodedMetainfo = try! BEncoder.decodeStringKeyedDictionary(data) @@ -34,8 +34,9 @@ class TorrentMetaInfo { } if let announceData = decodedMetainfo["announce"], - let announceString = String(asciiData: announceData as? Data) { - self.announce = announceString + let announceString = String(asciiData: announceData as? Data), + let announceURL = URL(string: announceString) { + self.announce = announceURL } else { return nil } diff --git a/BitTorrent/Models/TorrentMetaInfoTests.swift b/BitTorrent/Models/TorrentMetaInfoTests.swift index 15c89e1..a290c36 100644 --- a/BitTorrent/Models/TorrentMetaInfoTests.swift +++ b/BitTorrent/Models/TorrentMetaInfoTests.swift @@ -25,8 +25,8 @@ extension Array where Element: Equatable { class TorrentMetaInfoTests: XCTestCase { let filePieceLength = 16384 - let singleFilePiece = Data(bytes: [0x3f, 0x3f, 0x11, 0x09, 0x64, 0x07, 0x00, 0x3f, 0x42, - 0x35, 0x3f, 0x3f, 0x59, 0x2e, 0x23, 0x13, 0x3f, 0x18, 0x23, 0x3e]) + let singleFilePiece = Data(bytes: [0x3f, 0x3f, 0x11, 0x09, 0x64, 0x07, 0x00, 0x3f, 0x42, 0x35, + 0x3f, 0x3f, 0x59, 0x2e, 0x23, 0x13, 0x3f, 0x18, 0x23, 0x3e]) let torrentName = "Torrent Name" let singleFileName = "test.txt" let singleFileLength = 117 @@ -37,7 +37,7 @@ class TorrentMetaInfoTests: XCTestCase { let multipleFileLength2 = 115 let multipleFilePath1 = "/test/path" let multipleFilePath2 = "/test/path2" - let announceString = "annouce string" + let announceURL = URL(string: "announceURL.com")! let announceList: [[String]] = [ [ "tracker1", "tracker2" ], ["backup1"] ] let creationDateInt: Int = 123456789 let creationDate = Date(timeIntervalSince1970: 123456789) @@ -109,7 +109,7 @@ class TorrentMetaInfoTests: XCTestCase { func unEncodedMetaInfoWithInfoDictionary(_ infoDictionary: [String : AnyObject]) -> [String : AnyObject] { return [ "info" : infoDictionary as AnyObject, - "announce" : announceString as AnyObject, + "announce" : announceURL.absoluteString as AnyObject, "announce-list": announceList as AnyObject, "creation date": creationDateInt as AnyObject, "comment": comment as AnyObject, @@ -121,7 +121,7 @@ class TorrentMetaInfoTests: XCTestCase { func testCanInitialiseWithDictionary() { let metaInfo = TorrentMetaInfo(data: self.exampleMetaInfoDictionary())! - XCTAssertEqual(metaInfo.announce, announceString) + XCTAssertEqual(metaInfo.announce, announceURL) XCTAssertEqual(metaInfo.announceList! as NSArray, announceList as NSArray) XCTAssertEqual(metaInfo.creationDate!, creationDate) XCTAssertEqual(metaInfo.comment!, comment) @@ -140,8 +140,8 @@ class TorrentMetaInfoTests: XCTestCase { let data = try! Data(contentsOf: URL(fileURLWithPath: path!)) let metaInfo = TorrentMetaInfo(data: data)! - let hash = Data(bytes:[ 0xf0, 0xb8, 0x71, 0x98, 0x99, 0x53, 0x97, 0x3f, 0xbf, 0xa9, 0x4d, - 0xc8, 0x14, 0x98, 0xee, 0x8d, 0x20, 0x5b, 0xb2, 0x23]) + let hash = Data(bytes:[ 0xf0, 0xb8, 0x71, 0x98, 0x99, 0x53, 0x97, 0x3f, 0xbf, 0xa9, + 0x4d, 0xc8, 0x14, 0x98, 0xee, 0x8d, 0x20, 0x5b, 0xb2, 0x23]) XCTAssertEqual(hash, metaInfo.infoHash) } diff --git a/BitTorrent/Tracker/TorrentHTTPTracker.swift b/BitTorrent/Tracker/TorrentHTTPTracker.swift new file mode 100644 index 0000000..3798eb7 --- /dev/null +++ b/BitTorrent/Tracker/TorrentHTTPTracker.swift @@ -0,0 +1,72 @@ +// +// Tracker.swift +// BitTorrent +// +// Created by Ben Davis on 27/06/2017. +// Copyright © 2017 Ben Davis. All rights reserved. +// + +import Foundation + +//tracker.announceClient(self.peerId, +// port: 6881, +// numberOfBytes: self.metaInfo.length, +// infoHash: self.metaInfo.infoHash, +// numwant: 20, +// key: "-BD0000-bxa]N#IRKqv`"); + +//func makePeerId() -> String { +// var peerId = "-BD0000-" +// +// for _ in 0...11 { +// let asciiCharacters = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" +// let numberOfAscii = asciiCharacters.characters.count +// let randomIndex = arc4random() % UInt32(numberOfAscii) +// let random = asciiCharacters[Int(randomIndex)] +// peerId += random +// } +// +// if (GENERAL_DEBUG_LOG) { print("Client Peer ID: \(peerId)") } +// +// return peerId +//} + +class TorrentHTTPTracker { + + let metaInfo: TorrentMetaInfo + let connection: BasicHTTPConnection + + init(metaInfo: TorrentMetaInfo, connection: BasicHTTPConnection = HTTPConnection()) { + self.metaInfo = metaInfo + self.connection = connection + } + + func announceClient(with peerId: String, + port: Int, + numberOfBytesRemaining: Int, + infoHash: Data, + numberOfPeersToFetch: Int, + peerKey: String) { + + let urlParameters = [ + "info_hash" : String(urlEncodingData: metaInfo.infoHash), + "peer_id" : "\(peerId)", + "port" : "\(port)", + "uploaded" : "0", + "downloaded" : "0", + "left" : "\(numberOfBytesRemaining)", + "compact" : "1", + "event" : "started", + "numwant" : "\(numberOfPeersToFetch)", + "key" : peerKey, + ] + + connection.makeRequest(url: metaInfo.announce, urlParameters: urlParameters) { response in + + if let data = response.responseData, let utf8Text = String(data: data, encoding: .utf8) { + print("Data: \(utf8Text)") + } + } + } + +} diff --git a/BitTorrent/Tracker/TorrentHTTPTrackerTests.swift b/BitTorrent/Tracker/TorrentHTTPTrackerTests.swift new file mode 100644 index 0000000..c9d846b --- /dev/null +++ b/BitTorrent/Tracker/TorrentHTTPTrackerTests.swift @@ -0,0 +1,56 @@ +// +// TorrentHTTPTrackerTests.swift +// BitTorrentTests +// +// Created by Ben Davis on 27/06/2017. +// Copyright © 2017 Ben Davis. All rights reserved. +// + +import XCTest +@testable import BitTorrent + +class TorrentHTTPTrackerTests: XCTestCase { + + var connectionStub: HTTPConnectionStub! + var sut: TorrentHTTPTracker! + + override func setUp() { + super.setUp() + + let path = Bundle(for: type(of: self)).path(forResource: "TestText", ofType: "torrent") + let data = try! Data(contentsOf: URL(fileURLWithPath: path!)) + let metaInfo = TorrentMetaInfo(data: data)! + + connectionStub = HTTPConnectionStub() + sut = TorrentHTTPTracker(metaInfo: metaInfo, connection: connectionStub) + } + + func test_announce() { + + sut.announceClient(with: "peerId", + port: 123, + numberOfBytesRemaining: 456, + infoHash: Data(bytes: [7,8,9]), + numberOfPeersToFetch: 321, + peerKey: "key") + + let request = connectionStub.lastRequest + + let expectedURLParameters = [ + "info_hash": "%F0%B8q%98%99S%97%3F%BF%A9M%C8%14%98%EE%8D%20%5B%B2%23", + "peer_id" : "peerId", + "port" : "123", + "uploaded" : "0", + "downloaded" : "0", + "left" : "456", + "compact" : "1", + "event" : "started", + "numwant" : "321", + "key" : "key", + ] + + XCTAssertEqual(request.url.absoluteString, "http://127.0.0.1:53420/announce") + XCTAssertEqual(request.urlParameters!, expectedURLParameters) + } + +} diff --git a/BitTorrentExample/AppDelegate.swift b/BitTorrentExample/AppDelegate.swift new file mode 100644 index 0000000..e67c815 --- /dev/null +++ b/BitTorrentExample/AppDelegate.swift @@ -0,0 +1,43 @@ +// +// AppDelegate.swift +// BitTorrentExample +// +// Created by Ben Davis on 27/06/2017. +// Copyright © 2017 Ben Davis. All rights reserved. +// + +import UIKit +@testable import BitTorrent + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + var tracker: TorrentHTTPTracker! + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + window = UIWindow(frame: UIScreen.main.bounds) + window!.rootViewController = UIViewController() + window!.backgroundColor = .white + window!.makeKeyAndVisible() + + + let path = Bundle(for: type(of: self)).path(forResource: "TestText", ofType: "torrent") + let data = try! Data(contentsOf: URL(fileURLWithPath: path!)) + let metaInfo = TorrentMetaInfo(data: data)! + + tracker = TorrentHTTPTracker(metaInfo: metaInfo) + + tracker.announceClient(with: "-BD0000-bxa]N#IRKqv`", + port: 6881, + numberOfBytesRemaining: 117, + infoHash: Data(bytes:[ 0xf0, 0xb8, 0x71, 0x98, 0x99, 0x53, 0x97, 0x3f, 0xbf, 0xa9, + 0x4d, 0xc8, 0x14, 0x98, 0xee, 0x8d, 0x20, 0x5b, 0xb2, 0x23]), + numberOfPeersToFetch: 50, + peerKey: "key") + + return true + } + +} diff --git a/BitTorrentExample/Assets.xcassets/AppIcon.appiconset/Contents.json b/BitTorrentExample/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..1d060ed --- /dev/null +++ b/BitTorrentExample/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,93 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/BitTorrentExample/Base.lproj/LaunchScreen.storyboard b/BitTorrentExample/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..fdf3f97 --- /dev/null +++ b/BitTorrentExample/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BitTorrentExample/Info.plist b/BitTorrentExample/Info.plist new file mode 100644 index 0000000..4222ac2 --- /dev/null +++ b/BitTorrentExample/Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Podfile b/Podfile new file mode 100644 index 0000000..d5dacf7 --- /dev/null +++ b/Podfile @@ -0,0 +1,18 @@ +target 'BitTorrent' do + use_frameworks! + + pod 'Alamofire', '4.5.0' + + target 'BitTorrentTests' do + inherit! :search_paths + + pod 'OHHTTPStubs' + + end + + target 'BitTorrentExample' do + use_frameworks! + + end + +end diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 0000000..3f3911a --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,27 @@ +PODS: + - Alamofire (4.5.0) + - OHHTTPStubs (6.0.0): + - OHHTTPStubs/Default (= 6.0.0) + - OHHTTPStubs/Core (6.0.0) + - OHHTTPStubs/Default (6.0.0): + - OHHTTPStubs/Core + - OHHTTPStubs/JSON + - OHHTTPStubs/NSURLSession + - OHHTTPStubs/OHPathHelpers + - OHHTTPStubs/JSON (6.0.0): + - OHHTTPStubs/Core + - OHHTTPStubs/NSURLSession (6.0.0): + - OHHTTPStubs/Core + - OHHTTPStubs/OHPathHelpers (6.0.0) + +DEPENDENCIES: + - Alamofire (= 4.5.0) + - OHHTTPStubs + +SPEC CHECKSUMS: + Alamofire: f28cdffd29de33a7bfa022cbd63ae95a27fae140 + OHHTTPStubs: 752f9b11fd810a15162d50f11c06ff94f8e012eb + +PODFILE CHECKSUM: 9fe25bcdf8fe1b5a1322474e68acc83c6dfd666c + +COCOAPODS: 1.2.0 diff --git a/TestText.torrent b/Test Torrents/Single text file/TestText.torrent similarity index 100% rename from TestText.torrent rename to Test Torrents/Single text file/TestText.torrent diff --git a/Test Torrents/Single text file/text.txt b/Test Torrents/Single text file/text.txt new file mode 100644 index 0000000..bfa7d9c --- /dev/null +++ b/Test Torrents/Single text file/text.txt @@ -0,0 +1 @@ +Hello world my name is Ben and this is a test text file with some data so that I can tell when bit's aren't aligning. \ No newline at end of file