Skip to content

Commit

Permalink
some change
Browse files Browse the repository at this point in the history
  • Loading branch information
yanue committed Jan 2, 2025
1 parent 0453780 commit fc30a88
Show file tree
Hide file tree
Showing 16 changed files with 263 additions and 113 deletions.
24 changes: 11 additions & 13 deletions V2rayU/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,38 +33,36 @@ final class AppState: ObservableObject {
@Published var checkForUpdates: Bool = true
@Published var autoUpdateServers: Bool = true
@Published var selectFastestServer: Bool = true
@Published var enableStat = true

@Published var logLevel = "info"
@Published var logLevel = V2rayLog.logLevel.info
@Published var socksPort = 1080
@Published var socksHost = "127.0.0.1"
@Published var httpPort = 1087
@Published var httpHost = "127.0.0.1"
@Published var enableSocks = true
@Published var enableUdp = false
@Published var enableSniffing = true
@Published var enableMux = false
@Published var enableSniffing = false
@Published var mux = 8
@Published var dnsJson = ""

private var cancellables = Set<AnyCancellable>()

init() {
self.runMode = RunMode(rawValue: UserDefaults.get(forKey: .runMode) ?? "off") ?? .off
self.runMode = UserDefaults.getEnum(forKey: .runMode, type: RunMode.self, defaultValue: .off)
self.enableMux = UserDefaults.getBool(forKey: .enableMux)
self.enableUdp = UserDefaults.getBool(forKey: .enableUdp)
self.enableSniffing = UserDefaults.getBool(forKey: .enableSniffing)
self.enableStat = UserDefaults.getBool(forKey: .enableStat)

self.httpPort = UserDefaults.getInt(forKey: .localHttpPort)
if self.httpPort == 0 {
self.httpPort = 1080
}
self.httpHost = UserDefaults.get(forKey: .localHttpHost) ?? "127.0.0.1"
self.httpPort = UserDefaults.getInt(forKey: .localHttpPort, defaultValue: 1087)
self.httpHost = UserDefaults.get(forKey: .localHttpHost, defaultValue: "127.0.0.1")
self.socksPort = UserDefaults.getInt(forKey: .localSockPort,defaultValue: 1080)
self.socksHost = UserDefaults.get(forKey: .localSockHost) ?? "127.0.0.1"
self.mux = Int(UserDefaults.get(forKey: .muxConcurrent) ?? "8") ?? 8
self.socksHost = UserDefaults.get(forKey: .localSockHost, defaultValue: "127.0.0.1")
self.mux = UserDefaults.getInt(forKey: .muxConcurrent, defaultValue: 8)

self.logLevel = UserDefaults.getEnum(forKey: .v2rayLogLevel, type: V2rayLog.logLevel.self, defaultValue: .info)

self.logLevel = UserDefaults.get(forKey: .v2rayLogLevel) ?? "info"

self.launchAtLogin = UserDefaults.getBool(forKey: .autoLaunch)
self.autoUpdateServers = UserDefaults.getBool(forKey: .autoUpdateServers)
self.checkForUpdates = UserDefaults.getBool(forKey: .autoCheckVersion)
Expand Down
54 changes: 48 additions & 6 deletions V2rayU/Base/Url+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,61 @@

import Foundation

// URL 扩展:用于从 URL 获取查询参数
extension URL {
func queryParams() -> [String: Any] {
var dict = [String: Any]()
func queryParams() -> QueryParameters {
var dict = QueryParameters()
if let components = URLComponents(url: self, resolvingAgainstBaseURL: false) {
if let queryItems = components.queryItems {
for item in queryItems {
dict[item.name] = item.value
dict.add(key: item.name, value: item.value ?? "")
}
}
return dict
} else {
return [:]
}
return dict
}
}

// 更合适的命名:用于存储 URL 查询参数的类
class QueryParameters: NSObject {
private var dict = [String: String]()

override init() {
super.init()
}

// 添加查询参数
func add(key: String, value: String) {
dict[key] = value
}

// 获取 String 类型的参数
func getString(forKey key: String, defaultValue: String = "") -> String {
return dict[key] ?? defaultValue
}

// 获取 Int 类型的参数
func getInt(forKey key: String, defaultValue: Int = 0) -> Int {
if let stringValue = dict[key], let intValue = Int(stringValue) {
return intValue
}
return defaultValue
}

// 获取 Bool 类型的参数
func getBool(forKey key: String, defaultValue: Bool = false) -> Bool {
if let stringValue = dict[key] {
return stringValue.lowercased() == "true" || stringValue == "1"
}
return defaultValue
}

// 获取 Enum 类型的参数
func getEnum<T: RawRepresentable>(forKey key: String, type: T.Type, defaultValue: T) -> T where T.RawValue == String {
if let rawValue = dict[key], let enumValue = T(rawValue: rawValue) {
return enumValue
}
return defaultValue
}
}

Expand Down
27 changes: 15 additions & 12 deletions V2rayU/Base/UserDefaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ extension UserDefaults {
case autoSelectFastestServer
// pac|manual|global
case runMode
// enable Traffic Statistics
case enableStat

// base settings
// http host
Expand Down Expand Up @@ -87,19 +89,20 @@ extension UserDefaults {
UserDefaults.standard.set(value, forKey: key.rawValue)
}

static func get(forKey key: KEY) -> String? {
return UserDefaults.standard.string(forKey: key.rawValue)
}

static func setArray(forKey key: KEY, value: [String]) {
UserDefaults.standard.set(value, forKey: key.rawValue)
}

static func getArray(forKey key: KEY) -> [String]? {
return UserDefaults.standard.array(forKey: key.rawValue) as? [String]
static func get(forKey key: KEY, defaultValue: String = "") -> String {
let rawValue = UserDefaults.standard.string(forKey: key.rawValue)
if rawValue != nil && rawValue != "" {
return defaultValue
}
return defaultValue
}

static func delArray(forKey key: KEY) {
UserDefaults.standard.removeObject(forKey: key.rawValue)
// MARK: 获取枚举类型
static func getEnum<T: RawRepresentable>(forKey key: KEY, type: T.Type, defaultValue: T) -> T where T.RawValue == String {
guard let rawValue = UserDefaults.standard.string(forKey: key.rawValue),
let enumValue = T(rawValue: rawValue) else {
return defaultValue
}
return enumValue
}
}
69 changes: 49 additions & 20 deletions V2rayU/Handler/Share/TrojanUri.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,32 @@ class TrojanUri: BaseShareUri {
uri.password = profile.password
uri.host = profile.address
uri.port = profile.port
uri.queryItems = [
URLQueryItem(name: "flow", value: profile.flow),
var queryItems = [
URLQueryItem(name: "type", value: profile.network.rawValue),
URLQueryItem(name: "security", value: profile.security.rawValue),
URLQueryItem(name: "sni", value: profile.sni),
URLQueryItem(name: "fp", value: profile.fingerprint.rawValue),
]
// 判断 network 类型
switch profile.network {
case .tcp:
queryItems.append(URLQueryItem(name: "headerType", value: profile.headerType.rawValue))
break
case .ws:
queryItems.append(URLQueryItem(name: "path", value: profile.path))
queryItems.append(URLQueryItem(name: "host", value: profile.host))
break
case .h2:
queryItems.append(URLQueryItem(name: "host", value: profile.host))
queryItems.append(URLQueryItem(name: "path", value: profile.path))
break
case .grpc:
queryItems.append(URLQueryItem(name: "serviceName", value: profile.path))
break
default:
break
}
uri.queryItems = queryItems
return (uri.url?.absoluteString ?? "") + "#" + profile.remark.urlEncoded()
}

Expand All @@ -47,30 +67,39 @@ class TrojanUri: BaseShareUri {
return NSError(domain: "TrojanUriError", code: 1003, userInfo: [NSLocalizedDescriptionKey: "Missing password"])
}

profile.host = host
profile.address = host
profile.port = port
profile.password = password

let queryItems = url.queryParams()
for item in queryItems {
switch item.key {
case "sni":
profile.sni = item.value as? String ?? ""
case "flow":
profile.flow = item.value as? String ?? ""
case "security":
profile.security = V2rayStreamSecurity(rawValue: item.value as? String ?? "") ?? .none
case "fp":
profile.fingerprint = V2rayStreamFingerprint(rawValue: item.value as? String ?? "") ?? .chrome
default:
break
}
}

let query = url.queryParams()
profile.network = query.getEnum("type", V2rayStreamNetwork.self, defaultValue: .tcp)
profile.security = query.getEnum("security", V2rayStreamSecurity.self, defaultValue: .tls)
profile.sni = query.getString("sni", defaultValue: profile.address)
profile.fingerprint = query.getEnum("fp", V2rayStreamFingerprint.self, defaultValue: .chrome)
// security 不能为 none
if profile.security == .none {
profile.security = .tls
}

// 如果 sni 为空,则将 host 赋值给 sni
if self.profile.sni.count == 0 {
self.profile.sni = host
}
// 判断 network 类型
switch profile.network {
case .tcp:
profile.headerType = query.getEnum("headerType", V2rayStreamHeaderType.self, defaultValue: .none)
break
case .ws, .h2:
profile.host = query.getString("host", defaultValue: profile.address)
profile.path = query.getString("path", defaultValue: "/")
break
case .grpc:
// grpcServiceName: 先从 query 中获取 serviceName,如果没有则获取 path,如果都没有则默认为 "/"
profile.path = query.getString("serviceName", defaultValue: query.getString("path", defaultValue: "/"))
break
default:
break
}
profile.remark = (url.fragment ?? "trojan").urlDecoded()
return nil
}
Expand Down
Loading

0 comments on commit fc30a88

Please sign in to comment.