Upload media like video and image with Websocket in swift - ios

I am trying to upload and receive image and video media using WebSocket. Image and video are in base64 string format. I am getting an error while receiving the string from the server through socket "Domain=kNWErrorDomainPOSIX Code=40 "Message too long" UserInfo={NSDescription=Message too long}".
//MARK: Receive
func receiveMessage(){
let workItem = DispatchWorkItem{ [weak self] in
self?.webSocket?.receive(completionHandler: { result in
switch result {
case .success(let message):
switch message {
case .data(let data):
//print("data")
case .string(let strMessgae):
//print("strMessgae")
default:
break
}
case .failure(let error):
print("Error Receiving \(error)")
}
}
}
Getting error in case .failure. Please help me out with the error and how to resolve it.
Thanks in advance.

What I see is just a function of WebSocket that receives a Message.
case .data(let data):
In the data case, you will receive data (image, document, video)
case .string(let strMessgae):
//print("strMessgae")
In strMessage, you will be receiving a text message (eg: hi, hello)
public func sendData(data: String) {
webSocket?.send(URLSessionWebSocketTask.Message.data(data.data(using: .utf8)!), completionHandler: { error in
if let error = error {
print(error.localizedDescription)
}
})
}
try sending your image and video in the function above. Websocket has two functions to send message, either by Message or data.
Try this receive function:
public func receiveMessage() {
webSocket?.receive(completionHandler: { [weak self] result in
switch result {
case .success(let message):
DispatchQueue.main.async {
switch message {
case .data(let data):
print("Data is \(data)")
case .string(let text):
print("Receive Message \(text)")
#unknown default:
break
}
}
case .failure(let error):
print(error)
}
self?.receiveMessage()
})
}

Related

How do I fix the prompt Open AI response?

I am using the OpenAI API to generate text completions for prompts, but I am encountering an issue where the API response returns an error
No value associated with key CodingKeys(stringValue: "object",
intValue: nil) ("object")
I have checked that the prompt I am sending is valid and I have tested with different prompts, but the issue persists. What could be causing this problem and how can I fix it? Any help or insights would be greatly appreciated.
Thank you.
class NetworkManager{
static let shared = NetworkManager()
#frozen enum Constants{
static let key = ""
}
private var client: OpenAISwift?
private init() {}
func setUp(){
self.client = OpenAISwift(authToken: Constants.key)
}
func getResponse(input: String, completion: #escaping (Result<String, Error>) -> Void) {
let prompt = """
translate from English to Nigerian Pidgin:
\(input)
Output:
"""
client?.sendCompletion(with: prompt, model: .gpt3(.davinci), maxTokens: 60) { result in
switch result {
case .success(let response):
let output = response.choices.first?.text ?? ""
print(response)
completion(.success(output))
case .failure(let error):
completion(.failure(error))
print(error.localizedDescription)
}
}
}
networkManager.getResponse(input: inputText) { result in
switch result {
case .success(let outputText):
DispatchQueue.main.async {
self.secondTextField.text = outputText
}
case .failure(let error):
print("Error translating text: \(error)")
}
}

Swift 5, Alamofire, Combine, MVVM throws error

func fetchData(from endpoint:ScrapeAPI )->AnyPublisher<T, APIError>{
return AF.request(endpoint.mockurl,
method: .post,
parameters: endpoint.parameters,
encoder: JSONParameterEncoder.prettyPrinted,
headers: endpoint.headers)
.validate()
.publishDecodable(type:T.self)
.value()
.mapError{_ in APIError.unknown}
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
enum APIError:Error {
case decodingError
case errorCOde(Int)
case unknown
}
extension APIError: LocalizedError{
var errorDescription: String? {
switch self {
case .decodingError:
return "Failed to decode the object from the service"
case .errorCOde(let code ):
return "\(code)- Something went wrong"
case .unknown:
return "the error is unknown"
}
}
}
var subscriptions = Set<AnyCancellable>()
fetchData(from:ScrapeAPI.getScrape).sink(
receiveCompletion: { completion in
switch completion {
case .failure(let error):
print(error)
case .finished:
print("Success")
}
},
receiveValue: { value in
print(value)}
).store(in: &subscriptions)
This prints error "unknown". It reaches the API and API responds with a body. It seems it is not getting published to T. Interestingly, Alamofire .responseJSON works. Ideally, I would like to verify T has new JSON data from API. How do I go about it?

NSPOSIXErrorDomain Code=57 "Socket is not connected"

I'm creating a chat app using websocket.
I'm connecting to server with URLSessionWebSocketTask.
url = ws://"appname".herokuapp.com/chats/listen/
func connect(url: String) {
self.socket = session.webSocketTask(with: URL(string: url)!)
self.listen()
self.socket.resume()
}
func listen() {
self.socket.receive { [weak self] (result) in
guard let self = self else { return }
switch result {
case .failure(let error):
print(error)
return
case .success(let message):
switch message {
case .data(let data):
self.handle(data)
case .string(let str):
guard let data = str.data(using: .utf8) else { return }
self.handle(data)
#unknown default:
break
}
}
self.listen()
}
}
It's running okay on localhost, but after I deploy the server to Heroku, I get this message:
NSPOSIXErrorDomain Code=57 "Socket is not connected
I guest it was auto disconnect after a time out.
So, I add ping function to ping every 10s. Then, it works:
func sendPing() {
self.socket.sendPing { (error) in
if let error = error {
print("Sending PING failed: \(error)")
}
DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
self.sendPing()
}
}
}

How to generate and handle errors in Swift

I'm working on an app where users need to login. The webapplication uses a token, that users can get from calling a webservice using their username and password. My question now is what's the best way the handle errors that can occur. What I have now:
LoginViewController.swift
self.api.token(forUsername: "a", password: "b") { (result) in
switch (result) {
case .failure(let error):
print("something when wrong \(error)")
case .success(let token):
print("token \(token)")
}
LoginAPIClient (the self.api) using https://github.com/3lvis/Networking
class LoginAPIClient {
enum ResponseError: Error {
case unexpectedDataError
case unknownError
}
enum Result {
case success(String)
case failure(Error)
}
lazy var networking: Networking = {
let networking = Networking(baseURL: APIClient.serverURL())
return networking
}()
func token(forUsername username: String, password: String, completion: #escaping (Result) -> Void) {
let parameters = ["username" : username, "password" : password]
networking.post("/api/login", parameters: parameters) { (result) in
switch result {
case .failure(let response):
return completion(.failure(response.error))
case .success(let response):
if var token = response.headers["Authorization"] as? String {
token = token.replacingOccurrences(of: "Bearer ", with: "")
return completion(.success(token))
}
return completion(.failure(ResponseError.unknownError))
}
}
}
}
Here for example I'm creating my own error return completion(.failure(ResponseError.unknownError)) in case the server responds with a successful status code (200) but somehow the Authorization header is missing from the response.
This works, the only problem is that now when I handle the error in the ViewController I don't know the exact reason why it fails. For example, from the Networking library I get an error code (400 or 401 etc) but this is lost because first it was an NSError. I could use an NSError but somehow this doesn't feel right. Could anyone point me in the right direction?
One of the solutions I thought of was to add an extra enum and then do something like this:
enum Result {
case success(String)
case networkFailure(FailureJSONResponse)
case failure(Error)
}
self.api.token(forUsername: "a", password: "b") { (result) in
switch (result) {
case .failure(let error):
print("something when wrong \(error)")
case .networkFailure(let response):
print("something when wrong \(error)")
case .success(let token):
print("token \(token)")
}
But I rather have just 1 success and 1 failure in the switch.
Every application usually has its own "Error", so in your case you can define
public enum AppError: Swift.Error, CustomStringConvertible {
case networkError(code: Int)
case anotherError(message: String?)
case underlying(Swift.Error)
public var description: String {
switch self {
case .networkError(let code):
return "Network error with code \(code)"
default://I'm not gonna cover all cases, but you should :)
return "Error"
}
}
}
then you can use your approach
enum Result {
case success(String)
case failure(AppError)
}
You can add second parameter to completion block:
func token(forUsername username: String, password: String, completion: #escaping (Result, error: ResponseError?) -> Void)

Completion handler for Alamofire network fetch

I am attempting to create a function which will return a list of custom objects, created from parsing JSON. I am using AlamoFire to download the content. I have written this function which, on success, creates an array of locations to be returned. However, the returns are always nil. My code is below:
func fetchLocations() -> [Location]? {
var locations : [Location]?
Alamofire.request(.GET, myURL)
.responseJSON { response in
switch response.result {
case .Success(let data):
locations = createMapLocations(data)
case .Failure(let error):
print("Request failed with error: \(error)")
}
}
return locations
}
I am pretty positive the issue is that the functioning is returning before the network request is complete. I am new to Swift, and unsure how to handle this. Any help would be appreciated!
You can read more about closures/ completion handlers https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html or google.
func fetchLocations(completionHandler: (locations: [Location]?, error: NSError) -> ()) -> () {
var locations : [Location]?
Alamofire.request(.GET, myURL)
.responseJSON { response in
switch response.result {
case .Success(let data):
locations = createMapLocations(data)
completionHandler(locations, error: nil)
case .Failure(let error):
print("Request failed with error: \(error)")
completionHandler(locations: nil, error: error)
}
}
}
Usage
fetchLocations(){
data in
if(data.locations != nil){
//do something witht he data
}else{
//Handle error here
print(data.error)
}
}

Resources