Skip to content

Commit

Permalink
Update tophatctl so that it can wait for a response from Tophat (#43)
Browse files Browse the repository at this point in the history
  • Loading branch information
lfroms authored Dec 4, 2024
1 parent 66c205a commit 9d16e45
Show file tree
Hide file tree
Showing 27 changed files with 433 additions and 336 deletions.
28 changes: 14 additions & 14 deletions Tophat.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
8005282F2CB718C200226174 /* TophatKit in Frameworks */ = {isa = PBXBuildFile; productRef = 8005282E2CB718C200226174 /* TophatKit */; };
800528312CB718C700226174 /* TophatKit in Frameworks */ = {isa = PBXBuildFile; productRef = 800528302CB718C700226174 /* TophatKit */; };
8006E7F02943D3090089805E /* VisualEffects in Frameworks */ = {isa = PBXBuildFile; productRef = 8006E7EF2943D3090089805E /* VisualEffects */; };
802635052CFE68720020D841 /* TophatControlServices in Frameworks */ = {isa = PBXBuildFile; productRef = 802635042CFE68720020D841 /* TophatControlServices */; };
802635072CFE6B930020D841 /* TophatControlServices in Frameworks */ = {isa = PBXBuildFile; productRef = 802635062CFE6B930020D841 /* TophatControlServices */; };
80346F042BEBD527002F54BC /* AsyncAlgorithms in Frameworks */ = {isa = PBXBuildFile; productRef = 80346F032BEBD527002F54BC /* AsyncAlgorithms */; };
803B874B290055C70062F070 /* AndroidDeviceKit in Frameworks */ = {isa = PBXBuildFile; productRef = 803B874A290055C70062F070 /* AndroidDeviceKit */; };
805543CC2CB715EB004E1D18 /* TophatUtilities in Frameworks */ = {isa = PBXBuildFile; productRef = 805543CB2CB715EB004E1D18 /* TophatUtilities */; };
805543CE2CB715F1004E1D18 /* TophatUtilities in Frameworks */ = {isa = PBXBuildFile; productRef = 805543CD2CB715F1004E1D18 /* TophatUtilities */; };
807D7B0F29835762007942B4 /* TophatFoundation in Frameworks */ = {isa = PBXBuildFile; productRef = 807D7B0E29835762007942B4 /* TophatFoundation */; };
807D7B1629835795007942B4 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 807D7B1529835795007942B4 /* ArgumentParser */; };
807D7B1A298357C6007942B4 /* tophatctl in Copy tophatctl */ = {isa = PBXBuildFile; fileRef = 807D7B0729835756007942B4 /* tophatctl */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
Expand Down Expand Up @@ -189,10 +189,10 @@
files = (
80F74E252909E8EA0040F026 /* AppleDeviceKit in Frameworks */,
B6AA44CF296DF8EF0017321C /* ZIPFoundation in Frameworks */,
802635052CFE68720020D841 /* TophatControlServices in Frameworks */,
8006E7F02943D3090089805E /* VisualEffects in Frameworks */,
7F4532AD251A6C4700F2CFC8 /* Logging in Frameworks */,
8090E268296775BE003106B9 /* Collections in Frameworks */,
805543CC2CB715EB004E1D18 /* TophatUtilities in Frameworks */,
80C18345290232D1008D3B80 /* TophatFoundation in Frameworks */,
80346F042BEBD527002F54BC /* AsyncAlgorithms in Frameworks */,
80DC0FD82C82225600E5C9EE /* Sparkle in Frameworks */,
Expand All @@ -217,7 +217,7 @@
files = (
807D7B1629835795007942B4 /* ArgumentParser in Frameworks */,
807D7B0F29835762007942B4 /* TophatFoundation in Frameworks */,
805543CE2CB715F1004E1D18 /* TophatUtilities in Frameworks */,
802635072CFE6B930020D841 /* TophatControlServices in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -305,8 +305,8 @@
B6AA44CE296DF8EF0017321C /* ZIPFoundation */,
80346F032BEBD527002F54BC /* AsyncAlgorithms */,
80DC0FD72C82225600E5C9EE /* Sparkle */,
805543CB2CB715EB004E1D18 /* TophatUtilities */,
8005282E2CB718C200226174 /* TophatKit */,
802635042CFE68720020D841 /* TophatControlServices */,
);
productName = Tophat;
productReference = 7F35024F24A5060500EE76EA /* Tophat.app */;
Expand Down Expand Up @@ -352,7 +352,7 @@
packageProductDependencies = (
807D7B0E29835762007942B4 /* TophatFoundation */,
807D7B1529835795007942B4 /* ArgumentParser */,
805543CD2CB715F1004E1D18 /* TophatUtilities */,
802635062CFE6B930020D841 /* TophatControlServices */,
);
productName = tophatctl;
productReference = 807D7B0729835756007942B4 /* tophatctl */;
Expand Down Expand Up @@ -1141,6 +1141,14 @@
package = 8006E7EE2943D3090089805E /* XCRemoteSwiftPackageReference "VisualEffects" */;
productName = VisualEffects;
};
802635042CFE68720020D841 /* TophatControlServices */ = {
isa = XCSwiftPackageProductDependency;
productName = TophatControlServices;
};
802635062CFE6B930020D841 /* TophatControlServices */ = {
isa = XCSwiftPackageProductDependency;
productName = TophatControlServices;
};
80346F032BEBD527002F54BC /* AsyncAlgorithms */ = {
isa = XCSwiftPackageProductDependency;
package = 80346F022BEBD527002F54BC /* XCRemoteSwiftPackageReference "swift-async-algorithms" */;
Expand All @@ -1150,14 +1158,6 @@
isa = XCSwiftPackageProductDependency;
productName = AndroidDeviceKit;
};
805543CB2CB715EB004E1D18 /* TophatUtilities */ = {
isa = XCSwiftPackageProductDependency;
productName = TophatUtilities;
};
805543CD2CB715F1004E1D18 /* TophatUtilities */ = {
isa = XCSwiftPackageProductDependency;
productName = TophatUtilities;
};
807D7B0E29835762007942B4 /* TophatFoundation */ = {
isa = XCSwiftPackageProductDependency;
productName = TophatFoundation;
Expand Down
24 changes: 10 additions & 14 deletions Tophat/TophatApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ private final class AppDelegate: NSObject, NSApplicationDelegate {
let extensionHost = ExtensionHost()
private let server = TophatServer()
private let urlHandler = URLReader()
private let notificationHandler = NotificationHandler()
private let remoteControlReceiver = RemoteControlReceiver()

let deviceManager: DeviceManager
let utilityPathPreferences: UtilityPathPreferences
Expand Down Expand Up @@ -138,7 +138,7 @@ private final class AppDelegate: NSObject, NSApplicationDelegate {
configureEventSubscriptions()

self.server.delegate = self
self.notificationHandler.delegate = self
self.remoteControlReceiver.delegate = self
self.taskStatusReporter.delegate = self
}

Expand Down Expand Up @@ -269,10 +269,10 @@ extension AppDelegate: TophatServerDelegate {
}
}

// MARK: - NotificationHandlerDelegate
// MARK: - RemoteControlReceiverDelegate

extension AppDelegate: NotificationHandlerDelegate {
func notificationHandler(didReceiveRequestToAddQuickLaunchEntry quickLaunchEntry: QuickLaunchEntry) {
extension AppDelegate: RemoteControlReceiverDelegate {
func remoteControlReceiver(didReceiveRequestToAddQuickLaunchEntry quickLaunchEntry: QuickLaunchEntry) {
let context = ModelContext(modelContainer)

let existingID = quickLaunchEntry.id
Expand Down Expand Up @@ -302,7 +302,7 @@ extension AppDelegate: NotificationHandlerDelegate {
}
}

func notificationHandler(didReceiveRequestToRemoveQuickLaunchEntryWithIdentifier quickLaunchEntryIdentifier: QuickLaunchEntry.ID) {
func remoteControlReceiver(didReceiveRequestToRemoveQuickLaunchEntryWithIdentifier quickLaunchEntryIdentifier: QuickLaunchEntry.ID) {
let context = ModelContext(modelContainer)

do {
Expand All @@ -315,16 +315,12 @@ extension AppDelegate: NotificationHandlerDelegate {
}
}

func notificationHandler(didOpenURL url: URL, launchArguments: [String]) {
Task {
await launchApp(artifactURL: url, launchArguments: launchArguments)
}
func remoteControlReceiver(didOpenURL url: URL, launchArguments: [String]) async {
await launchApp(artifactURL: url, launchArguments: launchArguments)
}

func notificationHandler(didReceiveRequestToLaunchApplicationWithRecipes recipes: [InstallRecipe]) {
Task {
await launchApp(recipes: recipes)
}
func remoteControlReceiver(didReceiveRequestToLaunchApplicationWithRecipes recipes: [InstallRecipe]) async {
await launchApp(recipes: recipes)
}
}

Expand Down
91 changes: 0 additions & 91 deletions Tophat/Utilities/NotificationHandler.swift

This file was deleted.

96 changes: 96 additions & 0 deletions Tophat/Utilities/RemoteControlReceiver.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
//
// RemoteControlReceiver.swift
// Tophat
//
// Created by Lukas Romsicki on 2023-01-27.
// Copyright © 2023 Shopify. All rights reserved.
//

import Foundation
import TophatFoundation
import TophatControlServices

protocol RemoteControlReceiverDelegate: AnyObject {
func remoteControlReceiver(didReceiveRequestToAddQuickLaunchEntry quickLaunchEntry: QuickLaunchEntry)
func remoteControlReceiver(didReceiveRequestToRemoveQuickLaunchEntryWithIdentifier quickLaunchEntryIdentifier: QuickLaunchEntry.ID)
func remoteControlReceiver(didReceiveRequestToLaunchApplicationWithRecipes recipes: [InstallRecipe]) async
func remoteControlReceiver(didOpenURL url: URL, launchArguments: [String]) async
}

final class RemoteControlReceiver {
weak var delegate: RemoteControlReceiverDelegate?

private let service = TophatRemoteControlService()

init() {
Task {
for await request in service.requests(for: InstallFromURLRequest.self) {
let requestValue = request.value

await delegate?.remoteControlReceiver(didOpenURL: requestValue.url, launchArguments: requestValue.launchArguments)
request.reply(.init())
}
}

Task {
for await request in service.requests(for: InstallFromRecipesRequest.self) {
let requestValue = request.value

let recipes = requestValue.recipes.map { recipe in
let artifactProviderMetadata = ArtifactProviderMetadata(
id: recipe.artifactProviderID,
parameters: recipe.artifactProviderParameters
)

return InstallRecipe(
source: .artifactProvider(metadata: artifactProviderMetadata),
launchArguments: recipe.launchArguments,
platformHint: recipe.platformHint,
destinationHint: recipe.destinationHint
)
}

await delegate?.remoteControlReceiver(didReceiveRequestToLaunchApplicationWithRecipes: recipes)
request.reply(.init())
}
}

Task {
for await request in service.requests(for: AddQuickLaunchEntryRequest.self) {
let requestValue = request.value

let configuration = requestValue.configuration

let quickLaunchEntry = QuickLaunchEntry(
id: configuration.id,
name: configuration.name,
recipes: configuration.recipes.map { source in
let artifactProviderMetadata = ArtifactProviderMetadata(
id: source.artifactProviderID,
parameters: source.artifactProviderParameters
)

return QuickLaunchEntryRecipe(
artifactProviderID: artifactProviderMetadata.id,
artifactProviderParameters: artifactProviderMetadata.parameters,
launchArguments: source.launchArguments,
platformHint: source.platformHint,
destinationHint: source.destinationHint
)
}
)

delegate?.remoteControlReceiver(didReceiveRequestToAddQuickLaunchEntry: quickLaunchEntry)
}
}

Task {
for await request in service.requests(for: RemoveQuickLaunchEntryRequest.self) {
let requestValue = request.value
delegate?.remoteControlReceiver(
didReceiveRequestToRemoveQuickLaunchEntryWithIdentifier: requestValue.quickLaunchEntryID
)
}
}
}
}
2 changes: 1 addition & 1 deletion TophatCtl/Commands/Apps.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import ArgumentParser

struct Apps: ParsableCommand {
struct Apps: AsyncParsableCommand {
static var configuration = CommandConfiguration(
abstract: "Adds, removes, or modifies Quick Launch entries.",
subcommands: [
Expand Down
14 changes: 5 additions & 9 deletions TophatCtl/Commands/Apps/Apps+Add.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
import Foundation
import ArgumentParser
import TophatFoundation
import TophatUtilities
import TophatControlServices
import AppKit

extension Apps {
struct Add: ParsableCommand {
struct Add: AsyncParsableCommand {
static var configuration = CommandConfiguration(
abstract: "Adds a new application to Quick Launch.",
discussion: "If an existing item with the same identifier already exists, the item will be updated with new information."
Expand All @@ -22,20 +22,16 @@ extension Apps {
@Argument(help: "The path to the configuration file for the app.")
var path: URL

func run() throws {
func run() async throws {
if !NSRunningApplication.isTophatRunning {
print("Warning: Tophat must be running for this command to succeed, but it is not running.")
}

let data = try Data(contentsOf: path)
let configuration = try JSONDecoder().decode(UserSpecifiedQuickLaunchEntryConfiguration.self, from: data)

let payload = TophatAddQuickLaunchEntryNotification.Payload(
configuration: configuration
)

let notification = TophatAddQuickLaunchEntryNotification(payload: payload)
TophatInterProcessNotifier().send(notification: notification)
let request = AddQuickLaunchEntryRequest(configuration: configuration)
try TophatRemoteControlService().send(request: request)
}
}
}
Loading

0 comments on commit 9d16e45

Please sign in to comment.