<commit_before>import Foundation
import APIKit
import RxSwift
import KeychainAccess

class RedditService {
    static let shared = RedditService()

    private var keychain: Keychain {
        let service = "\(Bundle.main.bundleIdentifier!).reddit"
        return Keychain(service: service)
    }

    var hasRefreshToken: Bool {
        return keychain["refreshToken"] != nil
    }

    var hasUser: Bool {
        return currentUser != nil
    }

    var accessToken: String? {
        return keychain["accessToken"]
    }

    private(set) var currentUser: RedditUser?

    func fetchUserInfo(credential: RedditCredential) -> Observable<RedditUser> {
        storeCredential(credential)

        return fetchUserInfo()
    }

    func fetchUserInfo() -> Observable<RedditUser> {
        let request = RedditAPI.UserRequest()
        return Session.shared.rx
            .response(request)
            .do(onNext: { user in
                self.currentUser = user
            })
    }

    private func storeCredential(_ credential: RedditCredential) {
        let keychain = self.keychain<commit_msg>Refresh access token when expired<commit_after>import Foundation
import APIKit
import RxSwift
import KeychainAccess

class RedditService {
    static let shared = RedditService()

    let clientID: String

    private var keychain: Keychain {
        let service = "\(Bundle.main.bundleIdentifier!).reddit"
        return Keychain(service: service)
    }

    var hasRefreshToken: Bool {
        return keychain["refreshToken"] != nil
    }

    var hasUser: Bool {
        return currentUser != nil
    }

    var accessToken: String? {
        return keychain["accessToken"]
    }

    private var refreshToken: String? {
        return keychain["refreshToken"]
    }

    private(set) var currentUser: RedditUser?

    init(clientID: String = RedditServiceConfiguration.clientID) {
        self.clientID = clientID
    }

    func fetchUserInfo(credential: RedditCredential) -> Observable<RedditUser> {
        storeCredential(credential)

        return fetchUserInfo()
    }

    func fetchUserInfo() -> Observable<RedditUser> {
        let request = RedditAPI.UserRequest()
        return Session.shared.rx
            .response(request)
            .retryWhen { (errors: Observable<Error>) in
                return errors.flatMapWithIndex { error, retryCount -> Observable<RedditCredential> in
                    if case SessionTaskError.responseError(ResponseError.unacceptableStatusCode(401)) = error, retryCount < 1 {
                        return self.refreshAccessToken()
                    }
                    return Observable.error(error)
                }
            }
            .do(onNext: { user in
                self.currentUser = user
            })
    }

    func refreshAccessToken() -> Observable<RedditCredential> {
        guard let refreshToken = refreshToken else {
            fatalError("refresh token not found")
        }

        let request = RedditAPI.AccessTokenRequest(clientID: clientID, refreshToken: refreshToken)
        return Session.shared.rx.response(request)
            .do(onNext: { credential in
                self.storeCredential(credential)
            })
    }

    private func storeCredential(_ credential: RedditCredential) {
        let keychain = self.keychain
{'fraction_non_alphanumeric': 0.0819081908190819, 'fraction_numerical': 0.0012001200120012002, 'mean_word_length': 2.3273453093812377, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7036133', 'n_tokens_mistral': 878, 'n_tokens_neox': 834, 'n_words': 209}