Manager

/***
Responsible for creating and managing 'Request' objects, as well as their underlying 'NSURLSession'.
*/

public class Manager {
    // MARK: - Properties
    /**
        A shared instance of 'Manager', used by top-
        level Alamofire request for any ad hoc request
    */
    public static let sharedInstance = {
        ket configuration = NSURLSessionConfiguration, defaultSessionConfiguration()
        configuration.HTTPAdditionalHeaders = Manager.defaultHTTPHeaders

        return Manager(configuration: configuration)
    }()

    /**
        Creates default values for the "Accept-Encoding" ...
    */
    public static let defaultHTTPHeaders: [String: String] = {

    }()

    let queue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL)

    // The underlying session
    public let session: NSURLSession

    // The session delegate handling all the task and 
    // session delegate callbacks.
    public let delegate: SessionDelegate

    // Whether to start requests immediately after 
    // being constructed. 'true' by default
    public var startRequestsImmediately: Bool = true

    /**

    */
    public var backgroundCompletionHandler: (() -> Void)?

    // MARK: - Lifecycle
    public init(configuration: NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: SessionDelegate = SessionDelegate(), serverTrustPolicyManager: ServerTrustPolicyManager? = nil) {
        self.delegate = delegate
        self.session = NSURLSession(configuration: configuration, delegate:delegate, delegateQueue:nil)

        commonInit(serverTrustPolicyManager: serverTrustPolicyManager)
    }

    public init?(session: NSURLSession, delegate:SessionDelegate, serverTrustPolicyManager: ServerTrustPolicyManager? = nil) {
        self.delegate = delegate
        self.session = session

        guard delegate === session.delegate else {
            return nil
        }

        commonInit(serverTrustPolicyManager: serverTrustPolicyManager)
    }

    private func commonInit(serverTrustPolicyManager serverTrustPolicyManager: ServerTrustPolicyManager?) {
        session.serverTrustPolicyManager = serverTrustPolicyManager

        delegate.sessionDidFinishEventsForBackgroundURLSession = { [weak self] session in
            guard let strongSelf = self else { return }
            dispatch_async(dispatch_get_main_queue()) {
                strongSelf.backgroundCompletionHandler?()
            }
        }
    }

    deinit {
        session.invalidateAndCancel()
    }

    /**
        Creates a request fro the specified method, URL 
        string, parameters, parameter encoding and 
        headers.
    */
    public func request(method: Method, _ URLString: URLStringConvertible, parameter: ParameterEncoding = .URL, headers: [String: String]? = nil) ->Request {
        let mutableURLRequest = URLRequest(method, URLString, headers: headers)
        let encodedURLRequest = encoding.encode(mutableURLRequest, parameters:parameters).0

        return request(encodedURLRequest)
    }

    /**
        Creates a request for the specified URL request
    */
    public func request(URLRequest: URLRequestConvertible) -> Request {
        var dataTask: NSURLSessionDataTask!
        dispatch_sync(queue) {
          dataTask = self.session.dataTaskWithRequest(URLRequest.URLRequest)
        }

        let request = Request(session: session, task: dataTask)
        delegate[request.delegate.task] = request.delegate

        if startRequestsImmediately {
            request.resume()
        }

        return request
    }

    // MARK: - SessionDelegate
    /**
        Responsible for handling all delegate callbacks for the underlying session.
    */
    public final class SessionDelegate: NSObject, NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate {
        private var subdelegates: [Int: Request.TaskDelegate] = [:]
        private let subdelegateQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT)

        subscript(task: NSURLSessionTask) -> Request.TaskDelegate? {
            get {
                var subdelegate: Request.TaskDelegate?
                dispatch_sync(subdelegateQueue) { subdelegate = self.subdelegates[task.taskIdentifier] }

                return subdelegate
            }

            set {
                dispatch_barrier_async(subdelegateQueue) { self.subdelegates[task.taskIdentifier] = newValue }
            }
        }

        /**
            Initializes the `SessionDelegate` instance.
            - returns: The new `SessionDelegate` instance.
        */
        public override init() {
            super.init()
        }

        // MARK: - NSURLSessionDelegate
        // MARK: Override Closures
        /// Overrides default behavior for NSURLSessionDelegate method `URLSession:didBecomeInvalidWithError:`.
        public var sessionDidBecomeInvalidWithError: ((NSURLSession, NSError?) -> Void)?

        /// Overrides default behavior for NSURLSessionDelegate method `URLSession:didReceiveChallenge:completionHandler:`.
        public var sessionDidReceiveChallenge: ((NSURLSession, NSURLAuthenticationChallenge) -> (NSURLSessionAuthChallengeDisposition, NSURLCredential?))?

        /// Overrides default behavior for NSURLSessionDelegate method `URLSessionDidFinishEventsForBackgroundURLSession:`.
        public var sessionDidFinishEventsForBackgroundURLSession: ((NSURLSession) -> Void)?

        // MARK: Delegate Methods

        /**
            Tells the delegate that the session has been invalidated.
            - parameter session: The session object that was invalidated.
            - parameter error:   The error that caused invalidation, or nil if the invalidation was explicit.
        */
        public func URLSession(session: NSURLSession, didBecomeInvalidWithError error: NSError?) {
            sessionDidBecomeInvalidWithError?(session, error)
        }  

        /**
            Requests credentials from the delegate in response to a session-level authentication request from the remote server.
            - parameter session:           The session containing the task that requested authentication.
            - parameter challenge:         An object that contains the request for authentication.
            - parameter completionHandler: A handler that your delegate method must call providing the disposition and credential.
         */
        public func URLSession(
              session: NSURLSession,
              didReceiveChallenge challenge: NSURLAuthenticationChallenge,
              completionHandler: ((NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void)) {
                  var disposition: NSURLSessionAuthChallengeDisposition = .PerformDefaultHandling
                  var credential: NSURLCredential?

                  if let sessionDidReceiveChallenge = sessionDidReceiveChallenge {
                      (disposition, credential) = sessionDidReceiveChallenge(session, challenge)
                  } else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
                      let host = challenge.protectionSpace.host

                      if let serverTrustPolicy = session.serverTrustPolicyManager?.serverTrustPolicyForHost(host),
                        serverTrust = challenge.protectionSpace.serverTrust {
                          if serverTrustPolicy.evaluateServerTrust(serverTrust, isValidForHost: host) {
                            disposition = .UseCredential
                            credential = NSURLCredential(forTrust: serverTrust)
                          } else {
                              disposition = .CancelAuthenticationChallenge
                          }
                  }
              }

              completionHandler(disposition, credential)
        }

        /**
            Tells the delegate that all messages enqueued for a session have been delivered.
        */
        public func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession) {
            sessionDidFinishEventsForBackgroundURLSession?(session)
        }

        // MARK: - NSURLSessionTaskDelegate
        // MARK: Override Closures

        /// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:`.
        public var taskWillPerformHTTPRedirection: ((NSURLSession, NSURLSessionTask, NSHTTPURLResponse, NSURLRequest) -> NSURLRequest?)?

        /// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:task:didReceiveChallenge:completionHandler:`.
        public var taskDidReceiveChallenge: ((NSURLSession, NSURLSessionTask, NSURLAuthenticationChallenge) -> (NSURLSessionAuthChallengeDisposition, NSURLCredential?))?

        /// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:session:task:needNewBodyStream:`.
        public var taskNeedNewBodyStream: ((NSURLSession, NSURLSessionTask) -> NSInputStream!)?

        /// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:`.
        public var taskDidSendBodyData: ((NSURLSession, NSURLSessionTask, Int64, Int64, Int64) -> Void)?

        /// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:task:didCompleteWithError:`.
        public var taskDidComplete: ((NSURLSession, NSURLSessionTask, NSError?) -> Void)?

        // MARK: Delegate Methods
        public func URLSession(
            session: NSURLSession,
            task: NSURLSessionTask,
            willPerformHTTPRedirection response: NSHTTPURLResponse,
            newRequest request: NSURLRequest,
            completionHandler: ((NSURLRequest?) -> Void)) {
              var redirectRequest: NSURLRequest? = request

              if let taskWillPerformHTTPRedirection = taskWillPerformHTTPRedirection {
                  redirectRequest = taskWillPerformHTTPRedirection(session, task, response, request)
              }

              completionHandler(redirectRequest)
        }

        /**
            Requests credentials from the delegate in response to an authentication request from the remote server.
        */
        public func URLSession(
            session: NSURLSession,
            task: NSURLSessionTask,
            didReceiveChallenge challenge: NSURLAuthenticationChallenge,
            completionHandler: ((NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void)) {
              if let taskDidReceiveChallenge = taskDidReceiveChallenge {
                completionHandler(taskDidReceiveChallenge(session, task, challenge))
              } else if let delegate = self[task] {
                  delegate.URLSession(session,task: task,didReceiveChallenge: challenge,completionHandler: completionHandler )
              } else {
                  URLSession(session, didReceiveChallenge: challenge, completionHandler: completionHandler)
              }
         }

         /**
            Tells the delegate when a task requires a new request body stream to send to the remote server.
         */
        public func URLSession(session: NSURLSession, task: NSURLSessionTask, needNewBodyStream completionHandler: ((NSInputStream?) -> Void)) {
            if let taskNeedNewBodyStream = taskNeedNewBodyStream {
                completionHandler(taskNeedNewBodyStream(session, task))
            } else if let delegate = self[task] {
                delegate.URLSession(session, task: task, needNewBodyStream: completionHandler)
            }
        }

        /**
            Periodically informs the delegate of the progress of sending body content to the server.
        */
        public func URLSession(session: NSURLSession,task: NSURLSessionTask,didSendBodyData bytesSent: Int64,totalBytesSent: Int64,totalBytesExpectedToSend: Int64) {
            if let taskDidSendBodyData = taskDidSendBodyData {
                taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalBytesExpectedToSend)
            } else if let delegate = self[task] as? Request.UploadTaskDelegate {
                delegate.URLSession(session,task: task,didSendBodyData: bytesSent,totalBytesSent: totalBytesSent,totalBytesExpectedToSend:totalBytesExpectedToSend)
            }
         }

        /**
            Tells the delegate that the task finished transferring data.
        */
        public func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
            if let taskDidComplete = taskDidComplete {
                taskDidComplete(session, task, error)
            } else if let delegate = self[task] {
                delegate.URLSession(session, task: task, didCompleteWithError: error)
            }
            NSNotificationCenter.defaultCenter().postNotificationName(Notifications.Task.DidComplete, object: task)
            self[task] = nil
        }

        // MARK: - NSURLSessionDataDelegate
        // MARK: Override Closures

        /// Overrides default behavior for NSURLSessionDataDelegate method `URLSession:dataTask:didReceiveResponse:completionHandler:`.
        public var dataTaskDidReceiveResponse: ((NSURLSession, NSURLSessionDataTask, NSURLResponse) -> NSURLSessionResponseDisposition)?

        /// Overrides default behavior for NSURLSessionDataDelegate method `URLSession:dataTask:didBecomeDownloadTask:`.
        public var dataTaskDidBecomeDownloadTask: ((NSURLSession, NSURLSessionDataTask, NSURLSessionDownloadTask) -> Void)?

        /// Overrides default behavior for NSURLSessionDataDelegate method `URLSession:dataTask:didReceiveData:`.
        public var dataTaskDidReceiveData: ((NSURLSession, NSURLSessionDataTask, NSData) -> Void)?

        /// Overrides default behavior for NSURLSessionDataDelegate method `URLSession:dataTask:willCacheResponse:completionHandler:`.
        public var dataTaskWillCacheResponse: ((NSURLSession, NSURLSessionDataTask, NSCachedURLResponse) -> NSCachedURLResponse!)?

        // MARK: Delegate Methods

        /**
            Tells the delegate that the data task received the initial reply (headers) from the server.
        */
        public func URLSession(session: NSURLSession,dataTask: NSURLSessionDataTask,didReceiveResponse response: NSURLResponse,completionHandler: ((NSURLSessionResponseDisposition) -> Void)) {
            var disposition: NSURLSessionResponseDisposition = .Allow

            if let dataTaskDidReceiveResponse = dataTaskDidReceiveResponse {
                disposition = dataTaskDidReceiveResponse(session, dataTask, response)
            }

            completionHandler(disposition)
        }

        /**
            Tells the delegate that the data task was changed to a download task.
        */
        public func URLSession(session: NSURLSession,dataTask: NSURLSessionDataTask,didBecomeDownloadTask downloadTask:NSURLSessionDownloadTask) {
            if let dataTaskDidBecomeDownloadTask = dataTaskDidBecomeDownloadTask {
                dataTaskDidBecomeDownloadTask(session, dataTask, downloadTask)
            } else {
                let downloadDelegate = Request.DownloadTaskDelegate(task: downloadTask)
                self[downloadTask] = downloadDelegate
            }
        }

        /**
            Tells the delegate that the data task has received some of the expected data.
        */
        public func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
            if let dataTaskDidReceiveData = dataTaskDidReceiveData {
                dataTaskDidReceiveData(session, dataTask, data)
            } else if let delegate = self[dataTask] as? Request.DataTaskDelegate {
                delegate.URLSession(session, dataTask: dataTask, didReceiveData: data)
            }
        }

        /**
            Asks the delegate whether the data (or upload) task should store the response in the cache.
        */
        public func URLSession(session: NSURLSession,dataTask: NSURLSessionDataTask,willCacheResponse proposedResponse: NSCachedURLResponse,completionHandler: ((NSCachedURLResponse?) -> Void)) {
            if let dataTaskWillCacheResponse = dataTaskWillCacheResponse {
                completionHandler(dataTaskWillCacheResponse(session, dataTask, proposedResponse))
            } else if let delegate = self[dataTask] as? Request.DataTaskDelegate {
                delegate.URLSession(session,dataTask: dataTask,willCacheResponse: proposedResponse,completionHandler: completionHandler)
            } else {
                completionHandler(proposedResponse)
            }
        }

        // MARK: - NSURLSessionDownloadDelegate
        // MARK: Override Closures
        /// Overrides default behavior for NSURLSessionDownloadDelegate method `URLSession:downloadTask:didFinishDownloadingToURL:`.
    public var downloadTaskDidFinishDownloadingToURL: ((NSURLSession, NSURLSessionDownloadTask, NSURL) -> Void)?

        /// Overrides default behavior for NSURLSessionDownloadDelegate method `URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:`.
        public var downloadTaskDidWriteData: ((NSURLSession, NSURLSessionDownloadTask, Int64, Int64, Int64) -> Void)?

        /// Overrides default behavior for NSURLSessionDownloadDelegate method `URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:`.
        public var downloadTaskDidResumeAtOffset: ((NSURLSession, NSURLSessionDownloadTask, Int64, Int64) -> Void)?

        // MARK: Delegate Methods

        /**
            Tells the delegate that a download task has finished downloading.
        */
        public func URLSession(session: NSURLSession,downloadTask: NSURLSessionDownloadTask,didFinishDownloadingToURL location: NSURL) {
            if let downloadTaskDidFinishDownloadingToURL = downloadTaskDidFinishDownloadingToURL {
                downloadTaskDidFinishDownloadingToURL(session, downloadTask, location)
            } else if let delegate = self[downloadTask] as? Request.DownloadTaskDelegate {
                delegate.URLSession(session, downloadTask: downloadTask, didFinishDownloadingToURL: location)
            }
        }

        /**
            Periodically informs the delegate about the download’s progress.
        */
        public func URLSession(session: NSURLSession,downloadTask: NSURLSessionDownloadTask,didWriteData bytesWritten: Int64,totalBytesWritten: Int64,totalBytesExpectedToWrite: Int64) {
            if let downloadTaskDidWriteData = downloadTaskDidWriteData {
                downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite)
            } else if let delegate = self[downloadTask] as? Request.DownloadTaskDelegate {
                delegate.URLSession(session,downloadTask: downloadTask,didWriteData: bytesWritten,totalBytesWritten: totalBytesWritten,totalBytesExpectedToWrite: totalBytesExpectedToWrite )
            }
        }

        /**
            Tells the delegate that the download task has resumed downloading
        */
        public func URLSession(session: NSURLSession,downloadTask: NSURLSessionDownloadTask,didResumeAtOffset fileOffset: Int64,expectedTotalBytes: Int64) {
            if let downloadTaskDidResumeAtOffset = downloadTaskDidResumeAtOffset {
                downloadTaskDidResumeAtOffset(session, downloadTask, fileOffset, expectedTotalBytes)
            } else if let delegate = self[downloadTask] as? Request.DownloadTaskDelegate {
                delegate.URLSession(session,downloadTask: downloadTask,didResumeAtOffset: fileOffset,expectedTotalBytes: expectedTotalBytes)
            }
        }

        // MARK: - NSURLSessionStreamDelegate
        var _streamTaskReadClosed: Any?
        var _streamTaskWriteClosed: Any?
        var _streamTaskBetterRouteDiscovered: Any?
        var _streamTaskDidBecomeInputStream: Any?

        // MARK: - NSObject
        public override func respondsToSelector(selector: Selector) -> Bool {
            switch selector {
              case "URLSession:didBecomeInvalidWithError:":
                return sessionDidBecomeInvalidWithError != nil
              case "URLSession:didReceiveChallenge:completionHandler:":
                return sessionDidReceiveChallenge != nil
              case "URLSessionDidFinishEventsForBackgroundURLSession:":
                return sessionDidFinishEventsForBackgroundURLSession != nil
              case "URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:":
                return taskWillPerformHTTPRedirection != nil
              case "URLSession:dataTask:didReceiveResponse:completionHandler:":
                return dataTaskDidReceiveResponse != nil
              default:
                return self.dynamicType.instancesRespondToSelector(selector)
            }
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拦焚,老刑警劉巖凡简,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件稳捆,死亡現(xiàn)場(chǎng)離奇詭異鸥印,居然都是意外死亡看尼,警方通過(guò)查閱死者的電腦和手機(jī)揭绑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)弓候,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人他匪,你說(shuō)我怎么就攤上這事弓叛。” “怎么了诚纸?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵撰筷,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我畦徘,道長(zhǎng)毕籽,這世上最難降的妖魔是什么抬闯? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮关筒,結(jié)果婚禮上溶握,老公的妹妹穿的比我還像新娘。我一直安慰自己蒸播,他們只是感情好睡榆,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著袍榆,像睡著了一般胀屿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上包雀,一...
    開(kāi)封第一講書(shū)人閱讀 52,262評(píng)論 1 308
  • 那天宿崭,我揣著相機(jī)與錄音,去河邊找鬼才写。 笑死葡兑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赞草。 我是一名探鬼主播讹堤,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼厨疙!你這毒婦竟也來(lái)了蜕劝?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤轰异,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后暑始,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體搭独,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年廊镜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了牙肝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嗤朴,死狀恐怖配椭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情雹姊,我是刑警寧澤股缸,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站吱雏,受9級(jí)特大地震影響敦姻,放射性物質(zhì)發(fā)生泄漏瘾境。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一镰惦、第九天 我趴在偏房一處隱蔽的房頂上張望迷守。 院中可真熱鬧,春花似錦旺入、人聲如沸兑凿。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)礼华。三九已至,卻和暖如春龄捡,著一層夾襖步出監(jiān)牢的瞬間卓嫂,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工聘殖, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留晨雳,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓奸腺,卻偏偏與公主長(zhǎng)得像餐禁,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子突照,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容