Update API [skip ci]

This commit is contained in:
Ilya Laktyushin 2023-09-12 18:57:18 +04:00
parent e893cca836
commit f401a79e39
8 changed files with 540 additions and 32 deletions

View File

@ -73,6 +73,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1834973166] = { return Api.BaseTheme.parse_baseThemeTinted($0) }
dict[-1132882121] = { return Api.Bool.parse_boolFalse($0) }
dict[-1720552011] = { return Api.Bool.parse_boolTrue($0) }
dict[245261184] = { return Api.Booster.parse_booster($0) }
dict[-1778593322] = { return Api.BotApp.parse_botApp($0) }
dict[1571189943] = { return Api.BotApp.parse_botAppNotModified($0) }
dict[-1032140601] = { return Api.BotCommand.parse_botCommand($0) }
@ -419,7 +420,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-193992412] = { return Api.InputWebFileLocation.parse_inputWebFileAudioAlbumThumbLocation($0) }
dict[-1625153079] = { return Api.InputWebFileLocation.parse_inputWebFileGeoPointLocation($0) }
dict[-1036396922] = { return Api.InputWebFileLocation.parse_inputWebFileLocation($0) }
dict[1048946971] = { return Api.Invoice.parse_invoice($0) }
dict[1572428309] = { return Api.Invoice.parse_invoice($0) }
dict[-1059185703] = { return Api.JSONObjectValue.parse_jsonObjectValue($0) }
dict[-146520221] = { return Api.JSONValue.parse_jsonArray($0) }
dict[-952869270] = { return Api.JSONValue.parse_jsonBool($0) }
@ -1175,9 +1176,10 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[276907596] = { return Api.storage.FileType.parse_fileWebp($0) }
dict[1862033025] = { return Api.stories.AllStories.parse_allStories($0) }
dict[291044926] = { return Api.stories.AllStories.parse_allStoriesNotModified($0) }
dict[2061518568] = { return Api.stories.BoostsStatus.parse_boostsStatus($0) }
dict[-203604707] = { return Api.stories.BoostersList.parse_boostersList($0) }
dict[1726619631] = { return Api.stories.BoostsStatus.parse_boostsStatus($0) }
dict[-1021889145] = { return Api.stories.CanApplyBoostResult.parse_canApplyBoostOk($0) }
dict[-1532908712] = { return Api.stories.CanApplyBoostResult.parse_canApplyBoostReplace($0) }
dict[1898726997] = { return Api.stories.CanApplyBoostResult.parse_canApplyBoostReplace($0) }
dict[-890861720] = { return Api.stories.PeerStories.parse_peerStories($0) }
dict[1574486984] = { return Api.stories.Stories.parse_stories($0) }
dict[-560009955] = { return Api.stories.StoryViews.parse_storyViews($0) }
@ -1287,6 +1289,8 @@ public extension Api {
_1.serialize(buffer, boxed)
case let _1 as Api.Bool:
_1.serialize(buffer, boxed)
case let _1 as Api.Booster:
_1.serialize(buffer, boxed)
case let _1 as Api.BotApp:
_1.serialize(buffer, boxed)
case let _1 as Api.BotCommand:
@ -2057,6 +2061,8 @@ public extension Api {
_1.serialize(buffer, boxed)
case let _1 as Api.stories.AllStories:
_1.serialize(buffer, boxed)
case let _1 as Api.stories.BoostersList:
_1.serialize(buffer, boxed)
case let _1 as Api.stories.BoostsStatus:
_1.serialize(buffer, boxed)
case let _1 as Api.stories.CanApplyBoostResult:

View File

@ -892,6 +892,46 @@ public extension Api {
}
}
public extension Api {
enum Booster: TypeConstructorDescription {
case booster(userId: Int64, expires: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .booster(let userId, let expires):
if boxed {
buffer.appendInt32(245261184)
}
serializeInt64(userId, buffer: buffer, boxed: false)
serializeInt32(expires, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .booster(let userId, let expires):
return ("booster", [("userId", userId as Any), ("expires", expires as Any)])
}
}
public static func parse_booster(_ reader: BufferReader) -> Booster? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Int32?
_2 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.Booster.booster(userId: _1!, expires: _2!)
}
else {
return nil
}
}
}
}
public extension Api {
enum BotApp: TypeConstructorDescription {
case botApp(flags: Int32, id: Int64, accessHash: Int64, shortName: String, title: String, description: String, photo: Api.Photo, document: Api.Document?, hash: Int64)

View File

@ -116,13 +116,13 @@ public extension Api {
}
public extension Api {
enum Invoice: TypeConstructorDescription {
case invoice(flags: Int32, currency: String, prices: [Api.LabeledPrice], maxTipAmount: Int64?, suggestedTipAmounts: [Int64]?, recurringTermsUrl: String?)
case invoice(flags: Int32, currency: String, prices: [Api.LabeledPrice], maxTipAmount: Int64?, suggestedTipAmounts: [Int64]?, termsUrl: String?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .invoice(let flags, let currency, let prices, let maxTipAmount, let suggestedTipAmounts, let recurringTermsUrl):
case .invoice(let flags, let currency, let prices, let maxTipAmount, let suggestedTipAmounts, let termsUrl):
if boxed {
buffer.appendInt32(1048946971)
buffer.appendInt32(1572428309)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(currency, buffer: buffer, boxed: false)
@ -137,15 +137,15 @@ public extension Api {
for item in suggestedTipAmounts! {
serializeInt64(item, buffer: buffer, boxed: false)
}}
if Int(flags) & Int(1 << 9) != 0 {serializeString(recurringTermsUrl!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 10) != 0 {serializeString(termsUrl!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .invoice(let flags, let currency, let prices, let maxTipAmount, let suggestedTipAmounts, let recurringTermsUrl):
return ("invoice", [("flags", flags as Any), ("currency", currency as Any), ("prices", prices as Any), ("maxTipAmount", maxTipAmount as Any), ("suggestedTipAmounts", suggestedTipAmounts as Any), ("recurringTermsUrl", recurringTermsUrl as Any)])
case .invoice(let flags, let currency, let prices, let maxTipAmount, let suggestedTipAmounts, let termsUrl):
return ("invoice", [("flags", flags as Any), ("currency", currency as Any), ("prices", prices as Any), ("maxTipAmount", maxTipAmount as Any), ("suggestedTipAmounts", suggestedTipAmounts as Any), ("termsUrl", termsUrl as Any)])
}
}
@ -165,15 +165,15 @@ public extension Api {
_5 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
} }
var _6: String?
if Int(_1!) & Int(1 << 9) != 0 {_6 = parseString(reader) }
if Int(_1!) & Int(1 << 10) != 0 {_6 = parseString(reader) }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 8) == 0) || _4 != nil
let _c5 = (Int(_1!) & Int(1 << 8) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 9) == 0) || _6 != nil
let _c6 = (Int(_1!) & Int(1 << 10) == 0) || _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.Invoice.invoice(flags: _1!, currency: _2!, prices: _3!, maxTipAmount: _4, suggestedTipAmounts: _5, recurringTermsUrl: _6)
return Api.Invoice.invoice(flags: _1!, currency: _2!, prices: _3!, maxTipAmount: _4, suggestedTipAmounts: _5, termsUrl: _6)
}
else {
return nil

View File

@ -281,27 +281,93 @@ public extension Api.stories {
}
}
public extension Api.stories {
enum BoostsStatus: TypeConstructorDescription {
case boostsStatus(flags: Int32, level: Int32, boosts: Int32, nextLevelBoosts: Int32?)
enum BoostersList: TypeConstructorDescription {
case boostersList(flags: Int32, count: Int32, boosters: [Api.Booster], nextOffset: String?, users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .boostsStatus(let flags, let level, let boosts, let nextLevelBoosts):
case .boostersList(let flags, let count, let boosters, let nextOffset, let users):
if boxed {
buffer.appendInt32(2061518568)
buffer.appendInt32(-203604707)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(level, buffer: buffer, boxed: false)
serializeInt32(boosts, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(nextLevelBoosts!, buffer: buffer, boxed: false)}
serializeInt32(count, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(boosters.count))
for item in boosters {
item.serialize(buffer, true)
}
if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .boostsStatus(let flags, let level, let boosts, let nextLevelBoosts):
return ("boostsStatus", [("flags", flags as Any), ("level", level as Any), ("boosts", boosts as Any), ("nextLevelBoosts", nextLevelBoosts as Any)])
case .boostersList(let flags, let count, let boosters, let nextOffset, let users):
return ("boostersList", [("flags", flags as Any), ("count", count as Any), ("boosters", boosters as Any), ("nextOffset", nextOffset as Any), ("users", users as Any)])
}
}
public static func parse_boostersList(_ reader: BufferReader) -> BoostersList? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: [Api.Booster]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Booster.self)
}
var _4: String?
if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) }
var _5: [Api.User]?
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
let _c5 = _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.stories.BoostersList.boostersList(flags: _1!, count: _2!, boosters: _3!, nextOffset: _4, users: _5!)
}
else {
return nil
}
}
}
}
public extension Api.stories {
enum BoostsStatus: TypeConstructorDescription {
case boostsStatus(flags: Int32, level: Int32, currentLevelBoosts: Int32, boosts: Int32, nextLevelBoosts: Int32?, premiumAudience: Api.StatsPercentValue?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .boostsStatus(let flags, let level, let currentLevelBoosts, let boosts, let nextLevelBoosts, let premiumAudience):
if boxed {
buffer.appendInt32(1726619631)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(level, buffer: buffer, boxed: false)
serializeInt32(currentLevelBoosts, buffer: buffer, boxed: false)
serializeInt32(boosts, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(nextLevelBoosts!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {premiumAudience!.serialize(buffer, true)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .boostsStatus(let flags, let level, let currentLevelBoosts, let boosts, let nextLevelBoosts, let premiumAudience):
return ("boostsStatus", [("flags", flags as Any), ("level", level as Any), ("currentLevelBoosts", currentLevelBoosts as Any), ("boosts", boosts as Any), ("nextLevelBoosts", nextLevelBoosts as Any), ("premiumAudience", premiumAudience as Any)])
}
}
@ -313,13 +379,21 @@ public extension Api.stories {
var _3: Int32?
_3 = reader.readInt32()
var _4: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_4 = reader.readInt32() }
_4 = reader.readInt32()
var _5: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_5 = reader.readInt32() }
var _6: Api.StatsPercentValue?
if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() {
_6 = Api.parse(reader, signature: signature) as? Api.StatsPercentValue
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.stories.BoostsStatus.boostsStatus(flags: _1!, level: _2!, boosts: _3!, nextLevelBoosts: _4)
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 1) == 0) || _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.stories.BoostsStatus.boostsStatus(flags: _1!, level: _2!, currentLevelBoosts: _3!, boosts: _4!, nextLevelBoosts: _5, premiumAudience: _6)
}
else {
return nil
@ -343,7 +417,7 @@ public extension Api.stories {
break
case .canApplyBoostReplace(let currentBoost, let chats):
if boxed {
buffer.appendInt32(-1532908712)
buffer.appendInt32(1898726997)
}
currentBoost.serialize(buffer, true)
buffer.appendInt32(481674261)

View File

@ -8664,6 +8664,23 @@ public extension Api.functions.stories {
})
}
}
public extension Api.functions.stories {
static func getBoostersList(peer: Api.InputPeer, offset: String, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.stories.BoostersList>) {
let buffer = Buffer()
buffer.appendInt32(863959424)
peer.serialize(buffer, true)
serializeString(offset, buffer: buffer, boxed: false)
serializeInt32(limit, buffer: buffer, boxed: false)
return (FunctionDescription(name: "stories.getBoostersList", parameters: [("peer", String(describing: peer)), ("offset", String(describing: offset)), ("limit", String(describing: limit))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.stories.BoostersList? in
let reader = BufferReader(buffer)
var result: Api.stories.BoostersList?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.stories.BoostersList
}
return result
})
}
}
public extension Api.functions.stories {
static func getBoostsStatus(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.stories.BoostsStatus>) {
let buffer = Buffer()

View File

@ -6,12 +6,16 @@ import SwiftSignalKit
public final class ChannelBoostStatus: Equatable {
public let level: Int
public let boosts: Int
public let currentLevelBoosts: Int
public let nextLevelBoosts: Int?
public let premiumAudience: StatsPercentValue?
public init(level: Int, boosts: Int, nextLevelBoosts: Int?) {
public init(level: Int, boosts: Int, currentLevelBoosts: Int, nextLevelBoosts: Int?, premiumAudience: StatsPercentValue?) {
self.level = level
self.boosts = boosts
self.currentLevelBoosts = currentLevelBoosts
self.nextLevelBoosts = nextLevelBoosts
self.premiumAudience = premiumAudience
}
public static func ==(lhs: ChannelBoostStatus, rhs: ChannelBoostStatus) -> Bool {
@ -21,9 +25,15 @@ public final class ChannelBoostStatus: Equatable {
if lhs.boosts != rhs.boosts {
return false
}
if lhs.currentLevelBoosts != rhs.currentLevelBoosts {
return false
}
if lhs.nextLevelBoosts != rhs.nextLevelBoosts {
return false
}
if lhs.premiumAudience != rhs.premiumAudience {
return false
}
return true
}
}
@ -47,8 +57,8 @@ func _internal_getChannelBoostStatus(account: Account, peerId: PeerId) -> Signal
}
switch result {
case let .boostsStatus(_, level, boosts, nextLevelBoosts):
return ChannelBoostStatus(level: Int(level), boosts: Int(boosts), nextLevelBoosts: nextLevelBoosts.flatMap(Int.init))
case let .boostsStatus(_, level, currentLevelBoosts, boosts, nextLevelBoosts, premiumAudience):
return ChannelBoostStatus(level: Int(level), boosts: Int(boosts), currentLevelBoosts: Int(currentLevelBoosts), nextLevelBoosts: nextLevelBoosts.flatMap(Int.init), premiumAudience: premiumAudience.flatMap({ StatsPercentValue(apiPercentValue: $0) }))
}
}
}
@ -58,8 +68,9 @@ public enum CanApplyBoostStatus {
public enum ErrorReason {
case generic
case premiumRequired
case floodWait
case floodWait(Int32)
case peerBoostAlreadyActive
case giftedPremiumNotAllowed
}
case ok
@ -84,9 +95,21 @@ func _internal_canApplyChannelBoost(account: Account, peerId: PeerId) -> Signal<
if error.errorDescription == "PREMIUM_ACCOUNT_REQUIRED" {
reason = .premiumRequired
} else if error.errorDescription.hasPrefix("FLOOD_WAIT_") {
reason = .floodWait
} else if error.errorDescription == "SAME_BOOST_ALREADY_ACTIVE" {
let errorText = error.errorDescription ?? ""
if let underscoreIndex = errorText.lastIndex(of: "_") {
let timeoutText = errorText[errorText.index(after: underscoreIndex)...]
if let timeoutValue = Int32(String(timeoutText)) {
reason = .floodWait(timeoutValue)
} else {
reason = .generic
}
} else {
reason = .generic
}
} else if error.errorDescription == "SAME_BOOST_ALREADY_ACTIVE" || error.errorDescription == "BOOST_NOT_MODIFIED" {
reason = .peerBoostAlreadyActive
} else if error.errorDescription == "PREMIUM_GIFTED_NOT_ALLOWED" {
reason = .giftedPremiumNotAllowed
} else {
reason = .generic
}
@ -115,3 +138,346 @@ func _internal_canApplyChannelBoost(account: Account, peerId: PeerId) -> Signal<
}
}
}
func _internal_applyChannelBoost(account: Account, peerId: PeerId) -> Signal<Bool, NoError> {
return account.postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}
|> mapToSignal { inputPeer -> Signal<Bool, NoError> in
guard let inputPeer = inputPeer else {
return .single(false)
}
return account.network.request(Api.functions.stories.applyBoost(peer: inputPeer))
|> `catch` { error -> Signal<Api.Bool, NoError> in
return .single(.boolFalse)
}
|> map { result -> Bool in
if case .boolTrue = result {
return true
}
return false
}
}
}
private final class ChannelBoostersContextImpl {
private let queue: Queue
private let account: Account
private let peerId: PeerId
private let disposable = MetaDisposable()
private let updateDisposables = DisposableSet()
private var isLoadingMore: Bool = false
private var hasLoadedOnce: Bool = false
private var canLoadMore: Bool = true
private var loadedFromCache = false
private var results: [ChannelBoostersContext.State.Booster] = []
private var count: Int32
private var lastOffset: String?
private var populateCache: Bool = true
let state = Promise<ChannelBoostersContext.State>()
init(queue: Queue, account: Account, peerId: PeerId) {
self.queue = queue
self.account = account
self.peerId = peerId
self.count = 0
self.isLoadingMore = true
self.disposable.set((account.postbox.transaction { transaction -> (peers: [ChannelBoostersContext.State.Booster], count: Int32, canLoadMore: Bool)? in
let cachedResult = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedChannelBoosters, key: CachedChannelBoosters.key(peerId: peerId)))?.get(CachedChannelBoosters.self)
if let cachedResult = cachedResult {
var result: [ChannelBoostersContext.State.Booster] = []
for peerId in cachedResult.peerIds {
if let peer = transaction.getPeer(peerId), let expires = cachedResult.dates[peerId] {
result.append(ChannelBoostersContext.State.Booster(peer: EnginePeer(peer), expires: expires))
} else {
return nil
}
}
return (result, cachedResult.count, true)
} else {
return nil
}
}
|> deliverOn(self.queue)).start(next: { [weak self] cachedPeersCountAndCanLoadMore in
guard let strongSelf = self else {
return
}
strongSelf.isLoadingMore = false
if let (cachedPeers, cachedCount, canLoadMore) = cachedPeersCountAndCanLoadMore {
strongSelf.results = cachedPeers
strongSelf.count = cachedCount
strongSelf.hasLoadedOnce = true
strongSelf.canLoadMore = canLoadMore
strongSelf.loadedFromCache = true
}
strongSelf.loadMore()
}))
self.loadMore()
}
deinit {
self.disposable.dispose()
}
func reload() {
self.loadedFromCache = true
self.populateCache = true
self.loadMore()
}
func loadMore() {
if self.isLoadingMore {
return
}
self.isLoadingMore = true
let account = self.account
let accountPeerId = account.peerId
let peerId = self.peerId
let populateCache = self.populateCache
if self.loadedFromCache {
self.loadedFromCache = false
}
let lastOffset = self.lastOffset
self.disposable.set((self.account.postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}
|> mapToSignal { inputPeer -> Signal<([ChannelBoostersContext.State.Booster], Int32, String?), NoError> in
if let inputPeer = inputPeer {
let offset = lastOffset ?? ""
let limit: Int32 = lastOffset == nil ? 25 : 50
let signal = account.network.request(Api.functions.stories.getBoostersList(peer: inputPeer, offset: offset, limit: limit))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.stories.BoostersList?, NoError> in
return .single(nil)
}
|> mapToSignal { result -> Signal<([ChannelBoostersContext.State.Booster], Int32, String?), NoError> in
return account.postbox.transaction { transaction -> ([ChannelBoostersContext.State.Booster], Int32, String?) in
guard let result = result else {
return ([], 0, nil)
}
switch result {
case let .boostersList(_, count, boosters, nextOffset, users):
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: AccumulatedPeers(users: users))
var resultBoosters: [ChannelBoostersContext.State.Booster] = []
for booster in boosters {
let peerId: EnginePeer.Id
let expires: Int32
switch booster {
case let .booster(userId, expiresValue):
peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
expires = expiresValue
}
if let peer = transaction.getPeer(peerId) {
resultBoosters.append(ChannelBoostersContext.State.Booster(peer: EnginePeer(peer), expires: expires))
}
}
if populateCache {
if let entry = CodableEntry(CachedChannelBoosters(boosters: resultBoosters, count: count)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedChannelBoosters, key: CachedChannelBoosters.key(peerId: peerId)), entry: entry)
}
}
return (resultBoosters, count, nextOffset)
}
}
}
return signal
} else {
return .single(([], 0, nil))
}
}
|> deliverOn(self.queue)).start(next: { [weak self] boosters, updatedCount, nextOffset in
guard let strongSelf = self else {
return
}
strongSelf.lastOffset = nextOffset
if strongSelf.populateCache {
strongSelf.populateCache = false
strongSelf.results.removeAll()
}
var existingIds = Set(strongSelf.results.map { $0.peer.id })
for booster in boosters {
if !existingIds.contains(booster.peer.id) {
strongSelf.results.append(booster)
existingIds.insert(booster.peer.id)
}
}
strongSelf.isLoadingMore = false
strongSelf.hasLoadedOnce = true
strongSelf.canLoadMore = !boosters.isEmpty
if strongSelf.canLoadMore {
strongSelf.count = max(updatedCount, Int32(strongSelf.results.count))
} else {
strongSelf.count = Int32(strongSelf.results.count)
}
strongSelf.updateState()
}))
self.updateState()
}
private func updateCache() {
guard self.hasLoadedOnce && !self.isLoadingMore else {
return
}
let peerId = self.peerId
let resultBoosters = Array(self.results.prefix(50))
let count = self.count
self.updateDisposables.add(self.account.postbox.transaction({ transaction in
if let entry = CodableEntry(CachedChannelBoosters(boosters: resultBoosters, count: count)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedChannelBoosters, key: CachedChannelBoosters.key(peerId: peerId)), entry: entry)
}
}).start())
}
private func updateState() {
self.state.set(.single(ChannelBoostersContext.State(boosters: self.results, isLoadingMore: self.isLoadingMore, hasLoadedOnce: self.hasLoadedOnce, canLoadMore: self.canLoadMore, count: self.count)))
}
}
public final class ChannelBoostersContext {
public struct State: Equatable {
public struct Booster: Equatable {
public var peer: EnginePeer
public var expires: Int32
}
public var boosters: [Booster]
public var isLoadingMore: Bool
public var hasLoadedOnce: Bool
public var canLoadMore: Bool
public var count: Int32
public static var Empty = State(boosters: [], isLoadingMore: false, hasLoadedOnce: true, canLoadMore: false, count: 0)
public static var Loading = State(boosters: [], isLoadingMore: false, hasLoadedOnce: false, canLoadMore: false, count: 0)
}
private let queue: Queue = Queue()
private let impl: QueueLocalObject<ChannelBoostersContextImpl>
public var state: Signal<State, NoError> {
return Signal { subscriber in
let disposable = MetaDisposable()
self.impl.with { impl in
disposable.set(impl.state.get().start(next: { value in
subscriber.putNext(value)
}))
}
return disposable
}
}
public init(account: Account, peerId: PeerId) {
let queue = self.queue
self.impl = QueueLocalObject(queue: queue, generate: {
return ChannelBoostersContextImpl(queue: queue, account: account, peerId: peerId)
})
}
public func loadMore() {
self.impl.with { impl in
impl.loadMore()
}
}
public func reload() {
self.impl.with { impl in
impl.reload()
}
}
}
private final class CachedChannelBoosters: Codable {
private enum CodingKeys: String, CodingKey {
case peerIds
case expires
case count
}
private struct DictionaryPair: Codable, Hashable {
var key: Int64
var value: String
init(_ key: Int64, value: String) {
self.key = key
self.value = value
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: StringCodingKey.self)
self.key = try container.decode(Int64.self, forKey: "k")
self.value = try container.decode(String.self, forKey: "v")
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: StringCodingKey.self)
try container.encode(self.key, forKey: "k")
try container.encode(self.value, forKey: "v")
}
}
let peerIds: [EnginePeer.Id]
let dates: [EnginePeer.Id: Int32]
let count: Int32
static func key(peerId: EnginePeer.Id) -> ValueBoxKey {
let key = ValueBoxKey(length: 8)
key.setInt64(0, value: peerId.toInt64())
return key
}
init(boosters: [ChannelBoostersContext.State.Booster], count: Int32) {
self.peerIds = boosters.map { $0.peer.id }
self.dates = boosters.reduce(into: [EnginePeer.Id: Int32]()) {
$0[$1.peer.id] = $1.expires
}
self.count = count
}
init(peerIds: [PeerId], dates: [PeerId: Int32], count: Int32) {
self.peerIds = peerIds
self.dates = dates
self.count = count
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.peerIds = (try container.decode([Int64].self, forKey: .peerIds)).map(EnginePeer.Id.init)
var dates: [EnginePeer.Id: Int32] = [:]
let datesArray = try container.decode([Int64].self, forKey: .expires)
for index in stride(from: 0, to: datesArray.endIndex, by: 2) {
let userId = datesArray[index]
let date = datesArray[index + 1]
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
dates[peerId] = Int32(clamping: date)
}
self.dates = dates
self.count = try container.decode(Int32.self, forKey: .count)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.peerIds.map { $0.toInt64() }, forKey: .peerIds)
var dates: [Int64] = []
for (peerId, date) in self.dates {
dates.append(peerId.id._internalGetInt64Value())
dates.append(Int64(date))
}
try container.encode(dates, forKey: .expires)
try container.encode(self.count, forKey: .count)
}
}

View File

@ -110,6 +110,7 @@ public struct Namespaces {
public static let cachedPeerStoryListHeads: Int8 = 27
public static let displayedStoryNotifications: Int8 = 28
public static let storySendAsPeerIds: Int8 = 29
public static let cachedChannelBoosters: Int8 = 30
}
public struct UnorderedItemList {

View File

@ -1196,6 +1196,10 @@ public extension TelegramEngine {
public func canApplyChannelBoost(peerId: EnginePeer.Id) -> Signal<CanApplyBoostStatus, NoError> {
return _internal_canApplyChannelBoost(account: self.account, peerId: peerId)
}
public func applyChannelBoost(peerId: EnginePeer.Id) -> Signal<Bool, NoError> {
return _internal_applyChannelBoost(account: self.account, peerId: peerId)
}
}
}