Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Mac checks

on:
pull_request:
workflow_dispatch:

permissions:
contents: read

concurrency:
group: mac-checks-${{ github.ref }}
cancel-in-progress: true

jobs:
check:
name: impl-swift checks
runs-on: macos-15
env:
DEVELOPER_DIR: /Applications/Xcode_26.2.app/Contents/Developer
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: 检查格式、lint 与 SwiftPM 测试
run: bash scripts/check.sh
4 changes: 4 additions & 0 deletions .swift-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"version": 1,
"indentation": { "spaces": 4 }
}
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ Capture 和此次 Mac 分发尚未发布,直接修订候选 schema,不增加

同次提交不得换 UUID、变更材料或改投另一个信息库。只有经过指纹核对的共享回执可以清理本机材料。选区失败不能读旧剪贴板充数;截图只持久化明确选择的区域。

运行 `swift test` 和 `bash scripts/build-app.sh`。编译不证明系统权限、真实选区、焦点或多屏行为;真实应用验证使用合成内容,按实际结果记录。开发包使用 `dev.inkcre.capture`;发布身份、签名、公证只能使用显式提供的输入。
运行 `bash scripts/check.sh` 和 `bash scripts/build-app.sh`。前者与 CI 共用 Xcode 26.2 的 Swift 格式/lint 检查和测试入口,覆盖 Host、PeerCore 与 first-party 扩展;固定来源的 Vendor 代码按上游格式维护。编译不证明系统权限、真实选区、焦点或多屏行为;真实应用验证使用合成内容,按实际结果记录。开发包使用 `dev.inkcre.capture`;发布身份、签名、公证只能使用显式提供的输入。
4 changes: 3 additions & 1 deletion Packages/PeerCore/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ let package = Package(
],
dependencies: [.package(url: "https://github.com/vapor/postgres-nio.git", from: "1.32.0")],
targets: [
.target(name: "PeerCore", dependencies: [.product(name: "PostgresNIO", package: "postgres-nio")]),
.target(
name: "PeerCore", dependencies: [.product(name: "PostgresNIO", package: "postgres-nio")]
),
.target(name: "PeerMacUI", dependencies: ["PeerCore"]),
]
)
148 changes: 75 additions & 73 deletions Packages/PeerCore/Sources/PeerCore/BundledParticipation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,82 +2,84 @@ import Foundation
import PostgresNIO

