Skip to content

Commit 08ce60d

Browse files
committed
chore: corrections based on review
1 parent aae3e1d commit 08ce60d

File tree

6 files changed

+59
-207
lines changed

6 files changed

+59
-207
lines changed
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11

2-
ooni_logo.xml
3-
logo_probe.xml
2+
logo_probe.xml
3+
ooni_logo.xml
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11

2-
ic_launcher_monochrome.xml
32
ic_launcher_foreground.xml
4-
notification_icon.xml
3+
notification_icon.xml
4+
ic_launcher_monochrome.xml

composeApp/src/commonMain/resources/assets/.gitignore

Lines changed: 0 additions & 2 deletions
This file was deleted.

composeApp/src/desktopMain/kotlin/org/ooni/probe/Main.kt

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,16 @@ fun main(args: Array<String>) {
4646

4747
val deepLinkFlow = MutableSharedFlow<DeepLink?>(extraBufferCapacity = 1)
4848

49-
// Initialize the deep link handler
50-
val deepLinkHandler = DeepLinkHandler()
51-
deepLinkHandler.initialize(args)
49+
var deepLinkHandler: DeepLinkHandler? = null
5250

53-
if ((dependencies.platformInfo.platform as? Platform.Desktop)?.os == DesktopOS.Mac) {
54-
Desktop.getDesktop().setOpenURIHandler { event ->
55-
deepLinkFlow.tryEmit(DeepLink.AddDescriptor(event.uri.path.split("/").last()))
51+
dependencies.platformInfo.platform.let { platform ->
52+
if (platform is Platform.Desktop && platform.os == DesktopOS.Mac) {
53+
Desktop.getDesktop().setOpenURIHandler { event ->
54+
deepLinkFlow.tryEmit(DeepLink.AddDescriptor(event.uri.path.split("/").last()))
55+
}
56+
} else {
57+
deepLinkHandler = DeepLinkHandler()
58+
deepLinkHandler.initialize(args)
5659
}
5760
}
5861

@@ -70,10 +73,10 @@ fun main(args: Array<String>) {
7073
}
7174

7275
LaunchedEffect(Unit) {
73-
deepLinkHandler.addMessageListener { message ->
76+
deepLinkHandler?.addMessageListener { message ->
7477
message?.let { message ->
7578
isWindowVisible = true
76-
deepLinkFlow.tryEmit(DeepLink.AddDescriptor(message.split("/").last()))
79+
deepLinkFlow.tryEmit(message)
7780
}
7881
}
7982
}
@@ -120,7 +123,7 @@ fun main(args: Array<String>) {
120123
Item(
121124
"Exit",
122125
onClick = {
123-
deepLinkHandler.shutdown()
126+
deepLinkHandler?.shutdown()
124127
exitApplication()
125128
},
126129
)

composeApp/src/desktopMain/kotlin/org/ooni/probe/data/DeepLinkHandler.kt

Lines changed: 24 additions & 192 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,29 @@ package org.ooni.probe.data
22

33
import co.touchlab.kermit.Logger
44
import org.ooni.probe.APP_ID
5+
import org.ooni.probe.data.models.DeepLink
56
import tk.pratanumandal.unique4j.Unique4j
67
import tk.pratanumandal.unique4j.exception.Unique4jException
7-
import java.io.File
8-
import java.nio.file.Files
9-
import java.nio.file.Paths
108
import java.util.Date
119

1210
class DeepLinkHandler {
1311
private var unique: Unique4j? = null
14-
private val messageListeners = mutableListOf<(String?) -> Unit>()
12+
private val messageListeners = mutableListOf<(DeepLink.AddDescriptor?) -> Unit>()
1513

16-
fun addMessageListener(listener: (String?) -> Unit) {
17-
messageListeners.add(listener)
14+
companion object {
15+
private const val OONI_PROTOCOL = "ooni://"
1816
}
1917

20-
fun parseDeepLink(deepLink: String): Map<String, String> {
21-
val params = mutableMapOf<String, String>()
22-
23-
if (deepLink.startsWith("ooni://")) {
24-
val parts = deepLink.removePrefix("ooni://").split("/")
25-
if (parts.size >= 2 && parts[0] == "runv2") {
26-
params["command"] = "runv2"
27-
params["testId"] = parts[1]
28-
}
29-
}
18+
fun addMessageListener(listener: (DeepLink.AddDescriptor?) -> Unit) {
19+
messageListeners.add(listener)
20+
}
3021

31-
return params
22+
fun parseDeepLink(deepLink: String): DeepLink.AddDescriptor? {
23+
return deepLink.takeIf { it.startsWith(OONI_PROTOCOL) }
24+
?.removePrefix(OONI_PROTOCOL)
25+
?.split("/")
26+
?.takeIf { it.size >= 2 && it[0] == "runv2" }
27+
?.let { DeepLink.AddDescriptor(it[1]) }
3228
}
3329

3430
fun initialize(args: Array<String>) {
@@ -37,10 +33,10 @@ class DeepLinkHandler {
3733
override fun receiveMessage(message: String) {
3834
Logger.d("Received message: $message")
3935

40-
// Parse deep link if it starts with ooni://
41-
if (message.startsWith("ooni://")) {
42-
val params = parseDeepLink(message)
43-
handleDeepLinkCommand(message, params)
36+
parseDeepLink(message)?.let { deepLink ->
37+
messageListeners.forEach { listener ->
38+
listener(deepLink)
39+
}
4440
}
4541
}
4642

@@ -64,17 +60,13 @@ class DeepLinkHandler {
6460
if (lockFlag) {
6561
Logger.d("Application instance started successfully")
6662

67-
// If this is the first instance and has a deep link, handle it directly
68-
val deepLink = findDeepLinkInArgs(args)
69-
if (deepLink != null) {
70-
val params = parseDeepLink(deepLink)
71-
// messageListeners.forEach { it("Initial deep link: $deepLink, params: $params") }
72-
handleDeepLinkCommand(deepLink, params)
63+
findDeepLinkInArgs(args)?.let { deepLink ->
64+
parseDeepLink(deepLink)?.let { deepLink ->
65+
messageListeners.forEach { listener ->
66+
listener(deepLink)
67+
}
68+
}
7369
}
74-
75-
// TODO: Implement with conveyor
76-
// Register as a protocol handler if not already registered
77-
registerProtocolHandler()
7870
} else {
7971
Logger.d("Could not acquire lock - this should not happen")
8072
}
@@ -94,7 +86,7 @@ class DeepLinkHandler {
9486
// Windows may process URLs differently, so handle various formats
9587
for (arg in args) {
9688
// Standard format
97-
if (arg.startsWith("ooni://")) {
89+
if (arg.startsWith(OONI_PROTOCOL)) {
9890
return arg
9991
}
10092

@@ -112,167 +104,7 @@ class DeepLinkHandler {
112104
return null
113105
}
114106

115-
private fun handleDeepLinkCommand(
116-
deepLink: String,
117-
params: Map<String, String>,
118-
) {
119-
// Handle different commands based on the deep link
120-
when (params["command"]) {
121-
"runv2" -> {
122-
val testId = params["testId"]
123-
Logger.d("Running test with ID: $testId")
124-
// Here you would implement the actual test running logic
125-
messageListeners.forEach { it(testId) }
126-
}
127-
}
128-
}
129-
130107
fun shutdown() {
131108
unique?.freeLock()
132109
}
133-
134-
// TODO: Move this to conveyor
135-
136-
// Register the application as a handler for ooni:// protocol
137-
private fun registerProtocolHandler() {
138-
val isWindows = System.getProperty("os.name").lowercase().contains("win")
139-
140-
if (isWindows) {
141-
registerWindowsProtocolHandler()
142-
} else {
143-
registerLinuxProtocolHandler()
144-
}
145-
}
146-
147-
// Register protocol handler for Linux using XDG
148-
private fun registerLinuxProtocolHandler() {
149-
try {
150-
// Get the current executable path
151-
val executablePath = getExecutablePath()
152-
if (executablePath != null) {
153-
// Create desktop entry for protocol handler
154-
val desktopEntryPath = Paths.get(
155-
System.getProperty("user.home"),
156-
".local",
157-
"share",
158-
"applications",
159-
"ooni-handler.desktop",
160-
)
161-
162-
val desktopEntry = """
163-
[Desktop Entry]
164-
Type=Application
165-
Name=OONI Deep Link Handler
166-
Exec=$executablePath %u
167-
Terminal=false
168-
MimeType=x-scheme-handler/ooni;
169-
NoDisplay=true
170-
Comment=Handler for OONI deep links
171-
""".trimIndent()
172-
173-
// Create parent directories if they don't exist
174-
Files.createDirectories(desktopEntryPath.parent)
175-
176-
// Write the desktop entry file
177-
Files.write(desktopEntryPath, desktopEntry.toByteArray())
178-
179-
// Register the desktop entry as the handler for the ooni:// protocol
180-
try {
181-
val processBuilder = ProcessBuilder(
182-
"xdg-mime",
183-
"default",
184-
"ooni-handler.desktop",
185-
"x-scheme-handler/ooni",
186-
)
187-
val process = processBuilder.start()
188-
process.waitFor()
189-
Logger.d("Registered as handler for ooni:// protocol on Linux")
190-
} catch (e: Exception) {
191-
Logger.d("Failed to register protocol handler on Linux: ${e.message}")
192-
}
193-
}
194-
} catch (e: Exception) {
195-
Logger.e(e) { "Failed to register protocol handler on Linux" }
196-
}
197-
}
198-
199-
// Register protocol handler for Windows using Registry
200-
private fun registerWindowsProtocolHandler() {
201-
try {
202-
val executablePath = getExecutablePath()
203-
if (executablePath != null) {
204-
// Escape backslashes in the path for command prompt
205-
val escapedPath = executablePath.replace("\\", "\\\\")
206-
207-
// Create the registry entry for the ooni:// protocol
208-
val command = """
209-
reg add "HKCU\Software\Classes\ooni" /ve /d "URL:OONI Protocol" /f
210-
reg add "HKCU\Software\Classes\ooni" /v "URL Protocol" /d "" /f
211-
reg add "HKCU\Software\Classes\ooni\DefaultIcon" /ve /d "$escapedPath,1" /f
212-
reg add "HKCU\Software\Classes\ooni\shell\open\command" /ve /d "\"$escapedPath\" \"%1\"" /f
213-
""".trimIndent()
214-
215-
// Execute the registry command
216-
try {
217-
val process = Runtime.getRuntime().exec(arrayOf("cmd.exe", "/c", command))
218-
val exitCode = process.waitFor()
219-
220-
if (exitCode == 0) {
221-
Logger.d("Successfully registered ooni:// protocol handler on Windows")
222-
} else {
223-
Logger.d("Failed to register protocol handler on Windows, exit code: $exitCode")
224-
}
225-
} catch (e: Exception) {
226-
Logger.e(e) { "Failed to execute registry command" }
227-
}
228-
}
229-
} catch (e: Exception) {
230-
Logger.e(e) { "Failed to register protocol handler on Windows" }
231-
}
232-
}
233-
234-
// Get the path to the current executable based on the operating system
235-
private fun getExecutablePath(): String? {
236-
val isWindows = System.getProperty("os.name").lowercase().contains("win")
237-
238-
// Try to get the path from the conveyor system property if using Conveyor
239-
val conveyorPath = System.getProperty("app.home")
240-
if (conveyorPath != null) {
241-
val conveyorExecutable = if (isWindows) {
242-
File(conveyorPath, "bin/app.exe")
243-
} else {
244-
File(conveyorPath, "bin/app")
245-
}
246-
247-
if (conveyorExecutable.exists()) {
248-
return conveyorExecutable.absolutePath
249-
}
250-
}
251-
252-
if (isWindows) {
253-
// For Windows, try to use jpackage executable path
254-
val processPath = System.getProperty("jpackage.app-path")
255-
if (processPath != null) {
256-
return processPath
257-
}
258-
259-
// Alternatively, use the Java executable with classpath
260-
val javaHome = System.getProperty("java.home")
261-
val javaBin = File(javaHome, "bin/java.exe").absolutePath
262-
val classpath = System.getProperty("java.class.path")
263-
return "\"$javaBin\" -cp \"$classpath\" MainKt"
264-
} else {
265-
// For Linux, try to get the symbolic link of the current process
266-
try {
267-
val currentPid = ProcessHandle.current().pid()
268-
val processPath = Files.readSymbolicLink(Paths.get("/proc/$currentPid/exe"))
269-
return processPath.toString()
270-
} catch (e: Exception) {
271-
Logger.e(e) { "Could not determine executable path" }
272-
}
273-
274-
// If all else fails, just use java with the classpath
275-
return "java -cp ${System.getProperty("java.class.path")} MainKt"
276-
}
277-
}
278110
}

conveyor.conf

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,23 @@ app {
2121
url-schemes = [ ooni ]
2222
}
2323

24+
app.linux.desktop-file."Desktop Entry" {
25+
Type=Application
26+
Name=OONI Deep Link Handler
27+
Exec = ${app.linux.install-path}/bin/${app.fsname} %f
28+
Terminal=false
29+
MimeType=x-scheme-handler/ooni;
30+
NoDisplay=true
31+
Comment=Handler for OONI deep links
32+
}
33+
34+
app.windows.manifests.msix.extensions-xml = """
35+
<uap:Extension Category="windows.protocol">
36+
<uap:Protocol Name="ooni">
37+
<uap:DisplayName>OONI Deep Link Handler</uap:DisplayName>
38+
<uap:Parameters>%1</uap:Parameters>
39+
</uap:Protocol>
40+
</uap:Extension>
41+
"""
42+
2443
conveyor.compatibility-level = 17

0 commit comments

Comments
 (0)