WSMessage.m 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /**
  2. * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
  3. * SPDX-License-Identifier: GPL-3.0-or-later
  4. */
  5. #import "WSMessage.h"
  6. #import "NextcloudTalk-Swift.h"
  7. static NSTimeInterval kSendMessageTimeoutInterval = 15;
  8. @interface WSMessage ()
  9. @property NSTimer *timeoutTimer;
  10. @property NSURLSessionWebSocketTask *webSocketTask;
  11. @end
  12. @implementation WSMessage
  13. - (instancetype)initWithMessage:(NSDictionary *)message
  14. {
  15. self = [super init];
  16. if (self) {
  17. self.message = message;
  18. }
  19. return self;
  20. }
  21. - (instancetype)initWithMessage:(NSDictionary *)message withCompletionBlock:(SendMessageCompletionBlock)block
  22. {
  23. self = [self initWithMessage:message];
  24. if (self) {
  25. self.completionBlock = block;
  26. }
  27. return self;
  28. }
  29. - (void)setMessageId:(NSString *)messageId
  30. {
  31. _messageId = messageId;
  32. NSMutableDictionary *newMessageDict = [[NSMutableDictionary alloc] initWithDictionary:_message];
  33. [newMessageDict setObject:messageId forKey:@"id"];
  34. _message = newMessageDict;
  35. }
  36. - (BOOL)isHelloMessage
  37. {
  38. if ([[_message objectForKey:@"type"] isEqualToString:@"hello"]) {
  39. return YES;
  40. }
  41. return NO;
  42. }
  43. - (BOOL)isJoinMessage
  44. {
  45. if ([[_message objectForKey:@"type"] isEqualToString:@"room"]) {
  46. return YES;
  47. }
  48. return NO;
  49. }
  50. - (void)setMessageTimeout
  51. {
  52. // NSTimer uses the runloop of the current thread. Only the main thread guarantees a runloop, so make sure we dispatch it to main!
  53. // This is mainly a problem for the "hello message", because it's send from a NSURL delegate and the timer sometimes fails to run
  54. dispatch_async(dispatch_get_main_queue(), ^{
  55. self->_timeoutTimer = [NSTimer scheduledTimerWithTimeInterval:kSendMessageTimeoutInterval target:self selector:@selector(executeCompletionBlockWithSocketError) userInfo:nil repeats:NO];
  56. });
  57. }
  58. - (void)ignoreCompletionBlock
  59. {
  60. dispatch_async(dispatch_get_main_queue(), ^{
  61. self.completionBlock = nil;
  62. [self->_timeoutTimer invalidate];
  63. });
  64. }
  65. - (void)executeCompletionBlockWithStatus:(NCExternalSignalingSendMessageStatus)status
  66. {
  67. // As the timer was create on the main thread, it needs to be invalidated on the main thread as well
  68. dispatch_async(dispatch_get_main_queue(), ^{
  69. if (self.completionBlock) {
  70. self.completionBlock(self.webSocketTask, status);
  71. self.completionBlock = nil;
  72. [self->_timeoutTimer invalidate];
  73. }
  74. });
  75. }
  76. - (void)executeCompletionBlockWithSocketError
  77. {
  78. [self executeCompletionBlockWithStatus:SendMessageSocketError];
  79. }
  80. - (NSString *)webSocketMessage
  81. {
  82. NSError *error;
  83. NSString *jsonString = nil;
  84. NSData *jsonData = [NSJSONSerialization dataWithJSONObject:_message
  85. options:0
  86. error:&error];
  87. if (!jsonData) {
  88. NSLog(@"Error creating websocket message: %@", error);
  89. } else {
  90. jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
  91. }
  92. return jsonString;
  93. }
  94. - (void)sendMessageWithWebSocket:(NSURLSessionWebSocketTask *)webSocketTask
  95. {
  96. self.webSocketTask = webSocketTask;
  97. if (self.completionBlock) {
  98. [self setMessageTimeout];
  99. }
  100. //NSLog(@"Sending: %@", self.webSocketMessage);
  101. NSURLSessionWebSocketMessage *message = [[NSURLSessionWebSocketMessage alloc] initWithString:self.webSocketMessage];
  102. [webSocketTask sendMessage:message completionHandler:^(NSError * _Nullable error) {
  103. if (error && self.completionBlock) {
  104. [self executeCompletionBlockWithSocketError];
  105. }
  106. }];
  107. }
  108. @end