|
|
|
@ -12,13 +12,10 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
|
|
|
|
|
// MARK: Public Chat
|
|
|
|
|
private static let channelInfoType = "net.patter-app.settings"
|
|
|
|
|
private static let attachmentType = "net.app.core.oembed"
|
|
|
|
|
public static let avatarType = "network.loki.messenger.avatar"
|
|
|
|
|
public static let profilePictureType = "network.loki.messenger.avatar"
|
|
|
|
|
@objc public static let publicChatMessageType = "network.loki.messenger.publicChat"
|
|
|
|
|
|
|
|
|
|
@objc public static let defaultChats: [LokiPublicChat] = {
|
|
|
|
|
var result: [LokiPublicChat] = []
|
|
|
|
|
return result
|
|
|
|
|
}()
|
|
|
|
|
@objc public static let defaultChats: [LokiPublicChat] = [] // Currently unused
|
|
|
|
|
|
|
|
|
|
// MARK: Convenience
|
|
|
|
|
private static var userDisplayName: String {
|
|
|
|
@ -70,6 +67,11 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static func clearCaches(for channel: UInt64, on server: String) {
|
|
|
|
|
removeLastMessageServerID(for: channel, on: server)
|
|
|
|
|
removeLastDeletionServerID(for: channel, on: server)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: Public API
|
|
|
|
|
public static func getMessages(for channel: UInt64, on server: String) -> Promise<[LokiPublicChatMessage]> {
|
|
|
|
|
var queryParameters = "include_annotations=1"
|
|
|
|
@ -97,23 +99,26 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
|
|
|
|
|
}
|
|
|
|
|
var avatar: LokiPublicChatMessage.Avatar? = nil
|
|
|
|
|
let displayName = user["name"] as? String ?? NSLocalizedString("Anonymous", comment: "")
|
|
|
|
|
if let userAnnotations = user["annotations"] as? [JSON], let avatarAnnotation = userAnnotations.first(where: { $0["type"] as? String == avatarType }),
|
|
|
|
|
if let userAnnotations = user["annotations"] as? [JSON], let avatarAnnotation = userAnnotations.first(where: { $0["type"] as? String == profilePictureType }),
|
|
|
|
|
let avatarValue = avatarAnnotation["value"] as? JSON, let profileKeyString = avatarValue["profileKey"] as? String, let profileKey = Data(base64Encoded: profileKeyString), let url = avatarValue["url"] as? String {
|
|
|
|
|
avatar = LokiPublicChatMessage.Avatar(profileKey: profileKey, url: url)
|
|
|
|
|
}
|
|
|
|
|
let lastMessageServerID = getLastMessageServerID(for: channel, on: server)
|
|
|
|
|
if serverID > (lastMessageServerID ?? 0) { setLastMessageServerID(for: channel, on: server, to: serverID) }
|
|
|
|
|
let quote: LokiPublicChatMessage.Quote?
|
|
|
|
|
if let quoteAsJSON = value["quote"] as? JSON, let quotedMessageTimestamp = quoteAsJSON["id"] as? UInt64, let quoteeHexEncodedPublicKey = quoteAsJSON["author"] as? String, let quotedMessageBody = quoteAsJSON["text"] as? String {
|
|
|
|
|
if let quoteAsJSON = value["quote"] as? JSON, let quotedMessageTimestamp = quoteAsJSON["id"] as? UInt64, let quoteeHexEncodedPublicKey = quoteAsJSON["author"] as? String,
|
|
|
|
|
let quotedMessageBody = quoteAsJSON["text"] as? String {
|
|
|
|
|
let quotedMessageServerID = message["reply_to"] as? UInt64
|
|
|
|
|
quote = LokiPublicChatMessage.Quote(quotedMessageTimestamp: quotedMessageTimestamp, quoteeHexEncodedPublicKey: quoteeHexEncodedPublicKey, quotedMessageBody: quotedMessageBody, quotedMessageServerID: quotedMessageServerID)
|
|
|
|
|
quote = LokiPublicChatMessage.Quote(quotedMessageTimestamp: quotedMessageTimestamp, quoteeHexEncodedPublicKey: quoteeHexEncodedPublicKey, quotedMessageBody: quotedMessageBody,
|
|
|
|
|
quotedMessageServerID: quotedMessageServerID)
|
|
|
|
|
} else {
|
|
|
|
|
quote = nil
|
|
|
|
|
}
|
|
|
|
|
let signature = LokiPublicChatMessage.Signature(data: Data(hex: hexEncodedSignatureData), version: signatureVersion)
|
|
|
|
|
let attachmentsAsJSON = annotations.filter { $0["type"] as? String == attachmentType }
|
|
|
|
|
let attachments: [LokiPublicChatMessage.Attachment] = attachmentsAsJSON.compactMap { attachmentAsJSON in
|
|
|
|
|
guard let value = attachmentAsJSON["value"] as? JSON, let kindAsString = value["lokiType"] as? String, let kind = LokiPublicChatMessage.Attachment.Kind(rawValue: kindAsString), let serverID = value["id"] as? UInt64, let contentType = value["contentType"] as? String, let size = value["size"] as? UInt, let url = value["url"] as? String else { return nil }
|
|
|
|
|
guard let value = attachmentAsJSON["value"] as? JSON, let kindAsString = value["lokiType"] as? String, let kind = LokiPublicChatMessage.Attachment.Kind(rawValue: kindAsString),
|
|
|
|
|
let serverID = value["id"] as? UInt64, let contentType = value["contentType"] as? String, let size = value["size"] as? UInt, let url = value["url"] as? String else { return nil }
|
|
|
|
|
let fileName = value["fileName"] as? String ?? UUID().description
|
|
|
|
|
let width = value["width"] as? UInt ?? 0
|
|
|
|
|
let height = value["height"] as? UInt ?? 0
|
|
|
|
@ -127,9 +132,11 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return LokiPublicChatMessage.Attachment(kind: kind, server: server, serverID: serverID, contentType: contentType, size: size, fileName: fileName, flags: flags, width: width, height: height, caption: caption, url: url, linkPreviewURL: linkPreviewURL, linkPreviewTitle: linkPreviewTitle)
|
|
|
|
|
return LokiPublicChatMessage.Attachment(kind: kind, server: server, serverID: serverID, contentType: contentType, size: size, fileName: fileName, flags: flags,
|
|
|
|
|
width: width, height: height, caption: caption, url: url, linkPreviewURL: linkPreviewURL, linkPreviewTitle: linkPreviewTitle)
|
|
|
|
|
}
|
|
|
|
|
let result = LokiPublicChatMessage(serverID: serverID, hexEncodedPublicKey: hexEncodedPublicKey, displayName: displayName, avatar: avatar, body: body, type: publicChatMessageType, timestamp: timestamp, quote: quote, attachments: attachments, signature: signature)
|
|
|
|
|
let result = LokiPublicChatMessage(serverID: serverID, hexEncodedPublicKey: hexEncodedPublicKey, displayName: displayName, avatar: avatar,
|
|
|
|
|
body: body, type: publicChatMessageType, timestamp: timestamp, quote: quote, attachments: attachments, signature: signature)
|
|
|
|
|
guard result.hasValidSignature() else {
|
|
|
|
|
print("[Loki] Ignoring public chat message with invalid signature.")
|
|
|
|
|
return nil
|
|
|
|
@ -260,7 +267,7 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
|
|
|
|
|
|
|
|
|
|
public static func getUserCount(for channel: UInt64, on server: String) -> Promise<Int> {
|
|
|
|
|
return getAuthToken(for: server).then(on: DispatchQueue.global()) { token -> Promise<Int> in
|
|
|
|
|
let queryParameters = "count=2500"
|
|
|
|
|
let queryParameters = "count=200"
|
|
|
|
|
let url = URL(string: "\(server)/channels/\(channel)/subscribers?\(queryParameters)")!
|
|
|
|
|
let request = TSRequest(url: url)
|
|
|
|
|
request.allHTTPHeaderFields = [ "Content-Type" : "application/json", "Authorization" : "Bearer \(token)" ]
|
|
|
|
@ -306,7 +313,7 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@objc (isUserModerator:forGroup:onServer:)
|
|
|
|
|
@objc(isUserModerator:forChannel:onServer:)
|
|
|
|
|
public static func isUserModerator(_ hexEncodedPublicString: String, for channel: UInt64, on server: String) -> Bool {
|
|
|
|
|
return moderators[server]?[channel]?.contains(hexEncodedPublicString) ?? false
|
|
|
|
|
}
|
|
|
|
@ -322,13 +329,13 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
|
|
|
|
|
print("Couldn't update display name due to error: \(error).")
|
|
|
|
|
throw error
|
|
|
|
|
}
|
|
|
|
|
}.retryingIfNeeded(maxRetryCount: 3)
|
|
|
|
|
}.retryingIfNeeded(maxRetryCount: maxRetryCount)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static func setProfilePictureURL(to url: String?, using profileKey: Data, on server: String) -> Promise<Void> {
|
|
|
|
|
print("[Loki] Updating profile picture on server: \(server).")
|
|
|
|
|
return getAuthToken(for: server).then(on: DispatchQueue.global()) { token -> Promise<Void> in
|
|
|
|
|
var annotation: JSON = [ "type" : avatarType ]
|
|
|
|
|
var annotation: JSON = [ "type" : profilePictureType ]
|
|
|
|
|
if let url = url {
|
|
|
|
|
annotation["value"] = [ "profileKey" : profileKey.base64EncodedString(), "url" : url ]
|
|
|
|
|
}
|
|
|
|
@ -340,7 +347,7 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
|
|
|
|
|
print("[Loki] Couldn't update profile picture due to error: \(error).")
|
|
|
|
|
throw error
|
|
|
|
|
}
|
|
|
|
|
}.retryingIfNeeded(maxRetryCount: 3)
|
|
|
|
|
}.retryingIfNeeded(maxRetryCount: maxRetryCount)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static func getInfo(for channel: UInt64, on server: String) -> Promise<LokiPublicChatInfo> {
|
|
|
|
@ -366,11 +373,6 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
|
|
|
|
|
return LokiFileServerProxy(for: server).perform(request).map { _ in }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@objc public static func clearCaches(for channel: UInt64, on server: String) {
|
|
|
|
|
removeLastMessageServerID(for: channel, on: server)
|
|
|
|
|
removeLastDeletionServerID(for: channel, on: server)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: Public API (Obj-C)
|
|
|
|
|
@objc(getMessagesForGroup:onServer:)
|
|
|
|
|
public static func objc_getMessages(for group: UInt64, on server: String) -> AnyPromise {
|
|
|
|
|