Skip to content
This repository was archived by the owner on Jul 30, 2024. It is now read-only.

Overhaul cluster module #49

Merged
merged 1 commit into from
Sep 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.scalajs.nodejs

import scala.scalajs.js

trait HasFileDescriptor extends js.Object {
def fd: FileDescriptor
}
7 changes: 7 additions & 0 deletions app/current/src/main/scala/io/scalajs/nodejs/HasHandle.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.scalajs.nodejs

import scala.scalajs.js

trait HasHandle extends js.Object {
def _handle: js.Any
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
package io.scalajs.nodejs.cluster

import scala.scalajs.js
import scala.scalajs.js.|

/**
* Address
*/
@js.native
trait Address extends js.Object {

def address: String = js.native

def port: Integer = js.native
def port: Int = js.native

/**
* The addressType is one of:
Expand All @@ -19,6 +17,6 @@ trait Address extends js.Object {
* -1 (unix domain socket)
* "udp4" or "udp6" (UDP v4 or v6)
*/
def addressType: js.Any = js.native
def addressType: String | Int = js.native

}
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ trait Cluster extends IEventEmitter {
* This can only be called from the master process.
* @example cluster.disconnect([callback])
*/
def disconnect(callback: js.Function = null): Unit = js.native
def disconnect(callback: js.Function = js.native): Unit = js.native

/**
* Spawn a new worker process.
* This can only be called from the master process.
* @return a new worker
* @example cluster.fork([env])
*/
def fork(env: js.Any = null): Worker = js.native
def fork(env: js.Any = js.native): Worker = js.native

/**
* setupMaster is used to change the default 'fork' behavior. Once called, the settings will be present in cluster.settings.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package io.scalajs.nodejs.cluster

import io.scalajs.util.ScalaJsHelper._
import com.thoughtworks.enableIf
import io.scalajs.JsNumber
import io.scalajs.nodejs.{GID, UID}

import scala.scalajs.js
import scala.scalajs.js.|

/**
* Cluster Settings
Expand All @@ -11,35 +14,55 @@ import scala.scalajs.js
trait ClusterSettings extends js.Object {

/** <Array> list of string arguments passed to the Node.js executable. (Default=process.execArgv) */
var execArgv: js.Array[js.Any] = js.native
var execArgv: js.Array[String] = js.native

/** <String> file path to worker file. (Default=process.argv[1]) */
var exec: String = js.native

/** <Array> string arguments passed to worker. (Default=process.argv.slice(2)) */
var args: js.Array[js.Any] = js.native
var args: js.Array[String] = js.native

/** <Boolean> whether or not to send output to parent's stdio. (Default=false) */
var silent: Boolean = js.native

/** <Number> Sets the user identity of the process. (See setuid(2).) */
var uid: Integer = js.native
var uid: UID = js.native

/* <Number> Sets the group identity of the process. (See setgid(2).) */
var gid: Integer = js.native
/** <Number> Sets the group identity of the process. (See setgid(2).) */
var gid: GID = js.native

var stdio: js.Array[js.Any] = js.native

var inspectPort: JsNumber | js.Function = js.native

@enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10)
var cwd: String = js.native

@enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10)
var windowsHide: Boolean = js.native
}

