punchnet-macos/punchnet/Views/AppContext.swift

118 lines
3.5 KiB
Swift

//
// LoginState.swift
// punchnet
//
// Created by on 2026/1/16.
//
import Foundation
import Observation
@Observable
class AppContext {
var noticePort: Int
// "/connect"
var networkContext: SDLAPIClient.NetworkContext = .default()
// app
var loginScene: LoginScene = .login(username: nil)
//
enum LoginScene: Equatable {
case login(username: String?)
case register
case resetPassword
}
//
var loginCredit: Credit?
enum Credit {
case token(token: String, session: SDLAPIClient.NetworkSession)
case accountAndPasword(account: String, password: String, session: SDLAPIClient.NetworkSession)
}
@ObservationIgnored
var networkSession: SDLAPIClient.NetworkSession? {
guard let loginCredit = self.loginCredit else {
return nil
}
switch loginCredit {
case .token(_, let session):
return session
case .accountAndPasword(_, _, let session):
return session
}
}
init(noticePort: Int) {
self.noticePort = noticePort
}
func loginWith(token: String) async throws {
let networkSession = try await SDLAPIClient.loginWithToken(token: token)
self.loginCredit = .token(token: token, session: networkSession)
// keychain
if let data = token.data(using: .utf8) {
try KeychainStore.shared.save(data, account: "token")
}
}
func loginWith(username: String, password: String) async throws {
let networkSession = try await SDLAPIClient.loginWithAccountAndPassword(username: username, password: password)
self.loginCredit = .accountAndPasword(account: username, password: password, session: networkSession)
// keychain
if let data = "\(username):\(password)".data(using: .utf8) {
try KeychainStore.shared.save(data, account: "accountAndPasword")
}
}
//
func connectNetwork() async throws {
guard let session = self.networkSession else {
return
}
let context = try await SDLAPIClient.connectNetwork(accesToken: session.accessToken)
if let options = SystemConfig.getOptions(
networkId: UInt32(session.networkId),
networkDomain: session.networkDomain,
ip: context.ip,
maskLen: context.maskLen,
accessToken: session.accessToken,
identityId: context.identityId,
hostname: context.hostname,
noticePort: noticePort
) {
try await VPNManager.shared.enableVpn(options: options)
self.networkContext = context
}
}
func loadCacheToken() -> String? {
if let data = try? KeychainStore.shared.load(account: "token") {
return String(data: data, encoding: .utf8)
}
return nil
}
func loadCacheUsernameAndPassword() -> (String, String)? {
if let data = try? KeychainStore.shared.load(account: "accountAndPasword"),
let str = String(data: data, encoding: .utf8) {
let parts = str.split(separator: ":")
if parts.count == 2 {
return (String(parts[0]), String(parts[1]))
}
}
return nil
}
// 退
func logout() async throws {
try await VPNManager.shared.disableVpn()
}
}