Skip to content

Instantly share code, notes, and snippets.

@MosheBerman
Created February 19, 2016 16:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MosheBerman/1fbc4d220cd195ef31be to your computer and use it in GitHub Desktop.
Save MosheBerman/1fbc4d220cd195ef31be to your computer and use it in GitHub Desktop.
Submission Manager
import UIKit
class SubmissionManager: NSObject {
static let sharedManager = SubmissionManager()
var serverURLComponents : NSURLComponents = NSURLComponents()
private let keyDefaultsServerAddress : String = "com.company.serverURL"
private override init() {
super.init()
NSUserDefaults.standardUserDefaults().registerDefaults([
keyDefaultsServerAddress : [
"scheme" : "http",
"host" : "192.168.1.5",
"port" : NSNumber(int: 8000),
"path" : "/api/submit/"
]
])
if let components = self.loadURLComponents() {
self.serverURLComponents = components
}
}
// MARK: - Server URL Settings
/**
Loads the most recent server URL from the defaults store.
*/
func loadURLComponents() -> NSURLComponents? {
var returnComponents : NSURLComponents? = nil
if let serverComponentsDictionary : [String : AnyObject] = NSUserDefaults.standardUserDefaults().dictionaryForKey(keyDefaultsServerAddress) {
let components : NSURLComponents = NSURLComponents()
components.scheme = serverComponentsDictionary["scheme"] as? String
components.host = serverComponentsDictionary["host"] as? String
components.port = serverComponentsDictionary["port"] as? NSNumber
components.path = serverComponentsDictionary["path"] as? String
returnComponents = components
}
return returnComponents
}
/**
Saves the components to NSUserDefaults.
- parameter components: The URL components to save.
*/
func saveURLComponents(urlComponents components: NSURLComponents) {
var componentsToSave : [String : AnyObject] = [:]
if let scheme = components.scheme, let host = components.host, let port = components.port, let path = components.path {
componentsToSave["scheme"] = scheme
componentsToSave["host"] = host
componentsToSave["port"] = port
componentsToSave["path"] = path
}
NSUserDefaults.standardUserDefaults().setObject(componentsToSave, forKey: keyDefaultsServerAddress)
self.serverURLComponents = components
}
// MARK: - Uploading a Submission
/**
Uploads a PDF to the server.
*/
func uploadPDF(pdf data: NSData, withName name: String, andHandler handler: (response : NSURLResponse?, error : NSError?) -> Void) {
guard let payload = self.payload(withData: data, andName: name) else {
let error = NSError(domain: "com.company.product", code: -3, userInfo: ["reason" : "Failed to convert data into payload."])
handler(response: nil, error: error)
return
}
self.uploadData(payload, withName: name, andHandler: handler)
}
/**
Uploads a Dictionary to the server.
*/
func uploadJSON(submission : NSDictionary, withName name: String, andHandler handler: (response : NSURLResponse?, error : NSError?) -> Void) {
print("(Product) : JSON Submission started...")
// Step 1. Prepare the data for upload.
guard let payload = self.payload(withDictionary: submission, andName:name) else {
let error = NSError(domain: "com.company.product", code: -2, userInfo: ["reason" : "Failed to convert dictionary into payload."])
handler(response: nil, error: error)
return
}
self.uploadData(payload, withName: name, andHandler: handler)
}
/**
Uploads a prepared payload to the server.
*/
private func uploadData(payload : NSData, withName name: String, andHandler handler: (response : NSURLResponse?, error : NSError?) -> Void) {
print("(Product) : Payload prepared (\(payload.length) bytes).")
// Step 2. Prepare the URL
guard let url = self.serverURLComponents.URL else {
print("(Product) : URL generation failed.")
handler(response: nil, error: NSError(domain: "com.company.product", code: -1, userInfo: ["reason" : "Failed to create url from components."]))
return
}
print("(Product) : URL generated, preparing request.")
// Required for successful submission.
let boundary : String = "----------SwIfTeRhTtPrEqUeStBoUnDaRy"
let request : NSMutableURLRequest = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.HTTPBody = payload
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
request.setValue("\(payload.length)", forHTTPHeaderField: "Content-Length")
let session = NSURLSession.sharedSession()
let uploadTask = session.uploadTaskWithRequest(request, fromData: payload, completionHandler: { (responseData: NSData?, response : NSURLResponse?, error : NSError?) -> Void in
print("(Product) : Upload completed, processing response...")
handler(response: response, error: error)
if let data = responseData {
do {
let responseDictionary = try NSJSONSerialization.JSONObjectWithData(data, options: [])
print("(Product) Response: \(responseDictionary)")
}
catch let e as NSError
{
print("(Product) Error unwrapping response : \(e)")
print("\(NSString(data: data, encoding: NSUTF8StringEncoding))")
}
}
else
{
print("(Product) : Didn't receive a response. \(error)")
}
print("(Product) Done.")
})
print("(Product) : Task prepared.")
uploadTask.resume()
}
// MARK: - Test Server Connection
func testServerConnection() {
if let task = self.testTask() {
task.resume()
}
}
func testTask() -> NSURLSessionDataTask? {
let components = NSURLComponents()
components.scheme = self.serverURLComponents.scheme
components.host = self.serverURLComponents.host
components.port = self.serverURLComponents.port
components.path = "/"
guard let url = components.URL else {
print("Failed to build URL from components. \(components)")
return nil
}
let request = NSURLRequest(URL: url)
let task = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration()).dataTaskWithRequest(request, completionHandler: { (data : NSData?, response : NSURLResponse?, error : NSError?) -> Void in
var success : Bool = false
if let data = data {
if let responseString : NSString = NSString(data: data, encoding: NSUTF8StringEncoding) {
if responseString == "Hello world." {
success = true
}
}
}
var results : String
if success {
results = "Successfully connected to server at '\(url)'."
}
else
{
results = "Connection failed to server at '\(url)'."
}
let alert : UIAlertController = UIAlertController(title: "", message: "\(results)", preferredStyle: UIAlertControllerStyle.Alert)
let cancel = UIAlertAction(title: "OK", style: .Cancel, handler: { (action : UIAlertAction) -> Void in
if let rootViewController = UIApplication.sharedApplication().keyWindow?.rootViewController {
rootViewController.dismissViewControllerAnimated(true, completion: nil)
}
})
alert.addAction(cancel)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
if let rootViewController = UIApplication.sharedApplication().keyWindow?.rootViewController {
rootViewController.presentViewController(alert, animated: true, completion: { () -> Void in
})
}
})
})
return task
}
// MARK: - Converting a submission dictionary into data.
/**
Converts a submission into a data payload for upload to server.
*/
func payload(withDictionary dictionary : NSDictionary, andName name:String) -> NSData? {
var returnData : NSData? = nil
do {
guard let data : NSData = try NSJSONSerialization.dataWithJSONObject(dictionary, options: .PrettyPrinted) else {
return nil
}
returnData = self.payload(withData: data, andName: name)
}
catch let e as NSError {
print("Error converting dictionary to data:\(e)")
}
return returnData
}
func payload(withData data : NSData, andName name:String) -> NSData? {
var returnData : NSData? = nil
let boundary : String = "----------SwIfTeRhTtPrEqUeStBoUnDaRy"
let contentDisposition : String = "Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(name)\"\r\n"
let contentType : String = "Content-Type: application/octet-stream\r\n\r\n"
let payload : NSMutableData = NSMutableData()
if let encodedBoundary = ("--\(boundary)\r\n").dataUsingEncoding(NSUTF8StringEncoding),
let metadata1 = contentDisposition.dataUsingEncoding(NSUTF8StringEncoding),
let metadata2 = contentType.dataUsingEncoding(NSUTF8StringEncoding),
let trailingNewlineData = "\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)
{
payload.appendData(encodedBoundary)
payload.appendData(metadata1)
payload.appendData(metadata2)
payload.appendData(data)
payload.appendData(trailingNewlineData)
payload.appendData(encodedBoundary)
}
returnData = payload
return returnData
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment