Debug actions for calling

For testing stale hangup/busy messages

Extracted MessageSender promise API
Moved call debug actions to their own page

// FREEBIE
This commit is contained in:
Michael Kirk 2017-08-11 09:13:54 -04:00
parent a90f11490b
commit 3d9796db77
7 changed files with 132 additions and 85 deletions

View File

@ -143,6 +143,8 @@
454EBAB41F2BE14C00ACE0BB /* OWSAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D99C911F2937CC00D284D6 /* OWSAnalytics.swift */; };
455A16DD1F1FEA0000F86704 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 455A16DB1F1FEA0000F86704 /* Metal.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
455A16DE1F1FEA0000F86704 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 455A16DC1F1FEA0000F86704 /* MetalKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
45638BDC1F3DD0D400128435 /* DebugUICalling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45638BDB1F3DD0D400128435 /* DebugUICalling.swift */; };
45638BDF1F3DDB2200128435 /* MessageSender+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45638BDE1F3DDB2200128435 /* MessageSender+Promise.swift */; };
4563ADF11F22BD7100DEB8C7 /* OWS106EnsureProfileComplete.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4563ADF01F22BD7100DEB8C7 /* OWS106EnsureProfileComplete.swift */; };
45666EC61D99483D008FE134 /* OWSAvatarBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666EC51D99483D008FE134 /* OWSAvatarBuilder.m */; };
45666EC91D994C0D008FE134 /* OWSGroupAvatarBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666EC81D994C0D008FE134 /* OWSGroupAvatarBuilder.m */; };
@ -587,6 +589,8 @@
454B35071D08EED80026D658 /* mk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = mk; path = translations/mk.lproj/Localizable.strings; sourceTree = "<group>"; };
455A16DB1F1FEA0000F86704 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
455A16DC1F1FEA0000F86704 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };
45638BDB1F3DD0D400128435 /* DebugUICalling.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugUICalling.swift; sourceTree = "<group>"; };
45638BDE1F3DDB2200128435 /* MessageSender+Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MessageSender+Promise.swift"; sourceTree = "<group>"; };
4563ADF01F22BD7100DEB8C7 /* OWS106EnsureProfileComplete.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWS106EnsureProfileComplete.swift; sourceTree = "<group>"; };
45666EC41D99483D008FE134 /* OWSAvatarBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSAvatarBuilder.h; sourceTree = "<group>"; };
45666EC51D99483D008FE134 /* OWSAvatarBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSAvatarBuilder.m; sourceTree = "<group>"; };
@ -1105,6 +1109,7 @@
452037D01EE84975004E4CDF /* DebugUISessionState.m */,
34D8C0251ED3673300188D7C /* DebugUITableViewController.h */,
34D8C0261ED3673300188D7C /* DebugUITableViewController.m */,
45638BDB1F3DD0D400128435 /* DebugUICalling.swift */,
);
path = DebugUI;
sourceTree = "<group>";
@ -1769,6 +1774,7 @@
45BB93371E688E14001E3939 /* UIDevice+featureSupport.swift */,
45C0DC1A1E68FE9000E04C47 /* UIApplication+OWS.swift */,
45C0DC1D1E69011F00E04C47 /* UIStoryboard+OWS.swift */,
45638BDE1F3DDB2200128435 /* MessageSender+Promise.swift */,
);
name = "UI Categories";
path = ..;
@ -2214,6 +2220,7 @@
45666EC91D994C0D008FE134 /* OWSGroupAvatarBuilder.m in Sources */,
3471B1DA1EB7C63600F6AEC8 /* NewNonContactConversationViewController.m in Sources */,
34B3F87C1E8DF1700035BE1A /* FingerprintViewController.m in Sources */,
45638BDC1F3DD0D400128435 /* DebugUICalling.swift in Sources */,
76EB058218170B33006006FC /* Environment.m in Sources */,
34B3F8921E8DF1710035BE1A /* SignalAttachment.swift in Sources */,
45464DBC1DFA041F001D3FD6 /* DataChannelMessage.swift in Sources */,
@ -2262,6 +2269,7 @@
45AE48511E0732D6004D96C2 /* TurnServerInfo.swift in Sources */,
34B3F8771E8DF1700035BE1A /* ContactsPicker.swift in Sources */,
45C0DC1B1E68FE9000E04C47 /* UIApplication+OWS.swift in Sources */,
45638BDF1F3DDB2200128435 /* MessageSender+Promise.swift in Sources */,
34535D821E256BE9008A4747 /* UIView+OWS.m in Sources */,
45F3AEB61DFDE7900080CE33 /* AvatarImageView.swift in Sources */,
7038632718F70C0700D4A43F /* CryptoTools.m in Sources */,