/**
* Cluster Settings Companion
*/
object ClusterSettings {

def apply(exec: String = null, args: js.Array[js.Any] = null, silent: Boolean = false): ClusterSettings = {
val settings = New[ClusterSettings]
settings.exec = exec
settings.args = args
settings.silent = silent
settings
def apply(execArgv: js.Array[String] = null,
exec: String = null,
args: js.Array[String] = null,
silent: Boolean = false,
stdio: js.Array[js.Any] = null,
inspectPort: JsNumber | js.Function = null,
cwd: String = null,
windowsHide: Boolean = false): ClusterSettings = {
val settings = js.Dynamic.literal()
settings.updateDynamic("execArgv")(execArgv)
settings.updateDynamic("exec")(exec)
settings.updateDynamic("args")(args)
settings.updateDynamic("silent")(silent)
settings.updateDynamic("stdio")(stdio)
settings.updateDynamic("inspectPort")(inspectPort.asInstanceOf[js.Any])
settings.updateDynamic("cwd")(cwd)
settings.updateDynamic("windowsHide")(windowsHide)
settings.asInstanceOf[ClusterSettings]
}

}
29 changes: 7 additions & 22 deletions app/current/src/main/scala/io/scalajs/nodejs/cluster/Worker.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.scalajs.nodejs.cluster

import io.scalajs.nodejs.Process
import io.scalajs.nodejs.Handle
import io.scalajs.nodejs.child_process.ChildProcess
import io.scalajs.nodejs.events.IEventEmitter

import scala.scalajs.js
Expand All @@ -22,13 +23,13 @@ trait Worker extends IEventEmitter {
* The boolean worker.exitedAfterDisconnect lets you distinguish between voluntary and accidental exit, the master
* may choose not to respawn a worker based on this value.
*/
def exitedAfterDisconnect: Boolean = js.native
def exitedAfterDisconnect: js.UndefOr[Boolean] = js.native

/**
* Each new worker is given its own unique id, this id is stored in the id.
* While a worker is alive, this is the key that indexes it in cluster.workers
*/
def id: Integer = js.native
def id: Int = js.native

/**
* All workers are created using child_process.fork(), the returned object from this function is stored as .process.
Expand All @@ -37,7 +38,7 @@ trait Worker extends IEventEmitter {
* Note that workers will call process.exit(0) if the 'disconnect' event occurs on process and .exitedAfterDisconnect
* is not true. This protects against accidental disconnection.
*/
def process: Process = js.native
def process: ChildProcess = js.native

/**
* An alias to worker.exitedAfterDisconnect.
Expand Down Expand Up @@ -100,30 +101,14 @@ trait Worker extends IEventEmitter {
* @param signal the name of the kill signal to send to the worker process.
* @example kill([signal='SIGTERM'])
*/
def kill(signal: String = null): Unit = js.native
def kill(signal: String = js.native): Unit = js.native

/**
* Send a message to a worker or master, optionally with a handle.
* In the master this sends a message to a specific worker. It is identical to ChildProcess.send().
* In a worker this sends a message to the master. It is identical to process.send().
* @example worker.send(message[, sendHandle][, callback])
*/
def send(message: Message, sendHandle: js.Function, callback: js.Function): Unit = js.native

/**
* Send a message to a worker or master, optionally with a handle.
* In the master this sends a message to a specific worker. It is identical to ChildProcess.send().
* In a worker this sends a message to the master. It is identical to process.send().
* @example worker.send(message[, sendHandle][, callback])
*/
def send(message: Message, callback: js.Function): Unit = js.native

/**
* Send a message to a worker or master, optionally with a handle.
* In the master this sends a message to a specific worker. It is identical to ChildProcess.send().
* In a worker this sends a message to the master. It is identical to process.send().
* @example worker.send(message[, sendHandle][, callback])
*/
def send(message: Message): Unit = js.native
def send(message: Message, sendHandle: Handle = js.native, callback: js.Function = js.native): Unit = js.native

}
30 changes: 15 additions & 15 deletions app/current/src/main/scala/io/scalajs/nodejs/cluster/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ package object cluster {
* Cluster Events
* @param cluster the given [[Cluster cluster]]
*/
implicit class ClusterEvents(val cluster: Cluster) extends AnyVal {
implicit final class ClusterEvents(private val cluster: Cluster) extends AnyVal {

/**
* Emitted after the worker IPC channel has disconnected. This can occur when a worker exits gracefully, is killed,
Expand All @@ -32,7 +32,7 @@ package object cluster {
* @param callback the event handler
*/
@inline
def onDisconnect(callback: Worker => Any): cluster.type = cluster.on("disconnect", callback)
def onDisconnect(callback: Worker => Any): Cluster = cluster.on("disconnect", callback)

/**
* Similar to the cluster.on('exit') event, but specific to this worker.
Expand All @@ -44,15 +44,15 @@ package object cluster {
* </ul>
*/
@inline
def onExit(callback: (Worker, Int, String) => Any): cluster.type = cluster.on("exit", callback)
def onExit(callback: (Worker, Int, String) => Any): Cluster = cluster.on("exit", callback)

/**
* When a new worker is forked the cluster module will emit a 'fork' event. This can be used to log worker activity,
* and create your own timeout.
* @param callback the event handler
*/
@inline
def onFork(callback: Worker => Any): cluster.type = cluster.on("fork", callback)
def onFork(callback: Worker => Any): Cluster = cluster.on("fork", callback)

/**
* After calling listen() from a worker, when the 'listening' event is emitted on the server, a 'listening' event
Expand All @@ -64,7 +64,7 @@ package object cluster {
* @param callback the event handler
*/
@inline
def onListening(callback: (Worker, Address) => Any): cluster.type = cluster.on("listening", callback)
def onListening(callback: (Worker, Address) => Any): Cluster = cluster.on("listening", callback)

/**
* Emitted when any worker receives a message.
Expand All @@ -75,7 +75,7 @@ package object cluster {
* @param callback the event handler
*/
@inline
def onMessage(callback: (Worker, Message, js.Any) => Any): cluster.type = cluster.on("message", callback)
def onMessage(callback: (Worker, Message, js.Any) => Any): Cluster = cluster.on("message", callback)

/**
* After forking a new worker, the worker should respond with an online message. When the master receives an online
Expand All @@ -84,7 +84,7 @@ package object cluster {
* @param callback the event handler
*/
@inline
def onOnline(callback: Worker => Any): cluster.type = cluster.on("online", callback)
def onOnline(callback: Worker => Any): Cluster = cluster.on("online", callback)

/**
* Emitted every time .setupMaster() is called.
Expand All @@ -95,7 +95,7 @@ package object cluster {
* @param callback the event handler
*/
@inline
def onSetup(callback: ClusterSettings => Any): cluster.type = cluster.on("setup", callback)
def onSetup(callback: ClusterSettings => Any): Cluster = cluster.on("setup", callback)

}

Expand All @@ -107,7 +107,7 @@ package object cluster {
* Worker Events and Extensions
* @param worker the given [[Worker worker]]
*/
implicit class WorkerEvents(val worker: Worker) extends AnyVal {
implicit final class WorkerEvents(private val worker: Worker) extends AnyVal {

/////////////////////////////////////////////////////////////////////////////////
// Worker Extensions
Expand All @@ -131,15 +131,15 @@ package object cluster {
* @param callback the event handler
*/
@inline
def onDisconnect(callback: () => Any): worker.type = worker.on("disconnect", callback)
def onDisconnect(callback: () => Any): Worker = worker.on("disconnect", callback)

/**
* This event is the same as the one provided by child_process.fork().
* In a worker you can also use process.on('error').
* @param callback the error handler
*/
@inline
def onError(callback: nodejs.Error => Any): worker.type = worker.on("error", callback)
def onError(callback: nodejs.Error => Any): Worker = worker.on("error", callback)

/**
* Similar to the cluster.on('exit') event, but specific to this worker.
Expand All @@ -151,14 +151,14 @@ package object cluster {
* </ul>
*/
@inline
def onExit(callback: (Worker, Int, String) => Any): worker.type = worker.on("exit", callback)
def onExit(callback: (Worker, Int, String) => Any): Worker = worker.on("exit", callback)

/**
* Similar to the cluster.on('listening') event, but specific to this worker.
* @param callback the event handler
*/
@inline
def onListening(callback: Address => Any): worker.type = worker.on("listening", callback)
def onListening(callback: Address => Any): Worker = worker.on("listening", callback)

/**
* Similar to the cluster.on('message') event, but specific to this worker.
Expand All @@ -167,14 +167,14 @@ package object cluster {
* @param callback the event handler
*/
@inline
def onMessage(callback: Message => Any): worker.type = worker.on("message", callback)
def onMessage(callback: Message => Any): Worker = worker.on("message", callback)

/**
* Similar to the cluster.on('online') event, but specific to this worker.
* @param callback the event handler
*/
@inline
def onOnline(callback: () => Any): worker.type = worker.on("online", callback)
def onOnline(callback: () => Any): Worker = worker.on("online", callback)

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import scala.scalajs.js.|
*/
@js.native
@JSImport("net", "Socket")
class Socket(options: SocketOptions | RawOptions = js.native) extends IDuplex {
class Socket(options: SocketOptions | RawOptions = js.native) extends IDuplex with HasHandle {

/////////////////////////////////////////////////////////////////////////////////
// Properties
Expand Down Expand Up @@ -218,6 +218,8 @@ class Socket(options: SocketOptions | RawOptions = js.native) extends IDuplex {
*/
def unref(): this.type = js.native

// TODO: test me
override def _handle: js.Any = js.native
}

/**
Expand Down
3 changes: 3 additions & 0 deletions app/current/src/main/scala/io/scalajs/nodejs/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ package object nodejs {

type UID = Int

// The handle object can be either a server, a socket (anything with an underlying _handle member), or an object with an fd member that is a valid file descriptor.
type Handle = js.Function | HasHandle | HasFileDescriptor

/////////////////////////////////////////////////////////////////////////////////
// Built-in Properties
/////////////////////////////////////////////////////////////////////////////////
Expand Down
3 changes: 0 additions & 3 deletions core/src/main/scala/io/scalajs/util/ScalaJsHelper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ object ScalaJsHelper {
@inline
def isDefined(obj: js.Any): Boolean = obj != null && !js.isUndefined(obj)

@inline
def New[T <: js.Any]: T = new js.Object().asInstanceOf[T]

////////////////////////////////////////////////////////////////////////
// Implicit Definitions and Classes
////////////////////////////////////////////////////////////////////////
Expand Down