Skip to content

Commit

Permalink
add curl bindings for Spottie frontend to communicate with PlayerCore
Browse files Browse the repository at this point in the history
  • Loading branch information
Lee Jun Kit committed Oct 8, 2021
1 parent daa6459 commit 379c88d
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 0 deletions.
124 changes: 124 additions & 0 deletions Spottie/Backend/CURL/CurlClient.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
//
// CurlClient.swift
// Spottie
//
// Created by Lee Jun Kit on 19/8/21.
//

import Foundation

class CurlReceivedData {
var data: Data?
init() {}
}

class CurlBodyData {
var data: Data
var bytesLeftToCopy: Int
init(_ d: Data) {
data = d
bytesLeftToCopy = d.count
}
}

enum CurlError: Error {
case unknown
}

struct CurlClient {
let socketPath: String
let queue = DispatchQueue(label: "ljk.spottie.curl", qos: .userInteractive)
let curl = curl_easy_init()
let readFunc: curl_read_callback = { (buffer, size, num, p) -> Int in
let wrapper = Unmanaged<CurlBodyData>.fromOpaque(p!).takeRetainedValue()
let bufferSize = size * num

var numBytesToCopy = wrapper.bytesLeftToCopy
if numBytesToCopy == 0 {
Unmanaged<CurlBodyData>.fromOpaque(p!).release()
return 0
}

if numBytesToCopy > bufferSize {
numBytesToCopy = bufferSize
}

// perform the copy
let start = wrapper.data.count - wrapper.bytesLeftToCopy
let range = start..<(start+numBytesToCopy)
let bufferPointer = UnsafeMutableRawBufferPointer(start: buffer, count: bufferSize)
let numBytesCopied = wrapper.data.copyBytes(to: bufferPointer, from: range)

// update the state
wrapper.bytesLeftToCopy = wrapper.bytesLeftToCopy - numBytesCopied
return numBytesCopied
}

let writeFunc: curl_write_callback = { (buffer, size, num, p) -> Int in
let received = Unmanaged<CurlReceivedData>.fromOpaque(p!).takeUnretainedValue()
let bytes = UnsafeRawPointer(buffer!)
let length = size * num
let data = Data(bytes: bytes, count: length)
received.data = data
return length
}

init(socketPath: String) {
self.socketPath = socketPath
}

func run(_ originalReq: URLRequest) async -> Result<CurlReceivedData, CurlError> {
let req = (originalReq as NSURLRequest).copy() as! URLRequest
return await withCheckedContinuation { continuation in
queue.async {
curl_easy_setopt_long(curl, CURLOPT_VERBOSE, 1)
curl_easy_setopt_string(curl, CURLOPT_UNIX_SOCKET_PATH, socketPath)

// convert the request into CURL arguments
curl_easy_setopt_string(curl, CURLOPT_URL, req.url?.absoluteString)

// set post
if req.httpMethod == "POST" {
curl_easy_setopt_long(curl, CURLOPT_POST, 1)
}

// handle request body
if let body = req.httpBody {
curl_easy_setopt_func_read(curl, CURLOPT_READFUNCTION, readFunc)
let bodyWrapper = CurlBodyData(body)
let bodyWrapperPointer = Unmanaged.passRetained(bodyWrapper).toOpaque()
curl_easy_setopt_pointer(curl, CURLOPT_READDATA, bodyWrapperPointer)
curl_easy_setopt_long(curl, CURLOPT_POSTFIELDSIZE, bodyWrapper.data.count)
}

// handle headers
var slist: UnsafeMutablePointer<curl_slist>? = nil
if let reqHeaders = req.allHTTPHeaderFields {
for (key, value) in reqHeaders {
slist = curl_slist_append(slist, "\(key): \(value)")
}
}
curl_easy_setopt_slist(curl, CURLOPT_HTTPHEADER, slist)

// setup write function
let received = CurlReceivedData()
let pointer = Unmanaged.passUnretained(received).toOpaque()
curl_easy_setopt_func_write(curl, CURLOPT_WRITEFUNCTION, writeFunc)
curl_easy_setopt_pointer(curl, CURLOPT_WRITEDATA, pointer)

let res = curl_easy_perform(curl)
if res == CURLE_OK {
var code: Int64 = 0
curl_easy_getinfo_long(curl, CURLINFO_RESPONSE_CODE, &code)
continuation.resume(returning: Result.success(received))
} else {
continuation.resume(returning: Result.failure(CurlError.unknown))
}

// cleanup
curl_slist_free_all(slist)
curl_easy_reset(curl)
}
}
}
}
35 changes: 35 additions & 0 deletions Spottie/Backend/CURL/spottie_curl.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,45 @@

#include "spottie_curl.h"

CURLcode curl_easy_setopt_long(CURL *curl, CURLoption option, long param) {
return curl_easy_setopt(curl, option, param);
}

CURLcode curl_easy_setopt_string(CURL *curl, CURLoption option, const char *param) {
return curl_easy_setopt(curl, option, param);
}

CURLcode curl_easy_setopt_bool(CURL *curl, CURLoption option, bool param) {
return curl_easy_setopt(curl, option, param);
}

CURLcode curl_easy_setopt_slist(CURL *curl, CURLoption option, struct curl_slist *param) {
return curl_easy_setopt(curl, option, param);
}

CURLcode curl_easy_setopt_func_write(CURL *curl, CURLoption option, curl_write_callback param) {
return curl_easy_setopt(curl, option, param);
}

CURLcode curl_easy_setopt_func_read(CURL *curl, CURLoption option, curl_read_callback param) {
return curl_easy_setopt(curl, option, param);
}

CURLcode curl_easy_setopt_pointer(CURL *curl, CURLoption option, void *param) {
return curl_easy_setopt(curl, option, param);
}

CURLcode curl_easy_getinfo_long(CURL *handle, CURLINFO option, int64_t *param)
{
return curl_easy_getinfo(handle, option, param);
}

CURLcode curl_easy_getinfo_string(CURL *handle, CURLINFO option, const char **param)
{
return curl_easy_getinfo(handle, option, param);
}

CURLcode curl_easy_getinfo_double(CURL *handle, CURLINFO option, double *param)
{
return curl_easy_getinfo(handle, option, param);
}
8 changes: 8 additions & 0 deletions Spottie/Backend/CURL/spottie_curl.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,15 @@
#include <stdbool.h>
#include <curl/curl.h>

CURLcode curl_easy_setopt_long(CURL *curl, CURLoption option, long param);
CURLcode curl_easy_setopt_string(CURL *curl, CURLoption option, const char *param);
CURLcode curl_easy_setopt_bool(CURL *curl, CURLoption option, bool param);
CURLcode curl_easy_setopt_slist(CURL *handle, CURLoption option, struct curl_slist *param);
CURLcode curl_easy_setopt_func_write(CURL *curl, CURLoption option, curl_write_callback param);
CURLcode curl_easy_setopt_func_read(CURL *curl, CURLoption option, curl_read_callback param);
CURLcode curl_easy_setopt_pointer(CURL *curl, CURLoption option, void *param);
CURLcode curl_easy_getinfo_long(CURL *handle, CURLINFO option, int64_t *param);
CURLcode curl_easy_getinfo_string(CURL *handle, CURLINFO option, const char **param);
CURLcode curl_easy_getinfo_double(CURL *handle, CURLINFO option, double *param);

#endif /* spottie_curl_h */

0 comments on commit 379c88d

Please sign in to comment.