mirror of
https://github.com/signalapp/libsignal.git
synced 2024-09-19 19:42:19 +02:00
swift: Expose the reason a ChatService was disconnected
This commit is contained in:
parent
a2702a1435
commit
aaa481aa9a
@ -17,7 +17,7 @@ type ReceivedIncomingMessage = extern "C" fn(
|
|||||||
cleanup: *mut ServerMessageAck,
|
cleanup: *mut ServerMessageAck,
|
||||||
);
|
);
|
||||||
type ReceivedQueueEmpty = extern "C" fn(ctx: *mut c_void);
|
type ReceivedQueueEmpty = extern "C" fn(ctx: *mut c_void);
|
||||||
type ConnectionInterrupted = extern "C" fn(ctx: *mut c_void);
|
type ConnectionInterrupted = extern "C" fn(ctx: *mut c_void, error: *mut SignalFfiError);
|
||||||
type DestroyChatListener = extern "C" fn(ctx: *mut c_void);
|
type DestroyChatListener = extern "C" fn(ctx: *mut c_void);
|
||||||
|
|
||||||
/// Callbacks for [`ChatListener`].
|
/// Callbacks for [`ChatListener`].
|
||||||
@ -77,8 +77,14 @@ impl ChatListener for ChatListenerStruct {
|
|||||||
(self.0.received_queue_empty)(self.0.ctx)
|
(self.0.received_queue_empty)(self.0.ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: pass `_disconnect_cause` to `connection_interrupted`
|
fn connection_interrupted(&mut self, disconnect_cause: ChatServiceError) {
|
||||||
fn connection_interrupted(&mut self, _disconnect_cause: ChatServiceError) {
|
let error = match disconnect_cause {
|
||||||
(self.0.connection_interrupted)(self.0.ctx)
|
ChatServiceError::ServiceIntentionallyDisconnected => None,
|
||||||
|
c => Some(Box::new(SignalFfiError::from(c))),
|
||||||
|
};
|
||||||
|
(self.0.connection_interrupted)(
|
||||||
|
self.0.ctx,
|
||||||
|
error.map_or(std::ptr::null_mut(), Box::into_raw),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,13 +12,7 @@ public protocol ConnectionEventsListener<Service>: AnyObject {
|
|||||||
/// Called when the client gets disconnected from the server.
|
/// Called when the client gets disconnected from the server.
|
||||||
///
|
///
|
||||||
/// This includes both deliberate disconnects as well as unexpected socket closures.
|
/// This includes both deliberate disconnects as well as unexpected socket closures.
|
||||||
///
|
func connectionWasInterrupted(_ service: Service, error: Error?)
|
||||||
/// The default implementation of this method does nothing.
|
|
||||||
func connectionWasInterrupted(_ service: Service)
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ConnectionEventsListener {
|
|
||||||
func connectionWasInterrupted(_: Service) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public protocol ChatListener: ConnectionEventsListener<AuthenticatedChatService> {
|
public protocol ChatListener: ConnectionEventsListener<AuthenticatedChatService> {
|
||||||
@ -89,13 +83,15 @@ internal class ChatListenerBridge {
|
|||||||
|
|
||||||
bridge.chatListener.chatServiceDidReceiveQueueEmpty(chatService)
|
bridge.chatListener.chatServiceDidReceiveQueueEmpty(chatService)
|
||||||
}
|
}
|
||||||
let connectionInterrupted: SignalConnectionInterrupted = { rawCtx in
|
let connectionInterrupted: SignalConnectionInterrupted = { rawCtx, maybeError in
|
||||||
let bridge = Unmanaged<ChatListenerBridge>.fromOpaque(rawCtx!).takeUnretainedValue()
|
let bridge = Unmanaged<ChatListenerBridge>.fromOpaque(rawCtx!).takeUnretainedValue()
|
||||||
guard let chatService = bridge.chatService else {
|
guard let chatService = bridge.chatService else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bridge.chatListener.connectionWasInterrupted(chatService)
|
let error = convertError(maybeError)
|
||||||
|
|
||||||
|
bridge.chatListener.connectionWasInterrupted(chatService, error: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
return .init(
|
return .init(
|
||||||
@ -130,13 +126,15 @@ internal final class UnauthConnectionEventsListenerBridge {
|
|||||||
let receivedQueueEmpty: SignalReceivedQueueEmpty = { _ in
|
let receivedQueueEmpty: SignalReceivedQueueEmpty = { _ in
|
||||||
fatalError("not used for the unauth listener")
|
fatalError("not used for the unauth listener")
|
||||||
}
|
}
|
||||||
let connectionInterrupted: SignalConnectionInterrupted = { rawCtx in
|
let connectionInterrupted: SignalConnectionInterrupted = { rawCtx, maybeError in
|
||||||
let bridge = Unmanaged<UnauthConnectionEventsListenerBridge>.fromOpaque(rawCtx!).takeUnretainedValue()
|
let bridge = Unmanaged<UnauthConnectionEventsListenerBridge>.fromOpaque(rawCtx!).takeUnretainedValue()
|
||||||
guard let chatService = bridge.chatService else {
|
guard let chatService = bridge.chatService else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bridge.listener.connectionWasInterrupted(chatService)
|
let error = convertError(maybeError)
|
||||||
|
|
||||||
|
bridge.listener.connectionWasInterrupted(chatService, error: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
return .init(
|
return .init(
|
||||||
|
@ -70,6 +70,19 @@ public enum SignalError: Error {
|
|||||||
|
|
||||||
internal typealias SignalFfiErrorRef = OpaquePointer
|
internal typealias SignalFfiErrorRef = OpaquePointer
|
||||||
|
|
||||||
|
internal func convertError(_ error: SignalFfiErrorRef?) -> Error? {
|
||||||
|
// It would be *slightly* more efficient for checkError to call convertError,
|
||||||
|
// instead of the other way around. However, then it would be harder to implement
|
||||||
|
// checkError, since some of the conversion operations can themselves throw.
|
||||||
|
// So this is more maintainable.
|
||||||
|
do {
|
||||||
|
try checkError(error)
|
||||||
|
return nil
|
||||||
|
} catch let thrownError {
|
||||||
|
return thrownError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal func checkError(_ error: SignalFfiErrorRef?) throws {
|
internal func checkError(_ error: SignalFfiErrorRef?) throws {
|
||||||
guard let error = error else { return }
|
guard let error = error else { return }
|
||||||
|
|
||||||
|
@ -634,7 +634,7 @@ typedef void (*SignalReceivedIncomingMessage)(void *ctx, SignalOwnedBuffer envel
|
|||||||
|
|
||||||
typedef void (*SignalReceivedQueueEmpty)(void *ctx);
|
typedef void (*SignalReceivedQueueEmpty)(void *ctx);
|
||||||
|
|
||||||
typedef void (*SignalConnectionInterrupted)(void *ctx);
|
typedef void (*SignalConnectionInterrupted)(void *ctx, SignalFfiError *error);
|
||||||
|
|
||||||
typedef void (*SignalDestroyChatListener)(void *ctx);
|
typedef void (*SignalDestroyChatListener)(void *ctx);
|
||||||
|
|
||||||
|
@ -197,8 +197,9 @@ final class ChatServiceTests: TestCaseBase {
|
|||||||
self.queueEmpty.fulfill()
|
self.queueEmpty.fulfill()
|
||||||
}
|
}
|
||||||
|
|
||||||
func connectionWasInterrupted(_: AuthenticatedChatService) {
|
func connectionWasInterrupted(_: AuthenticatedChatService, error: Error?) {
|
||||||
XCTAssertEqual(self.stage, 3)
|
XCTAssertEqual(self.stage, 3)
|
||||||
|
XCTAssertNotNil(error)
|
||||||
self.stage += 1
|
self.stage += 1
|
||||||
self.connectionInterrupted.fulfill()
|
self.connectionInterrupted.fulfill()
|
||||||
}
|
}
|
||||||
@ -263,6 +264,7 @@ final class ChatServiceTests: TestCaseBase {
|
|||||||
|
|
||||||
func chatServiceDidReceiveQueueEmpty(_: AuthenticatedChatService) {}
|
func chatServiceDidReceiveQueueEmpty(_: AuthenticatedChatService) {}
|
||||||
func chatService(_ chat: AuthenticatedChatService, didReceiveIncomingMessage envelope: Data, serverDeliveryTimestamp: UInt64, sendAck: () async throws -> Void) {}
|
func chatService(_ chat: AuthenticatedChatService, didReceiveIncomingMessage envelope: Data, serverDeliveryTimestamp: UInt64, sendAck: () async throws -> Void) {}
|
||||||
|
func connectionWasInterrupted(_ service: AuthenticatedChatService, error: Error?) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let net = Net(env: .staging, userAgent: Self.userAgent)
|
let net = Net(env: .staging, userAgent: Self.userAgent)
|
||||||
@ -298,7 +300,8 @@ final class ChatServiceTests: TestCaseBase {
|
|||||||
self.expectation = expectation
|
self.expectation = expectation
|
||||||
}
|
}
|
||||||
|
|
||||||
func connectionWasInterrupted(_: UnauthenticatedChatService) {
|
func connectionWasInterrupted(_: UnauthenticatedChatService, error: Error?) {
|
||||||
|
XCTAssertNil(error)
|
||||||
self.expectation.fulfill()
|
self.expectation.fulfill()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user