diff --git a/Soyuz.xcodeproj/project.pbxproj b/Soyuz.xcodeproj/project.pbxproj index 2686359..8386d09 100755 --- a/Soyuz.xcodeproj/project.pbxproj +++ b/Soyuz.xcodeproj/project.pbxproj @@ -9,7 +9,7 @@ /* Begin PBXBuildFile section */ E124B9D929941A4D00C0D2D2 /* PrinterConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E124B9D829941A4D00C0D2D2 /* PrinterConfigView.swift */; }; E16378B229A43CE1002F05E9 /* SoyuzScratchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16378B129A43CE1002F05E9 /* SoyuzScratchTests.swift */; }; - E16378B429A491E6002F05E9 /* MoonrakerSocketManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16378B329A491E6002F05E9 /* MoonrakerSocketManager.swift */; }; + E16378B429A491E6002F05E9 /* MoonrakerSocketManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16378B329A491E6002F05E9 /* MoonrakerSocketManagerTests.swift */; }; E180B5E92992CD9100425DB0 /* SoyuzApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = E180B5E82992CD9100425DB0 /* SoyuzApp.swift */; }; E180B5ED2992CD9200425DB0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E180B5EC2992CD9200425DB0 /* Assets.xcassets */; }; E180B5F02992CD9200425DB0 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E180B5EF2992CD9200425DB0 /* Preview Assets.xcassets */; }; @@ -47,7 +47,7 @@ E124B9D72993FE5500C0D2D2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; E124B9D829941A4D00C0D2D2 /* PrinterConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrinterConfigView.swift; sourceTree = ""; }; E16378B129A43CE1002F05E9 /* SoyuzScratchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoyuzScratchTests.swift; sourceTree = ""; }; - E16378B329A491E6002F05E9 /* MoonrakerSocketManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoonrakerSocketManager.swift; sourceTree = ""; }; + E16378B329A491E6002F05E9 /* MoonrakerSocketManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoonrakerSocketManagerTests.swift; sourceTree = ""; }; E180B5E52992CD9100425DB0 /* Soyuz.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Soyuz.app; sourceTree = BUILT_PRODUCTS_DIR; }; E180B5E82992CD9100425DB0 /* SoyuzApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoyuzApp.swift; sourceTree = ""; }; E180B5EC2992CD9200425DB0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -143,7 +143,7 @@ E180B5FF2992CD9300425DB0 /* SoyuzTests.swift */, E16378B129A43CE1002F05E9 /* SoyuzScratchTests.swift */, E1A93C6829CD627100BAE750 /* BonjourBrowserTests.swift */, - E16378B329A491E6002F05E9 /* MoonrakerSocketManager.swift */, + E16378B329A491E6002F05E9 /* MoonrakerSocketManagerTests.swift */, ); path = SoyuzTests; sourceTree = ""; @@ -328,7 +328,7 @@ buildActionMask = 2147483647; files = ( E180B6002992CD9300425DB0 /* SoyuzTests.swift in Sources */, - E16378B429A491E6002F05E9 /* MoonrakerSocketManager.swift in Sources */, + E16378B429A491E6002F05E9 /* MoonrakerSocketManagerTests.swift in Sources */, E1A93C6929CD627100BAE750 /* BonjourBrowserTests.swift in Sources */, E16378B229A43CE1002F05E9 /* SoyuzScratchTests.swift in Sources */, ); diff --git a/Soyuz/Assets.xcassets/ButtonForegroundColor.colorset/Contents.json b/Soyuz/Assets.xcassets/ButtonForegroundColor.colorset/Contents.json new file mode 100644 index 0000000..ec93c8f --- /dev/null +++ b/Soyuz/Assets.xcassets/ButtonForegroundColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.300", + "green" : "0.300", + "red" : "0.300" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Soyuz/Info.plist b/Soyuz/Info.plist index ddfddf3..ee751d1 100755 --- a/Soyuz/Info.plist +++ b/Soyuz/Info.plist @@ -2,6 +2,11 @@ + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + CFBundleURLTypes @@ -21,7 +26,5 @@ _moonraker._tcp. _http._tcp. - NSServices - diff --git a/Soyuz/ViewModels/MoonrakerSocketManager.swift b/Soyuz/ViewModels/MoonrakerSocketManager.swift index e479ed1..31f15dd 100755 --- a/Soyuz/ViewModels/MoonrakerSocketManager.swift +++ b/Soyuz/ViewModels/MoonrakerSocketManager.swift @@ -1,5 +1,5 @@ // -// PrinterRequestManager.swift +// MoonrakerSocketManager.swift // KlipperMon // // Created by maddiefuzz on 2/7/23. @@ -11,8 +11,6 @@ import AppKit import Starscream -// MARK: PrinterRequestManager -//@MainActor class MoonrakerSocketManager: ObservableObject, WebSocketDelegate { let WEBSOCKET_TIMEOUT_INTERVAL: TimeInterval = 60.0 @@ -32,10 +30,11 @@ class MoonrakerSocketManager: ObservableObject, WebSocketDelegate { private var socket: WebSocket? private var lastPingDate = Date() + private var starscreamEngine: Engine // MARK: PRM init() - init() { + init(starscreamEngine: Engine = WSEngine(transport: TCPTransport())) { state = "" progress = 0.0 extruderTemperature = 0.0 @@ -43,6 +42,8 @@ class MoonrakerSocketManager: ObservableObject, WebSocketDelegate { socketHost = "" socketPort = "" + self.starscreamEngine = starscreamEngine + // Set up sleep/wake notification observers let center = NSWorkspace.shared.notificationCenter; let mainQueue = OperationQueue.main @@ -80,7 +81,8 @@ class MoonrakerSocketManager: ObservableObject, WebSocketDelegate { let hostString = "\(host)" let regex = try! Regex("%(.+)") let match = hostString.firstMatch(of: regex) - let sanitizedHost = hostString.replacingOccurrences(of: match!.0, with: "") + + let sanitizedHost = hostString.replacingOccurrences(of: match?.0 ?? "", with: "") print("[sanitized] Resolved \(sanitizedHost):\(port)") @@ -111,8 +113,9 @@ class MoonrakerSocketManager: ObservableObject, WebSocketDelegate { //let fullUrlString = "http://\(socketHost):\(socketPort)/websocket" var request = URLRequest(url: URL(string: "http://\(socketHost):\(socketPort)/websocket")!) request.timeoutInterval = 5 - socket = WebSocket(request: request) + socket = WebSocket(request: request, engine: starscreamEngine) socket!.delegate = self + print("About to connect to WebSocket at: \(request.debugDescription)") socket!.connect() } @@ -125,7 +128,7 @@ class MoonrakerSocketManager: ObservableObject, WebSocketDelegate { self.openWebsocket() } - // MARK: Callsbacks + // MARK: Callbacks func screenChangedSleepState(_ notification: Notification) { switch(notification.name) { case NSWorkspace.screensDidSleepNotification: diff --git a/Soyuz/Views/PrinterConfigView.swift b/Soyuz/Views/PrinterConfigView.swift index 54df80e..f955476 100755 --- a/Soyuz/Views/PrinterConfigView.swift +++ b/Soyuz/Views/PrinterConfigView.swift @@ -38,7 +38,7 @@ struct PrinterConfigView: View { printerManager.connectToBonjourEndpoint(result.endpoint) } label: { Text("Connect") - .foregroundColor(.white) + //.foregroundColor(.white) .padding() } } diff --git a/Soyuz/Views/SoyuzMenuBarExtraView.swift b/Soyuz/Views/SoyuzMenuBarExtraView.swift index 631edf7..7635848 100755 --- a/Soyuz/Views/SoyuzMenuBarExtraView.swift +++ b/Soyuz/Views/SoyuzMenuBarExtraView.swift @@ -83,7 +83,7 @@ struct SoyuzMenuBarExtraView: View { openWindow(id: "soyuz_cfg") } label: { Text("Printers") - .foregroundColor(.white) + .foregroundColor(Color("ButtonForegroundColor")) } Spacer() if(printerManager.isConnected) { diff --git a/SoyuzTests/MoonrakerSocketManager.swift b/SoyuzTests/MoonrakerSocketManager.swift deleted file mode 100755 index 374afec..0000000 --- a/SoyuzTests/MoonrakerSocketManager.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// PrinterRequestsManagerTests.swift -// SoyuzTests -// -// Created by maddiefuzz on 2/21/23. -// - -import XCTest -import Starscream -import Network -@testable import Soyuz - -class PrinterRequestManagerTests: XCTestCase { - var socketManager: MoonrakerSocketManager? - - // Server-side test variables - let server = WebSocketServer() - let address = "localhost" - let port: UInt16 = 80 - - override func setUp() { - let server = WebSocketServer() - - let error = server.start(address: address, port: port) - - if let err = error { - print("Error starting WebSocket server: \(err)") - } - - socketManager = MoonrakerSocketManager() - } - - func testBlah() { - guard let url = URL(string: "\(address):\(port)") else { - return - } - print("Success") - let endpoint = NWEndpoint.url(url) - print(endpoint.debugDescription) - socketManager?.connectToBonjourEndpoint(endpoint) - return - } - -// override func setUp() { -// printerRequestManager = PrinterRequestManager(browser: NWBrowser(for: .bonjour(type: "_http._tcp", domain: "local."), using: .tcp)) -// -// // Set up test bonjour server -// //let parameters = NWParameters(tls: .none, tcp: NWListener.) -// do { -// testBonjourListener = try NWListener(using: .tcp, on: .http) -// testBonjourListener!.start(queue: DispatchQueue.main) -// } catch { -// print("Error: \(error)") -// } -// } -// -// func testBonjourDiscoveredItemsNotNil() { -// XCTAssertNotNil(printerRequestManager?.nwBrowserDiscoveredItems) -// } -} diff --git a/SoyuzTests/MoonrakerSocketManagerTests.swift b/SoyuzTests/MoonrakerSocketManagerTests.swift new file mode 100755 index 0000000..f38ed9e --- /dev/null +++ b/SoyuzTests/MoonrakerSocketManagerTests.swift @@ -0,0 +1,87 @@ +// +// MoonrakerSocketManagerTests.swift +// SoyuzTests +// +// Created by maddiefuzz on 2/21/23. +// + +import XCTest +import Starscream +import Combine +import Network +@testable import Soyuz + +class DummyEngine: Engine { + var delegate: Starscream.EngineDelegate? + + @Published var startCalled = false + + func register(delegate: Starscream.EngineDelegate) { + self.delegate = delegate + } + + func start(request: URLRequest) { + startCalled = true + } + + func stop(closeCode: UInt16) { + return + } + + func forceStop() { + return + } + + func write(data: Data, opcode: Starscream.FrameOpCode, completion: (() -> ())?) { + return + } + + func write(string: String, completion: (() -> ())?) { + return + } + + +} + +class MoonrakerSocketManagerTests: XCTestCase { + var socketManager: MoonrakerSocketManager? + var bonjourListener: NWListener? + var engine: DummyEngine! + var cancellable: AnyCancellable? + + override func setUp() { + engine = DummyEngine() + socketManager = MoonrakerSocketManager(starscreamEngine: engine!) + + do { + bonjourListener = try NWListener(using: .tcp, on: .http) + + bonjourListener!.newConnectionHandler = { newConnection in + return + } + + bonjourListener!.start(queue: DispatchQueue.main) + } catch { + print("Error: \(error)") + } + } + + + func testConnectToBonjourEndpoint() { + let endpoint = NWEndpoint.hostPort(host: "localhost", port: .http) + print("Trying to connect to bonjour endpoint \(endpoint)") + + let expectation = XCTestExpectation(description: "MoonrakerSocketManager.connectToBonjourEndpoint opens Starscream socket") + + cancellable = engine.$startCalled + .sink(receiveValue: { newValue in + if newValue == true { + expectation.fulfill() + } + }) + + socketManager?.connectToBonjourEndpoint(endpoint) + wait(for: [expectation], timeout: 2) + XCTAssertTrue(engine.startCalled) + } +}