View File

@ -0,0 +1,25 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
import Foundation
import PromiseKit
public extension MessageSender {
/**
* Wrap message sending in a Promise for easier callback chaining.
*/
public func sendPromise(message: TSOutgoingMessage) -> Promise<Void> {
let promise: Promise<Void> = Promise { fulfill, reject in
self.send(message, success: fulfill, failure: reject)
}
// Ensure sends complete before they're GC'd.
// This *should* be redundant, since we should be calling retainUntilComplete
// at all call sites where the promise isn't otherwise retained.
promise.retainUntilComplete()
return promise
}
}

View File

@ -6,6 +6,7 @@
#import "AppSettingsViewController.h"
#import "AttachmentSharing.h"
#import "DebugUIPage.h"
#import "Environment.h"
#import "FLAnimatedImage.h"
#import "FingerprintViewController.h"

View File

@ -0,0 +1,88 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
import Foundation
class DebugUICalling: DebugUIPage {
let TAG = "[DebugUICalling]"
// MARK: Dependencies
var notificationsAdapter: CallNotificationsAdapter {
return Environment.getCurrent().callService.notificationsAdapter
}
var messageSender: MessageSender {
return Environment.getCurrent().messageSender
}
// MARK: Overrides
override func name() -> String {
return "Calling"
}
override func section(thread aThread: TSThread?) -> OWSTableSection? {
guard let thread = aThread as? TSContactThread else {
owsFail("Calling is only valid for contact thread, got thread: \(String(describing: aThread))")
return nil
}
let sectionItems = [
OWSTableItem(title:"⚠️ Missed Call") {
self.delayedDispatchWithFakeCall(thread: thread) { call in
self.notificationsAdapter.presentMissedCall(call, callerName: thread.name())
}
},
OWSTableItem(title:"⚠️ New Safety Number (rejected)") {
self.delayedDispatchWithFakeCall(thread: thread) { call in
self.notificationsAdapter.presentMissedCallBecauseOfNewIdentity(call: call, callerName: thread.name())
}
},
OWSTableItem(title:"⚠️ No Longer Verified (rejected)") {
self.delayedDispatchWithFakeCall(thread: thread) { call in
self.notificationsAdapter.presentMissedCallBecauseOfNoLongerVerifiedIdentity(call: call, callerName: thread.name())
}
},
OWSTableItem(title:"Send 'hangup' for old call") {
let kFakeCallId = UInt64(12345)
let hangupMessage = OWSCallHangupMessage(callId: kFakeCallId)
let callMessage = OWSOutgoingCallMessage(thread: thread, hangupMessage: hangupMessage)
self.messageSender.sendPromise(message: callMessage).then {
Logger.debug("\(self.TAG) Successfully sent hangup call message to \(thread.contactIdentifier())")
}.catch { error in
Logger.error("\(self.TAG) failed to send hangup call message to \(thread.contactIdentifier()) with error: \(error)")
}
},
OWSTableItem(title:"Send 'busy' for old call") {
let kFakeCallId = UInt64(12345)
let busyMessage = OWSCallBusyMessage(callId: kFakeCallId)
let callMessage = OWSOutgoingCallMessage(thread: thread, busyMessage: busyMessage)
self.messageSender.sendPromise(message: callMessage).then {
Logger.debug("\(self.TAG) Successfully sent busy call message to \(thread.contactIdentifier())")
}.catch { error in
Logger.error("\(self.TAG) failed to send busy call message to \(thread.contactIdentifier()) with error: \(error)")
}
}
]
return OWSTableSection(title: "Call Notifications (⚠️) have delay: \(kNotificationDelay)s", items: sectionItems)
}
// MARK: Helpers
// After enqueing the notification you may want to background the app or lock the screen before it triggers, so
// we give a little delay.
let kNotificationDelay: TimeInterval = 5
func delayedDispatchWithFakeCall(thread: TSContactThread, callBlock: @escaping (SignalCall) -> Void) {
let call = SignalCall.incomingCall(localId: UUID(), remotePhoneNumber: thread.contactIdentifier(), signalingId: 0)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + kNotificationDelay) {
callBlock(call)
}
}
}

