Skip to content

Commit

Permalink
Merge pull request #92 from makinosp/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
makinosp authored Oct 18, 2024
2 parents 6f933f1 + d9faac0 commit d53d7bc
Show file tree
Hide file tree
Showing 11 changed files with 100 additions and 40 deletions.
6 changes: 6 additions & 0 deletions Sources/VRCKit/Models/Favorite/FavoriteListModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ public struct FavoriteList: Sendable, Identifiable {
public let favorites: [Favorite]
}

public extension FavoriteList {
init(id: ID) {
self.init(id: id, favorites: [])
}
}

public extension FavoriteList {
func allFavoritesAre(_ type: FavoriteType) -> Bool {
favorites.allSatisfy { $0.type == type }
Expand Down
1 change: 1 addition & 0 deletions Sources/VRCKit/Models/Friend/FriendModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public struct Friend: Sendable, ProfileElementRepresentable, LocationRepresentab
public let friendKey: String
}

@MemberwiseInit(.public)
public struct FriendsLocation: Sendable, LocationRepresentable {
public let location: Location
public let friends: [Friend]
Expand Down
21 changes: 21 additions & 0 deletions Sources/VRCKit/Models/User/PresenceModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// PresenceModel.swift
// VRCKit
//
// Created by makinosp on 2024/10/12.
//

import MemberwiseInit

@MemberwiseInit(.public)
public struct Presence: Codable, Hashable, Sendable {
public let groups: [String]
public let id: String
public let instance: String
public let instanceType: String
public let platform: UserPlatform
public let status: UserStatus
public let travelingToInstance: String
public let travelingToWorld: String
public let world: String
}
2 changes: 1 addition & 1 deletion Sources/VRCKit/Models/User/UserModel+Decodable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ extension User: Decodable {
lastPlatform = try container.decode(String.self, forKey: .lastPlatform)
offlineFriends = try container.decode([String].self, forKey: .offlineFriends)
onlineFriends = try container.decode([String].self, forKey: .onlineFriends)
pastDisplayNames = try container.decode([User.DisplayName].self, forKey: .pastDisplayNames)
pastDisplayNames = try container.decode([DisplayName].self, forKey: .pastDisplayNames)
profilePicOverride = try? container.decodeIfPresent(URL.self, forKey: .profilePicOverride)
state = try container.decode(User.State.self, forKey: .state)
status = try container.decode(UserStatus.self, forKey: .status)
Expand Down
25 changes: 6 additions & 19 deletions Sources/VRCKit/Models/User/UserModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,6 @@ public struct User: Sendable, ProfileDetailRepresentable {
public let userLanguageCode: String?
public let presence: Presence

@MemberwiseInit(.public)
public struct DisplayName: Codable, Sendable, Hashable {
public let displayName: String
public let updatedAt: Date
}

public enum State: String, Codable, Sendable {
/// User is online in VRChat
case online
Expand All @@ -55,19 +49,6 @@ public struct User: Sendable, ProfileDetailRepresentable {
/// User is offline
case offline
}

@MemberwiseInit(.public)
public struct Presence: Codable, Hashable, Sendable {
public let groups: [String]
public let id: String
public let instance: String
public let instanceType: String
public let platform: UserPlatform
public let status: UserStatus
public let travelingToInstance: String
public let travelingToWorld: String
public let world: String
}
}

public extension User {
Expand All @@ -79,3 +60,9 @@ public extension User {
URL(string: [Const.homeBaseUrl, "user", id].joined(separator: "/"))
}
}

@MemberwiseInit(.public)
public struct DisplayName: Codable, Sendable, Hashable {
public let displayName: String
public let updatedAt: Date
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

public extension FavoriteWorld {
/// Initialize from `World` mode.
init(world: World, favoriteGroup: String) {
init(world: World, favoriteId: String, favoriteGroup: String) {
self.init(
id: world.id,
name: world.name,
Expand All @@ -32,6 +32,7 @@ public extension FavoriteWorld {
popularity: world.popularity,
heat: world.heat,
favoriteGroup: favoriteGroup,
favoriteId: favoriteId,
version: world.version,
unityPackages: world.unityPackages
)
Expand Down
1 change: 1 addition & 0 deletions Sources/VRCKit/Models/World/FavoriteWorldModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public struct FavoriteWorld: Codable, Sendable, Identifiable, Hashable {
public let popularity: Int
public let heat: Int
public let favoriteGroup: String
public let favoriteId: String
public let version: Int?
public let unityPackages: [UnityPackage]
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/VRCKit/Protocols/FavoriteServiceProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

public protocol FavoriteServiceProtocol: Sendable {
func listFavoriteGroups() async throws -> [FavoriteGroup]
func listFavorites(n: Int, type: FavoriteType, tag: String?) async throws -> [Favorite]
func fetchFavoriteList(favoriteGroups: [FavoriteGroup]) async throws -> [FavoriteList]
func listFavorites(type: FavoriteType) async throws -> [Favorite]
func fetchFavoriteList(favoriteGroups: [FavoriteGroup], type: FavoriteType) async throws -> [FavoriteList]
func addFavorite(type: FavoriteType, favoriteId: String, tag: String) async throws -> Favorite
func updateFavoriteGroup(
source: FavoriteGroup,
Expand Down
2 changes: 1 addition & 1 deletion Sources/VRCKit/Protocols/WorldServiceProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@

public protocol WorldServiceProtocol: Sendable {
func fetchWorld(worldId: String) async throws -> World
func fetchFavoritedWorlds(n: Int) async throws -> [FavoriteWorld]
func fetchFavoritedWorlds() async throws -> [FavoriteWorld]
}
48 changes: 34 additions & 14 deletions Sources/VRCKit/Services/FavoriteService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import MemberwiseInit
@MemberwiseInit(.public)
public final actor FavoriteService: APIService, FavoriteServiceProtocol {
public let client: APIClient
private let limit = 100
private let maxCount = 400

/// Asynchronously retrieves a list of favorite groups from the server.
/// - Returns: An array of `FavoriteGroup` objects.
Expand All @@ -20,20 +22,41 @@ public final actor FavoriteService: APIService, FavoriteServiceProtocol {
return try await Serializer.shared.decode(response.data)
}

/// Lists a user's all favorites with the specified parameters.
/// - Parameter type: The type of favorite (e.g., friend, world).
/// - Returns: An array of `Favorite` objects.
public func listFavorites(type: FavoriteType) async throws -> [Favorite] {
try await withThrowingTaskGroup(of: [Favorite].self) { taskGroup in
for offset in stride(from: .zero, to: maxCount, by: limit) {
taskGroup.addTask { [weak self] in
guard let self = self else { return [] }
return try await listFavorites(n: limit, offset: offset, type: type)
}
}
var results: [Favorite] = []
for try await favorites in taskGroup {
results.append(contentsOf: favorites)
}
return results
}
}

/// Lists a user's favorites with the specified parameters.
/// - Parameters:
/// - n: The number of favorites to retrieve. Default is `60``.
/// - type: The type of favorite (e.g., friend, world).
/// - tag: An optional tag to filter favorites.
/// - Returns: An array of `Favorite` objects.
public func listFavorites(
n: Int = 60,
private func listFavorites(
n: Int = 100,
offset: Int = 0,
type: FavoriteType,
tag: String? = nil
) async throws -> [Favorite] {
let path = "favorites"
var queryItems = [
URLQueryItem(name: "n", value: n.description),
URLQueryItem(name: "offset", value: offset.description),
URLQueryItem(name: "type", value: type.rawValue)
]
if let tag = tag {
Expand All @@ -44,28 +67,25 @@ public final actor FavoriteService: APIService, FavoriteServiceProtocol {
}

/// Fetches details of favorite groups asynchronously.
/// - Parameter favoriteGroups: An array of `FavoriteGroup` objects.
/// - Parameters:
/// - favoriteGroups: An array of `FavoriteGroup` objects.
/// - type: The type of favorite (e.g., friend, world).
/// - Returns: An array of `FavoriteDetail` objects containing detailed information about the favorite groups.
public func fetchFavoriteList(favoriteGroups: [FavoriteGroup]) async throws -> [FavoriteList] {
var results: [FavoriteList] = []
public func fetchFavoriteList(favoriteGroups: [FavoriteGroup], type: FavoriteType) async throws -> [FavoriteList] {
try await withThrowingTaskGroup(of: FavoriteList.self) { taskGroup in
for favoriteGroup in favoriteGroups.filter({ $0.type == .friend }) {
for favoriteGroup in favoriteGroups.filter({ $0.type == type }) {
taskGroup.addTask { [weak self] in
guard let self = self else {
throw VRCKitError.unexpected
}
let favorites = try await self.listFavorites(
type: .friend,
tag: favoriteGroup.name
)
guard let self = self else { return FavoriteList(id: favoriteGroup.id) }
let favorites = try await listFavorites(type: type, tag: favoriteGroup.name)
return FavoriteList(id: favoriteGroup.id, favorites: favorites)
}
}
var results: [FavoriteList] = []
for try await favoriteGroupDetail in taskGroup {
results.append(favoriteGroupDetail)
}
return results
}
return results
}

/// Adds a new favorite to a specific group.
Expand Down
27 changes: 25 additions & 2 deletions Sources/VRCKit/Services/WorldService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,37 @@ import MemberwiseInit
public final actor WorldService: APIService, WorldServiceProtocol {
public let client: APIClient
private let path = "worlds"
private let limit = 100
private let maxCount = 400
private typealias FavoriteWorldsWithOffset = (offset: Int, worlds: [FavoriteWorld])

public func fetchWorld(worldId: String) async throws -> World {
let response = try await client.request(path: "\(path)/\(worldId)", method: .get)
return try await Serializer.shared.decode(response.data)
}

public func fetchFavoritedWorlds(n: Int = 100) async throws -> [FavoriteWorld] {
let queryItems = [URLQueryItem(name: "n", value: n.description)]
public func fetchFavoritedWorlds() async throws -> [FavoriteWorld] {
try await withThrowingTaskGroup(of: FavoriteWorldsWithOffset.self) { taskGroup in
for offset in stride(from: .zero, to: maxCount, by: limit) {
taskGroup.addTask { [weak self] in
guard let self = self else { return (offset, []) }
let worlds = try await fetchFavoritedWorlds(n: limit, offset: offset)
return (offset, worlds)
}
}
var resultsDict: [FavoriteWorldsWithOffset] = []
for try await result in taskGroup { resultsDict.append(result) }
return resultsDict
.sorted { $0.offset < $1.offset }
.flatMap { $0.worlds }
}
}

private func fetchFavoritedWorlds(n: Int, offset: Int) async throws -> [FavoriteWorld] {
let queryItems = [
URLQueryItem(name: "n", value: n.description),
URLQueryItem(name: "offset", value: offset.description)
]
let response = try await client.request(path: "\(path)/favorites", method: .get, queryItems: queryItems)
let favoriteWorldWrapper: SafeDecodingArray<FavoriteWorld> = try await Serializer.shared.decode(response.data)
return favoriteWorldWrapper.wrappedValue
Expand Down

0 comments on commit d53d7bc

Please sign in to comment.