diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 01a6fa1b7..75888b09e 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 3533495136D843E85211E3E2 /* Pods_Mastodon_MastodonUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1B4523A7981F1044DE89C21 /* Pods_Mastodon_MastodonUITests.framework */; }; + 5D526FE225BE9AC400460CB9 /* MastodonSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 5D526FE125BE9AC400460CB9 /* MastodonSDK */; }; 5E44BF88AD33646E64727BCF /* Pods_MastodonTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD92E0F10BDE4FE7C4B999F2 /* Pods_MastodonTests.framework */; }; 7A9135D4559750AF07CA9BE4 /* Pods_Mastodon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 602D783BEC22881EBAD84419 /* Pods_Mastodon.framework */; }; DB3D0FF325BAA61700EAA174 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB3D0FF225BAA61700EAA174 /* AlamofireImage */; }; @@ -76,6 +77,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 5D526FE225BE9AC400460CB9 /* MastodonSDK in Frameworks */, 7A9135D4559750AF07CA9BE4 /* Pods_Mastodon.framework in Frameworks */, DB3D0FF325BAA61700EAA174 /* AlamofireImage in Frameworks */, ); @@ -226,6 +228,7 @@ name = Mastodon; packageProductDependencies = ( DB3D0FF225BAA61700EAA174 /* AlamofireImage */, + 5D526FE125BE9AC400460CB9 /* MastodonSDK */, ); productName = Mastodon; productReference = DB427DD225BAA00100D1B89D /* Mastodon.app */; @@ -830,6 +833,10 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 5D526FE125BE9AC400460CB9 /* MastodonSDK */ = { + isa = XCSwiftPackageProductDependency; + productName = MastodonSDK; + }; DB3D0FF225BAA61700EAA174 /* AlamofireImage */ = { isa = XCSwiftPackageProductDependency; package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index 8842af1ee..17197be49 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -18,6 +18,33 @@ "revision": "3e8edbeb75227f8542aa87f90240cf0424d6362f", "version": "4.1.0" } + }, + { + "package": "swift-nio", + "repositoryURL": "https://github.com/apple/swift-nio.git", + "state": { + "branch": null, + "revision": "8da5c5a4e6c5084c296b9f39dc54f00be146e0fa", + "version": "1.14.2" + } + }, + { + "package": "swift-nio-zlib-support", + "repositoryURL": "https://github.com/apple/swift-nio-zlib-support.git", + "state": { + "branch": null, + "revision": "37760e9a52030bb9011972c5213c3350fa9d41fd", + "version": "1.0.0" + } + }, + { + "package": "SwiftyJSON", + "repositoryURL": "https://github.com/SwiftyJSON/SwiftyJSON.git", + "state": { + "branch": null, + "revision": "2b6054efa051565954e1d2b9da831680026cd768", + "version": "5.0.0" + } } ] }, diff --git a/Mastodon/ViewController.swift b/Mastodon/ViewController.swift index 235112a12..a90e181b7 100644 --- a/Mastodon/ViewController.swift +++ b/Mastodon/ViewController.swift @@ -6,11 +6,13 @@ // import UIKit +import MastodonSDK class ViewController: UIViewController { - + override func viewDidLoad() { super.viewDidLoad() + // Do any additional setup after loading the view. } diff --git a/MastodonSDK/Package.swift b/MastodonSDK/Package.swift index 61755106c..47589f32c 100644 --- a/MastodonSDK/Package.swift +++ b/MastodonSDK/Package.swift @@ -14,15 +14,18 @@ let package = Package( targets: ["MastodonSDK"]), ], dependencies: [ - // Dependencies declare other packages that this package depends on. - // .package(url: /* package url */, from: "1.0.0"), + .package(url: "https://github.com/SwiftyJSON/SwiftyJSON.git", from: "5.0.0"), + .package(url: "https://github.com/apple/swift-nio.git", from: "1.0.0"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "MastodonSDK", - dependencies: [] + dependencies: [ + .product(name: "SwiftyJSON", package: "SwiftyJSON"), + .product(name: "NIOHTTP1", package: "swift-nio"), + ] ), .testTarget( name: "MastodonSDKTests", diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+App.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+App.swift new file mode 100644 index 000000000..7d31280a5 --- /dev/null +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+App.swift @@ -0,0 +1,60 @@ +// +// Mastodon+API+App.swift +// +// +// Created by xiaojian sun on 2021/1/25. +// + +import Combine +import Foundation + +public extension Mastodon.API.App { + internal static let appEndpointURL = Mastodon.API.endpointURL.appendingPathComponent("apps") + + struct OAuth2Credentials: Codable { + public let id: String + + public let name: String + public let website: String? + public let redirectURI: String + public let clientID: String + public let clientSecret: String + public let vapidKey: String + + enum CodingKeys: String, CodingKey { + case id + + case name + case website + case redirectURI = "redirect_uri" + case clientID = "client_id" + case clientSecret = "client_secret" + case vapidKey = "vapid_key" + } + } + + struct registerAppQuery { + public let client_name: String + public let redirect_uris: String + public let scopes: String + public let website: String + + public init(client_name: String, redirect_uris: String, scopes: String, website: String) { + self.client_name = client_name + self.redirect_uris = redirect_uris + self.scopes = scopes + self.website = website + } + + var queryItems: [URLQueryItem]? { + var items: [URLQueryItem] = [] + items.append(URLQueryItem(name: "client_name", value: client_name)) + items.append(URLQueryItem(name: "redirect_uris", value: redirect_uris)) + items.append(URLQueryItem(name: "scopes", value: scopes)) + guard !items.isEmpty else { return nil } + return items + } + } +} + +extension Mastodon.API.App.OAuth2Credentials: Equatable {} diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API.swift new file mode 100644 index 000000000..cf25fb091 --- /dev/null +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API.swift @@ -0,0 +1,73 @@ +// +// Mastodon+API.swift +// +// +// Created by xiaojian sun on 2021/1/25. +// + +import Foundation +import NIOHTTP1 + +public extension Mastodon.API { + static var baseUrl = "" + static let endpointURL = URL(string: baseUrl + "/api/v1/")! + + static let timeoutInterval: TimeInterval = 10 + static let decoder: JSONDecoder = { + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = .MastodonStrategy + return decoder + }() + + static let httpHeaderDateFormatter: DateFormatter = { + let formatter = DateFormatter() + formatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss zzz" + return formatter + }() + + enum App {} +} + +extension Mastodon.API { + // Error Response when request V1 endpoint + struct ErrorResponse: Codable { + let errors: [ErrorDescription] + + struct ErrorDescription: Codable { + public let code: Int + public let message: String + } + } + + // Alternative Error Response when request V1 endpoint + struct ErrorRequestResponse: Codable { + let request: String + let error: String + } +} + +extension Mastodon.API { + +} + +private extension JSONDecoder.DateDecodingStrategy { + static let MastodonStrategy = custom { decoder throws -> Date in + let container = try decoder.singleValueContainer() + let string = try container.decode(String.self) + + let formatterV1 = DateFormatter() + formatterV1.locale = Locale(identifier: "en") + formatterV1.dateFormat = "EEE MMM dd HH:mm:ss ZZZZZ yyyy" + if let date = formatterV1.date(from: string) { + return date + } + + let formatterV2 = ISO8601DateFormatter() + formatterV2.formatOptions.insert(.withFractionalSeconds) + if let date = formatterV2.date(from: string) { + return date + } + + throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid date: \(string)") + } +} diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity.swift new file mode 100644 index 000000000..761f2b0ed --- /dev/null +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity.swift @@ -0,0 +1,9 @@ +// +// File.swift +// +// +// Created by xiaojian sun on 2021/1/25. +// + +import Foundation +extension Mastodon.Entity { } diff --git a/MastodonSDK/Sources/MastodonSDK/Mastodon.swift b/MastodonSDK/Sources/MastodonSDK/Mastodon.swift new file mode 100644 index 000000000..da1cdd7a7 --- /dev/null +++ b/MastodonSDK/Sources/MastodonSDK/Mastodon.swift @@ -0,0 +1,15 @@ +// +// File.swift +// +// +// Created by xiaojian sun on 2021/1/25. +// + +import Foundation + +public enum Mastodon { + public enum Request { } + public enum Response { } + public enum API { } + public enum Entity { } +} diff --git a/MastodonSDK/Sources/MastodonSDK/MastodonSDK.swift b/MastodonSDK/Sources/MastodonSDK/MastodonSDK.swift index 89c41049e..8b1378917 100644 --- a/MastodonSDK/Sources/MastodonSDK/MastodonSDK.swift +++ b/MastodonSDK/Sources/MastodonSDK/MastodonSDK.swift @@ -1,3 +1 @@ -struct MastodonSDK { - var text = "Hello, World!" -} +