Skip to content

Commit 4bfd44b

Browse files
committed
Add manual GC
1 parent 955da9f commit 4bfd44b

File tree

4 files changed

+86
-12
lines changed

4 files changed

+86
-12
lines changed

Diff for: Planet/IPFS/IPFSCommand.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ struct IPFSCommand {
221221

222222
static func launchDaemon() -> IPFSCommand {
223223
IPFSCommand(arguments: [
224-
"daemon", "--migrate", "--enable-namesys-pubsub", "--enable-pubsub-experiment", "--enable-gc",
224+
"daemon", "--migrate", "--enable-namesys-pubsub", "--enable-pubsub-experiment",
225225
])
226226
}
227227

Diff for: Planet/IPFS/IPFSDaemon.swift

+31
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Foundation
22
import SwiftyJSON
3+
import UserNotifications
34
import os
45

56
actor IPFSDaemon {
@@ -659,6 +660,36 @@ actor IPFSDaemon {
659660
try await IPFSDaemon.shared.api(path: "pin/rm", args: ["arg": cid], timeout: 120)
660661
}
661662

663+
func gc() async throws {
664+
Self.logger.info("Running garbage collection")
665+
let result = try await IPFSDaemon.shared.api(path: "repo/gc", timeout: 120)
666+
// Parse JSON result array
667+
let count = String(data: result, encoding: .utf8)?
668+
.components(separatedBy: .newlines)
669+
.filter { $0.contains("Key") }
670+
.count ?? 0
671+
672+
if count > 0 {
673+
// Create and schedule notification
674+
let content = UNMutableNotificationContent()
675+
content.title = "IPFS Garbage Collection Complete"
676+
content.body = "Removed \(count) unused objects"
677+
content.sound = .default
678+
content.interruptionLevel = .timeSensitive
679+
680+
let request = UNNotificationRequest(
681+
identifier: UUID().uuidString,
682+
content: content,
683+
trigger: nil
684+
)
685+
686+
try? await UNUserNotificationCenter.current().add(request)
687+
Self.logger.info("Garbage collection removed \(count) objects")
688+
} else {
689+
Self.logger.info("Garbage collection did not remove any objects")
690+
}
691+
}
692+
662693
func getFile(ipns: String, path: String = "") async throws -> Data {
663694
Self.logger.info("Getting file from IPNS \(ipns)\(path)")
664695
guard let gatewayPort else {

Diff for: Planet/IPFS/Status Views/IPFSStatusView.swift

+53-10
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55

66
import SwiftUI
77

8-
98
struct IPFSStatusView: View {
109
@EnvironmentObject private var ipfsState: IPFSState
10+
@State private var showingGCAlert = false
1111

1212
static let formatter = {
1313
let byteCountFormatter = ByteCountFormatter()
@@ -45,7 +45,21 @@ struct IPFSStatusView: View {
4545
ProgressView()
4646
.progressViewStyle(.circular)
4747
.controlSize(.small)
48-
} else {
48+
}
49+
else {
50+
Button {
51+
showingGCAlert = true
52+
} label: {
53+
Image(systemName: "arrow.3.trianglepath")
54+
.resizable()
55+
.aspectRatio(contentMode: .fit)
56+
.frame(height: 15)
57+
.foregroundStyle(Color.secondary)
58+
}
59+
.buttonStyle(.plain)
60+
.help("Run IPFS garbage collection.")
61+
.disabled(!ipfsState.online)
62+
4963
if !ipfsState.isShowingStatusWindow {
5064
Button {
5165
IPFSStatusWindowManager.shared.activate()
@@ -66,14 +80,18 @@ struct IPFSStatusView: View {
6680
Task.detached(priority: .userInitiated) {
6781
if newValue {
6882
try? await IPFSDaemon.shared.launch()
69-
} else {
83+
}
84+
else {
7085
try? await IPFSDaemon.shared.shutdown()
7186
}
7287
await IPFSState.shared.updateStatus()
7388
await MainActor.run {
7489
self.isDaemonOnline = newValue
7590
}
76-
UserDefaults.standard.setValue(newValue, forKey: IPFSState.lastUserLaunchState)
91+
UserDefaults.standard.setValue(
92+
newValue,
93+
forKey: IPFSState.lastUserLaunchState
94+
)
7795
}
7896
}
7997
}
@@ -83,14 +101,32 @@ struct IPFSStatusView: View {
83101
.padding(.vertical, 12)
84102
.frame(height: 44)
85103
}
86-
.padding(0)
104+
.background(.regularMaterial)
105+
.alert(isPresented: $showingGCAlert) {
106+
Alert(
107+
title: Text("Are you sure you want to manually run garbage collection?"),
108+
message: Text("This will free up disk space by removing unused data."),
109+
primaryButton: .destructive(Text("Run GC")) {
110+
Task {
111+
do {
112+
try await IPFSDaemon.shared.gc()
113+
}
114+
catch {
115+
debugPrint("failed to run gc: \(error)")
116+
}
117+
}
118+
},
119+
secondaryButton: .cancel()
120+
)
121+
}
87122
.frame(width: 280)
88123
.background(.regularMaterial)
89124
.task {
90125
Task.detached(priority: .background) {
91126
do {
92127
try await self.ipfsState.calculateRepoSize()
93-
} catch {
128+
}
129+
catch {
94130
debugPrint("failed to calculate repo size: \(error)")
95131
}
96132
}
@@ -103,9 +139,15 @@ struct IPFSStatusView: View {
103139
HStack {
104140
Text("Local Gateway")
105141
Spacer(minLength: 1)
106-
Link(self.ipfsState.getGateway(), destination: URL(string: self.ipfsState.getGateway() + "/ipns/k51qzi5uqu5dibstm2yxidly22jx94embd7j3xjstfk65ulictn2ajnjvpiac7")!)
107-
.focusable(false)
108-
.disabled(!self.ipfsState.online)
142+
Link(
143+
self.ipfsState.getGateway(),
144+
destination: URL(
145+
string: self.ipfsState.getGateway()
146+
+ "/ipns/k51qzi5uqu5dibstm2yxidly22jx94embd7j3xjstfk65ulictn2ajnjvpiac7"
147+
)!
148+
)
149+
.focusable(false)
150+
.disabled(!self.ipfsState.online)
109151
}
110152
HStack {
111153
Text("Repo Size")
@@ -114,7 +156,8 @@ struct IPFSStatusView: View {
114156
ProgressView()
115157
.progressViewStyle(.circular)
116158
.controlSize(.mini)
117-
} else {
159+
}
160+
else {
118161
if let repoSize = ipfsState.repoSize {
119162
Text(Self.formatter.string(fromByteCount: repoSize))
120163
}

Diff for: Planet/versioning.xcconfig

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
CURRENT_PROJECT_VERSION = 2307
1+
CURRENT_PROJECT_VERSION = 2308

0 commit comments

Comments
 (0)