0

I am trying to make my own DynamicIP updater as a command line tool so I can set it up to run as a launch agent. I thought this would be a pretty simple thing to do, but I am not getting anything when I run this bit of code.

main.swift:

import AppKit

let userName = "yourUserName"
let password = "yourPassword"
let domain = "yourDomainName"
let ftp = "ftp"
let www = "www"
let checkIPURL = URL(string: "https://svc.joker.com/nic/checkip")
let domainUpdateURL = URL(string: "https://svc.joker.com/nic/update?username=\(userName)&password=\(password)&hostname=\(domain)")
let ftpUpdateURL = URL(string: "https://svc.joker.com/nic/update?username=\(userName)&password=\(password)&hostname=\(ftp).\(domain)")
let wwwUpdateURL = URL(string: "https://svc.joker.com/nic/update?username=\(userName)&password=\(password)&hostname=\(www).\(domain)")
var ipAddress = ""

if let url = checkIPURL {
    print("1 - \(url)")
    var request = URLRequest(url: url)
    print("2 - \(request.url!)")
    request.httpMethod = "POST"
    print("3")
    let session = URLSession.shared
    print("4")
    session.dataTask(with: request) { data, response, error in
        print("4.1")
        guard error == nil else {
            print("Error:", error ?? "")
            return
        }
        print("4.2")
        guard (response as? HTTPURLResponse)?
            .statusCode == 200 else {
            print("down")
            return
        }
        print("4.3")
        if let data = data {
            if let dataString = String(decoding: data, as: UTF8.self).removeHtmlTags() {
                if let startIndex = dataString.lastIndex(of: " ") {
                    let chars = dataString.distance(from: startIndex, to: dataString.endIndex)-1
                    ipAddress = String(dataString.suffix(chars))
                }
            }
            print(ipAddress)
        } else {
            print("No data")
        }
        print("up - \(response!)")
    }.resume()
    print("Done.")
}

extension String {
    // Credit - Andrew - https://stackoverflow.com/questions/25983558/stripping-out-html-tags-from-a-string
    func removeHtmlTags() -> String? {
        do {
            guard let data = self.data(using: .utf8) else {
                return nil
            }
            let attributed = try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
            return attributed.string
        } catch {
            return nil
        }
    }
}

Everything outside of the session prints, but nothing inside of it prints (4.x statements).

I deleted the AppSandbox because when I have AppSandbox as a Capability and turn on Outgoing Connections I get a crash with EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).

But even with AppSandbox deleted it does not work.

The strange thing is this works fine in a playground (with a slight modification turning the String extension into a function within the playground), which really makes this a head scratcher for me.

Here's my playground code:

import AppKit

let userName = "yourUserName"
let password = "yourPassword"
let domain = "yourDomainName"
let ftp = "ftp"
let www = "www"
let checkIPURL = URL(string: "https://svc.joker.com/nic/checkip")
let domainUpdateURL = URL(string: "https://svc.joker.com/nic/update?username=\(userName)&password=\(password)&hostname=\(domain)")
let ftpUpdateURL = URL(string: "https://svc.joker.com/nic/update?username=\(userName)&password=\(password)&hostname=\(ftp).\(domain)")
let wwwUpdateURL = URL(string: "https://svc.joker.com/nic/update?username=\(userName)&password=\(password)&hostname=\(www).\(domain)")
var ipAddress = ""

if let url = checkIPURL {
    print("1 - \(url)")
    var request = URLRequest(url: url)
    print("2 - \(request.url!)")
    request.httpMethod = "POST"
    print("3")
    let session = URLSession.shared
    print("4")
    session.dataTask(with: request) { data, response, error in
        print("4.1")
        guard error == nil else {
            print("Error:", error ?? "")
            return
        }
        print("4.2")
        guard (response as? HTTPURLResponse)?
            .statusCode == 200 else {
            print("down")
            return
        }
        print("4.3")
        if let data = data {
            //if let dataString = String(decoding: data, as: UTF8.self).removeHtmlTags() {
            if let dataString = removeHtmlTags(data: data) {
                if let startIndex = dataString.lastIndex(of: " ") {
                    let chars = dataString.distance(from: startIndex, to: dataString.endIndex)-1
                    ipAddress = String(dataString.suffix(chars))
                }
            }
            print(ipAddress)
        } else {
            print("No data")
        }
        print("up - \(response!)")
    }.resume()
    print("Done.")
}

func removeHtmlTags(data: Data) -> String? {
    do {
        let attributed = try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
        return attributed.string
    } catch {
        return nil
    }
}

Is there something else I need to do to get this to work within the command line tool app I am trying to build?

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
SouthernYankee65
  • 1,129
  • 10
  • 22
  • 3
    If i'ts a Command Line Tool, the issue is that the programs ends before the async callback of `URLSession` is called. That's why. – Larme Jun 10 '22 at 14:42
  • 2
    https://stackoverflow.com/questions/31944011/how-to-prevent-a-command-line-tool-from-exiting-before-asynchronous-operation-co https://stackoverflow.com/questions/28590701/multiple-workers-in-swift-command-line-tool etc. – Larme Jun 10 '22 at 14:43
  • @Larme, yep, the sema example on the first post fixed it. Thank you! – SouthernYankee65 Jun 10 '22 at 15:36
  • @Larme any idea why appSandBox causes a crash when added as a capability with Outgoing Connections checked? – SouthernYankee65 Jun 10 '22 at 19:22

0 Answers0