trilemma-dev / SecureXPC

A simple and secure XPC framework for Swift
MIT License
75 stars 15 forks source link

Adds support for errors to optionally be part of a route's definition #72

Closed jakaplan closed 2 years ago

jakaplan commented 2 years ago

Overview of changes:

jakaplan commented 2 years ago

@amomchilov for your review when you have the time

amomchilov commented 2 years ago

Heyo

I'm a little busy this week. I'll try to review it this weekend. I like the idea.

jakaplan commented 2 years ago

I'm a little busy this week. I'll try to review it this weekend. I like the idea.

No worries, I appreciate all of the time you've spent contributing to this project.

jakaplan commented 2 years ago

@amomchilov would you have a chance to review this weekend? If not I completely understand, but I'll probably go back to committing without review. However, I'll keep using pull requests to make it easier for later feedback.

amomchilov commented 2 years ago

Hey Josh, sorry for the delay. I've just sat down to take look through this.

jakaplan commented 2 years ago

One high level design question:

Does it make sense to limit thrown types to only 1 type, and expect users to make their own union of all thrown types they want? That could simplify the framework, but adds a bit more burden on the user.

No, that's not the expectation. Any number of types can be registered, but each registration needs to be done with its own function call. However, these function calls can be chained so it should be relatively convenient. For example:

let route = XPCRoute.named("process")
                    .throwsType(AllowedCommandError.self)
                    .throwsType(SharedConstantsError.self)

The reason this needs to be done is that a variadic parameter of a generic type doesn't work here because Swift will try to resolve the error to its actual type, not a common protocol each argument conforms to. As a result, passing in two different types is not accepted by the compiler. This is at least is my empirical experience combined with my less than comprehensive knowledge of Swift's generics.

As an example let's say there was a function:

public func throwsTypes<E: Error & Codable>(_ errorTypes: E.Type...) -> XPCRouteWithoutMessageWithoutReply {
        XPCRouteWithoutMessageWithoutReply(self.route.pathComponents,
                                           errorTypes: self.route.errorTypes + errorTypes)
}

And then at the call site we attempted to do:

let route = XPCRoute.named("process")
                     .throwsTypes(AllowedCommandError.self, SharedConstantsError.self)

Where AllowedCommandError and SharedConstantsError both conform to Error and Codable. The compiler will provide the error:

Cannot convert value of type 'SharedConstants.SharedConstantsError.Type' to expected argument type 'AllowedCommandError.Type'