extension PeerDatabase {
/// First joining may create a selection; subsequent reconnects never recreate removed participation.
public func join(
_ target: ConnectionTarget, password: String, extension descriptor: NativeExtensionDescriptor
) async throws {
let defaults = UserDefaults(suiteName: "dev.inkcre.native-participation")!
let key = "\(target.peerID).\(descriptor.name)"
let firstJoin = !defaults.bool(forKey: key)
let client = try client(for: target, password: password)
let issue: String? = try await client.withTransaction(logger: Self.logger) { connection in
if firstJoin {
try await connection.query(
"INSERT INTO inkcre.extensions(name) VALUES (\(descriptor.name)) ON CONFLICT (name) DO NOTHING",
logger: Self.logger)
try await connection.query(
"""
INSERT INTO inkcre.extension_peer_participations(name,peer_id,distribution,version,enabled)
VALUES (\(descriptor.name),\(target.peerID),\(descriptor.distribution),\(descriptor.version),true)
ON CONFLICT (name,peer_id) DO NOTHING
""", logger: Self.logger)
}
do {
try await Self.requireSelection(descriptor, peerID: target.peerID, on: connection)
return nil
} catch PeerError.needsAction(let message) { return message }
/// First joining may create a selection; subsequent reconnects never recreate removed participation.
public func join(
_ target: ConnectionTarget, password: String,
extension descriptor: NativeExtensionDescriptor
) async throws {
let defaults = UserDefaults(suiteName: "dev.inkcre.native-participation")!
let key = "\(target.peerID).\(descriptor.name)"
let firstJoin = !defaults.bool(forKey: key)
let client = try client(for: target, password: password)
let issue: String? = try await client.withTransaction(logger: Self.logger) { connection in
if firstJoin {
try await connection.query(
"INSERT INTO inkcre.extensions(name) VALUES (\(descriptor.name)) ON CONFLICT (name) DO NOTHING",
logger: Self.logger)
try await connection.query(
"""
INSERT INTO inkcre.extension_peer_participations(name,peer_id,distribution,version,enabled)
VALUES (\(descriptor.name),\(target.peerID),\(descriptor.distribution),\(descriptor.version),true)
ON CONFLICT (name,peer_id) DO NOTHING
""", logger: Self.logger)
}
do {
try await Self.requireSelection(descriptor, peerID: target.peerID, on: connection)
return nil
} catch PeerError.needsAction(let message) { return message }
}
defaults.set(true, forKey: key)
if let issue { throw PeerError.needsAction(issue) }
}
defaults.set(true, forKey: key)
if let issue { throw PeerError.needsAction(issue) }
}

public static func requireSelection(
_ descriptor: NativeExtensionDescriptor, peerID: UUID, on connection: PostgresConnection
) async throws {
let rows = try await connection.query(
"""
SELECT distribution,version,enabled FROM inkcre.extension_peer_participations
WHERE name=\(descriptor.name) AND peer_id=\(peerID) FOR SHARE
""", logger: Self.logger)
for try await (distribution, version, enabled) in rows.decode((String?, String, Bool).self) {
guard distribution == descriptor.distribution, version == descriptor.version else {
throw PeerError.needsAction("此 Peer 选择的扩展版本不在当前应用中,请核对扩展选择。")
}
guard enabled else { throw PeerError.needsAction("信息库中的扩展参与已停用;本机材料保留,请在线明确启用后继续。") }
return
public static func requireSelection(
_ descriptor: NativeExtensionDescriptor, peerID: UUID, on connection: PostgresConnection
) async throws {
let rows = try await connection.query(
"""
SELECT distribution,version,enabled FROM inkcre.extension_peer_participations
WHERE name=\(descriptor.name) AND peer_id=\(peerID) FOR SHARE
""", logger: Self.logger)
for try await (distribution, version, enabled) in rows.decode((String?, String, Bool).self)
{
guard distribution == descriptor.distribution, version == descriptor.version else {
throw PeerError.needsAction("此 Peer 选择的扩展版本不在当前应用中,请核对扩展选择。")
}
guard enabled else { throw PeerError.needsAction("信息库中的扩展参与已停用;本机材料保留,请在线明确启用后继续。") }
return
}
throw PeerError.needsAction("此 Peer 的扩展参与已移除;不会在重连时自动重建。")
}
throw PeerError.needsAction("此 Peer 的扩展参与已移除;不会在重连时自动重建。")
}

public func setEnabled(
_ enabled: Bool, target: ConnectionTarget, password: String,
extension descriptor: NativeExtensionDescriptor
) async throws {
_ = try await register(target, password: password)
let client = try client(for: target, password: password)
try await client.withTransaction(logger: Self.logger) { connection in
if enabled {
try await connection.query(
"INSERT INTO inkcre.extensions(name) VALUES (\(descriptor.name)) ON CONFLICT (name) DO NOTHING",
logger: Self.logger)
try await connection.query(
"""
INSERT INTO inkcre.extension_peer_participations(name,peer_id,distribution,version,enabled)
VALUES (\(descriptor.name),\(target.peerID),\(descriptor.distribution),\(descriptor.version),true)
ON CONFLICT (name,peer_id) DO NOTHING
""", logger: Self.logger)
}
let rows = try await connection.query(
"""
UPDATE inkcre.extension_peer_participations SET enabled=\(enabled)
WHERE name=\(descriptor.name) AND peer_id=\(target.peerID)
AND distribution=\(descriptor.distribution) AND version=\(descriptor.version)
RETURNING name
""", logger: Self.logger)
for try await _ in rows.decode(String.self) { return }
if enabled { throw PeerError.needsAction("信息库中没有与本机匹配的扩展选择。") }
public func setEnabled(
_ enabled: Bool, target: ConnectionTarget, password: String,
extension descriptor: NativeExtensionDescriptor
) async throws {
_ = try await register(target, password: password)
let client = try client(for: target, password: password)
try await client.withTransaction(logger: Self.logger) { connection in
if enabled {
try await connection.query(
"INSERT INTO inkcre.extensions(name) VALUES (\(descriptor.name)) ON CONFLICT (name) DO NOTHING",
logger: Self.logger)
try await connection.query(
"""
INSERT INTO inkcre.extension_peer_participations(name,peer_id,distribution,version,enabled)
VALUES (\(descriptor.name),\(target.peerID),\(descriptor.distribution),\(descriptor.version),true)
ON CONFLICT (name,peer_id) DO NOTHING
""", logger: Self.logger)
}
let rows = try await connection.query(
"""
UPDATE inkcre.extension_peer_participations SET enabled=\(enabled)
WHERE name=\(descriptor.name) AND peer_id=\(target.peerID)
AND distribution=\(descriptor.distribution) AND version=\(descriptor.version)
RETURNING name
""", logger: Self.logger)
for try await _ in rows.decode(String.self) { return }
if enabled { throw PeerError.needsAction("信息库中没有与本机匹配的扩展选择。") }
}
let defaults = UserDefaults(suiteName: "dev.inkcre.native-participation")!
defaults.set(true, forKey: "\(target.peerID).\(descriptor.name)")
}
let defaults = UserDefaults(suiteName: "dev.inkcre.native-participation")!
defaults.set(true, forKey: "\(target.peerID).\(descriptor.name)")
}
}
6 changes: 4 additions & 2 deletions Packages/PeerCore/Sources/PeerCore/ConnectionSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ public actor ConnectionSettings {
let web = web.trimmingCharacters(in: .whitespacesAndNewlines)
let webURL = web.isEmpty ? nil : URL(string: web)
if !web.isEmpty && webURL == nil { throw PeerError.invalid("Web 地址无效。") }
let same = previous?.host == host && previous?.port == port && previous?.database == database
let same =
previous?.host == host && previous?.port == port && previous?.database == database
let sameCredentials = same && previous?.username == username
let target = ConnectionTarget(
id: sameCredentials ? previous!.id : UUID(), peerID: same ? previous!.peerID : UUID(),
host: host, port: port, database: database, username: username, tls: tls, webURL: webURL,
host: host, port: port, database: database, username: username, tls: tls,
webURL: webURL,
name: host)
try target.validate()
if !password.isEmpty { try credentials.save(password, for: target.id) }
Expand Down
2 changes: 2 additions & 0 deletions Packages/PeerCore/Sources/PeerCore/InfoBase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public struct GraphBlock: Sendable, Encodable {
self.content = content
}
}
// 数据库图协议直接使用 from_/to_ 字段。
// swift-format-ignore: AlwaysUseLowerCamelCase
public struct GraphRelation: Sendable, Encodable {
public let from_: Int
public let to_: Int
Expand Down
4 changes: 3 additions & 1 deletion Packages/PeerCore/Sources/PeerCore/PeerDatabase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ public actor PeerDatabase {
""", logger: Self.logger)
let rows = try await connection.query(
"SELECT inkcre.renew_peer_lease(\(target.peerID),120)", logger: Self.logger)
for try await expiry in rows.decode(Date.self) { return expiry.addingTimeInterval(-120) }
for try await expiry in rows.decode(Date.self) {
return expiry.addingTimeInterval(-120)
}
throw PeerError.connection("信息库未返回 Peer 联络结果。")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,18 @@ public struct PeerConnectionEditor: View {
defer { saving = false }
do {
let saved = try await settings.saveEdited(
host: server, port: port, database: database, username: username, tls: tls,
web: web, password: secret, previous: target, credentials: credentials)
host: server, port: port, database: database, username: username,
tls: tls,
web: web, password: secret, previous: target,
credentials: credentials)
onSaved(saved)
secret = ""
dismiss()
} catch { issue = error.localizedDescription }
}
}.keyboardShortcut(.defaultAction)
.disabled(saving || server.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
.disabled(
saving || server.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
}
}.padding(20).frame(width: 520)
.interactiveDismissDisabled(saving)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
需要 Xcode 26.2 / Swift 6.2。PostgresNIO 及依赖通过 SwiftPM 解析,精确修订固定在 Package.resolved。

```sh
swift test
bash scripts/check.sh
bash scripts/build-app.sh
open dist/InKCre.app
```
Expand Down
Loading
Loading