View File

@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN
- (NSString *)name;
- (nullable OWSTableSection *)sectionForThread:(nullable TSThread *)thread;
- (nullable OWSTableSection *)sectionForThread:(nullable TSThread *)thread NS_SWIFT_NAME(section(thread:));
@end

View File

@ -92,77 +92,13 @@ NS_ASSUME_NONNULL_BEGIN
if ([thread isKindOfClass:[TSContactThread class]]) {
[subsectionItems
addObject:[self itemForSubsection:[DebugUISessionState new] viewController:viewController thread:thread]];
[subsectionItems
addObject:[self itemForSubsection:[DebugUICalling new] viewController:viewController thread:thread]];
}
[subsectionItems addObject:[self itemForSubsection:[DebugUIMisc new] viewController:viewController thread:thread]];
[contents addSection:[OWSTableSection sectionWithTitle:@"Sections" items:subsectionItems]];
if ([thread isKindOfClass:[TSContactThread class]]) {
// After enqueing the notification you may want to background the app or lock the screen before it triggers, so
// we give a little delay.
uint64_t notificationDelay = 5;
[contents
addSection:
[OWSTableSection
sectionWithTitle:[NSString
stringWithFormat:@"Call Notifications (%llu second delay)", notificationDelay]
items:@[
[OWSTableItem
itemWithTitle:@"Missed Call"
actionBlock:^{
SignalCall *call =
[SignalCall incomingCallWithLocalId:[NSUUID new]
remotePhoneNumber:thread.contactIdentifier
signalingId:0];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(notificationDelay * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
[[Environment getCurrent].callService.notificationsAdapter
presentMissedCall:call
callerName:thread.name];
});
}],
[OWSTableItem
itemWithTitle:@"Rejected Call with New Safety Number"
actionBlock:^{
SignalCall *call =
[SignalCall incomingCallWithLocalId:[NSUUID new]
remotePhoneNumber:thread.contactIdentifier
signalingId:0];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(notificationDelay * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
[[Environment getCurrent].callService.notificationsAdapter
presentMissedCallBecauseOfNewIdentityWithCall:call
callerName:thread.name];
});
}],
[OWSTableItem
itemWithTitle:@"Rejected Call with No Longer Verified Safety Number"
actionBlock:^{
SignalCall *call =
[SignalCall incomingCallWithLocalId:[NSUUID new]
remotePhoneNumber:thread.contactIdentifier
signalingId:0];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(notificationDelay * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
[[Environment getCurrent].callService.notificationsAdapter
presentMissedCallBecauseOfNoLongerVerifiedIdentityWithCall:call
callerName:
thread
.name];
});
}],
]]];
} // end contact thread section
viewController.contents = contents;
[viewController presentFromViewController:fromViewController];
}

View File

