damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

AttachMediaUtility.swift (4095B)


      1 //
      2 //  AttachMediaUtility.swift
      3 //  damus
      4 //
      5 //  Created by Swift on 2/17/23.
      6 //
      7 
      8 import SwiftUI
      9 import UIKit
     10 import CoreGraphics
     11 import UniformTypeIdentifiers
     12 
     13 enum ImageUploadResult {
     14     case success(String)
     15     case failed(Error?)
     16 }
     17 
     18 enum ImageUploadMediaType {
     19     case normal
     20     case profile_picture
     21 }
     22 
     23 protocol AttachMediaUtilityProtocol {
     24     static func create_upload_request(mediaToUpload: MediaUpload, mediaUploader: any MediaUploaderProtocol, mediaType: ImageUploadMediaType, progress: URLSessionTaskDelegate, keypair: Keypair?) async -> ImageUploadResult
     25 }
     26 
     27 class AttachMediaUtility {
     28     fileprivate static func create_upload_body(mediaData: Data, boundary: String, mediaUploader: any MediaUploaderProtocol, mediaToUpload: MediaUpload, mediaType: ImageUploadMediaType) -> Data {
     29         let mediaTypeFieldValue = mediaUploader.mediaTypeValue(for: mediaType)
     30         let mediaTypeFieldEntry: String?
     31         if let mediaTypeFieldValue {
     32             mediaTypeFieldEntry = "; \(mediaUploader.mediaTypeParam)=\(mediaTypeFieldValue)"
     33         }
     34         else {
     35             mediaTypeFieldEntry = nil
     36         }
     37         let body = NSMutableData();
     38         let contentType = mediaToUpload.mime_type
     39         body.appendString(string: "Content-Type: multipart/form-data; boundary=\(boundary)\r\n\r\n")
     40         body.appendString(string: "--\(boundary)\r\n")
     41         body.appendString(string: "Content-Disposition: form-data; name=\(mediaUploader.nameParam); filename=\(mediaToUpload.genericFileName)\(mediaTypeFieldEntry ?? "")\r\n")
     42         body.appendString(string: "Content-Type: \(contentType)\r\n\r\n")
     43         body.append(mediaData as Data)
     44         body.appendString(string: "\r\n")
     45         body.appendString(string: "--\(boundary)--\r\n")
     46         return body as Data
     47     }
     48 
     49     static func create_upload_request(mediaToUpload: MediaUpload, mediaUploader: any MediaUploaderProtocol, mediaType: ImageUploadMediaType, progress: URLSessionTaskDelegate, keypair: Keypair? = nil) async -> ImageUploadResult {
     50         var mediaData: Data?
     51         guard let url = URL(string: mediaUploader.postAPI) else {
     52             return .failed(nil)
     53         }
     54         
     55         var request = URLRequest(url: url)
     56         request.httpMethod = "POST";
     57         let boundary = "Boundary-\(UUID().description)"
     58         request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
     59         
     60         // If uploading to a media host that support NIP-98 authorization, add the header
     61         if mediaUploader.requiresNip98,
     62            let keypair,
     63             let method = request.httpMethod,
     64             let signature = create_nip98_signature(keypair: keypair, method: method, url: url) {
     65 
     66              request.setValue(signature, forHTTPHeaderField: "Authorization")
     67         }
     68         
     69         switch mediaToUpload {
     70         case .image(let url):
     71             do {
     72                 mediaData = try Data(contentsOf: url)
     73             } catch {
     74                 return .failed(error)
     75             }
     76         case .video(let url):
     77             do {
     78                 mediaData = try Data(contentsOf: url)
     79             } catch {
     80                 return .failed(error)
     81             }
     82         }
     83 
     84         guard let mediaData else {
     85             return .failed(nil)
     86         }
     87 
     88         request.httpBody = create_upload_body(mediaData: mediaData, boundary: boundary, mediaUploader: mediaUploader, mediaToUpload: mediaToUpload, mediaType: mediaType)
     89         
     90         do {
     91             let (data, _) = try await URLSession.shared.data(for: request, delegate: progress)
     92 
     93             guard let url = mediaUploader.getMediaURL(from: data) else {
     94                 print("Upload failed getting media url")
     95                 return .failed(nil)
     96             }
     97             
     98             return .success(url)
     99             
    100         } catch {
    101             return .failed(error)
    102         }
    103     }
    104 }
    105 
    106 extension NSMutableData {
    107     func appendString(string: String) {
    108         guard let data = string.data(using: String.Encoding.utf8, allowLossyConversion: true) else {
    109             return
    110         }
    111         append(data)
    112     }
    113 }