How to convert message received by Swift socket communication to String type - swift

I want to do TCP communication using a library called SwiftSocket.
Below is the sample code of SwiftSocket.
func echoService(client: TCPClient) {
print("Newclient from:\(client.address)[\(client.port)]")
var d = client.read(1024*10)
client.send(data: d!)
client.close()
}
func testServer() {
let server = TCPServer(address: "127.0.0.1", port: 8080)
switch server.listen() {
case .success:
while true {
if var client = server.accept() {
echoService(client: client)
} else {
print("accept error")
}
}
case .failure(let error):
print(error)
}
}
I want to convert the received message to String in the third line of the above code
var d = client.read(1024*10)
How can I do that?

Try this;
if let string = String(bytes: d, encoding: .utf8)
{
print(string)
} else
{
print("not a valid UTF-8 sequence")
}

Related

How to create a chat app using TCP in swift

I simply wants to pass a string from one phone to another (vice versa) using TCP connection. Hence, I have a few questions as I'm a bit confused.
Can this be achieved using two different simulators in two different mac machines ?
Can this be achieved using two different simulators in the same mac machine ?
If this can be done on simulators would replacing the IP of the mac would work with 8080 port ?
My partially completed code as bellow;
class NWTCPConnection: NSObject {
var connection: NWConnection!
func connectToTcp() {
let PORT: NWEndpoint.Port = 8080
let ipAddress :NWEndpoint.Host = "192.168.8.133" //Machines IP
let queue = DispatchQueue(label: "TCP Client Queue")
let tcp = NWProtocolTCP.Options.init()
tcp.noDelay = true
let params = NWParameters.init(tls: nil, tcp: tcp)
connection = NWConnection(to: NWEndpoint.hostPort(host: ipAddress, port: PORT), using: params)
connection.stateUpdateHandler = { (newState) in
switch (newState) {
case .ready:
print("Socket State: Ready")
UserDefaults.standard.set(true, forKey: "isConnected")
self.sendMSG()
self.receive()
default:
UserDefaults.standard.set(false, forKey: "isConnected")
break
}
}
connection.start(queue: queue)
}
func sendMSG() {
print("send data")
let message1 = "hello world"
let content: Data = message1.data(using: .utf8)!
connection.send(content: content, completion: NWConnection.SendCompletion.contentProcessed(({ (NWError) in
if (NWError == nil) {
print("Data was sent to TCP destination ")
} else {
print("ERROR! Error when data (Type: Data) sending. NWError: \n \(NWError!)")
}
})))
}
// How to trigger this ???
func receive() {
connection.receiveMessage { (data, context, isComplete, error) in
if (isComplete) {
print("Receive is complete, count bytes: \(data!.count)")
if (data != nil) {
print(data!)
} else {
print("Data == nil")
}
}
}
}
the moment I run the simulator and call the connectToTcp() I get the following error
nw_socket_handle_socket_event [C1:1] Socket SO_ERROR [61: Connection refused]

Swift NWConnection with Discord IPC (protocol error)

I try to connect with Discord using IPC, but whatever i try, the error message stays the same Optional("\u{02}\0\0\0(\0\0\0{"code":1003,"message":"protocol error"}")
I started with the encode function, but that is UInt8 because Swift apparently does not support an UInt32 data object.
Then i tried to create an UInt32 (memory) array, to convert that to Data, that failed as well.
can someone point me into the direction where I make a mistake.
import Foundation
import Cocoa
import Network
class Discord {
enum opcode: UInt32 {
case handshake = 0
case frame = 1
case close = 2
case ping = 3
case pong = 4
}
var appID: String
private var connection: NWConnection?
private let endpoint: String = NSTemporaryDirectory() + "discord-ipc-0"
init(appID: String) {
self.appID = appID
}
func connect() {
print("Connecting to \(endpoint)")
connection = NWConnection(
to: NWEndpoint.unix(path: endpoint),
using: .tcp
)
connection?.stateUpdateHandler = { state in
switch state {
case .setup:
print("Setting up...")
case .preparing:
print("Prepairing...")
case .waiting(let error):
print("Waiting: \(error)")
case .ready:
print("Ready...")
case .failed(let error):
print("Failed: \(error)")
case .cancelled:
print("Cancelled :'(")
default:
break
}
}
connection?.receiveMessage { completeContent, contentContext, isComplete, error in
print(
String(data: completeContent ?? Data(), encoding: .utf8),
error
)
}
connection?.start(queue: .global())
}
func uint32encode(opcode: opcode, message string: String) -> Data {
let payload = string.data(using: .utf8)!
var buffer = UnsafeMutableRawBufferPointer.allocate(byteCount: 8 + payload.count, alignment: 0)
defer { buffer.deallocate() }
buffer.copyBytes(from: payload)
buffer[8...] = buffer[..<payload.count]
buffer.storeBytes(of: opcode.rawValue, as: UInt32.self)
buffer.storeBytes(of: UInt32(payload.count), toByteOffset: 4, as: UInt32.self)
let uIntData = Data(bytes: &buffer, count: 8 + payload.count)
return uIntData
}
func encode(opcode: opcode, message string: String) -> Data {
let jsondata = string.data(using: .utf8)!
var data = Data()
data.append(UInt8(opcode.rawValue))
data.append(UInt8(jsondata.count))
data.append(contentsOf: [UInt8](jsondata))
/*
uint32 opcode (0 or 1)
uint32 length (length)
byte[length] jsonData (??)
*/
return data
}
func handshake() {
connect()
// We should say "hello", with opcode handshake
let hello = encode(opcode: .handshake, message: "{\"v\":1,\"client_id\":\"\(appID)\"}")
print("Sending \(String.init(data: hello, encoding: .utf8))")
connection?.send(
content: hello,
completion: .contentProcessed({ error in
print("Error:", error?.localizedDescription)
})
)
}
func handshakev2() {
connect()
// We should say "hello", with opcode handshake
let hello = uint32encode(opcode: .handshake, message: "{\"v\":1,\"client_id\":\"\(appID)\"}")
print("Sending (V2) \(String.init(data: hello, encoding: .utf8))")
connection?.send(
content: hello,
completion: .contentProcessed({ error in
print("Error (V2):", error?.localizedDescription)
})
)
}
}

Not sure how to implement the SMB project into my app

I'm trying to implement SMB into my app and found this https://github.com/amosavian/AMSMB2. I'm not sure how to implement this code into the UI of my app. For example, do I connect the connect function to a button and if so how would I proceed to do so. What would I put into the parameters of connect() when I call it if I call it.
Here's the code from the repository:
import AMSMB2
class SMBClient {
/// connect to: `smb://guest#XXX.XXX.XX.XX/share`
let serverURL = URL(string: "smb://XXX.XXX.XX.XX")!
let credential = URLCredential(user: "guest", password: "", persistence: URLCredential.Persistence.forSession)
let share = "share"
lazy private var client = AMSMB2(url: self.serverURL, credential: self.credential)!
private func connect(handler: #escaping (Result<AMSMB2, Error>) -> Void) {
// AMSMB2 can handle queueing connection requests
client.connectShare(name: self.share) { error in
if let error = error {
handler(.failure(error))
} else {
handler(.success(self.client))
}
}
}
func listDirectory(path: String) {
connect { result in
switch result {
case .success(let client):
client.contentsOfDirectory(atPath: path) { result in
switch result {
case .success(let files):
for entry in files {
print("name:", entry[.nameKey] as! String,
", path:", entry[.pathKey] as! String,
", type:", entry[.fileResourceTypeKey] as! URLFileResourceType,
", size:", entry[.fileSizeKey] as! Int64,
", modified:", entry[.contentModificationDateKey] as! Date,
", created:", entry[.creationDateKey] as! Date)
}
case .failure(let error):
print(error)
}
}
case .failure(let error):
print(error)
}
}
}
func moveItem(path: String, to toPath: String) {
self.connect { result in
switch result {
case .success(let client):
client.moveItem(atPath: path, toPath: toPath) { error in
if let error = error {
print(error)
} else {
print("\(path) moved successfully.")
}
// Disconnecting is optional, it will be called eventually
// when `AMSMB2` object is freed.
// You may call it explicitly to detect errors.
client.disconnectShare(completionHandler: { (error) in
if let error = error {
print(error)
}
})
}
case .failure(let error):
print(error)
}
}
}
}
late but for reference as i couldnt find much when i tried
add the amsmb2 library and that template class file to your project
in the class file set serverurl, share, credential correctly for your smb server
then
declare a variable of class smb_client
then from your button or whatever
var myclient:smb_client=smb_client()
myclient.connect()
to connect to your smb server for example
you can extend that class templete to download/upload items etc
the operations are asynchronous

refine twilio token connection error

At the moment, Users will get a "No internet connection" error, when the cloudfunctions API to get the Twilio token is offline or faulty. This should return a different error message. how do i refine the error message according to the kind of error encountered in swift?
class Token {
let value: String
init (url: String = "userTokenURL") throws {
guard let requestURL = URL(string: url) else {
throw Token.Error.invalidURL
}
do {
let data = try Data(contentsOf: requestURL)
guard let stringToken = String(data: data, encoding: .utf8) else {
throw Token.Error.couldNotConvertDataToString
}
value = stringToken
} catch let error as NSError {
print ("Error fetching token data, \(error)")
throw Token.Error.noInternet
}
}
}
extension Token {
enum Error: Swift.Error {
case invalidURL
case couldNotConvertDataToString
case noInternet
var description: String? {
switch self {
case .invalidURL:
return NSLocalizedString("Token URL is invalid.", comment: "")
case .couldNotConvertDataToString:
return NSLocalizedString("Token Data could not be converted to String.", comment: "")
case .noInternet:
return NSLocalizedString("Internet connection failed.", comment: "")
}
}
}
}

How to detect end of socket packet in Swift

I am building an HTTP server in Swift. The server will eventually run on Linux, but right now only compiles on Mac OS.
Anyways, I have the socket connections working perfectly and I'm able to receive the data stream, but I am having difficulty finding the best way to determine how to detect the end of the socket data stream.
I know there's many ways todo this, and I know that sockets basically just spit out pure binary data and have no concept of a "packet" that has a beginning and end. My question what are the best techniques used to detect the end of a packet sent from a web browser requesting a web page? I know for JSON it's pretty easy, but I'm curious about when the client is requesting a web page specifically.
Thanks
InputStream did that for you, you don't have to care about that.
Try to use this:
import Foundation
typealias OnComing = (String) -> (Void)
class SocketClient: NSObject, StreamDelegate {
var host:String?
var port:Int?
var inputStream: InputStream?
var outputStream: OutputStream?
var status = false;
var output = ""
var bufferSize = 1024;
var onComing:OnComing!
func makeCFStreamConnection(host: String, port: Int, onComing:#escaping OnComing) {
self.host = host
self.port = port
self.onComing = onComing
Stream.getStreamsToHost(withName: host, port: port, inputStream: &self.inputStream, outputStream: &self.outputStream)
if self.inputStream != nil && self.outputStream != nil {
self.inputStream!.delegate = self
self.outputStream!.delegate = self
self.inputStream!.schedule(in: .main, forMode: RunLoopMode.defaultRunLoopMode)
self.outputStream!.schedule(in: .main, forMode: RunLoopMode.defaultRunLoopMode)
self.inputStream!.open()
self.outputStream!.open()
}
}
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
if aStream === self.inputStream {
switch eventCode {
case Stream.Event.errorOccurred:
break
case Stream.Event.openCompleted:
break
case Stream.Event.hasBytesAvailable:
break
read()
default:
break
}
} else if aStream === self.outputStream {
switch eventCode {
case Stream.Event.errorOccurred:
break
case Stream.Event.openCompleted:
break
case Stream.Event.hasSpaceAvailable:
break
default:
break
}
}
}
func read() {
var buffer = [UInt8](repeating: 0, count: bufferSize)
while (self.inputStream!.hasBytesAvailable) {
let bytesRead: Int = inputStream!.read(&buffer, maxLength: buffer.count)
if bytesRead >= 0 {
output += NSString(bytes: UnsafePointer(buffer), length: bytesRead, encoding: String.Encoding.ascii.rawValue)! as String
} else {
print("# Stream read() error")
}
}
self.onComing(output)
}
func write(message:String) {
let encodedDataArray = [UInt8]("\(message)\n".utf8)
self.outputStream?.write(encodedDataArray, maxLength: encodedDataArray.count)
}
}
Your problem is resolved by read()