@ -322,7 +322,7 @@ protocol CallServiceObserver: class {
return peerConnectionClient.setLocalSessionDescription(sessionDescription).then {
let offerMessage = OWSCallOfferMessage(callId: call.signalingId, sessionDescription: sessionDescription.sdp)
let callMessage = OWSOutgoingCallMessage(thread: call.thread, offerMessage: offerMessage)
return self.messageSender.sendCallMessage(callMessage)
return self.messageSender.sendPromise(message: callMessage)
}
}.then {
guard self.call == call else {
@ -410,7 +410,7 @@ protocol CallServiceObserver: class {
Logger.error("\(self.TAG) Sending \(pendingIceUpdateMessages.count) pendingIceUpdateMessages")
let callMessage = OWSOutgoingCallMessage(thread: thread, iceUpdateMessages: pendingIceUpdateMessages)
let sendPromise = messageSender.sendCallMessage(callMessage).catch { error in
let sendPromise = messageSender.sendPromise(message: callMessage).catch { error in
Logger.error("\(self.TAG) failed to send ice updates in \(#function) with error: \(error)")
}
sendPromise.retainUntilComplete()
@ -471,7 +471,7 @@ protocol CallServiceObserver: class {
let busyMessage = OWSCallBusyMessage(callId: call.signalingId)
let callMessage = OWSOutgoingCallMessage(thread: thread, busyMessage: busyMessage)
let sendPromise = messageSender.sendCallMessage(callMessage)
let sendPromise = messageSender.sendPromise(message: callMessage)
sendPromise.retainUntilComplete()
handleMissedCall(call, thread: thread)
@ -629,10 +629,10 @@ protocol CallServiceObserver: class {
let answerMessage = OWSCallAnswerMessage(callId: newCall.signalingId, sessionDescription: negotiatedSessionDescription.sdp)
let callAnswerMessage = OWSOutgoingCallMessage(thread: thread, answerMessage: answerMessage)
return self.messageSender.sendCallMessage(callAnswerMessage)
return self.messageSender.sendPromise(message: callAnswerMessage)
}.then {
guard self.call == newCall else {
throw CallError.obsoleteCall(description: "sendCallMessage() response for obsolete call")
throw CallError.obsoleteCall(description: "sendPromise(message: ) response for obsolete call")
}
Logger.debug("\(self.TAG) successfully sent callAnswerMessage for: \(newCall.identifiersForLogs)")
@ -745,7 +745,7 @@ protocol CallServiceObserver: class {
if self.sendIceUpdatesImmediately {
Logger.info("\(self.TAG) in \(#function). Sending immediately.")
let callMessage = OWSOutgoingCallMessage(thread: call.thread, iceUpdateMessage: iceUpdateMessage)
let sendPromise = self.messageSender.sendCallMessage(callMessage)
let sendPromise = self.messageSender.sendPromise(message: callMessage)
sendPromise.retainUntilComplete()
} else {
// For outgoing messages, we wait to send ice updates until we're sure client received our call message.
@ -1023,7 +1023,7 @@ protocol CallServiceObserver: class {
// If the call hasn't started yet, we don't have a data channel to communicate the hang up. Use Signal Service Message.
let hangupMessage = OWSCallHangupMessage(callId: call.signalingId)
let callMessage = OWSOutgoingCallMessage(thread: call.thread, hangupMessage: hangupMessage)
let sendPromise = self.messageSender.sendCallMessage(callMessage).then {
let sendPromise = self.messageSender.sendPromise(message: callMessage).then {
Logger.debug("\(self.TAG) successfully sent hangup call message to \(call.thread.contactIdentifier())")
}.catch { error in
OWSProdInfo(OWSAnalyticsEvents.callServiceErrorHandleLocalHungupCall(), file:#file, function:#function, line:#line)
@ -1636,14 +1636,3 @@ protocol CallServiceObserver: class {
self.activeCallTimer = nil
}
}
fileprivate extension MessageSender {
/**
* Wrap message sending in a Promise for easier callback chaining.
*/
fileprivate func sendCallMessage(_ message: OWSOutgoingCallMessage) -> Promise<Void> {
return Promise { fulfill, reject in
self.send(message, success: fulfill, failure: reject)
}
}
}