-
-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
121 additions
and
54 deletions.
There are no files selected for viewing
35 changes: 35 additions & 0 deletions
35
bridge/src/main/scala/protocbridge/frontend/MacPluginFrontend.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package protocbridge.frontend | ||
|
||
import java.nio.file.attribute.PosixFilePermission | ||
import java.nio.file.{Files, Path} | ||
import java.{util => ju} | ||
|
||
/** PluginFrontend for macOS. | ||
* | ||
* Creates a server socket and uses `nc` to communicate with the socket. | ||
* We use a server socket instead of named pipes because named pipes are unreliable on macOS: | ||
* https://github.com/scalapb/protoc-bridge/issues/366. | ||
* Since `nc` is widely available on macOS, this is the simplest and most reliable solution for macOS. | ||
*/ | ||
object MacPluginFrontend extends SocketBasedPluginFrontend { | ||
|
||
protected def createShellScript(port: Int): Path = { | ||
val shell = sys.env.getOrElse("PROTOCBRIDGE_SHELL", "/bin/sh") | ||
// We use 127.0.0.1 instead of localhost for the (very unlikely) case that localhost is missing from /etc/hosts. | ||
val scriptName = PluginFrontend.createTempFile( | ||
"", | ||
s"""|#!$shell | ||
|set -e | ||
|nc 127.0.0.1 $port | ||
""".stripMargin | ||
) | ||
val perms = new ju.HashSet[PosixFilePermission] | ||
perms.add(PosixFilePermission.OWNER_EXECUTE) | ||
perms.add(PosixFilePermission.OWNER_READ) | ||
Files.setPosixFilePermissions( | ||
scriptName, | ||
perms | ||
) | ||
scriptName | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
bridge/src/main/scala/protocbridge/frontend/SocketBasedPluginFrontend.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package protocbridge.frontend | ||
|
||
import protocbridge.{ExtraEnv, ProtocCodeGenerator} | ||
|
||
import java.net.ServerSocket | ||
import java.nio.file.{Files, Path} | ||
import scala.concurrent.ExecutionContext.Implicits.global | ||
import scala.concurrent.{Future, blocking} | ||
|
||
/** PluginFrontend for Windows and macOS where a server socket is used. | ||
*/ | ||
abstract class SocketBasedPluginFrontend extends PluginFrontend { | ||
case class InternalState(serverSocket: ServerSocket, shellScript: Path) | ||
|
||
override def prepare( | ||
plugin: ProtocCodeGenerator, | ||
env: ExtraEnv | ||
): (Path, InternalState) = { | ||
val ss = new ServerSocket(0) // Bind to any available port. | ||
val sh = createShellScript(ss.getLocalPort) | ||
|
||
Future { | ||
blocking { | ||
// Accept a single client connection from the shell script. | ||
val client = ss.accept() | ||
try { | ||
val response = | ||
PluginFrontend.runWithInputStream(plugin, client.getInputStream, env) | ||
client.getOutputStream.write(response) | ||
} finally { | ||
client.close() | ||
} | ||
} | ||
} | ||
|
||
(sh, InternalState(ss, sh)) | ||
} | ||
|
||
override def cleanup(state: InternalState): Unit = { | ||
state.serverSocket.close() | ||
if (sys.props.get("protocbridge.debug") != Some("1")) { | ||
Files.delete(state.shellScript) | ||
} | ||
} | ||
|
||
protected def createShellScript(port: Int): Path | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
bridge/src/test/scala/protocbridge/frontend/MacPluginFrontendSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package protocbridge.frontend | ||
|
||
class MacPluginFrontendSpec extends OsSpecificFrontendSpec { | ||
if (PluginFrontend.isMac) { | ||
it must "execute a program that forwards input and output to given stream" in { | ||
val state = testSuccess(MacPluginFrontend) | ||
state.serverSocket.isClosed mustBe true | ||
} | ||
|
||
it must "not hang if there is an error in generator" in { | ||
val state = testFailure(MacPluginFrontend) | ||
state.serverSocket.isClosed mustBe true | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
bridge/src/test/scala/protocbridge/frontend/PosixPluginFrontendSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters