Skip to content

Socket for run and start commands, and basic socket protocol#155

Merged
beefon merged 8 commits into
macvmio:mainfrom
beefon:dev/beefon/SocketPing
Feb 2, 2026
Merged

Socket for run and start commands, and basic socket protocol#155
beefon merged 8 commits into
macvmio:mainfrom
beefon:dev/beefon/SocketPing

Conversation

@beefon
Copy link
Copy Markdown
Contributor

@beefon beefon commented Jan 30, 2026

In this PR start and run commands are getting optional --start-socket-at CLI arg. If it is set, then socket is created at specified path.

New socket command allows you to send a JSON contents into socket. JSON has to conform CurieSocketRequest. Help for the command has some examples:

USAGE: curie socket --socket-path <socket-path> --socket-request <socket-request>

OPTIONS:
  -p, --socket-path <socket-path>
                          Opened unix socket of the container to interact with
  -r, --socket-request <socket-request>
                          Payload to send to socket (values: 
                              Ping the server example JSON: {"ping":{}}, 
                              Terminate the VM example JSON: {"terminateVm":{}}), 
                              Make screenshot example JSON: {"makeScreenshot":{"savePngImageAtPath":"\/path\/to\/output.png"}})
  -h, --help              Show help information.

I've also added 3 payloads, one is for testing (ping; i'm happy to remove it in case you don't like to have it around) and two with actual feature (terminating the VM and making screenshots).

Happy to split screenshot making feature to a separate PR if you want, but i found it rather small.

Example usage:

  • Terminating VM

    ./.build/debug/curie socket -p /tmp/s.sock -r '{"terminateVm":{"waitToComplete": false}}'
    
  • Making screenshot

    ../.build/debug/curie socket -p /tmp/s.sock -r '{"makeScreenshot":{"savePngImageAtPath":"\/Users\/beefon\/Desktop\/screenshot.png"}}'
    

I've tried to make UnixDomainSocketProtocol's JSON as human friendly as possible with extensibility for the future needs.

Copy link
Copy Markdown
Contributor

@marciniwanicki marciniwanicki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Big, big thanks @beefon! The changes look great. Left few small comments but overall it works well.

Comment thread Sources/CurieCommand/Commands/RunCommand.swift Outdated
Comment thread Sources/CurieCommand/Commands/RunCommand.swift Outdated
Comment thread Sources/CurieCommand/Commands/SocketCommand.swift Outdated
Comment thread Sources/CurieCommand/Commands/SocketCommand.swift
vmSocketServer: r.resolve(VMSocketServer.self)
)
}
registry.register(VMSocketServer.self) { _ in
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe SocketServer and DefaultSocketServer to be aligned with the naming conventions of other utilities.

import Foundation

final class MakeScreenshotRequestProcessor {
private let vmScreenshotter: VMScreenshotter
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

screenshotter var will be more aligned with other "VM" variable types, e.g. bundle not vmBundle.

}

func process(request: MakeScreenshotPayload) -> PromisedSocketResponse {
DispatchQueue.main.sync {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe in the future we can try to use async await.

public func terminateVmAndCurrentProcess(
machineStateURL: URL
machineStateURL: URL,
postFlight: @escaping (Result<Void, Error>) -> Void = { _ in }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do we do with this result? Looks unused at the moment.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently it is used to provide feedback over socket whether VM has been terminated or failed, this is inside TerminateVmRequestProcessor:

            vm.terminateVmAndCurrentProcess(machineStateURL: vmBundle.machineState.asURL) { terminationResult in
                switch terminationResult {
                case .success:
                    settableResponse.set(response: .success([:]))
                case let .failure(error):
                    settableResponse.set(response: .error("Failed to terminate VM: \(error)"))
                }

                socketQueue.sync(flags: .barrier) {}
            }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah missed that, thank you.

@marciniwanicki
Copy link
Copy Markdown
Contributor

Thank you @beefon for all the updates, you should be able to merge it now.

@beefon
Copy link
Copy Markdown
Contributor Author

beefon commented Jan 31, 2026

image

@beefon beefon merged commit af3ff56 into macvmio:main Feb 2, 2026
3 checks passed
@beefon beefon deleted the dev/beefon/SocketPing branch February 2, 2026 22:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants