mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			135 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Swift
		
	
			
		
		
	
	
			135 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Swift
		
	
| // Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
 | |
| 
 | |
| import Foundation
 | |
| import Combine
 | |
| import SessionUtilitiesKit
 | |
| 
 | |
| public extension Network.PreparedRequest {
 | |
|     /// Send an onion request for the prepared data
 | |
|     func send(using dependencies: Dependencies) -> AnyPublisher<(ResponseInfoType, R), Error> {
 | |
|         // If we have a cached response then user that directly
 | |
|         if let cachedResponse: Network.PreparedRequest<R>.CachedResponse = self.cachedResponse {
 | |
|             return Just(cachedResponse)
 | |
|                 .setFailureType(to: Error.self)
 | |
|                 .handleEvents(
 | |
|                     receiveSubscription: { _ in self.subscriptionHandler?() },
 | |
|                     receiveOutput: self.outputEventHandler,
 | |
|                     receiveCompletion: self.completionEventHandler,
 | |
|                     receiveCancel: self.cancelEventHandler
 | |
|                 )
 | |
|                 .eraseToAnyPublisher()
 | |
|         }
 | |
|         
 | |
|         // Otherwise trigger the request
 | |
|         return Just(())
 | |
|             .setFailureType(to: Error.self)
 | |
|             .tryFlatMap { _ in
 | |
|                 switch target {
 | |
|                     case let serverTarget as any ServerRequestTarget:
 | |
|                         return dependencies.network
 | |
|                             .send(
 | |
|                                 .onionRequest(
 | |
|                                     request,
 | |
|                                     to: serverTarget.server,
 | |
|                                     with: serverTarget.x25519PublicKey,
 | |
|                                     timeout: timeout
 | |
|                                 ),
 | |
|                                 using: dependencies
 | |
|                             )
 | |
|                         
 | |
|                     case let snodeTarget as Network.SnodeTarget:
 | |
|                         guard let payload: Data = request.httpBody else { throw NetworkError.invalidPreparedRequest }
 | |
| 
 | |
|                         return dependencies.network
 | |
|                             .send(
 | |
|                                 .onionRequest(
 | |
|                                     payload,
 | |
|                                     to: snodeTarget.snode,
 | |
|                                     swarmPublicKey: snodeTarget.swarmPublicKey,
 | |
|                                     timeout: timeout
 | |
|                                 ),
 | |
|                                 using: dependencies
 | |
|                             )
 | |
|                         
 | |
|                     case let randomTarget as Network.RandomSnodeTarget:
 | |
|                         guard let payload: Data = request.httpBody else { throw NetworkError.invalidPreparedRequest }
 | |
| 
 | |
|                         return LibSession.getSwarm(swarmPublicKey: randomTarget.swarmPublicKey)
 | |
|                             .tryFlatMapWithRandomSnode(retry: randomTarget.retryCount, using: dependencies) { snode in
 | |
|                                 dependencies.network
 | |
|                                     .send(
 | |
|                                         .onionRequest(
 | |
|                                             payload,
 | |
|                                             to: snode,
 | |
|                                             swarmPublicKey: randomTarget.swarmPublicKey,
 | |
|                                             timeout: timeout
 | |
|                                         ),
 | |
|                                         using: dependencies
 | |
|                                     )
 | |
|                             }
 | |
|                         
 | |
|                     case let randomTarget as Network.RandomSnodeLatestNetworkTimeTarget:
 | |
|                         guard request.httpBody != nil else { throw NetworkError.invalidPreparedRequest }
 | |
|                         
 | |
|                         return LibSession.getSwarm(swarmPublicKey: randomTarget.swarmPublicKey)
 | |
|                             .tryFlatMapWithRandomSnode(retry: randomTarget.retryCount, using: dependencies) { snode in
 | |
|                                 SnodeAPI
 | |
|                                     .getNetworkTime(from: snode, using: dependencies)
 | |
|                                     .tryFlatMap { timestampMs in
 | |
|                                         guard
 | |
|                                             let updatedRequest: URLRequest = try? randomTarget
 | |
|                                                 .urlRequestWithUpdatedTimestampMs(timestampMs, dependencies),
 | |
|                                             let payload: Data = updatedRequest.httpBody
 | |
|                                         else { throw NetworkError.invalidPreparedRequest }
 | |
|                                         
 | |
|                                         return dependencies.network
 | |
|                                             .send(
 | |
|                                                 .onionRequest(
 | |
|                                                     payload,
 | |
|                                                     to: snode,
 | |
|                                                     swarmPublicKey: randomTarget.swarmPublicKey,
 | |
|                                                     timeout: timeout
 | |
|                                                 ),
 | |
|                                                 using: dependencies
 | |
|                                             )
 | |
|                                             .map { info, response -> (ResponseInfoType, Data?) in
 | |
|                                                 (
 | |
|                                                     SnodeAPI.LatestTimestampResponseInfo(
 | |
|                                                         code: info.code,
 | |
|                                                         headers: info.headers,
 | |
|                                                         timestampMs: timestampMs
 | |
|                                                     ),
 | |
|                                                     response
 | |
|                                                 )
 | |
|                                             }
 | |
|                                     }
 | |
|                             }
 | |
|                         
 | |
|                     default: throw NetworkError.invalidPreparedRequest
 | |
|                 }
 | |
|             }
 | |
|             .decoded(with: self, using: dependencies)
 | |
|             .retry(retryCount, using: dependencies)
 | |
|             .handleEvents(
 | |
|                 receiveSubscription: { _ in self.subscriptionHandler?() },
 | |
|                 receiveOutput: self.outputEventHandler,
 | |
|                 receiveCompletion: self.completionEventHandler,
 | |
|                 receiveCancel: self.cancelEventHandler
 | |
|             )
 | |
|             .eraseToAnyPublisher()
 | |
|     }
 | |
| }
 | |
| 
 | |
| public extension Optional {
 | |
|     func send<R>(
 | |
|         using dependencies: Dependencies
 | |
|     ) -> AnyPublisher<(ResponseInfoType, R), Error> where Wrapped == Network.PreparedRequest<R> {
 | |
|         guard let instance: Wrapped = self else {
 | |
|             return Fail(error: NetworkError.invalidPreparedRequest)
 | |
|                 .eraseToAnyPublisher()
 | |
|         }
 | |
|         
 | |
|         return instance.send(using: dependencies)
 | |
|     }
 | |
| }
 |