Thanks! That looks like a good start.
I don't have lots of time right now so please excuse my telegraph style comments below ![]()
- I think there are too many top-level types. I think the API could benefit from nesting related types
- why is it
swift-nio-http2-apns? I think you should drop thehttp2, I'm sure that if APNS switched to say HTTP/1.1 (unlikely
) you'd then implement that too in this package -
APNSResponse's API looks more complicated than necessary to me: You setresponse.dataand if that fails,response.errorgets set behind the scenes. I think there should be an initialiserinit<Bytes: Sequence>(bytes: Bytes) throws where Bytes.Element == UInt8and if the initialisation fails, it would justthrow - the APNS payload type is called
APSPayload, is there anNmissing? - API docs would be great. For example there's a
threadID, I believe that's for conversation threads or something? - why do we need the
APNSNotificationProtocolprotocol? Why don't we just pass the containedaps: APSPayload? -
APNSRequestEncodercloses theChannelif something goes wrong. Usually a reusableChannelHandlerthat is a NIO-citizen does not close theChannelitself. It rather usescontext.fireErrorCaught(error)through theChannelPipelineso that the user can choose what to do. In most cases, there's no recovery and the 'application handler' (usually the last handler in a pipeline) will close the connection. But in certain cases the user might be able to handle the error and then we shouldn't just throw away the channel. -
APNSStreamHandlershouldn't be necessary, you can just useRequestResponseHandlerwhich should be way more efficient and correct. - please do not
@_exported import(inExported.swift), this will break SemVer majorly - do we need the
APNSSignerprotocol? There is only one implementation (DataSigner). I think we could renameDataSignertoAPNSSigner. The parameters don't actually need to beData, you literally only get their pointer. If you just make theinit(data:)andsign(digest:)argumentsUnsafeRawBufferPointerthen you can addData,ByteBuffer, andArray<UInt8>convenience functions - this looks very dangerous:
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || !defined(LIBRESSL_VERSION_NUMBER)
typedef struct ECDSA_SIG_st {
BIGNUM *r;
BIGNUM *s;
} ECDSA_SIG;
#endif
because if defines a type that must match your system's OpenSSL version's definition of that struct. If it's not a perfect match then really bad things will happen.