Messages are large, You may want to consider smaller messages. node-ipc and swift (OSX)

203 views Asked by At

I have a node app that is trying to communicate with a swift application using a unix socket. I am broadcasting a Message ever 3 seconds using the following code with node-ipc:

const ipc = require('node-ipc').default;       

// Run IPC server for testing
const first = "FIRST";
const second = "SECOND";
const ipcSocketPath = `/tmp/${ipcAppId}`;

async function setupCoreCommunicationIpc() {
    await new Promise((resolve) => {
        ipc.serve(ipcSocketPath, () => {
            ipc.server.on('ping', (data, socket) => {
                ipc.server.emit(socket, 'pong');
            });

            return resolve(true);
        });
        ipc.server.start();
    });
}


function sendMessage(message, payload = {}) {
    ipc.server.broadcast(message, { ...payload, "valueOne": first, "valueTwo": seconds });
}


(async () => {
    try {
        await setupCoreCommunicationIpc()
    } catch (e) {
        // Deal with the fact the chain failed
    }
    // `text` is not available here
})();

setInterval(async () => {
    await sendMessage("first:message", {core_id: ipcAppId, app_id: ipcAppId, message_id: 5})
}, 3000);

The code on swift is a bit more complicated. But I am able to connect to the unix socket and receive the message. The Problem is the sending of the AckMessage. I tried different approaches for sending the message but it would not work. Here is the code in swift:

func startSocketStack(valueOne: String, valueTwo: String){
    let MTU = 65536
    let path = "/tmp/\(valueTwo)"
    print("starting socket at: %\(path)%")
    
    let client = socket(AF_UNIX, SOCK_STREAM, 0)
    var address = sockaddr_un()
    //address.sun_family = UInt8(AF_UNIX)
    address.sun_family = sa_family_t(AF_UNIX)
    //address.sun_len = UInt8(MemoryLayout<sockaddr_un>.size)
    address.sun_len = UInt8(MemoryLayout<UInt8>.size + MemoryLayout<sa_family_t>.size + path.utf8.count + 1)
    strlcpy(&address.sun_path.0, path, MemoryLayout.size(ofValue: address.sun_path))
    
    var adressUnwrap = address
    withUnsafePointer(to: &adressUnwrap) {
        $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
            let connection = connect(client, $0, socklen_t(address.sun_len))
            if (connection != 0) {
                print("startSocket: could not connect to socket at \(path)")
            }
        }
    }
    
    var buffer = UnsafeMutableRawPointer.allocate(byteCount: MTU,alignment: MemoryLayout<CChar>.size)
    while(true) {
        let readResult = read(client, &buffer, MTU)
        if (readResult == 0) {
            break;  // end of file
        } else if (readResult == -1) {
            print("Error reading form client\(client) - \(errno)")
            break;  // error
        } else {
            let strResult = withUnsafePointer(to: &buffer) {
                $0.withMemoryRebound(to: CChar.self, capacity: MemoryLayout.size(ofValue: readResult)) {
                    String(cString: $0)
                }
            }
            print("Received form client(\(client)): §\(strResult)§")
            print("§\(strResult)§")
            let trimmedString = strResult.components(separatedBy: .whitespacesAndNewlines).joined()
            print("§\(trimmedString)§")

          
            struct Message: Decodable {
                let type: String
                let data: MessageData
                
                struct MessageData: Decodable {
                    var valueOne: String
                    var valueTwo: String
                    var message_id: String
                }
            }
            
            struct AckMessage: Encodable {
                let type: String
                let data: Bool
            }
            
            do {
                let jsonMessage = trimmedString.components(separatedBy: "}")[0] + "}" + "}"
                let jsonData = jsonMessage.trimmingCharacters(in: CharacterSet.newlines).data(using: .utf8)!
                let receivedMessage: Message = try JSONDecoder().decode(Message.self, from: jsonData)
                let messageId = receivedMessage.data.message_id
                let ackMessage = AckMessage(type: messageId, data: true)
                let jsonAckMessage = try JSONEncoder().encode(ackMessage)
                let delimiter = #"\f"#.bytes
                let jsonAckMessageWithDelimiter = jsonAckMessage + delimiter
                print("jsonAckMessageWithDelimiter")
                print(jsonAckMessageWithDelimiter)

                
                
                // first attempt
                do {
                    try jsonAckMessageWithDelimiter.withUnsafeBytes() { [unowned self] (buffer: UnsafeRawBufferPointer) throws -> Int in
                        let buffer = buffer.baseAddress!
                        print(buffer)
                        let bufSize = jsonAckMessageWithDelimiter.count
                        print(bufSize)
                        
                        var sent = 0
                        var sendFlags: Int32 = 0
                        while sent < bufSize {

                            var s = 0
                            s = send(client, buffer.advanced(by: sent), Int(bufSize - sent), sendFlags)
                            if s <= 0 {

                                if errno == EAGAIN{

                                    // We have written out as much as we can...
                                    return sent
                                }
                            }
                            sent += s
                        }
                        return sent
                    }
                } catch {
                    print(error)
                }
                
                
                // second attempt
                jsonAckMessageWithDelimiter.withUnsafeBytes {
                    guard let pointer = $0.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
                      return
                    }
                    write(client, pointer, jsonAckMessageWithDelimiter.count)
                }
            } catch {
                print("Error on received message \(error)")
            }
        }
    }
}

In my node application I can not receive the AckMessage because I get the following error:

Messages are large, You may want to consider smaller messages.

Now from my experience from Windows and Linux I know that \f is the delimiter that should indicate the end of the message. I am sending it at the end of my json but it is somehow not recognized.

What could be the problem? Is the delimiter wrong? Is the buffersize a Problem?

When logging what I send it says that it has sent all 61 bytes as expected.

1

There are 1 answers

0
Silve2611 On BEST ANSWER

For anyone having this problem using "\u{000C}" instead of "\f" is the solution.