diff --git a/SwiftPamphletApp/GitHubAPI/ListView/IssuesListFromCustomView.swift b/SwiftPamphletApp/GitHubAPI/ListView/IssuesListFromCustomView.swift index b5aa1b008..c36c7f940 100644 --- a/SwiftPamphletApp/GitHubAPI/ListView/IssuesListFromCustomView.swift +++ b/SwiftPamphletApp/GitHubAPI/ListView/IssuesListFromCustomView.swift @@ -27,7 +27,6 @@ struct IssuesListFromCustomView: View { } } - .alert(vm.errMsg, isPresented: $vm.errHint, actions: {}) .onAppear { vm.doing(.customIssues) } diff --git a/SwiftPamphletApp/GitHubAPI/Network/APIRequest.swift b/SwiftPamphletApp/GitHubAPI/Network/APIRequest.swift index 3fd0e2e88..9ae75c8a3 100644 --- a/SwiftPamphletApp/GitHubAPI/Network/APIRequest.swift +++ b/SwiftPamphletApp/GitHubAPI/Network/APIRequest.swift @@ -5,90 +5,90 @@ // Created by Ming Dai on 2021/11/8. // -import Foundation -import Combine - -// MARK: - API Request Fundation - -protocol APIReqType { - associatedtype Res: Decodable - var path: String { get } - var qItems: [URLQueryItem]? { get } -} - -protocol APIVMable: ObservableObject { - associatedtype ActionType - func doing(_ somethinglike: ActionType) -} - -protocol APISevType { - func response(from req: Request) -> AnyPublisher where Request: APIReqType -} - -final class APISev: APISevType { - private let rootUrl: URL - - init(rootUrl: URL = URL(string: "https://api.github.com")!) { - self.rootUrl = rootUrl - } - - func response(from req: Request) -> AnyPublisher where Request : APIReqType { - let path = URL(string: req.path, relativeTo: rootUrl)! - var comp = URLComponents(url: path, resolvingAgainstBaseURL: true)! - comp.queryItems = req.qItems -// print(comp.url?.description ?? "url wrong") - var req = URLRequest(url: comp.url!) - - // token 处理 - // TODO: 支持 OAuth - // TODO: 访问受限后会crash,异常待处理 - var githubat = "" - if SPC.gitHubAccessToken.isEmpty == true { - githubat = SPC.githubAccessToken() - } else { - githubat = SPC.gitHubAccessToken - } - - req.addValue("token \(githubat)", forHTTPHeaderField: "Authorization") - -// print(req.allHTTPHeaderFields!) - let de = JSONDecoder() - de.keyDecodingStrategy = .convertFromSnakeCase - let sch = DispatchQueue(label: "GitHub API Queue", qos: .default, attributes: .concurrent) - return URLSession.shared.dataTaskPublisher(for: req) - .retry(3) - .subscribe(on: sch) - .receive(on: sch) - .map { data, _ in -// print(String(decoding: data, as: UTF8.self)) -// print(res.description) - // 打印api访问额度 -// let hres = res as! HTTPURLResponse -// print(hres.value(forHTTPHeaderField: "x-ratelimit-remaining") ?? "none") - return data - } - .mapError { _ in - APISevError.resError - } - .decode(type: Request.Res.self, decoder: de) - .mapError { _ in - APISevError.parseError - } - .receive(on: RunLoop.main) - .eraseToAnyPublisher() - } -} - -enum APISevError: Error { - case resError - case parseError - - var message: String { - switch self { - case .resError: - return "网络无法访问" - case .parseError: - return "网络出错" - } - } -} +//import Foundation +//import Combine +// +//// MARK: - API Request Fundation +// +//protocol APIReqType { +// associatedtype Res: Decodable +// var path: String { get } +// var qItems: [URLQueryItem]? { get } +//} +// +//protocol APIVMable: ObservableObject { +// associatedtype ActionType +// func doing(_ somethinglike: ActionType) +//} +// +//protocol APISevType { +// func response(from req: Request) -> AnyPublisher where Request: APIReqType +//} +// +//final class APISev: APISevType { +// private let rootUrl: URL +// +// init(rootUrl: URL = URL(string: "https://api.github.com")!) { +// self.rootUrl = rootUrl +// } +// +// func response(from req: Request) -> AnyPublisher where Request : APIReqType { +// let path = URL(string: req.path, relativeTo: rootUrl)! +// var comp = URLComponents(url: path, resolvingAgainstBaseURL: true)! +// comp.queryItems = req.qItems +//// print(comp.url?.description ?? "url wrong") +// var req = URLRequest(url: comp.url!) +// +// // token 处理 +// // TODO: 支持 OAuth +// // TODO: 访问受限后会crash,异常待处理 +// var githubat = "" +// if SPC.gitHubAccessToken.isEmpty == true { +// githubat = SPC.githubAccessToken() +// } else { +// githubat = SPC.gitHubAccessToken +// } +// +// req.addValue("token \(githubat)", forHTTPHeaderField: "Authorization") +// +//// print(req.allHTTPHeaderFields!) +// let de = JSONDecoder() +// de.keyDecodingStrategy = .convertFromSnakeCase +// let sch = DispatchQueue(label: "GitHub API Queue", qos: .default, attributes: .concurrent) +// return URLSession.shared.dataTaskPublisher(for: req) +// .retry(3) +// .subscribe(on: sch) +// .receive(on: sch) +// .map { data, _ in +//// print(String(decoding: data, as: UTF8.self)) +//// print(res.description) +// // 打印api访问额度 +//// let hres = res as! HTTPURLResponse +//// print(hres.value(forHTTPHeaderField: "x-ratelimit-remaining") ?? "none") +// return data +// } +// .mapError { _ in +// APISevError.resError +// } +// .decode(type: Request.Res.self, decoder: de) +// .mapError { _ in +// APISevError.parseError +// } +// .receive(on: RunLoop.main) +// .eraseToAnyPublisher() +// } +//} +// +//enum APISevError: Error { +// case resError +// case parseError +// +// var message: String { +// switch self { +// case .resError: +// return "网络无法访问" +// case .parseError: +// return "网络出错" +// } +// } +//} diff --git a/SwiftPamphletApp/GitHubAPI/Network/CCYGitHubAPI.swift b/SwiftPamphletApp/GitHubAPI/Network/CCYGitHubAPI.swift index 1835f34b9..dbb846077 100644 --- a/SwiftPamphletApp/GitHubAPI/Network/CCYGitHubAPI.swift +++ b/SwiftPamphletApp/GitHubAPI/Network/CCYGitHubAPI.swift @@ -5,95 +5,95 @@ // Created by Ming Dai on 2021/12/16. // -import Foundation -import SwiftUI - -enum Github {} - -// MARK: - /repos/{reponame} -extension Github { - static func repos(_ name: String) -> Repos { - Repos(path: "/repos/\(name)") - } - struct Repos { - let path: String - var get: Req { - .get(path) - } - } -} -// MARK: - /repos/{reponame}/issues/{issuenumber} -extension Github.Repos { - func issues(_ number: Int) -> Issues { - Issues(path: path + "/issues/\(number)") - } - struct Issues { - let path: String - var get: Req { - .get(path) - } - } -} -// MARK: - /repos/{reponame}/commits -extension Github.Repos { - var commits: Commits { - Commits(path: path + "/commits", query: [("per_page", "100")]) - } - - struct Commits { - let path: String - let query: [(String, String?)]? - var get: Req<[CommitModel]> { - .get(path, query: query) - } - } -} - -// MARK: - /user -extension Github { - static var user: User { - User() - } - struct User { - let path: String = "/user" - var get: Req { - .get(path) - } - } -} -// MARK: - /user/following -extension Github.User { - var following: Following { - Following() - } - struct Following { - let path: String = "/user/following" - var get: Req<[GitUserModel]> { - .get(path) - } - } -} -// MARK: - /users/{username} -extension Github { - static func users(_ name: String) -> Users { - Users(path: "/users/\(name)") - } - struct Users { - let path: String - var get: Req { - .get(path) - } - } -} -// MARK: - /users/{username}/followers -extension Github.Users { - var followers: Followers { - Followers(path: path + "/follower") - } - struct Followers { - let path: String - var get: Req<[GitUserModel]> { - .get(path) - } - } -} +//import Foundation +//import SwiftUI +// +//enum Github {} +// +//// MARK: - /repos/{reponame} +//extension Github { +// static func repos(_ name: String) -> Repos { +// Repos(path: "/repos/\(name)") +// } +// struct Repos { +// let path: String +// var get: Req { +// .get(path) +// } +// } +//} +//// MARK: - /repos/{reponame}/issues/{issuenumber} +//extension Github.Repos { +// func issues(_ number: Int) -> Issues { +// Issues(path: path + "/issues/\(number)") +// } +// struct Issues { +// let path: String +// var get: Req { +// .get(path) +// } +// } +//} +//// MARK: - /repos/{reponame}/commits +//extension Github.Repos { +// var commits: Commits { +// Commits(path: path + "/commits", query: [("per_page", "100")]) +// } +// +// struct Commits { +// let path: String +// let query: [(String, String?)]? +// var get: Req<[CommitModel]> { +// .get(path, query: query) +// } +// } +//} +// +//// MARK: - /user +//extension Github { +// static var user: User { +// User() +// } +// struct User { +// let path: String = "/user" +// var get: Req { +// .get(path) +// } +// } +//} +//// MARK: - /user/following +//extension Github.User { +// var following: Following { +// Following() +// } +// struct Following { +// let path: String = "/user/following" +// var get: Req<[GitUserModel]> { +// .get(path) +// } +// } +//} +//// MARK: - /users/{username} +//extension Github { +// static func users(_ name: String) -> Users { +// Users(path: "/users/\(name)") +// } +// struct Users { +// let path: String +// var get: Req { +// .get(path) +// } +// } +//} +//// MARK: - /users/{username}/followers +//extension Github.Users { +// var followers: Followers { +// Followers(path: path + "/follower") +// } +// struct Followers { +// let path: String +// var get: Req<[GitUserModel]> { +// .get(path) +// } +// } +//} diff --git a/SwiftPamphletApp/GitHubAPI/Network/CCYRSSReq.swift b/SwiftPamphletApp/GitHubAPI/Network/CCYRSSReq.swift index d3b66a80f..ae549aa00 100644 --- a/SwiftPamphletApp/GitHubAPI/Network/CCYRSSReq.swift +++ b/SwiftPamphletApp/GitHubAPI/Network/CCYRSSReq.swift @@ -5,17 +5,17 @@ // Created by Ming Dai on 2021/12/20. // -import Foundation - -func RSSReq(_ urlStr: String) async throws -> String? { - guard let url = URL(string: urlStr) else { - fatalError("wrong url") - } - let req = URLRequest(url: url) - let (data, res) = try await URLSession.shared.data(for: req) - guard (res as? HTTPURLResponse)?.statusCode == 200 else { - return "" - } - let dataStr = String(data: data, encoding: .utf8) - return dataStr -} +//import Foundation +// +//func RSSReq(_ urlStr: String) async throws -> String? { +// guard let url = URL(string: urlStr) else { +// fatalError("wrong url") +// } +// let req = URLRequest(url: url) +// let (data, res) = try await URLSession.shared.data(for: req) +// guard (res as? HTTPURLResponse)?.statusCode == 200 else { +// return "" +// } +// let dataStr = String(data: data, encoding: .utf8) +// return dataStr +//} diff --git a/SwiftPamphletApp/GitHubAPI/VM/IssueVM.swift b/SwiftPamphletApp/GitHubAPI/VM/IssueVM.swift index 9fb9b3215..1d94ccbcf 100644 --- a/SwiftPamphletApp/GitHubAPI/VM/IssueVM.swift +++ b/SwiftPamphletApp/GitHubAPI/VM/IssueVM.swift @@ -9,135 +9,26 @@ import Foundation import Combine @Observable -final class IssueVM: APIVMable { - private var cancellables: [AnyCancellable] = [] - - @ObservationIgnored - public let repoName: String - @ObservationIgnored - public let issueNumber: Int +final class IssueVM { @ObservationIgnored public let guideName: String - - var issue: IssueModel - var comments: [IssueComment] var customIssues: [CustomIssuesModel] - var cIADs: [SPActiveDevelopersModel] // 开发者动态 - var errHint = false - var errMsg = "" // MARK: - APISev - private let apiSev: APISev - - private let errSj = PassthroughSubject() - - private let apIssueSj = PassthroughSubject() - private let apCommentsSj = PassthroughSubject() - - private let resIssueSj = PassthroughSubject() - private let resCommetsSj = PassthroughSubject<[IssueComment], Never>() enum IssueActionType { - case inInit, customIssues, ciads, update + case customIssues } typealias ActionType = IssueActionType // 可在定义doing函数时,通过参数类型指定,类型推导出来 func doing(_ somethinglike: IssueActionType) { switch somethinglike { - case .inInit: // 初始化 - apIssueSj.send(()) - apCommentsSj.send(()) case .customIssues: // 内容 customIssues = loadBundleJSONFile(guideName + ".json") - case .ciads: // 开发者动态 - cIADs = loadBundleJSONFile("developers.json") - case .update: // 更新 - apIssueSj.send(()) - apCommentsSj.send(()) } } - init(repoName: String = "", issueNumber: Int = 0, guideName: String = "") { - self.repoName = repoName - self.issueNumber = issueNumber - self.guideName = guideName - self.apiSev = APISev() - self.issue = IssueModel() - self.comments = [IssueComment]() + init(guideName: String = "") { self.customIssues = [CustomIssuesModel]() - self.cIADs = [SPActiveDevelopersModel]() - - // MARK: - 议题的信息获取 - let reqIssue = IssueRequest(repoName: repoName, issueNumber: issueNumber) - let resIssueSm = apIssueSj - .flatMap { [apiSev] in - apiSev.response(from: reqIssue) - .catch { [weak self] error -> Empty in - self?.errSj.send(error) - return .init() - } - } - .share() - .subscribe(resIssueSj) - let repIssueSm = resIssueSj - .assign(to: \.issue, on: self) - - // MARK: - 议题的留言获取 - let reqComments = IssueCommentsRequest(repoName: repoName, issueNumber: issueNumber) - let resCommentsSm = apCommentsSj - .flatMap { [apiSev] in - apiSev.response(from: reqComments) - .catch { [weak self] error -> Empty<[IssueComment], Never> in - self?.errSj.send(error) - return .init() - } - } - .share() - .subscribe(resCommetsSj) - let repCommentsSm = resCommetsSj - .assign(to: \.comments, on: self) - - // MARK: - 错误 - let errMsgSm = errSj - .map { err -> String in - err.message - } - .assign(to: \.errMsg, on: self) - let errHintSm = errSj - .map { _ in - true - } - .assign(to: \.errHint, on: self) - - cancellables += [ - resIssueSm, repIssueSm, - resCommentsSm, repCommentsSm, - errMsgSm, errHintSm - ] - } -} - -struct IssueCommentsRequest: APIReqType { - typealias Res = [IssueComment] - var repoName: String - var issueNumber: Int - var path: String { - return "/repos/\(repoName)/issues/\(issueNumber)/comments" - } - var qItems: [URLQueryItem]? { - return [ - .init(name: "per_page", value: "100") - ] - } -} - -struct IssueRequest: APIReqType { - typealias Res = IssueModel - var repoName: String - var issueNumber: Int - var path: String { - return "/repos/\(repoName)/issues/\(issueNumber)" - } - var qItems: [URLQueryItem]? { - return nil + self.guideName = guideName } }