CharlesJS/SwiftyXPC

Could it be possible to stream line the boiler plate code?

Opened this issue · 1 comments

Hey Charles,

I starred the repo. It seems to bridge an annoying usability gap in the XPC framework,

What I have noticed is that there is a lot of boiler plate code when you have calls to remote functions that need to receive multiple parameters as well as callback functions to stream data.

In your example you have a "Long running function".

I have a similar case and needed to go through the hoops of creating listeners on the caller end and creating a data class to hold the multiple parameters to pass to the RPC call as well as the callback stream.

For example here:

// the callback side
let listener = try XPCListener(type: .anonymous, codeSigningRequirement: nil)
// Does name matter?

        // would be nice if we could call the functions as if they were plain methods . Actors?
        listener.setMessageHandler(name: "blah") { (_, value: SomeDecodableType) in
            print(value)
        }
        listener.errorHandler = { a, b in
            print(a,b)
        }
        let request = SomeCodableArgumentToPass(callback: listener.endpoint, .... all the parameters to pass along to the RPC....)
        listener.activate()
        try await service.sendMessage(name: "messageNameOnTheServerSide", request: request)



// the server side:

let serviceListener = try! XPCListener(type: .service, codeSigningRequirement: nil)
serviceListener.setMessageHandler(name: "some function name", handler: someHandler)


func someHandler(_ connection: XPCConnection, packedArguments: SomeCodableArgumentToPass) {
// boiler plate callback 
   let remoteConnection = try XPCConnection(
            type: .remoteServiceFromEndpoint(packedArguments.callback),
                    codeSigningRequirement: nil
                )
        remoteConnection.activate()
        for await d in Timer.publish(every: 1, on: .main, in: .default).autoconnect().values {
              ... do something ....
            try remoteConnection.sendOnewayMessage(message: SomeCodableResponse(....))
        }
}

Perhaps it would be possible to wrap somethings in macros and eliminate the boiler plate? or perhaps some reflection with naming conventions?

Thoughts?

That's a good point; I came up with the plan for this project before macros were available in Swift, so it's possible that there might be some area for future streamlining along those lines. I'll have to ponder over that for a while.

I didn't want to go the reflection route, because I kind of wanted to get away from the excessively "magical" way that NSXPCConnection works. The relative simplicity of this approach appeals to me, as it makes it less likely for weird bugs to show up, as well as probably performing a little better.