11package protocbridge .frontend
22
3+ import org .newsclub .net .unix .AFUNIXServerSocket
4+ import protocbridge .{ExtraEnv , ProtocCodeGenerator }
5+
6+ import java .net .ServerSocket
37import java .nio .file .attribute .PosixFilePermission
48import java .nio .file .{Files , Path }
59import java .{util => ju }
10+ import scala .concurrent .ExecutionContext .Implicits .global
11+ import scala .concurrent .{Future , blocking }
612
713/** PluginFrontend for macOS.
814 *
@@ -12,16 +18,58 @@ import java.{util => ju}
1218 * widely available on macOS, this is the simplest and most reliable solution
1319 * for macOS.
1420 */
15- object MacPluginFrontend extends SocketBasedPluginFrontend {
21+ object MacPluginFrontend extends PluginFrontend {
22+ case class InternalState (
23+ tempDirPath : Path ,
24+ socketPath : Path ,
25+ serverSocket : ServerSocket ,
26+ shellScript : Path
27+ )
28+
29+ override def prepare (
30+ plugin : ProtocCodeGenerator ,
31+ env : ExtraEnv
32+ ): (Path , InternalState ) = {
33+ val tempDirPath = Files .createTempDirectory(" protopipe-" )
34+ val socketPath = tempDirPath.resolve(" socket" )
35+ val serverSocket = AFUNIXServerSocket .bindOn(socketPath, true )
36+ val sh = createShellScript(socketPath)
37+
38+ Future {
39+ blocking {
40+ // Accept a single client connection from the shell script.
41+ val client = serverSocket.accept()
42+ try {
43+ val response =
44+ PluginFrontend .runWithInputStream(
45+ plugin,
46+ client.getInputStream,
47+ env
48+ )
49+ client.getOutputStream.write(response)
50+ } finally {
51+ client.close()
52+ }
53+ }
54+ }
55+ (sh, InternalState (tempDirPath, socketPath, serverSocket, sh))
56+ }
57+
58+ override def cleanup (state : InternalState ): Unit = {
59+ state.serverSocket.close()
60+ if (sys.props.get(" protocbridge.debug" ) != Some (" 1" )) {
61+ Files .delete(state.tempDirPath)
62+ Files .delete(state.shellScript)
63+ }
64+ }
1665
17- protected def createShellScript (port : Int ): Path = {
66+ private def createShellScript (socketPath : Path ): Path = {
1867 val shell = sys.env.getOrElse(" PROTOCBRIDGE_SHELL" , " /bin/sh" )
19- // We use 127.0.0.1 instead of localhost for the (very unlikely) case that localhost is missing from /etc/hosts.
2068 val scriptName = PluginFrontend .createTempFile(
2169 " " ,
2270 s """ |#! $shell
2371 |set -e
24- |nc 127.0.0.1 $port
72+ |nc -U " $socketPath "
2573 """ .stripMargin
2674 )
2775 val perms = new ju.HashSet [PosixFilePermission ]
0 commit comments