LoginSignup
1
2

More than 5 years have passed since last update.

Cocoaの機能を使ってURLをGET/POSTするAppleScriptハンドラ

Last updated at Posted at 2018-07-21

URLをGETするAppleScriptハンドラ

  • シェルでいうところのcurl 'http://www.example.com/'みたいなもの
GETRequestForURL.scpt
use scripting additions
use framework "Foundation"

set requestURL to current application's NSURL's URLWithString:"https://www.example.com/"

set response to my GETRequestForURL(requestURL)

set returnedString to current application's NSString's alloc()'s initWithData:(response's |data|) encoding:(current application's NSUTF8StringEncoding)
return returnedString as text

on GETRequestForURL(requestURL)
    --require framework: Foundation
    set session to my getValidURLSession()
    set task to session's dataTaskWithURL:requestURL
    task's resume()
    return my fetchURLSesstionTasksResult(current application's NSArray's arrayWithObject:task)'s firstObject()
end GETRequestForURL

on getValidURLSession()
    --require framework: Foundation
    global URLSession
    try
        if URLSession = missing value then
            error number -2753
        end if
    on error number -2753
        set configuration to current application's NSURLSessionConfiguration's ephemeralSessionConfiguration()
        set URLSession to current application's NSURLSession's sessionWithConfiguration:configuration delegate:(me) delegateQueue:(missing value)
    end try
    return URLSession
end getValidURLSession

on URLSession:session didBecomeInvalidWithError:anError
    global URLSession
    log "URLSession invalidated"
    set URLSession to missing value
end URLSession:didBecomeInvalidWithError:

on fetchURLSesstionTasksResult(tasks)
    my waitForCompletionOfURLSessionTasks(tasks)
    my errorURLSessionTasksIfNeeded(tasks)
    return my getResponsesToURLSessionTasks(tasks)
end fetchURLSesstionTasksResult

on waitForCompletionOfURLSessionTasks(tasks)
    --require framework: Foundation
    set tasksAreRunningPredicate to current application's NSPredicate's predicateWithFormat_("NONE state == %@", current application's NSURLSessionTaskStateRunning as integer)
    repeat until tasksAreRunningPredicate's evaluateWithObject:tasks
        delay 0.01
    end repeat
end waitForCompletionOfURLSessionTasks

on errorURLSessionTasksIfNeeded(tasks)
    --require framework: Foundation
    repeat with errorTask in (tasks's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:"error != nil"))
        error errorTask's |error|'s localizedDescription as text number errorTask's |error|'s code as integer
    end repeat
    repeat with notCompletedTask in (tasks's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat_("state != %@", current application's NSURLSessionTaskStateCompleted as integer)))
        error "task has not completed"
    end repeat
end errorURLSessionTasksIfNeeded

on getResponsesToURLSessionTasks(tasks)
    --require framework: Foundation
    global responsesToURLSessionTask
    try
        responsesToURLSessionTask
    on error number -2753
        set responsesToURLSessionTask to current application's NSMutableArray's alloc()'s init()
    end try
    set newTasksFilterPredicate to current application's NSPredicate's predicateWithFormat_("NOT (taskIdentifier IN %@)", responsesToURLSessionTask's valueForKeyPath:"task.taskIdentifier")
    repeat with newTask in (tasks's filteredArrayUsingPredicate:newTasksFilterPredicate)
        (responsesToURLSessionTask's addObject:{task:newTask, |data|:current application's NSMutableData's alloc()'s init()})
    end repeat
    responsesToURLSessionTask's sortUsingDescriptors:{current application's NSSortDescriptor's sortDescriptorWithKey:"task.taskIdentifier" ascending:true}
    set responsesFilterPredicate to current application's NSPredicate's predicateWithFormat_("task.taskIdentifier IN %@", tasks's valueForKey:"taskIdentifier")
    return responsesToURLSessionTask's filteredArrayUsingPredicate:responsesFilterPredicate
end getResponsesToURLSessionTasks

on getResponseToURLSesstionTask(task)
    --require framework: Foundation
    return my getResponsesToURLSessionTasks(current application's NSArray's arrayWithObject:task)'s firstObject()
end getResponseToURLSesstionTask

on URLSession:session taskIsWaitingForConnectivity:task
    log "waiting for connectivity..."
end URLSession:taskIsWaitingForConnectivity:

on URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalBytesExpectedToSend
    log "sending..."
end URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:

on URLSession:session dataTask:task didReceiveData:aData
    log "receiving..."
    set receivedData to my getResponseToURLSesstionTask(task)'s |data|
    receivedData's appendData:aData
end URLSession:dataTask:didReceiveData:

on URLSession:session task:task didCompleteWithError:anError
    log "URLSessionTask completed"
end URLSession:task:didCompleteWithError:

URLをPOSTするAppleScriptハンドラ

  • シェルでいうところのcurl -F 'name=value' 'http://www.example.com/'みたいなもの
POSTRequestForURL.scpt
use scripting additions
use framework "Foundation"

set requestURL to current application's NSURL's URLWithString:"https://www.example.com/"
set postString to current application's NSString's stringWithString:"name=value"
set allowedCharacters to current application's NSCharacterSet's URLQueryAllowedCharacterSet
set postData to (postString's stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters)'s dataUsingEncoding:(current application's NSUTF8StringEncoding)

set response to my POSTRequestForURL(requestURL, postData)

set returnedString to current application's NSString's alloc()'s initWithData:(response's |data|) encoding:(current application's NSUTF8StringEncoding)
return returnedString as text

on POSTRequestForURL(requestURL, dataToPost)
    --require framework: Foundation
    set request to current application's NSMutableURLRequest's requestWithURL:requestURL
    set request's HTTPMethod to "POST"
    request's setValue:"application/x-www-form-urlencoded" forHTTPHeaderField:"Content-Type"
    set session to my getValidURLSession()
    set task to session's uploadTaskWithRequest:request fromData:dataToPost
    task's resume()
    return my fetchURLSesstionTasksResult(current application's NSArray's arrayWithObject:task)'s firstObject()
end POSTRequestForURL

on getValidURLSession()
    --require framework: Foundation
    global URLSession
    try
        if URLSession = missing value then
            error number -2753
        end if
    on error number -2753
        set configuration to current application's NSURLSessionConfiguration's ephemeralSessionConfiguration()
        set URLSession to current application's NSURLSession's sessionWithConfiguration:configuration delegate:(me) delegateQueue:(missing value)
    end try
    return URLSession
end getValidURLSession

on URLSession:session didBecomeInvalidWithError:anError
    global URLSession
    log "URLSession invalidated"
    set URLSession to missing value
end URLSession:didBecomeInvalidWithError:

on fetchURLSesstionTasksResult(tasks)
    my waitForCompletionOfURLSessionTasks(tasks)
    my errorURLSessionTasksIfNeeded(tasks)
    return my getResponsesToURLSessionTasks(tasks)
end fetchURLSesstionTasksResult

on waitForCompletionOfURLSessionTasks(tasks)
    --require framework: Foundation
    set tasksAreRunningPredicate to current application's NSPredicate's predicateWithFormat_("NONE state == %@", current application's NSURLSessionTaskStateRunning as integer)
    repeat until tasksAreRunningPredicate's evaluateWithObject:tasks
        delay 0.01
    end repeat
end waitForCompletionOfURLSessionTasks

on errorURLSessionTasksIfNeeded(tasks)
    --require framework: Foundation
    repeat with errorTask in (tasks's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:"error != nil"))
        error errorTask's |error|'s localizedDescription as text number errorTask's |error|'s code as integer
    end repeat
    repeat with notCompletedTask in (tasks's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat_("state != %@", current application's NSURLSessionTaskStateCompleted as integer)))
        error "task has not completed"
    end repeat
end errorURLSessionTasksIfNeeded

on getResponsesToURLSessionTasks(tasks)
    --require framework: Foundation
    global responsesToURLSessionTask
    try
        responsesToURLSessionTask
    on error number -2753
        set responsesToURLSessionTask to current application's NSMutableArray's alloc()'s init()
    end try
    set newTasksFilterPredicate to current application's NSPredicate's predicateWithFormat_("NOT (taskIdentifier IN %@)", responsesToURLSessionTask's valueForKeyPath:"task.taskIdentifier")
    repeat with newTask in (tasks's filteredArrayUsingPredicate:newTasksFilterPredicate)
        (responsesToURLSessionTask's addObject:{task:newTask, |data|:current application's NSMutableData's alloc()'s init()})
    end repeat
    responsesToURLSessionTask's sortUsingDescriptors:{current application's NSSortDescriptor's sortDescriptorWithKey:"task.taskIdentifier" ascending:true}
    set responsesFilterPredicate to current application's NSPredicate's predicateWithFormat_("task.taskIdentifier IN %@", tasks's valueForKey:"taskIdentifier")
    return responsesToURLSessionTask's filteredArrayUsingPredicate:responsesFilterPredicate
end getResponsesToURLSessionTasks

on getResponseToURLSesstionTask(task)
    --require framework: Foundation
    return my getResponsesToURLSessionTasks(current application's NSArray's arrayWithObject:task)'s firstObject()
end getResponseToURLSesstionTask

on URLSession:session taskIsWaitingForConnectivity:task
    log "waiting for connectivity..."
end URLSession:taskIsWaitingForConnectivity:

on URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalBytesExpectedToSend
    log "sending..."
end URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:

on URLSession:session dataTask:task didReceiveData:aData
    log "receiving..."
    set receivedData to my getResponseToURLSesstionTask(task)'s |data|
    receivedData's appendData:aData
end URLSession:dataTask:didReceiveData:

on URLSession:session task:task didCompleteWithError:anError
    log "URLSessionTask completed"
end URLSession:task:didCompleteWithError:

複数のURLを並列でGETするAppleScriptハンドラ

parallelGETRequestForURLs.scpt
use scripting additions
use framework "Foundation"

set requestURLs to {current application's NSURL's URLWithString:"https://www.example.com/", current application's NSURL's URLWithString:"https://www.apple.com", current application's NSURL's URLWithString:"https://www.yahoo.co.jp"}

set responses to my parallelGETRequestForURLs(requestURLs)

repeat with response in responses
    set returnedString to (current application's NSString's alloc()'s initWithData:(response's |data|) encoding:(current application's NSUTF8StringEncoding))
    log returnedString as text
end repeat

on parallelGETRequestForURLs(requestURLs)
    --require framework: Foundation
    set session to my getValidURLSession()
    set tasks to current application's NSMutableArray's alloc()'s init()
    repeat with requestURL in requestURLs
        set task to (session's dataTaskWithURL:requestURL)
        task's resume()
        (tasks's addObject:task)
    end repeat
    return my fetchURLSesstionTasksResult(tasks)
end parallelGETRequestForURLs

on getValidURLSession()
    --require framework: Foundation
    global URLSession
    try
        if URLSession = missing value then
            error number -2753
        end if
    on error number -2753
        set configuration to current application's NSURLSessionConfiguration's ephemeralSessionConfiguration()
        set URLSession to current application's NSURLSession's sessionWithConfiguration:configuration delegate:(me) delegateQueue:(missing value)
    end try
    return URLSession
end getValidURLSession

on URLSession:session didBecomeInvalidWithError:anError
    global URLSession
    log "URLSession invalidated"
    set URLSession to missing value
end URLSession:didBecomeInvalidWithError:

on fetchURLSesstionTasksResult(tasks)
    my waitForCompletionOfURLSessionTasks(tasks)
    my errorURLSessionTasksIfNeeded(tasks)
    return my getResponsesToURLSessionTasks(tasks)
end fetchURLSesstionTasksResult

on waitForCompletionOfURLSessionTasks(tasks)
    --require framework: Foundation
    set tasksAreRunningPredicate to current application's NSPredicate's predicateWithFormat_("NONE state == %@", current application's NSURLSessionTaskStateRunning as integer)
    repeat until tasksAreRunningPredicate's evaluateWithObject:tasks
        delay 0.01
    end repeat
end waitForCompletionOfURLSessionTasks

on errorURLSessionTasksIfNeeded(tasks)
    --require framework: Foundation
    repeat with errorTask in (tasks's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:"error != nil"))
        error errorTask's |error|'s localizedDescription as text number errorTask's |error|'s code as integer
    end repeat
    repeat with notCompletedTask in (tasks's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat_("state != %@", current application's NSURLSessionTaskStateCompleted as integer)))
        error "task has not completed"
    end repeat
end errorURLSessionTasksIfNeeded

on getResponsesToURLSessionTasks(tasks)
    --require framework: Foundation
    global responsesToURLSessionTask
    try
        responsesToURLSessionTask
    on error number -2753
        set responsesToURLSessionTask to current application's NSMutableArray's alloc()'s init()
    end try
    set newTasksFilterPredicate to current application's NSPredicate's predicateWithFormat_("NOT (taskIdentifier IN %@)", responsesToURLSessionTask's valueForKeyPath:"task.taskIdentifier")
    repeat with newTask in (tasks's filteredArrayUsingPredicate:newTasksFilterPredicate)
        (responsesToURLSessionTask's addObject:{task:newTask, |data|:current application's NSMutableData's alloc()'s init()})
    end repeat
    responsesToURLSessionTask's sortUsingDescriptors:{current application's NSSortDescriptor's sortDescriptorWithKey:"task.taskIdentifier" ascending:true}
    set responsesFilterPredicate to current application's NSPredicate's predicateWithFormat_("task.taskIdentifier IN %@", tasks's valueForKey:"taskIdentifier")
    return responsesToURLSessionTask's filteredArrayUsingPredicate:responsesFilterPredicate
end getResponsesToURLSessionTasks

on getResponseToURLSesstionTask(task)
    --require framework: Foundation
    return my getResponsesToURLSessionTasks(current application's NSArray's arrayWithObject:task)'s firstObject()
end getResponseToURLSesstionTask

on URLSession:session taskIsWaitingForConnectivity:task
    log "waiting for connectivity..."
end URLSession:taskIsWaitingForConnectivity:

on URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalBytesExpectedToSend
    log "sending..."
end URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:

on URLSession:session dataTask:task didReceiveData:aData
    log "receiving..."
    set receivedData to my getResponseToURLSesstionTask(task)'s |data|
    receivedData's appendData:aData
end URLSession:dataTask:didReceiveData:

on URLSession:session task:task didCompleteWithError:anError
    log "URLSessionTask completed"
end URLSession:task:didCompleteWithError:

更新履歴

  • 2018-07-20: FoundationフレームワークのNSURLSessionクラスを使って作成
  • 2018-07-21: エラー対応機能を追加
  • 2018-08-17: POSTRequestForURLハンドラを作成
  • 2018-08-18: NSURLSessionConfigurationを、キャッシュやcookieを使用しないephemeralSessionConfigurationに変更
  • 2018-09-05: invalidateされたURLSessionを避けるためにgetValidURLSessionハンドラを作成
  • 2018-09-06: getResponsesToURLSessionTasksハンドラを作成して並列実行に対応
  • 2018-09-10: 並列にGETリクエストを実行するparallelGETRequestForURLsハンドラを作成
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2