Merge branch 'pr/159' into develop
# Conflicts: # ShadowsocksX-NG/Base.lproj/MainMenu.xib
This commit is contained in:
2
Podfile
2
Podfile
@ -6,7 +6,7 @@ target 'ShadowsocksX-NG' do
|
||||
use_frameworks!
|
||||
|
||||
# Pods for ShadowsocksX-NG
|
||||
pod 'Alamofire', '~> 4.0.1'
|
||||
pod 'Alamofire', '~> 4.2.0'
|
||||
pod "GCDWebServer", "~> 3.0"
|
||||
|
||||
target 'ShadowsocksX-NGTests' do
|
||||
|
10
Podfile.lock
10
Podfile.lock
@ -1,20 +1,20 @@
|
||||
PODS:
|
||||
- Alamofire (4.0.1)
|
||||
- Alamofire (4.2.0)
|
||||
- BRLOptionParser (0.3.1)
|
||||
- GCDWebServer (3.3.3):
|
||||
- GCDWebServer/Core (= 3.3.3)
|
||||
- GCDWebServer/Core (3.3.3)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Alamofire (~> 4.0.1)
|
||||
- Alamofire (~> 4.2.0)
|
||||
- BRLOptionParser (~> 0.3.1)
|
||||
- GCDWebServer (~> 3.0)
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Alamofire: 7682d43245de14874acd142ec137b144aa1dd335
|
||||
Alamofire: aa2e09d871c9160ac53c90e83c68064a94e3dfbe
|
||||
BRLOptionParser: a03256a8ff003ca1f5376c55f55f210e085a3958
|
||||
GCDWebServer: 1c39a1f0763e4eb492bee021e4270fce097d3555
|
||||
|
||||
PODFILE CHECKSUM: e675030dbd86de38216dc6c44e64ca1458be94bc
|
||||
PODFILE CHECKSUM: d717746ef98bb719d87cee4fc334a392005fd32e
|
||||
|
||||
COCOAPODS: 1.0.1
|
||||
COCOAPODS: 1.2.0.beta.1
|
||||
|
38
Pods/Alamofire/README.md
generated
38
Pods/Alamofire/README.md
generated
@ -55,8 +55,8 @@ In order to keep Alamofire focused specifically on core networking implementatio
|
||||
|
||||
## Requirements
|
||||
|
||||
- iOS 9.0+ / macOS 10.11+ / tvOS 9.0+ / watchOS 2.0+
|
||||
- Xcode 8.0+
|
||||
- iOS 8.0+ / macOS 10.10+ / tvOS 9.0+ / watchOS 2.0+
|
||||
- Xcode 8.1+
|
||||
- Swift 3.0+
|
||||
|
||||
## Migration Guides
|
||||
@ -130,13 +130,13 @@ If you prefer not to use either of the aforementioned dependency managers, you c
|
||||
|
||||
- Open up Terminal, `cd` into your top-level project directory, and run the following command "if" your project is not initialized as a git repository:
|
||||
|
||||
```bash
|
||||
```bash
|
||||
$ git init
|
||||
```
|
||||
|
||||
- Add Alamofire as a git [submodule](http://git-scm.com/docs/git-submodule) by running the following command:
|
||||
|
||||
```bash
|
||||
```bash
|
||||
$ git submodule add https://github.com/Alamofire/Alamofire.git
|
||||
```
|
||||
|
||||
@ -158,7 +158,7 @@ $ git submodule add https://github.com/Alamofire/Alamofire.git
|
||||
|
||||
- And that's it!
|
||||
|
||||
> The `Alamofire.framework` is automagically added as a target dependency, linked framework and embedded framework in a copy files build phase which is all you need to build on the simulator and a device.
|
||||
> The `Alamofire.framework` is automagically added as a target dependency, linked framework and embedded framework in a copy files build phase which is all you need to build on the simulator and a device.
|
||||
|
||||
---
|
||||
|
||||
@ -199,7 +199,7 @@ Alamofire contains five different response handlers by default including:
|
||||
// Response Handler - Unserialized Response
|
||||
func response(
|
||||
queue: DispatchQueue?,
|
||||
completionHandler: @escaping (DefaultDownloadResponse) -> Void)
|
||||
completionHandler: @escaping (DefaultDataResponse) -> Void)
|
||||
-> Self
|
||||
|
||||
// Response Data Handler - Serialized into Data
|
||||
@ -240,7 +240,7 @@ The `response` handler does NOT evaluate any of the response data. It merely for
|
||||
Alamofire.request("https://httpbin.org/get").response { response in
|
||||
print("Request: \(response.request)")
|
||||
print("Response: \(response.response)")
|
||||
print("Error: \(response.data)")
|
||||
print("Error: \(response.error)")
|
||||
|
||||
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
|
||||
print("Data: \(utf8Text)")
|
||||
@ -331,7 +331,7 @@ By default, Alamofire treats any completed request to be successful, regardless
|
||||
Alamofire.request("https://httpbin.org/get")
|
||||
.validate(statusCode: 200..<300)
|
||||
.validate(contentType: ["application/json"])
|
||||
.response { response in
|
||||
.responseData { response in
|
||||
switch response.result {
|
||||
case .success:
|
||||
print("Validation Successful")
|
||||
@ -360,7 +360,7 @@ Alamofire.request("https://httpbin.org/get").validate().responseJSON { response
|
||||
|
||||
Response Caching is handled on the system framework level by [`URLCache`](https://developer.apple.com/reference/foundation/urlcache). It provides a composite in-memory and on-disk cache and lets you manipulate the sizes of both the in-memory and on-disk portions.
|
||||
|
||||
> By default, Alamofire leverages the shared `URLCache`. In order to customize it, see the [Session Manager Configurations](#session-manager-configurations) section.
|
||||
> By default, Alamofire leverages the shared `URLCache`. In order to customize it, see the [Session Manager Configurations](#session-manager) section.
|
||||
|
||||
### HTTP Methods
|
||||
|
||||
@ -520,7 +520,7 @@ Alamofire.request("https://httpbin.org/headers", headers: headers).responseJSON
|
||||
}
|
||||
```
|
||||
|
||||
> For HTTP headers that do not change, it is recommended to set them on the `URLSessionConfiguration` so they are automatically applied to any `URLSessionTask` created by the underlying `URLSession`. For more information, see the [Session Manager Configurations](#session-manager-configurations) section.
|
||||
> For HTTP headers that do not change, it is recommended to set them on the `URLSessionConfiguration` so they are automatically applied to any `URLSessionTask` created by the underlying `URLSession`. For more information, see the [Session Manager Configurations](#session-manager) section.
|
||||
|
||||
The default Alamofire `SessionManager` provides a default set of headers for every `Request`. These include:
|
||||
|
||||
@ -528,7 +528,7 @@ The default Alamofire `SessionManager` provides a default set of headers for eve
|
||||
- `Accept-Language`, which defaults to up to the top 6 preferred languages on the system, formatted like `en;q=1.0`, per [RFC 7231 §5.3.5](https://tools.ietf.org/html/rfc7231#section-5.3.5).
|
||||
- `User-Agent`, which contains versioning information about the current app. For example: `iOS Example/1.0 (com.alamofire.iOS-Example; build:1; iOS 10.0.0) Alamofire/4.0.0`, per [RFC 7231 §5.5.3](https://tools.ietf.org/html/rfc7231#section-5.5.3).
|
||||
|
||||
If you need to customize these headers, a custom `URLSessionManagerConfiguration` should be created, the `defaultHTTPHeaders` property updated and the configuration applied to a new `SessionManager` instance.
|
||||
If you need to customize these headers, a custom `URLSessionConfiguration` should be created, the `defaultHTTPHeaders` property updated and the configuration applied to a new `SessionManager` instance.
|
||||
|
||||
### Authentication
|
||||
|
||||
@ -603,7 +603,7 @@ Alamofire.download("https://httpbin.org/image/png").responseData { response in
|
||||
}
|
||||
```
|
||||
|
||||
> The `Alamofire.download` APIs should also be used if you need to download data while your app is in the background. For more information, please see the [Session Manager Configurations](#session-manager-configurations) section.
|
||||
> The `Alamofire.download` APIs should also be used if you need to download data while your app is in the background. For more information, please see the [Session Manager Configurations](#session-manager) section.
|
||||
|
||||
#### Download File Destination
|
||||
|
||||
@ -623,7 +623,7 @@ let destination: DownloadRequest.DownloadFileDestination = { _, _ in
|
||||
Alamofire.download(urlString, to: destination).response { response in
|
||||
print(response)
|
||||
|
||||
if response.result.isSuccess, let imagePath = response.destinationURL?.path {
|
||||
if response.error == nil, let imagePath = response.destinationURL?.path {
|
||||
let image = UIImage(contentsOfFile: imagePath)
|
||||
}
|
||||
}
|
||||
@ -672,6 +672,8 @@ Alamofire.download("https://httpbin.org/image/png")
|
||||
|
||||
If a `DownloadRequest` is cancelled or interrupted, the underlying URL session may generate resume data for the active `DownloadRequest`. If this happens, the resume data can be re-used to restart the `DownloadRequest` where it left off. The resume data can be accessed through the download response, then reused when trying to restart the request.
|
||||
|
||||
> **IMPORTANT:** On the latest release of all the Apple platforms (iOS 10, macOS 10.12, tvOS 10, watchOS 3), `resumeData` is broken on background URL session configurations. There's an underlying bug in the `resumeData` generation logic where the data is written incorrectly and will always fail to resume the download. For more information about the bug and possible workarounds, please see this Stack Overflow [post](http://stackoverflow.com/a/39347461/1342462).
|
||||
|
||||
```swift
|
||||
class ImageRequestor {
|
||||
private var resumeData: Data?
|
||||
@ -711,7 +713,7 @@ class ImageRequestor {
|
||||
|
||||
When sending relatively small amounts of data to a server using JSON or URL encoded parameters, the `Alamofire.request` APIs are usually sufficient. If you need to send much larger amounts of data from a file URL or an `InputStream`, then the `Alamofire.upload` APIs are what you want to use.
|
||||
|
||||
> The `Alamofire.upload` APIs should also be used if you need to upload data while your app is in the background. For more information, please see the [Session Manager Configurations](#session-manager-configurations) section.
|
||||
> The `Alamofire.upload` APIs should also be used if you need to upload data while your app is in the background. For more information, please see the [Session Manager Configurations](#session-manager) section.
|
||||
|
||||
#### Uploading Data
|
||||
|
||||
@ -1289,8 +1291,12 @@ class OAuth2Handler: RequestAdapter, RequestRetrier {
|
||||
.responseJSON { [weak self] response in
|
||||
guard let strongSelf = self else { return }
|
||||
|
||||
if let json = response.result.value as? [String: String] {
|
||||
completion(true, json["access_token"], json["refresh_token"])
|
||||
if
|
||||
let json = response.result.value as? [String: Any],
|
||||
let accessToken = json["access_token"] as? String,
|
||||
let refreshToken = json["refresh_token"] as? String
|
||||
{
|
||||
completion(true, accessToken, refreshToken)
|
||||
} else {
|
||||
completion(false, nil, nil)
|
||||
}
|
||||
|
10
Pods/Alamofire/Source/AFError.swift
generated
10
Pods/Alamofire/Source/AFError.swift
generated
@ -132,6 +132,16 @@ public enum AFError: Error {
|
||||
case responseSerializationFailed(reason: ResponseSerializationFailureReason)
|
||||
}
|
||||
|
||||
// MARK: - Adapt Error
|
||||
|
||||
struct AdaptError: Error {
|
||||
let error: Error
|
||||
}
|
||||
|
||||
extension Error {
|
||||
var underlyingAdaptError: Error? { return (self as? AdaptError)?.error }
|
||||
}
|
||||
|
||||
// MARK: - Error Booleans
|
||||
|
||||
extension AFError {
|
||||
|
9
Pods/Alamofire/Source/Alamofire.swift
generated
9
Pods/Alamofire/Source/Alamofire.swift
generated
@ -222,6 +222,13 @@ public func download(
|
||||
/// If `destination` is not specified, the contents will remain in the temporary location determined by the
|
||||
/// underlying URL session.
|
||||
///
|
||||
/// On the latest release of all the Apple platforms (iOS 10, macOS 10.12, tvOS 10, watchOS 3), `resumeData` is broken
|
||||
/// on background URL session configurations. There's an underlying bug in the `resumeData` generation logic where the
|
||||
/// data is written incorrectly and will always fail to resume the download. For more information about the bug and
|
||||
/// possible workarounds, please refer to the following Stack Overflow post:
|
||||
///
|
||||
/// - http://stackoverflow.com/a/39347461/1342462
|
||||
///
|
||||
/// - parameter resumeData: The resume data. This is an opaque data blob produced by `URLSessionDownloadTask`
|
||||
/// when a task is cancelled. See `URLSession -downloadTask(withResumeData:)` for additional
|
||||
/// information.
|
||||
@ -435,6 +442,7 @@ public func upload(
|
||||
///
|
||||
/// - returns: The created `StreamRequest`.
|
||||
@discardableResult
|
||||
@available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
|
||||
public func stream(withHostName hostName: String, port: Int) -> StreamRequest {
|
||||
return SessionManager.default.stream(withHostName: hostName, port: port)
|
||||
}
|
||||
@ -449,6 +457,7 @@ public func stream(withHostName hostName: String, port: Int) -> StreamRequest {
|
||||
///
|
||||
/// - returns: The created `StreamRequest`.
|
||||
@discardableResult
|
||||
@available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
|
||||
public func stream(with netService: NetService) -> StreamRequest {
|
||||
return SessionManager.default.stream(with: netService)
|
||||
}
|
||||
|
62
Pods/Alamofire/Source/ParameterEncoding.swift
generated
62
Pods/Alamofire/Source/ParameterEncoding.swift
generated
@ -199,7 +199,39 @@ public struct URLEncoding: ParameterEncoding {
|
||||
var allowedCharacterSet = CharacterSet.urlQueryAllowed
|
||||
allowedCharacterSet.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
|
||||
|
||||
return string.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? string
|
||||
var escaped = ""
|
||||
|
||||
//==========================================================================================================
|
||||
//
|
||||
// Batching is required for escaping due to an internal bug in iOS 8.1 and 8.2. Encoding more than a few
|
||||
// hundred Chinese characters causes various malloc error crashes. To avoid this issue until iOS 8 is no
|
||||
// longer supported, batching MUST be used for encoding. This introduces roughly a 20% overhead. For more
|
||||
// info, please refer to:
|
||||
//
|
||||
// - https://github.com/Alamofire/Alamofire/issues/206
|
||||
//
|
||||
//==========================================================================================================
|
||||
|
||||
if #available(iOS 8.3, *) {
|
||||
escaped = string.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? string
|
||||
} else {
|
||||
let batchSize = 50
|
||||
var index = string.startIndex
|
||||
|
||||
while index != string.endIndex {
|
||||
let startIndex = index
|
||||
let endIndex = string.index(index, offsetBy: batchSize, limitedBy: string.endIndex) ?? string.endIndex
|
||||
let range = startIndex..<endIndex
|
||||
|
||||
let substring = string.substring(with: range)
|
||||
|
||||
escaped += substring.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? substring
|
||||
|
||||
index = endIndex
|
||||
}
|
||||
}
|
||||
|
||||
return escaped
|
||||
}
|
||||
|
||||
private func query(_ parameters: [String: Any]) -> String {
|
||||
@ -289,6 +321,34 @@ public struct JSONEncoding: ParameterEncoding {
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
/// Creates a URL request by encoding the JSON object and setting the resulting data on the HTTP body.
|
||||
///
|
||||
/// - parameter urlRequest: The request to apply the JSON object to.
|
||||
/// - parameter jsonObject: The JSON object to apply to the request.
|
||||
///
|
||||
/// - throws: An `Error` if the encoding process encounters an error.
|
||||
///
|
||||
/// - returns: The encoded request.
|
||||
public func encode(_ urlRequest: URLRequestConvertible, withJSONObject jsonObject: Any? = nil) throws -> URLRequest {
|
||||
var urlRequest = try urlRequest.asURLRequest()
|
||||
|
||||
guard let jsonObject = jsonObject else { return urlRequest }
|
||||
|
||||
do {
|
||||
let data = try JSONSerialization.data(withJSONObject: jsonObject, options: options)
|
||||
|
||||
if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
|
||||
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
}
|
||||
|
||||
urlRequest.httpBody = data
|
||||
} catch {
|
||||
throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))
|
||||
}
|
||||
|
||||
return urlRequest
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
97
Pods/Alamofire/Source/Request.swift
generated
97
Pods/Alamofire/Source/Request.swift
generated
@ -110,6 +110,9 @@ open class Request {
|
||||
/// The response received from the server, if any.
|
||||
open var response: HTTPURLResponse? { return task?.response as? HTTPURLResponse }
|
||||
|
||||
/// The number of times the request has been retried.
|
||||
open internal(set) var retryCount: UInt = 0
|
||||
|
||||
let originalTask: TaskConvertible?
|
||||
|
||||
var startTime: CFAbsoluteTime?
|
||||
@ -351,13 +354,25 @@ open class DataRequest: Request {
|
||||
let urlRequest: URLRequest
|
||||
|
||||
func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask {
|
||||
let urlRequest = try self.urlRequest.adapt(using: adapter)
|
||||
return queue.syncResult { session.dataTask(with: urlRequest) }
|
||||
do {
|
||||
let urlRequest = try self.urlRequest.adapt(using: adapter)
|
||||
return queue.syncResult { session.dataTask(with: urlRequest) }
|
||||
} catch {
|
||||
throw AdaptError(error: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
/// The request sent or to be sent to the server.
|
||||
open override var request: URLRequest? {
|
||||
if let request = super.request { return request }
|
||||
if let requestable = originalTask as? Requestable { return requestable.urlRequest }
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/// The progress of fetching the response data from the server for the request.
|
||||
open var progress: Progress { return dataDelegate.progress }
|
||||
|
||||
@ -438,22 +453,37 @@ open class DownloadRequest: Request {
|
||||
case resumeData(Data)
|
||||
|
||||
func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask {
|
||||
let task: URLSessionTask
|
||||
do {
|
||||
let task: URLSessionTask
|
||||
|
||||
switch self {
|
||||
case let .request(urlRequest):
|
||||
let urlRequest = try urlRequest.adapt(using: adapter)
|
||||
task = queue.syncResult { session.downloadTask(with: urlRequest) }
|
||||
case let .resumeData(resumeData):
|
||||
task = queue.syncResult { session.downloadTask(withResumeData: resumeData) }
|
||||
switch self {
|
||||
case let .request(urlRequest):
|
||||
let urlRequest = try urlRequest.adapt(using: adapter)
|
||||
task = queue.syncResult { session.downloadTask(with: urlRequest) }
|
||||
case let .resumeData(resumeData):
|
||||
task = queue.syncResult { session.downloadTask(withResumeData: resumeData) }
|
||||
}
|
||||
|
||||
return task
|
||||
} catch {
|
||||
throw AdaptError(error: error)
|
||||
}
|
||||
|
||||
return task
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
/// The request sent or to be sent to the server.
|
||||
open override var request: URLRequest? {
|
||||
if let request = super.request { return request }
|
||||
|
||||
if let downloadable = originalTask as? Downloadable, case let .request(urlRequest) = downloadable {
|
||||
return urlRequest
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/// The resume data of the underlying download task if available after a failure.
|
||||
open var resumeData: Data? { return downloadDelegate.resumeData }
|
||||
|
||||
@ -471,7 +501,7 @@ open class DownloadRequest: Request {
|
||||
NotificationCenter.default.post(
|
||||
name: Notification.Name.Task.DidCancel,
|
||||
object: self,
|
||||
userInfo: [Notification.Key.Task: task]
|
||||
userInfo: [Notification.Key.Task: task as Any]
|
||||
)
|
||||
}
|
||||
|
||||
@ -528,26 +558,42 @@ open class UploadRequest: DataRequest {
|
||||
case stream(InputStream, URLRequest)
|
||||
|
||||
func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask {
|
||||
let task: URLSessionTask
|
||||
do {
|
||||
let task: URLSessionTask
|
||||
|
||||
switch self {
|
||||
case let .data(data, urlRequest):
|
||||
let urlRequest = try urlRequest.adapt(using: adapter)
|
||||
task = queue.syncResult { session.uploadTask(with: urlRequest, from: data) }
|
||||
case let .file(url, urlRequest):
|
||||
let urlRequest = try urlRequest.adapt(using: adapter)
|
||||
task = queue.syncResult { session.uploadTask(with: urlRequest, fromFile: url) }
|
||||
case let .stream(_, urlRequest):
|
||||
let urlRequest = try urlRequest.adapt(using: adapter)
|
||||
task = queue.syncResult { session.uploadTask(withStreamedRequest: urlRequest) }
|
||||
switch self {
|
||||
case let .data(data, urlRequest):
|
||||
let urlRequest = try urlRequest.adapt(using: adapter)
|
||||
task = queue.syncResult { session.uploadTask(with: urlRequest, from: data) }
|
||||
case let .file(url, urlRequest):
|
||||
let urlRequest = try urlRequest.adapt(using: adapter)
|
||||
task = queue.syncResult { session.uploadTask(with: urlRequest, fromFile: url) }
|
||||
case let .stream(_, urlRequest):
|
||||
let urlRequest = try urlRequest.adapt(using: adapter)
|
||||
task = queue.syncResult { session.uploadTask(withStreamedRequest: urlRequest) }
|
||||
}
|
||||
|
||||
return task
|
||||
} catch {
|
||||
throw AdaptError(error: error)
|
||||
}
|
||||
|
||||
return task
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
/// The request sent or to be sent to the server.
|
||||
open override var request: URLRequest? {
|
||||
if let request = super.request { return request }
|
||||
|
||||
guard let uploadable = originalTask as? Uploadable else { return nil }
|
||||
|
||||
switch uploadable {
|
||||
case .data(_, let urlRequest), .file(_, let urlRequest), .stream(_, let urlRequest):
|
||||
return urlRequest
|
||||
}
|
||||
}
|
||||
|
||||
/// The progress of uploading the payload to the server for the upload request.
|
||||
open var uploadProgress: Progress { return uploadDelegate.uploadProgress }
|
||||
|
||||
@ -577,6 +623,7 @@ open class UploadRequest: DataRequest {
|
||||
#if !os(watchOS)
|
||||
|
||||
/// Specific type of `Request` that manages an underlying `URLSessionStreamTask`.
|
||||
@available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
|
||||
open class StreamRequest: Request {
|
||||
enum Streamable: TaskConvertible {
|
||||
case stream(hostName: String, port: Int)
|
||||
|
15
Pods/Alamofire/Source/Response.swift
generated
15
Pods/Alamofire/Source/Response.swift
generated
@ -38,13 +38,17 @@ public struct DefaultDataResponse {
|
||||
/// The error encountered while executing or validating the request.
|
||||
public let error: Error?
|
||||
|
||||
/// The timeline of the complete lifecycle of the request.
|
||||
public let timeline: Timeline
|
||||
|
||||
var _metrics: AnyObject?
|
||||
|
||||
init(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) {
|
||||
init(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?, timeline: Timeline = Timeline()) {
|
||||
self.request = request
|
||||
self.response = response
|
||||
self.data = data
|
||||
self.error = error
|
||||
self.timeline = timeline
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,7 +68,7 @@ public struct DataResponse<Value> {
|
||||
/// The result of response serialization.
|
||||
public let result: Result<Value>
|
||||
|
||||
/// The timeline of the complete lifecycle of the `Request`.
|
||||
/// The timeline of the complete lifecycle of the request.
|
||||
public let timeline: Timeline
|
||||
|
||||
var _metrics: AnyObject?
|
||||
@ -139,6 +143,9 @@ public struct DefaultDownloadResponse {
|
||||
/// The error encountered while executing or validating the request.
|
||||
public let error: Error?
|
||||
|
||||
/// The timeline of the complete lifecycle of the request.
|
||||
public let timeline: Timeline
|
||||
|
||||
var _metrics: AnyObject?
|
||||
|
||||
init(
|
||||
@ -147,7 +154,8 @@ public struct DefaultDownloadResponse {
|
||||
temporaryURL: URL?,
|
||||
destinationURL: URL?,
|
||||
resumeData: Data?,
|
||||
error: Error?)
|
||||
error: Error?,
|
||||
timeline: Timeline = Timeline())
|
||||
{
|
||||
self.request = request
|
||||
self.response = response
|
||||
@ -155,6 +163,7 @@ public struct DefaultDownloadResponse {
|
||||
self.destinationURL = destinationURL
|
||||
self.resumeData = resumeData
|
||||
self.error = error
|
||||
self.timeline = timeline
|
||||
}
|
||||
}
|
||||
|
||||
|
46
Pods/Alamofire/Source/ResponseSerialization.swift
generated
46
Pods/Alamofire/Source/ResponseSerialization.swift
generated
@ -84,6 +84,22 @@ public struct DownloadResponseSerializer<Value>: DownloadResponseSerializerProto
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Timeline
|
||||
|
||||
extension Request {
|
||||
var timeline: Timeline {
|
||||
let requestCompletedTime = self.endTime ?? CFAbsoluteTimeGetCurrent()
|
||||
let initialResponseTime = self.delegate.initialResponseTime ?? requestCompletedTime
|
||||
|
||||
return Timeline(
|
||||
requestStartTime: self.startTime ?? CFAbsoluteTimeGetCurrent(),
|
||||
initialResponseTime: initialResponseTime,
|
||||
requestCompletedTime: requestCompletedTime,
|
||||
serializationCompletedTime: CFAbsoluteTimeGetCurrent()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Default
|
||||
|
||||
extension DataRequest {
|
||||
@ -101,7 +117,8 @@ extension DataRequest {
|
||||
request: self.request,
|
||||
response: self.response,
|
||||
data: self.delegate.data,
|
||||
error: self.delegate.error
|
||||
error: self.delegate.error,
|
||||
timeline: self.timeline
|
||||
)
|
||||
|
||||
dataResponse.add(self.delegate.metrics)
|
||||
@ -136,22 +153,12 @@ extension DataRequest {
|
||||
self.delegate.error
|
||||
)
|
||||
|
||||
let requestCompletedTime = self.endTime ?? CFAbsoluteTimeGetCurrent()
|
||||
let initialResponseTime = self.delegate.initialResponseTime ?? requestCompletedTime
|
||||
|
||||
let timeline = Timeline(
|
||||
requestStartTime: self.startTime ?? CFAbsoluteTimeGetCurrent(),
|
||||
initialResponseTime: initialResponseTime,
|
||||
requestCompletedTime: requestCompletedTime,
|
||||
serializationCompletedTime: CFAbsoluteTimeGetCurrent()
|
||||
)
|
||||
|
||||
var dataResponse = DataResponse<T.SerializedObject>(
|
||||
request: self.request,
|
||||
response: self.response,
|
||||
data: self.delegate.data,
|
||||
result: result,
|
||||
timeline: timeline
|
||||
timeline: self.timeline
|
||||
)
|
||||
|
||||
dataResponse.add(self.delegate.metrics)
|
||||
@ -184,7 +191,8 @@ extension DownloadRequest {
|
||||
temporaryURL: self.downloadDelegate.temporaryURL,
|
||||
destinationURL: self.downloadDelegate.destinationURL,
|
||||
resumeData: self.downloadDelegate.resumeData,
|
||||
error: self.downloadDelegate.error
|
||||
error: self.downloadDelegate.error,
|
||||
timeline: self.timeline
|
||||
)
|
||||
|
||||
downloadResponse.add(self.delegate.metrics)
|
||||
@ -219,16 +227,6 @@ extension DownloadRequest {
|
||||
self.downloadDelegate.error
|
||||
)
|
||||
|
||||
let requestCompletedTime = self.endTime ?? CFAbsoluteTimeGetCurrent()
|
||||
let initialResponseTime = self.delegate.initialResponseTime ?? requestCompletedTime
|
||||
|
||||
let timeline = Timeline(
|
||||
requestStartTime: self.startTime ?? CFAbsoluteTimeGetCurrent(),
|
||||
initialResponseTime: initialResponseTime,
|
||||
requestCompletedTime: requestCompletedTime,
|
||||
serializationCompletedTime: CFAbsoluteTimeGetCurrent()
|
||||
)
|
||||
|
||||
var downloadResponse = DownloadResponse<T.SerializedObject>(
|
||||
request: self.request,
|
||||
response: self.response,
|
||||
@ -236,7 +234,7 @@ extension DownloadRequest {
|
||||
destinationURL: self.downloadDelegate.destinationURL,
|
||||
resumeData: self.downloadDelegate.resumeData,
|
||||
result: result,
|
||||
timeline: timeline
|
||||
timeline: self.timeline
|
||||
)
|
||||
|
||||
downloadResponse.add(self.delegate.metrics)
|
||||
|
70
Pods/Alamofire/Source/SessionDelegate.swift
generated
70
Pods/Alamofire/Source/SessionDelegate.swift
generated
@ -108,16 +108,53 @@ open class SessionDelegate: NSObject {
|
||||
#if !os(watchOS)
|
||||
|
||||
/// Overrides default behavior for URLSessionStreamDelegate method `urlSession(_:readClosedFor:)`.
|
||||
open var streamTaskReadClosed: ((URLSession, URLSessionStreamTask) -> Void)?
|
||||
@available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
|
||||
open var streamTaskReadClosed: ((URLSession, URLSessionStreamTask) -> Void)? {
|
||||
get {
|
||||
return _streamTaskReadClosed as? (URLSession, URLSessionStreamTask) -> Void
|
||||
}
|
||||
set {
|
||||
_streamTaskReadClosed = newValue
|
||||
}
|
||||
}
|
||||
|
||||
/// Overrides default behavior for URLSessionStreamDelegate method `urlSession(_:writeClosedFor:)`.
|
||||
open var streamTaskWriteClosed: ((URLSession, URLSessionStreamTask) -> Void)?
|
||||
@available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
|
||||
open var streamTaskWriteClosed: ((URLSession, URLSessionStreamTask) -> Void)? {
|
||||
get {
|
||||
return _streamTaskWriteClosed as? (URLSession, URLSessionStreamTask) -> Void
|
||||
}
|
||||
set {
|
||||
_streamTaskWriteClosed = newValue
|
||||
}
|
||||
}
|
||||
|
||||
/// Overrides default behavior for URLSessionStreamDelegate method `urlSession(_:betterRouteDiscoveredFor:)`.
|
||||
open var streamTaskBetterRouteDiscovered: ((URLSession, URLSessionStreamTask) -> Void)?
|
||||
@available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
|
||||
open var streamTaskBetterRouteDiscovered: ((URLSession, URLSessionStreamTask) -> Void)? {
|
||||
get {
|
||||
return _streamTaskBetterRouteDiscovered as? (URLSession, URLSessionStreamTask) -> Void
|
||||
}
|
||||
set {
|
||||
_streamTaskBetterRouteDiscovered = newValue
|
||||
}
|
||||
}
|
||||
|
||||
/// Overrides default behavior for URLSessionStreamDelegate method `urlSession(_:streamTask:didBecome:outputStream:)`.
|
||||
open var streamTaskDidBecomeInputAndOutputStreams: ((URLSession, URLSessionStreamTask, InputStream, OutputStream) -> Void)?
|
||||
@available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
|
||||
open var streamTaskDidBecomeInputAndOutputStreams: ((URLSession, URLSessionStreamTask, InputStream, OutputStream) -> Void)? {
|
||||
get {
|
||||
return _streamTaskDidBecomeInputStream as? (URLSession, URLSessionStreamTask, InputStream, OutputStream) -> Void
|
||||
}
|
||||
set {
|
||||
_streamTaskDidBecomeInputStream = newValue
|
||||
}
|
||||
}
|
||||
|
||||
var _streamTaskReadClosed: Any?
|
||||
var _streamTaskWriteClosed: Any?
|
||||
var _streamTaskBetterRouteDiscovered: Any?
|
||||
var _streamTaskDidBecomeInputStream: Any?
|
||||
|
||||
#endif
|
||||
|
||||
@ -166,17 +203,19 @@ open class SessionDelegate: NSObject {
|
||||
#endif
|
||||
|
||||
#if !os(watchOS)
|
||||
switch selector {
|
||||
case #selector(URLSessionStreamDelegate.urlSession(_:readClosedFor:)):
|
||||
return streamTaskReadClosed != nil
|
||||
case #selector(URLSessionStreamDelegate.urlSession(_:writeClosedFor:)):
|
||||
return streamTaskWriteClosed != nil
|
||||
case #selector(URLSessionStreamDelegate.urlSession(_:betterRouteDiscoveredFor:)):
|
||||
return streamTaskBetterRouteDiscovered != nil
|
||||
case #selector(URLSessionStreamDelegate.urlSession(_:streamTask:didBecome:outputStream:)):
|
||||
return streamTaskDidBecomeInputAndOutputStreams != nil
|
||||
default:
|
||||
break
|
||||
if #available(iOS 9.0, macOS 10.11, tvOS 9.0, *) {
|
||||
switch selector {
|
||||
case #selector(URLSessionStreamDelegate.urlSession(_:readClosedFor:)):
|
||||
return streamTaskReadClosed != nil
|
||||
case #selector(URLSessionStreamDelegate.urlSession(_:writeClosedFor:)):
|
||||
return streamTaskWriteClosed != nil
|
||||
case #selector(URLSessionStreamDelegate.urlSession(_:betterRouteDiscoveredFor:)):
|
||||
return streamTaskBetterRouteDiscovered != nil
|
||||
case #selector(URLSessionStreamDelegate.urlSession(_:streamTask:didBecome:outputStream:)):
|
||||
return streamTaskDidBecomeInputAndOutputStreams != nil
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -637,6 +676,7 @@ extension SessionDelegate: URLSessionDownloadDelegate {
|
||||
|
||||
#if !os(watchOS)
|
||||
|
||||
@available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
|
||||
extension SessionDelegate: URLSessionStreamDelegate {
|
||||
/// Tells the delegate that the read side of the connection has been closed.
|
||||
///
|
||||
|
175
Pods/Alamofire/Source/SessionManager.swift
generated
175
Pods/Alamofire/Source/SessionManager.swift
generated
@ -231,12 +231,14 @@ open class SessionManager {
|
||||
headers: HTTPHeaders? = nil)
|
||||
-> DataRequest
|
||||
{
|
||||
var originalRequest: URLRequest?
|
||||
|
||||
do {
|
||||
let urlRequest = try URLRequest(url: url, method: method, headers: headers)
|
||||
let encodedURLRequest = try encoding.encode(urlRequest, with: parameters)
|
||||
originalRequest = try URLRequest(url: url, method: method, headers: headers)
|
||||
let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters)
|
||||
return request(encodedURLRequest)
|
||||
} catch {
|
||||
return request(failedWith: error)
|
||||
return request(originalRequest, failedWith: error)
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,9 +250,11 @@ open class SessionManager {
|
||||
///
|
||||
/// - returns: The created `DataRequest`.
|
||||
open func request(_ urlRequest: URLRequestConvertible) -> DataRequest {
|
||||
var originalRequest: URLRequest?
|
||||
|
||||
do {
|
||||
let originalRequest = try urlRequest.asURLRequest()
|
||||
let originalTask = DataRequest.Requestable(urlRequest: originalRequest)
|
||||
originalRequest = try urlRequest.asURLRequest()
|
||||
let originalTask = DataRequest.Requestable(urlRequest: originalRequest!)
|
||||
|
||||
let task = try originalTask.task(session: session, adapter: adapter, queue: queue)
|
||||
let request = DataRequest(session: session, requestTask: .data(originalTask, task))
|
||||
@ -261,15 +265,29 @@ open class SessionManager {
|
||||
|
||||
return request
|
||||
} catch {
|
||||
return request(failedWith: error)
|
||||
return request(originalRequest, failedWith: error)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Private - Request Implementation
|
||||
|
||||
private func request(failedWith error: Error) -> DataRequest {
|
||||
let request = DataRequest(session: session, requestTask: .data(nil, nil), error: error)
|
||||
if startRequestsImmediately { request.resume() }
|
||||
private func request(_ urlRequest: URLRequest?, failedWith error: Error) -> DataRequest {
|
||||
var requestTask: Request.RequestTask = .data(nil, nil)
|
||||
|
||||
if let urlRequest = urlRequest {
|
||||
let originalTask = DataRequest.Requestable(urlRequest: urlRequest)
|
||||
requestTask = .data(originalTask, nil)
|
||||
}
|
||||
|
||||
let underlyingError = error.underlyingAdaptError ?? error
|
||||
let request = DataRequest(session: session, requestTask: requestTask, error: underlyingError)
|
||||
|
||||
if let retrier = retrier, error is AdaptError {
|
||||
allowRetrier(retrier, toRetry: request, with: underlyingError)
|
||||
} else {
|
||||
if startRequestsImmediately { request.resume() }
|
||||
}
|
||||
|
||||
return request
|
||||
}
|
||||
|
||||
@ -308,7 +326,7 @@ open class SessionManager {
|
||||
let encodedURLRequest = try encoding.encode(urlRequest, with: parameters)
|
||||
return download(encodedURLRequest, to: destination)
|
||||
} catch {
|
||||
return download(failedWith: error)
|
||||
return download(nil, to: destination, failedWith: error)
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,7 +352,7 @@ open class SessionManager {
|
||||
let urlRequest = try urlRequest.asURLRequest()
|
||||
return download(.request(urlRequest), to: destination)
|
||||
} catch {
|
||||
return download(failedWith: error)
|
||||
return download(nil, to: destination, failedWith: error)
|
||||
}
|
||||
}
|
||||
|
||||
@ -348,6 +366,13 @@ open class SessionManager {
|
||||
///
|
||||
/// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
|
||||
///
|
||||
/// On the latest release of all the Apple platforms (iOS 10, macOS 10.12, tvOS 10, watchOS 3), `resumeData` is broken
|
||||
/// on background URL session configurations. There's an underlying bug in the `resumeData` generation logic where the
|
||||
/// data is written incorrectly and will always fail to resume the download. For more information about the bug and
|
||||
/// possible workarounds, please refer to the following Stack Overflow post:
|
||||
///
|
||||
/// - http://stackoverflow.com/a/39347461/1342462
|
||||
///
|
||||
/// - parameter resumeData: The resume data. This is an opaque data blob produced by `URLSessionDownloadTask`
|
||||
/// when a task is cancelled. See `URLSession -downloadTask(withResumeData:)` for
|
||||
/// additional information.
|
||||
@ -372,23 +397,43 @@ open class SessionManager {
|
||||
{
|
||||
do {
|
||||
let task = try downloadable.task(session: session, adapter: adapter, queue: queue)
|
||||
let request = DownloadRequest(session: session, requestTask: .download(downloadable, task))
|
||||
let download = DownloadRequest(session: session, requestTask: .download(downloadable, task))
|
||||
|
||||
request.downloadDelegate.destination = destination
|
||||
download.downloadDelegate.destination = destination
|
||||
|
||||
delegate[task] = request
|
||||
delegate[task] = download
|
||||
|
||||
if startRequestsImmediately { request.resume() }
|
||||
if startRequestsImmediately { download.resume() }
|
||||
|
||||
return request
|
||||
return download
|
||||
} catch {
|
||||
return download(failedWith: error)
|
||||
return download(downloadable, to: destination, failedWith: error)
|
||||
}
|
||||
}
|
||||
|
||||
private func download(failedWith error: Error) -> DownloadRequest {
|
||||
let download = DownloadRequest(session: session, requestTask: .download(nil, nil), error: error)
|
||||
if startRequestsImmediately { download.resume() }
|
||||
private func download(
|
||||
_ downloadable: DownloadRequest.Downloadable?,
|
||||
to destination: DownloadRequest.DownloadFileDestination?,
|
||||
failedWith error: Error)
|
||||
-> DownloadRequest
|
||||
{
|
||||
var downloadTask: Request.RequestTask = .download(nil, nil)
|
||||
|
||||
if let downloadable = downloadable {
|
||||
downloadTask = .download(downloadable, nil)
|
||||
}
|
||||
|
||||
let underlyingError = error.underlyingAdaptError ?? error
|
||||
|
||||
let download = DownloadRequest(session: session, requestTask: downloadTask, error: underlyingError)
|
||||
download.downloadDelegate.destination = destination
|
||||
|
||||
if let retrier = retrier, error is AdaptError {
|
||||
allowRetrier(retrier, toRetry: download, with: underlyingError)
|
||||
} else {
|
||||
if startRequestsImmediately { download.resume() }
|
||||
}
|
||||
|
||||
return download
|
||||
}
|
||||
|
||||
@ -418,7 +463,7 @@ open class SessionManager {
|
||||
let urlRequest = try URLRequest(url: url, method: method, headers: headers)
|
||||
return upload(fileURL, with: urlRequest)
|
||||
} catch {
|
||||
return upload(failedWith: error)
|
||||
return upload(nil, failedWith: error)
|
||||
}
|
||||
}
|
||||
|
||||
@ -436,7 +481,7 @@ open class SessionManager {
|
||||
let urlRequest = try urlRequest.asURLRequest()
|
||||
return upload(.file(fileURL, urlRequest))
|
||||
} catch {
|
||||
return upload(failedWith: error)
|
||||
return upload(nil, failedWith: error)
|
||||
}
|
||||
}
|
||||
|
||||
@ -464,7 +509,7 @@ open class SessionManager {
|
||||
let urlRequest = try URLRequest(url: url, method: method, headers: headers)
|
||||
return upload(data, with: urlRequest)
|
||||
} catch {
|
||||
return upload(failedWith: error)
|
||||
return upload(nil, failedWith: error)
|
||||
}
|
||||
}
|
||||
|
||||
@ -482,7 +527,7 @@ open class SessionManager {
|
||||
let urlRequest = try urlRequest.asURLRequest()
|
||||
return upload(.data(data, urlRequest))
|
||||
} catch {
|
||||
return upload(failedWith: error)
|
||||
return upload(nil, failedWith: error)
|
||||
}
|
||||
}
|
||||
|
||||
@ -510,7 +555,7 @@ open class SessionManager {
|
||||
let urlRequest = try URLRequest(url: url, method: method, headers: headers)
|
||||
return upload(stream, with: urlRequest)
|
||||
} catch {
|
||||
return upload(failedWith: error)
|
||||
return upload(nil, failedWith: error)
|
||||
}
|
||||
}
|
||||
|
||||
@ -528,7 +573,7 @@ open class SessionManager {
|
||||
let urlRequest = try urlRequest.asURLRequest()
|
||||
return upload(.stream(stream, urlRequest))
|
||||
} catch {
|
||||
return upload(failedWith: error)
|
||||
return upload(nil, failedWith: error)
|
||||
}
|
||||
}
|
||||
|
||||
@ -614,6 +659,8 @@ open class SessionManager {
|
||||
let formData = MultipartFormData()
|
||||
multipartFormData(formData)
|
||||
|
||||
var tempFileURL: URL?
|
||||
|
||||
do {
|
||||
var urlRequestWithContentType = try urlRequest.asURLRequest()
|
||||
urlRequestWithContentType.setValue(formData.contentType, forHTTPHeaderField: "Content-Type")
|
||||
@ -637,6 +684,8 @@ open class SessionManager {
|
||||
let fileName = UUID().uuidString
|
||||
let fileURL = directoryURL.appendingPathComponent(fileName)
|
||||
|
||||
tempFileURL = fileURL
|
||||
|
||||
var directoryError: Error?
|
||||
|
||||
// Create directory inside serial queue to ensure two threads don't do this in parallel
|
||||
@ -652,16 +701,37 @@ open class SessionManager {
|
||||
|
||||
try formData.writeEncodedData(to: fileURL)
|
||||
|
||||
let upload = self.upload(fileURL, with: urlRequestWithContentType)
|
||||
|
||||
// Cleanup the temp file once the upload is complete
|
||||
upload.delegate.queue.addOperation {
|
||||
do {
|
||||
try FileManager.default.removeItem(at: fileURL)
|
||||
} catch {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
let encodingResult = MultipartFormDataEncodingResult.success(
|
||||
request: self.upload(fileURL, with: urlRequestWithContentType),
|
||||
request: upload,
|
||||
streamingFromDisk: true,
|
||||
streamFileURL: fileURL
|
||||
)
|
||||
|
||||
encodingCompletion?(encodingResult)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Cleanup the temp file in the event that the multipart form data encoding failed
|
||||
if let tempFileURL = tempFileURL {
|
||||
do {
|
||||
try FileManager.default.removeItem(at: tempFileURL)
|
||||
} catch {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
|
||||
DispatchQueue.main.async { encodingCompletion?(.failure(error)) }
|
||||
}
|
||||
}
|
||||
@ -684,13 +754,26 @@ open class SessionManager {
|
||||
|
||||
return upload
|
||||
} catch {
|
||||
return upload(failedWith: error)
|
||||
return upload(uploadable, failedWith: error)
|
||||
}
|
||||
}
|
||||
|
||||
private func upload(failedWith error: Error) -> UploadRequest {
|
||||
let upload = UploadRequest(session: session, requestTask: .upload(nil, nil), error: error)
|
||||
if startRequestsImmediately { upload.resume() }
|
||||
private func upload(_ uploadable: UploadRequest.Uploadable?, failedWith error: Error) -> UploadRequest {
|
||||
var uploadTask: Request.RequestTask = .upload(nil, nil)
|
||||
|
||||
if let uploadable = uploadable {
|
||||
uploadTask = .upload(uploadable, nil)
|
||||
}
|
||||
|
||||
let underlyingError = error.underlyingAdaptError ?? error
|
||||
let upload = UploadRequest(session: session, requestTask: uploadTask, error: underlyingError)
|
||||
|
||||
if let retrier = retrier, error is AdaptError {
|
||||
allowRetrier(retrier, toRetry: upload, with: underlyingError)
|
||||
} else {
|
||||
if startRequestsImmediately { upload.resume() }
|
||||
}
|
||||
|
||||
return upload
|
||||
}
|
||||
|
||||
@ -709,6 +792,7 @@ open class SessionManager {
|
||||
///
|
||||
/// - returns: The created `StreamRequest`.
|
||||
@discardableResult
|
||||
@available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
|
||||
open func stream(withHostName hostName: String, port: Int) -> StreamRequest {
|
||||
return stream(.stream(hostName: hostName, port: port))
|
||||
}
|
||||
@ -723,12 +807,14 @@ open class SessionManager {
|
||||
///
|
||||
/// - returns: The created `StreamRequest`.
|
||||
@discardableResult
|
||||
@available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
|
||||
open func stream(with netService: NetService) -> StreamRequest {
|
||||
return stream(.netService(netService))
|
||||
}
|
||||
|
||||
// MARK: Private - Stream Implementation
|
||||
|
||||
@available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
|
||||
private func stream(_ streamable: StreamRequest.Streamable) -> StreamRequest {
|
||||
do {
|
||||
let task = try streamable.task(session: session, adapter: adapter, queue: queue)
|
||||
@ -744,6 +830,7 @@ open class SessionManager {
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
|
||||
private func stream(failedWith error: Error) -> StreamRequest {
|
||||
let stream = StreamRequest(session: session, requestTask: .stream(nil, nil), error: error)
|
||||
if startRequestsImmediately { stream.resume() }
|
||||
@ -762,6 +849,7 @@ open class SessionManager {
|
||||
|
||||
request.delegate.task = task // resets all task delegate data
|
||||
|
||||
request.retryCount += 1
|
||||
request.startTime = CFAbsoluteTimeGetCurrent()
|
||||
request.endTime = nil
|
||||
|
||||
@ -769,8 +857,31 @@ open class SessionManager {
|
||||
|
||||
return true
|
||||
} catch {
|
||||
request.delegate.error = error
|
||||
request.delegate.error = error.underlyingAdaptError ?? error
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private func allowRetrier(_ retrier: RequestRetrier, toRetry request: Request, with error: Error) {
|
||||
DispatchQueue.utility.async { [weak self] in
|
||||
guard let strongSelf = self else { return }
|
||||
|
||||
retrier.should(strongSelf, retry: request, with: error) { shouldRetry, timeDelay in
|
||||
guard let strongSelf = self else { return }
|
||||
|
||||
guard shouldRetry else {
|
||||
if strongSelf.startRequestsImmediately { request.resume() }
|
||||
return
|
||||
}
|
||||
|
||||
let retrySucceeded = strongSelf.retry(request)
|
||||
|
||||
if retrySucceeded, let task = request.task {
|
||||
strongSelf.delegate[task] = request
|
||||
} else {
|
||||
if strongSelf.startRequestsImmediately { request.resume() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
48
Pods/Alamofire/Source/TaskDelegate.swift
generated
48
Pods/Alamofire/Source/TaskDelegate.swift
generated
@ -33,13 +33,16 @@ open class TaskDelegate: NSObject {
|
||||
/// The serial operation queue used to execute all operations after the task completes.
|
||||
open let queue: OperationQueue
|
||||
|
||||
/// The data returned by the server.
|
||||
public var data: Data? { return nil }
|
||||
|
||||
/// The error generated throughout the lifecyle of the task.
|
||||
public var error: Error?
|
||||
|
||||
var task: URLSessionTask? {
|
||||
didSet { reset() }
|
||||
}
|
||||
|
||||
var data: Data? { return nil }
|
||||
var error: Error?
|
||||
|
||||
var initialResponseTime: CFAbsoluteTime?
|
||||
var credential: URLCredential?
|
||||
var metrics: AnyObject? // URLSessionTaskMetrics
|
||||
@ -331,29 +334,30 @@ class DownloadTaskDelegate: TaskDelegate, URLSessionDownloadDelegate {
|
||||
{
|
||||
temporaryURL = location
|
||||
|
||||
if let destination = destination {
|
||||
let result = destination(location, downloadTask.response as! HTTPURLResponse)
|
||||
let destination = result.destinationURL
|
||||
let options = result.options
|
||||
guard
|
||||
let destination = destination,
|
||||
let response = downloadTask.response as? HTTPURLResponse
|
||||
else { return }
|
||||
|
||||
do {
|
||||
destinationURL = destination
|
||||
let result = destination(location, response)
|
||||
let destinationURL = result.destinationURL
|
||||
let options = result.options
|
||||
|
||||
if options.contains(.removePreviousFile) {
|
||||
if FileManager.default.fileExists(atPath: destination.path) {
|
||||
try FileManager.default.removeItem(at: destination)
|
||||
}
|
||||
}
|
||||
self.destinationURL = destinationURL
|
||||
|
||||
if options.contains(.createIntermediateDirectories) {
|
||||
let directory = destination.deletingLastPathComponent()
|
||||
try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true, attributes: nil)
|
||||
}
|
||||
|
||||
try FileManager.default.moveItem(at: location, to: destination)
|
||||
} catch {
|
||||
self.error = error
|
||||
do {
|
||||
if options.contains(.removePreviousFile), FileManager.default.fileExists(atPath: destinationURL.path) {
|
||||
try FileManager.default.removeItem(at: destinationURL)
|
||||
}
|
||||
|
||||
if options.contains(.createIntermediateDirectories) {
|
||||
let directory = destinationURL.deletingLastPathComponent()
|
||||
try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
|
||||
}
|
||||
|
||||
try FileManager.default.moveItem(at: location, to: destinationURL)
|
||||
} catch {
|
||||
self.error = error
|
||||
}
|
||||
}
|
||||
|
||||
|
10
Pods/Manifest.lock
generated
10
Pods/Manifest.lock
generated
@ -1,20 +1,20 @@
|
||||
PODS:
|
||||
- Alamofire (4.0.1)
|
||||
- Alamofire (4.2.0)
|
||||
- BRLOptionParser (0.3.1)
|
||||
- GCDWebServer (3.3.3):
|
||||
- GCDWebServer/Core (= 3.3.3)
|
||||
- GCDWebServer/Core (3.3.3)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Alamofire (~> 4.0.1)
|
||||
- Alamofire (~> 4.2.0)
|
||||
- BRLOptionParser (~> 0.3.1)
|
||||
- GCDWebServer (~> 3.0)
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Alamofire: 7682d43245de14874acd142ec137b144aa1dd335
|
||||
Alamofire: aa2e09d871c9160ac53c90e83c68064a94e3dfbe
|
||||
BRLOptionParser: a03256a8ff003ca1f5376c55f55f210e085a3958
|
||||
GCDWebServer: 1c39a1f0763e4eb492bee021e4270fce097d3555
|
||||
|
||||
PODFILE CHECKSUM: e675030dbd86de38216dc6c44e64ca1458be94bc
|
||||
PODFILE CHECKSUM: d717746ef98bb719d87cee4fc334a392005fd32e
|
||||
|
||||
COCOAPODS: 1.0.1
|
||||
COCOAPODS: 1.2.0.beta.1
|
||||
|
1197
Pods/Pods.xcodeproj/project.pbxproj
generated
1197
Pods/Pods.xcodeproj/project.pbxproj
generated
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,12 @@
|
||||
#ifdef __OBJC__
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#else
|
||||
#ifndef FOUNDATION_EXPORT
|
||||
#if defined(__cplusplus)
|
||||
#define FOUNDATION_EXPORT extern "C"
|
||||
#else
|
||||
#define FOUNDATION_EXPORT extern
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -1,4 +1,14 @@
|
||||
#ifdef __OBJC__
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#else
|
||||
#ifndef FOUNDATION_EXPORT
|
||||
#if defined(__cplusplus)
|
||||
#define FOUNDATION_EXPORT extern "C"
|
||||
#else
|
||||
#define FOUNDATION_EXPORT extern
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
FOUNDATION_EXPORT double AlamofireVersionNumber;
|
||||
|
@ -6,5 +6,6 @@ OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_ROOT = ${SRCROOT}
|
||||
PODS_TARGET_SRCROOT = ${PODS_ROOT}/Alamofire
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
|
||||
SKIP_INSTALL = YES
|
||||
|
2
Pods/Target Support Files/Alamofire/Info.plist
generated
2
Pods/Target Support Files/Alamofire/Info.plist
generated
@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.0.1</string>
|
||||
<string>4.2.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
@ -1,4 +1,12 @@
|
||||
#ifdef __OBJC__
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#else
|
||||
#ifndef FOUNDATION_EXPORT
|
||||
#if defined(__cplusplus)
|
||||
#define FOUNDATION_EXPORT extern "C"
|
||||
#else
|
||||
#define FOUNDATION_EXPORT extern
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -4,5 +4,6 @@ HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Priva
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_ROOT = ${SRCROOT}
|
||||
PODS_TARGET_SRCROOT = ${PODS_ROOT}/BRLOptionParser
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
|
||||
SKIP_INSTALL = YES
|
||||
|
@ -1,4 +1,12 @@
|
||||
#ifdef __OBJC__
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#else
|
||||
#ifndef FOUNDATION_EXPORT
|
||||
#if defined(__cplusplus)
|
||||
#define FOUNDATION_EXPORT extern "C"
|
||||
#else
|
||||
#define FOUNDATION_EXPORT extern
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -1,4 +1,14 @@
|
||||
#ifdef __OBJC__
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#else
|
||||
#ifndef FOUNDATION_EXPORT
|
||||
#if defined(__cplusplus)
|
||||
#define FOUNDATION_EXPORT extern "C"
|
||||
#else
|
||||
#define FOUNDATION_EXPORT extern
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#import "GCDWebServer.h"
|
||||
#import "GCDWebServerConnection.h"
|
||||
|
@ -6,5 +6,6 @@ OTHER_LDFLAGS = -l"z" -framework "SystemConfiguration"
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_ROOT = ${SRCROOT}
|
||||
PODS_TARGET_SRCROOT = ${PODS_ROOT}/GCDWebServer
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
|
||||
SKIP_INSTALL = YES
|
||||
|
@ -34,6 +34,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
</string>
|
||||
<key>License</key>
|
||||
<string>MIT</string>
|
||||
<key>Title</key>
|
||||
<string>Alamofire</string>
|
||||
<key>Type</key>
|
||||
@ -66,6 +68,8 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
</string>
|
||||
<key>License</key>
|
||||
<string>BSD</string>
|
||||
<key>Title</key>
|
||||
<string>GCDWebServer</string>
|
||||
<key>Type</key>
|
||||
|
@ -59,8 +59,13 @@ code_sign_if_enabled() {
|
||||
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
|
||||
# Use the current code_sign_identitiy
|
||||
echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
|
||||
echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements \"$1\""
|
||||
/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1"
|
||||
local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1""
|
||||
|
||||
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
|
||||
code_sign_cmd="$code_sign_cmd &"
|
||||
fi
|
||||
echo "$code_sign_cmd"
|
||||
eval "$code_sign_cmd"
|
||||
fi
|
||||
}
|
||||
|
||||
@ -91,3 +96,6 @@ if [[ "$CONFIGURATION" == "Release" ]]; then
|
||||
install_framework "$BUILT_PRODUCTS_DIR/Alamofire/Alamofire.framework"
|
||||
install_framework "$BUILT_PRODUCTS_DIR/GCDWebServer/GCDWebServer.framework"
|
||||
fi
|
||||
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
|
||||
wait
|
||||
fi
|
||||
|
@ -18,17 +18,14 @@ case "${TARGETED_DEVICE_FAMILY}" in
|
||||
2)
|
||||
TARGET_DEVICE_ARGS="--target-device ipad"
|
||||
;;
|
||||
3)
|
||||
TARGET_DEVICE_ARGS="--target-device tv"
|
||||
;;
|
||||
*)
|
||||
TARGET_DEVICE_ARGS="--target-device mac"
|
||||
;;
|
||||
esac
|
||||
|
||||
realpath() {
|
||||
DIRECTORY="$(cd "${1%/*}" && pwd)"
|
||||
FILENAME="${1##*/}"
|
||||
echo "$DIRECTORY/$FILENAME"
|
||||
}
|
||||
|
||||
install_resource()
|
||||
{
|
||||
if [[ "$1" = /* ]] ; then
|
||||
@ -70,7 +67,7 @@ EOM
|
||||
xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
|
||||
;;
|
||||
*.xcassets)
|
||||
ABSOLUTE_XCASSET_FILE=$(realpath "$RESOURCE_PATH")
|
||||
ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
|
||||
XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
|
||||
;;
|
||||
*)
|
||||
@ -93,7 +90,7 @@ then
|
||||
# Find all other xcassets (this unfortunately includes those of path pods and other targets).
|
||||
OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
|
||||
while read line; do
|
||||
if [[ $line != "`realpath $PODS_ROOT`*" ]]; then
|
||||
if [[ $line != "${PODS_ROOT}*" ]]; then
|
||||
XCASSET_FILES+=("$line")
|
||||
fi
|
||||
done <<<"$OTHER_XCASSETS"
|
||||
|
@ -1,4 +1,14 @@
|
||||
#ifdef __OBJC__
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#else
|
||||
#ifndef FOUNDATION_EXPORT
|
||||
#if defined(__cplusplus)
|
||||
#define FOUNDATION_EXPORT extern "C"
|
||||
#else
|
||||
#define FOUNDATION_EXPORT extern
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
FOUNDATION_EXPORT double Pods_ShadowsocksX_NGVersionNumber;
|
||||
|
@ -1,5 +1,5 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
|
||||
CODE_SIGN_IDENTITY =
|
||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/GCDWebServer"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/Frameworks'
|
||||
|
@ -1,5 +1,5 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
|
||||
CODE_SIGN_IDENTITY =
|
||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/GCDWebServer"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/Frameworks'
|
||||
|
@ -59,8 +59,13 @@ code_sign_if_enabled() {
|
||||
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
|
||||
# Use the current code_sign_identitiy
|
||||
echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
|
||||
echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements \"$1\""
|
||||
/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1"
|
||||
local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1""
|
||||
|
||||
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
|
||||
code_sign_cmd="$code_sign_cmd &"
|
||||
fi
|
||||
echo "$code_sign_cmd"
|
||||
eval "$code_sign_cmd"
|
||||
fi
|
||||
}
|
||||
|
||||
@ -82,3 +87,6 @@ strip_invalid_archs() {
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
|
||||
wait
|
||||
fi
|
||||
|
@ -18,17 +18,14 @@ case "${TARGETED_DEVICE_FAMILY}" in
|
||||
2)
|
||||
TARGET_DEVICE_ARGS="--target-device ipad"
|
||||
;;
|
||||
3)
|
||||
TARGET_DEVICE_ARGS="--target-device tv"
|
||||
;;
|
||||
*)
|
||||
TARGET_DEVICE_ARGS="--target-device mac"
|
||||
;;
|
||||
esac
|
||||
|
||||
realpath() {
|
||||
DIRECTORY="$(cd "${1%/*}" && pwd)"
|
||||
FILENAME="${1##*/}"
|
||||
echo "$DIRECTORY/$FILENAME"
|
||||
}
|
||||
|
||||
install_resource()
|
||||
{
|
||||
if [[ "$1" = /* ]] ; then
|
||||
@ -70,7 +67,7 @@ EOM
|
||||
xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
|
||||
;;
|
||||
*.xcassets)
|
||||
ABSOLUTE_XCASSET_FILE=$(realpath "$RESOURCE_PATH")
|
||||
ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
|
||||
XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
|
||||
;;
|
||||
*)
|
||||
@ -93,7 +90,7 @@ then
|
||||
# Find all other xcassets (this unfortunately includes those of path pods and other targets).
|
||||
OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
|
||||
while read line; do
|
||||
if [[ $line != "`realpath $PODS_ROOT`*" ]]; then
|
||||
if [[ $line != "${PODS_ROOT}*" ]]; then
|
||||
XCASSET_FILES+=("$line")
|
||||
fi
|
||||
done <<<"$OTHER_XCASSETS"
|
||||
|
@ -1,4 +1,14 @@
|
||||
#ifdef __OBJC__
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#else
|
||||
#ifndef FOUNDATION_EXPORT
|
||||
#if defined(__cplusplus)
|
||||
#define FOUNDATION_EXPORT extern "C"
|
||||
#else
|
||||
#define FOUNDATION_EXPORT extern
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
FOUNDATION_EXPORT double Pods_ShadowsocksX_NGTestsVersionNumber;
|
||||
|
@ -16,7 +16,7 @@
|
||||
<key>FooterText</key>
|
||||
<string>(The MIT License)
|
||||
|
||||
Copyright © 2013-2015 Stephen Celis (<stephen@stephencelis.com>)
|
||||
Copyright © 2013-2015 Stephen Celis (<stephen@stephencelis.com>)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
@ -37,6 +37,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
</string>
|
||||
<key>License</key>
|
||||
<string>MIT</string>
|
||||
<key>Title</key>
|
||||
<string>BRLOptionParser</string>
|
||||
<key>Type</key>
|
||||
|
@ -59,8 +59,13 @@ code_sign_if_enabled() {
|
||||
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
|
||||
# Use the current code_sign_identitiy
|
||||
echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
|
||||
echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements \"$1\""
|
||||
/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1"
|
||||
local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1""
|
||||
|
||||
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
|
||||
code_sign_cmd="$code_sign_cmd &"
|
||||
fi
|
||||
echo "$code_sign_cmd"
|
||||
eval "$code_sign_cmd"
|
||||
fi
|
||||
}
|
||||
|
||||
@ -82,3 +87,6 @@ strip_invalid_archs() {
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
|
||||
wait
|
||||
fi
|
||||
|
@ -18,17 +18,14 @@ case "${TARGETED_DEVICE_FAMILY}" in
|
||||
2)
|
||||
TARGET_DEVICE_ARGS="--target-device ipad"
|
||||
;;
|
||||
3)
|
||||
TARGET_DEVICE_ARGS="--target-device tv"
|
||||
;;
|
||||
*)
|
||||
TARGET_DEVICE_ARGS="--target-device mac"
|
||||
;;
|
||||
esac
|
||||
|
||||
realpath() {
|
||||
DIRECTORY="$(cd "${1%/*}" && pwd)"
|
||||
FILENAME="${1##*/}"
|
||||
echo "$DIRECTORY/$FILENAME"
|
||||
}
|
||||
|
||||
install_resource()
|
||||
{
|
||||
if [[ "$1" = /* ]] ; then
|
||||
@ -70,7 +67,7 @@ EOM
|
||||
xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
|
||||
;;
|
||||
*.xcassets)
|
||||
ABSOLUTE_XCASSET_FILE=$(realpath "$RESOURCE_PATH")
|
||||
ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
|
||||
XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
|
||||
;;
|
||||
*)
|
||||
@ -93,7 +90,7 @@ then
|
||||
# Find all other xcassets (this unfortunately includes those of path pods and other targets).
|
||||
OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
|
||||
while read line; do
|
||||
if [[ $line != "`realpath $PODS_ROOT`*" ]]; then
|
||||
if [[ $line != "${PODS_ROOT}*" ]]; then
|
||||
XCASSET_FILES+=("$line")
|
||||
fi
|
||||
done <<<"$OTHER_XCASSETS"
|
||||
|
@ -57,6 +57,8 @@ So after you quit the app, the ss-local maybe be still running.
|
||||
Added a manual mode which won't configure the system proxy settings.
|
||||
Then you could configure your apps to use socks5 proxy manual.
|
||||
|
||||
Added global Keyboard shortcut <kbd>⌃</kbd> + <kbd>⌘</kbd> + <kbd>P</kbd> to switch between `global` mode and `auto` mode.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions must be available on a separately named branch based on the latest version of the main branch develop.
|
||||
|
@ -430,7 +430,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0730;
|
||||
LastUpgradeCheck = 0730;
|
||||
LastUpgradeCheck = 0810;
|
||||
ORGANIZATIONNAME = qiuyuzhou;
|
||||
TargetAttributes = {
|
||||
9B0BFFE41D0460A70040E62B = {
|
||||
@ -543,7 +543,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
|
||||
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;
|
||||
};
|
||||
3545247EFCD033C3FA63EA6C /* [CP] Check Pods Manifest.lock */ = {
|
||||
@ -558,7 +558,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
|
||||
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;
|
||||
};
|
||||
3E819BD46B855EDB116A3C70 /* [CP] Copy Pods Resources */ = {
|
||||
@ -618,7 +618,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
|
||||
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;
|
||||
};
|
||||
D8C2D6AF002916F4095E15E3 /* [CP] Copy Pods Resources */ = {
|
||||
@ -768,6 +768,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
@ -778,8 +779,10 @@
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
@ -813,6 +816,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
@ -823,8 +827,10 @@
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
@ -843,6 +849,7 @@
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@ -850,6 +857,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = FE3237E9FB24D9B924A0E630 /* Pods-ShadowsocksX-NG.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
@ -877,6 +885,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = E9E9FB3855DA55D0710EE7BD /* Pods-ShadowsocksX-NG.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
LastUpgradeVersion = "0810"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@ -14,7 +14,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "79C040AFDDCE1BCBF6D8B5EB0B85887F"
|
||||
BlueprintIdentifier = "88E9EC28B8B46C3631E6B242B50F4442"
|
||||
BuildableName = "Alamofire.framework"
|
||||
BlueprintName = "Alamofire"
|
||||
ReferencedContainer = "container:Pods/Pods.xcodeproj">
|
||||
@ -28,7 +28,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "7AD154F318B10A340D705FD3003EAAC6"
|
||||
BlueprintIdentifier = "3CB2B8006B2B1ACAF9ADCA1DC82E2290"
|
||||
BuildableName = "libBRLOptionParser.a"
|
||||
BlueprintName = "BRLOptionParser"
|
||||
ReferencedContainer = "container:Pods/Pods.xcodeproj">
|
||||
@ -42,7 +42,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F69966EE760BB16DE7009DBE04D8B18D"
|
||||
BlueprintIdentifier = "76AB1BA247F8CB57FCB2BA6577D40FE6"
|
||||
BuildableName = "Pods_ShadowsocksX_NG.framework"
|
||||
BlueprintName = "Pods-ShadowsocksX-NG"
|
||||
ReferencedContainer = "container:Pods/Pods.xcodeproj">
|
||||
@ -56,7 +56,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "9D7253CF594B2D7CB8127F7CCAFF916F"
|
||||
BlueprintIdentifier = "339CC546E4A1696296EFEDC2FA79ADE0"
|
||||
BuildableName = "Pods_ShadowsocksX_NGTests.framework"
|
||||
BlueprintName = "Pods-ShadowsocksX-NGTests"
|
||||
ReferencedContainer = "container:Pods/Pods.xcodeproj">
|
||||
@ -70,7 +70,7 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "3F0FDAFB5467946C22EE9F2EC643E2B0"
|
||||
BlueprintIdentifier = "05800FAF969AA3CD7F8AEB1C36988B53"
|
||||
BuildableName = "libPods-proxy_conf_helper.a"
|
||||
BlueprintName = "Pods-proxy_conf_helper"
|
||||
ReferencedContainer = "container:Pods/Pods.xcodeproj">
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
LastUpgradeVersion = "0810"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
LastUpgradeVersion = "0810"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
import Carbon
|
||||
|
||||
@NSApplicationMain
|
||||
class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDelegate {
|
||||
@ -19,6 +19,10 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
||||
var editUserRulesWinCtrl: UserRulesController!
|
||||
var httpPreferencesWinCtrl : HTTPPreferencesWindowController!
|
||||
|
||||
let keyCode = kVK_ANSI_P
|
||||
let modifierKeys = cmdKey+controlKey
|
||||
var hotKeyRef: EventHotKeyRef?
|
||||
|
||||
var launchAtLoginController: LaunchAtLoginController = LaunchAtLoginController()
|
||||
|
||||
@IBOutlet weak var window: NSWindow!
|
||||
@ -42,6 +46,22 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
||||
|
||||
@IBOutlet weak var lanchAtLoginMenuItem: NSMenuItem!
|
||||
|
||||
@IBOutlet weak var hudWindow: NSPanel!
|
||||
@IBOutlet weak var panelView: NSView!
|
||||
@IBOutlet weak var isNameTextField: NSTextField!
|
||||
|
||||
let kHudFadeInDuration: Double = 0.25
|
||||
let kHudFadeOutDuration: Double = 0.5
|
||||
let kHudDisplayDuration: Double = 2.0
|
||||
|
||||
let kHudAlphaValue: CGFloat = 0.75
|
||||
let kHudCornerRadius: CGFloat = 18.0
|
||||
let kHudHorizontalMargin: CGFloat = 30
|
||||
let kHudHeight: CGFloat = 90.0
|
||||
|
||||
var timerToFadeOut: Timer? = nil
|
||||
var fadingOut: Bool = false
|
||||
|
||||
var statusItem: NSStatusItem!
|
||||
|
||||
static let StatusItemIconWidth:CGFloat = 20
|
||||
@ -137,8 +157,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
||||
userNote.subtitle = "By Handle SS URL".localized
|
||||
}
|
||||
userNote.informativeText = "Host: \(profile.serverHost)"
|
||||
" Port: \(profile.serverPort)"
|
||||
" Encription Method: \(profile.method)".localized
|
||||
//" Port: \(profile.serverPort)"
|
||||
//" Encription Method: \(profile.method)".localized
|
||||
userNote.soundName = NSUserNotificationDefaultSoundName
|
||||
|
||||
NSUserNotificationCenter.default
|
||||
@ -167,6 +187,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
||||
ProxyConfHelper.startMonitorPAC()
|
||||
applyConfig()
|
||||
SyncSSLocal()
|
||||
|
||||
// Register global hotkey
|
||||
registerHotkey()
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ aNotification: Notification) {
|
||||
@ -174,6 +197,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
||||
StopSSLocal()
|
||||
StopPrivoxy()
|
||||
ProxyConfHelper.disableProxy()
|
||||
if let ref = hotKeyRef { UnregisterEventHotKey(ref) }
|
||||
}
|
||||
|
||||
func applyConfig() {
|
||||
@ -198,6 +222,63 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Hotkey Methods
|
||||
func registerHotkey() -> Void {
|
||||
var gMyHotKeyID = EventHotKeyID()
|
||||
gMyHotKeyID.signature = OSType(fourCharCodeFrom(string: "sxng"))
|
||||
gMyHotKeyID.id = UInt32(keyCode)
|
||||
|
||||
var eventType = EventTypeSpec()
|
||||
eventType.eventClass = OSType(kEventClassKeyboard)
|
||||
eventType.eventKind = OSType(kEventHotKeyPressed)
|
||||
|
||||
// Void pointer to `self`:
|
||||
let context = Unmanaged.passUnretained(self).toOpaque()
|
||||
|
||||
// Install handler.
|
||||
InstallEventHandler(GetApplicationEventTarget(), {(nextHanlder, theEvent, userContext) -> OSStatus in
|
||||
// Extract pointer to `self` from void pointer:
|
||||
let mySelf = Unmanaged<AppDelegate>.fromOpaque(userContext!).takeUnretainedValue()
|
||||
|
||||
switch Globals.proxyType {
|
||||
case .pac:
|
||||
Globals.proxyType = .global
|
||||
UserDefaults.standard.setValue("global", forKey: "ShadowsocksRunningMode")
|
||||
mySelf.isNameTextField.stringValue = "Gobal Mode"
|
||||
mySelf.updateRunningModeMenu()
|
||||
mySelf.applyConfig()
|
||||
case .global:
|
||||
Globals.proxyType = .pac
|
||||
UserDefaults.standard.setValue("auto", forKey: "ShadowsocksRunningMode")
|
||||
mySelf.isNameTextField.stringValue = "Auto Mode"
|
||||
mySelf.updateRunningModeMenu()
|
||||
mySelf.applyConfig()
|
||||
}
|
||||
|
||||
mySelf.fadeInHud()
|
||||
|
||||
return noErr
|
||||
}, 1, &eventType, context, nil)
|
||||
|
||||
// Register hotkey.
|
||||
RegisterEventHotKey(UInt32(keyCode),
|
||||
UInt32(modifierKeys),
|
||||
gMyHotKeyID,
|
||||
GetApplicationEventTarget(),
|
||||
0,
|
||||
&hotKeyRef)
|
||||
}
|
||||
|
||||
func fourCharCodeFrom(string: String) -> FourCharCode {
|
||||
assert(string.characters.count == 4, "String length must be 4")
|
||||
var result: FourCharCode = 0
|
||||
for char in string.utf16 {
|
||||
result = (result << 8) + FourCharCode(char)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// MARK: - UI Methods
|
||||
@IBAction func toggleRunning(_ sender: NSMenuItem) {
|
||||
let defaults = UserDefaults.standard
|
||||
var isOn = defaults.bool(forKey: "ShadowsocksOn")
|
||||
@ -531,3 +612,93 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
||||
}
|
||||
}
|
||||
|
||||
extension AppDelegate {
|
||||
func fadeInHud() -> Void {
|
||||
if timerToFadeOut != nil {
|
||||
timerToFadeOut?.invalidate()
|
||||
timerToFadeOut = nil
|
||||
}
|
||||
|
||||
fadingOut = false
|
||||
|
||||
hudWindow.orderFrontRegardless()
|
||||
|
||||
CATransaction.begin()
|
||||
CATransaction.setAnimationDuration(kHudFadeInDuration)
|
||||
CATransaction.setCompletionBlock { self.didFadeIn() }
|
||||
panelView.layer?.opacity = 1.0
|
||||
CATransaction.commit()
|
||||
}
|
||||
|
||||
func didFadeIn() -> Void {
|
||||
timerToFadeOut = Timer.scheduledTimer(
|
||||
timeInterval: kHudDisplayDuration,
|
||||
target: self,
|
||||
selector: #selector(fadeOutHud),
|
||||
userInfo: nil,
|
||||
repeats: false)
|
||||
}
|
||||
|
||||
func fadeOutHud() -> Void {
|
||||
fadingOut = true
|
||||
|
||||
CATransaction.begin()
|
||||
CATransaction.setAnimationDuration(kHudFadeOutDuration)
|
||||
CATransaction.setCompletionBlock { self.didFadeOut() }
|
||||
panelView.layer?.opacity = 0.0
|
||||
CATransaction.commit()
|
||||
}
|
||||
|
||||
func didFadeOut() -> Void {
|
||||
if fadingOut {
|
||||
self.hudWindow.orderOut(nil)
|
||||
}
|
||||
fadingOut = false
|
||||
}
|
||||
|
||||
func setupHud() -> Void {
|
||||
isNameTextField.stringValue = "Global Mode"
|
||||
isNameTextField.sizeToFit()
|
||||
|
||||
var labelFrame: CGRect = isNameTextField.frame
|
||||
var hudWindowFrame: CGRect = hudWindow.frame
|
||||
hudWindowFrame.size.width = labelFrame.size.width + kHudHorizontalMargin * 2
|
||||
hudWindowFrame.size.height = kHudHeight
|
||||
|
||||
let screenRect: NSRect = NSScreen.screens()![0].visibleFrame
|
||||
hudWindowFrame.origin.x = (screenRect.size.width - hudWindowFrame.size.width) / 2
|
||||
hudWindowFrame.origin.y = (screenRect.size.height - hudWindowFrame.size.height) / 2
|
||||
hudWindow.setFrame(hudWindowFrame, display: true)
|
||||
|
||||
var viewFrame: NSRect = hudWindowFrame;
|
||||
viewFrame.origin.x = 0
|
||||
viewFrame.origin.y = 0
|
||||
panelView.frame = viewFrame
|
||||
|
||||
labelFrame.origin.x = kHudHorizontalMargin
|
||||
labelFrame.origin.y = (hudWindowFrame.size.height - labelFrame.size.height) / 2
|
||||
isNameTextField.frame = labelFrame
|
||||
}
|
||||
|
||||
func initUIComponent() -> Void {
|
||||
hudWindow.isOpaque = false
|
||||
hudWindow.backgroundColor = .clear
|
||||
hudWindow.level = Int(CGWindowLevelForKey(.utilityWindow)) + 1000
|
||||
hudWindow.styleMask = .borderless
|
||||
hudWindow.hidesOnDeactivate = false
|
||||
hudWindow.collectionBehavior = .canJoinAllSpaces
|
||||
|
||||
let viewLayer: CALayer = CALayer()
|
||||
viewLayer.backgroundColor = CGColor.init(red: 0.05, green: 0.05, blue: 0.05, alpha: kHudAlphaValue)
|
||||
viewLayer.cornerRadius = kHudCornerRadius
|
||||
panelView.wantsLayer = true
|
||||
panelView.layer = viewLayer
|
||||
panelView.layer?.opacity = 0.0
|
||||
|
||||
setupHud()
|
||||
}
|
||||
|
||||
override func awakeFromNib() {
|
||||
initUIComponent()
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11201" systemVersion="16B2548a" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11542" systemVersion="16B2555" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11201"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11542"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||
@ -14,13 +15,15 @@
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="ShadowsocksX_NG" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="RunningStatusMenuItem" destination="fzk-mE-CEV" id="R4x-gK-Qcw"/>
|
||||
<outlet property="autoModeMenuItem" destination="r07-Gu-aEz" id="9aH-pQ-Rgi"/>
|
||||
<outlet property="exportAllServerProfileItem" destination="6k0-gn-DQv" id="W2x-96-ISj"/>
|
||||
<outlet property="globalModeMenuItem" destination="Mw3-Jm-eXA" id="ar5-Yx-3ze"/>
|
||||
<outlet property="importBunchJsonFileItem" destination="T9g-gy-gvv" id="vua-jg-YWe"/>
|
||||
<outlet property="lanchAtLoginMenuItem" destination="eUq-p7-ICK" id="q3D-7x-0db"/>
|
||||
<outlet property="hudWindow" destination="QWV-F6-ac1" id="K6D-a4-oqE"/>
|
||||
<outlet property="isNameTextField" destination="rUN-Nq-HDb" id="ayK-aM-rSa"/>
|
||||
<outlet property="manualModeMenuItem" destination="8PR-gs-c5N" id="9qz-mU-5kt"/>
|
||||
<outlet property="panelView" destination="rai-SH-9tZ" id="5aU-ld-rWb"/>
|
||||
<outlet property="proxyMenuItem" destination="diI-fB-Rss" id="Qjk-9U-3Qy"/>
|
||||
<outlet property="runningStatusMenuItem" destination="fzk-mE-CEV" id="Vwm-Rg-Ykn"/>
|
||||
<outlet property="scanQRCodeMenuItem" destination="Qe6-bF-paT" id="XHa-pa-nCa"/>
|
||||
@ -185,7 +188,7 @@
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
<point key="canvasLocation" x="22" y="89"/>
|
||||
<point key="canvasLocation" x="-2367" y="-139"/>
|
||||
</menu>
|
||||
<menu id="2oY-e9-q1Z">
|
||||
<items>
|
||||
@ -199,6 +202,30 @@
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
</items>
|
||||
<point key="canvasLocation" x="-2113" y="-132"/>
|
||||
</menu>
|
||||
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" oneShot="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="QWV-F6-ac1" customClass="NSPanel">
|
||||
<windowStyleMask key="styleMask" closable="YES" miniaturizable="YES" resizable="YES" utility="YES"/>
|
||||
<rect key="contentRect" x="139" y="81" width="200" height="100"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
|
||||
<value key="minSize" type="size" width="200" height="100"/>
|
||||
<value key="maxSize" type="size" width="200" height="100"/>
|
||||
<view key="contentView" id="rai-SH-9tZ" userLabel="Panel View">
|
||||
<rect key="frame" x="0.0" y="0.0" width="200" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="162" translatesAutoresizingMaskIntoConstraints="NO" id="rUN-Nq-HDb" userLabel="Is Name">
|
||||
<rect key="frame" x="17" y="33" width="166" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="center" title="Label" usesSingleLineMode="YES" id="jcH-j9-Xl3">
|
||||
<font key="font" metaFont="system" size="24"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" name="alternateSelectedControlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
</view>
|
||||
<point key="canvasLocation" x="-2357" y="172"/>
|
||||
</window>
|
||||
</objects>
|
||||
</document>
|
||||
|
@ -51,7 +51,7 @@ class ServerProfileManager: NSObject {
|
||||
|
||||
if activeProfileId != nil {
|
||||
defaults.set(activeProfileId, forKey: "ActiveServerProfileId")
|
||||
writeSSLocalConfFile((getActiveProfile()?.toJsonConfig())!)
|
||||
_ = writeSSLocalConfFile((getActiveProfile()?.toJsonConfig())!)
|
||||
} else {
|
||||
defaults.removeObject(forKey: "ActiveServerProfileId")
|
||||
removeSSLocalConfFile()
|
||||
|
@ -23,3 +23,12 @@ extension Data {
|
||||
return hexBytes.joined(separator: "")
|
||||
}
|
||||
}
|
||||
|
||||
enum ProxyType {
|
||||
case pac
|
||||
case global
|
||||
}
|
||||
|
||||
struct Globals {
|
||||
static var proxyType = ProxyType.pac
|
||||
}
|
||||
|
@ -44,9 +44,9 @@
|
||||
|
||||
"Turn Shadowsocks On" = "打开 Shadowsocks";
|
||||
|
||||
"Proxy - Auto By PAC" = "代理 - PAC自动";
|
||||
"Proxy - Auto By PAC" = "代理 - PAC自动(⌃⌘P)";
|
||||
|
||||
"Proxy - Global" = "代理 - 全局";
|
||||
"Proxy - Global" = "代理 - 全局(⌃⌘P)";
|
||||
|
||||
"Proxy - Manual" = "代理 - 手动";
|
||||
|
||||
|
Reference in New Issue
Block a user