zeromq
Version:
Next-generation ZeroMQ bindings for Node.js
943 lines (862 loc) • 25.7 kB
text/typescript
/* eslint-disable @typescript-eslint/camelcase */
/* eslint-disable @typescript-eslint/no-var-requires */
/* The API of the compatibility layer and parts of the implementation has been
adapted from the original ZeroMQ.js version (up to 5.x) for which the license
and copyright notice is reproduced below.
Copyright (c) 2017-2019 Rolf Timmermans
Copyright (c) 2011 TJ Holowaychuk
Copyright (c) 2010, 2011 Justin Tulloss
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import {EventEmitter} from "events"
import * as zmq from "."
import {FullError} from "./errors"
type AnySocket =
| zmq.Pair
| zmq.Publisher
| zmq.Subscriber
| zmq.Request
| zmq.Reply
| zmq.Dealer
| zmq.Router
| zmq.Pull
| zmq.Push
| zmq.XPublisher
| zmq.XSubscriber
| zmq.Stream
let count = 1
const types = {
ZMQ_PAIR: 0,
ZMQ_PUB: 1,
ZMQ_SUB: 2,
ZMQ_REQ: 3,
ZMQ_REP: 4,
ZMQ_DEALER: 5,
ZMQ_XREQ: 5,
ZMQ_ROUTER: 6,
ZMQ_XREP: 6,
ZMQ_PULL: 7,
ZMQ_PUSH: 8,
ZMQ_XPUB: 9,
ZMQ_XSUB: 10,
ZMQ_STREAM: 11,
}
const longOptions = {
ZMQ_AFFINITY: 4,
ZMQ_IDENTITY: 5,
ZMQ_SUBSCRIBE: 6,
ZMQ_UNSUBSCRIBE: 7,
ZMQ_RATE: 8,
ZMQ_RECOVERY_IVL: 9,
ZMQ_RECOVERY_IVL_MSEC: 9,
ZMQ_SNDBUF: 11,
ZMQ_RCVBUF: 12,
ZMQ_RCVMORE: 13,
ZMQ_FD: 14,
ZMQ_EVENTS: 15,
ZMQ_TYPE: 16,
ZMQ_LINGER: 17,
ZMQ_RECONNECT_IVL: 18,
ZMQ_BACKLOG: 19,
ZMQ_RECONNECT_IVL_MAX: 21,
ZMQ_MAXMSGSIZE: 22,
ZMQ_SNDHWM: 23,
ZMQ_RCVHWM: 24,
ZMQ_MULTICAST_HOPS: 25,
ZMQ_RCVTIMEO: 27,
ZMQ_SNDTIMEO: 28,
ZMQ_IPV4ONLY: 31,
ZMQ_LAST_ENDPOINT: 32,
ZMQ_ROUTER_MANDATORY: 33,
ZMQ_TCP_KEEPALIVE: 34,
ZMQ_TCP_KEEPALIVE_CNT: 35,
ZMQ_TCP_KEEPALIVE_IDLE: 36,
ZMQ_TCP_KEEPALIVE_INTVL: 37,
ZMQ_TCP_ACCEPT_FILTER: 38,
ZMQ_DELAY_ATTACH_ON_CONNECT: 39,
ZMQ_XPUB_VERBOSE: 40,
ZMQ_ROUTER_RAW: 41,
ZMQ_IPV6: 42,
ZMQ_MECHANISM: 43,
ZMQ_PLAIN_SERVER: 44,
ZMQ_PLAIN_USERNAME: 45,
ZMQ_PLAIN_PASSWORD: 46,
ZMQ_CURVE_SERVER: 47,
ZMQ_CURVE_PUBLICKEY: 48,
ZMQ_CURVE_SECRETKEY: 49,
ZMQ_CURVE_SERVERKEY: 50,
ZMQ_ZAP_DOMAIN: 55,
ZMQ_HEARTBEAT_IVL: 75,
ZMQ_HEARTBEAT_TTL: 76,
ZMQ_HEARTBEAT_TIMEOUT: 77,
ZMQ_CONNECT_TIMEOUT: 79,
ZMQ_IO_THREADS: 1,
ZMQ_MAX_SOCKETS: 2,
ZMQ_ROUTER_HANDOVER: 56,
}
const pollStates = {
ZMQ_POLLIN: 1,
ZMQ_POLLOUT: 2,
ZMQ_POLLERR: 4,
}
const sendOptions = {
ZMQ_SNDMORE: 2,
}
const capabilities = {
ZMQ_CAN_MONITOR: 1,
ZMQ_CAN_DISCONNECT: 1,
ZMQ_CAN_UNBIND: 1,
ZMQ_CAN_SET_CTX: 1,
}
const socketStates = {
STATE_READY: 0,
STATE_BUSY: 1,
STATE_CLOSED: 2,
}
const shortOptions = {
_fd: longOptions.ZMQ_FD,
_ioevents: longOptions.ZMQ_EVENTS,
_receiveMore: longOptions.ZMQ_RCVMORE,
_subscribe: longOptions.ZMQ_SUBSCRIBE,
_unsubscribe: longOptions.ZMQ_UNSUBSCRIBE,
affinity: longOptions.ZMQ_AFFINITY,
backlog: longOptions.ZMQ_BACKLOG,
identity: longOptions.ZMQ_IDENTITY,
linger: longOptions.ZMQ_LINGER,
rate: longOptions.ZMQ_RATE,
rcvbuf: longOptions.ZMQ_RCVBUF,
last_endpoint: longOptions.ZMQ_LAST_ENDPOINT,
reconnect_ivl: longOptions.ZMQ_RECONNECT_IVL,
recovery_ivl: longOptions.ZMQ_RECOVERY_IVL,
sndbuf: longOptions.ZMQ_SNDBUF,
mechanism: longOptions.ZMQ_MECHANISM,
plain_server: longOptions.ZMQ_PLAIN_SERVER,
plain_username: longOptions.ZMQ_PLAIN_USERNAME,
plain_password: longOptions.ZMQ_PLAIN_PASSWORD,
curve_server: longOptions.ZMQ_CURVE_SERVER,
curve_publickey: longOptions.ZMQ_CURVE_PUBLICKEY,
curve_secretkey: longOptions.ZMQ_CURVE_SECRETKEY,
curve_serverkey: longOptions.ZMQ_CURVE_SERVERKEY,
zap_domain: longOptions.ZMQ_ZAP_DOMAIN,
heartbeat_ivl: longOptions.ZMQ_HEARTBEAT_IVL,
heartbeat_ttl: longOptions.ZMQ_HEARTBEAT_TTL,
heartbeat_timeout: longOptions.ZMQ_HEARTBEAT_TIMEOUT,
connect_timeout: longOptions.ZMQ_CONNECT_TIMEOUT,
}
class Context {
static setMaxThreads(value: number) {
zmq.context.ioThreads = value
}
static getMaxThreads() {
return zmq.context.ioThreads
}
static setMaxSockets(value: number) {
zmq.context.maxSockets = value
}
static getMaxSockets() {
return zmq.context.maxSockets
}
constructor() {
throw new Error("Context cannot be instantiated in compatibility mode")
}
}
type SocketType =
| "pair"
| "req"
| "rep"
| "pub"
| "sub"
| "dealer"
| "xreq"
| "router"
| "xrep"
| "pull"
| "push"
| "xpub"
| "xsub"
| "stream"
type Callback = (err?: Error) => void
class Socket extends EventEmitter {
[key: string]: any
type: SocketType
private _msg: zmq.MessageLike[] = []
private _recvQueue: zmq.Message[][] = []
private _sendQueue: Array<[zmq.MessageLike[], Callback | undefined]> = []
private _paused = false
private _socket: AnySocket
private _count = 0
constructor(type: SocketType) {
super()
this.type = type
switch (type) {
case "pair":
this._socket = new zmq.Pair()
break
case "req":
this._socket = new zmq.Request()
break
case "rep":
this._socket = new zmq.Reply()
break
case "pub":
this._socket = new zmq.Publisher()
break
case "sub":
this._socket = new zmq.Subscriber()
break
case "dealer":
case "xreq":
this._socket = new zmq.Dealer()
break
case "router":
case "xrep":
this._socket = new zmq.Router()
break
case "pull":
this._socket = new zmq.Pull()
break
case "push":
this._socket = new zmq.Push()
break
case "xpub":
this._socket = new zmq.XPublisher()
break
case "xsub":
this._socket = new zmq.XSubscriber()
break
case "stream":
this._socket = new zmq.Stream()
break
}
const recv = async () => {
this.once("_flushRecv", async () => {
while (!this._socket.closed && !this._paused) {
await this._recv()
}
if (!this._socket.closed) {
recv()
}
})
}
const send = () => {
this.once("_flushSend", async () => {
while (
!this._socket.closed &&
!this._paused &&
this._sendQueue.length
) {
await this._send()
}
if (!this._socket.closed) {
send()
}
})
}
if (type !== "push" && type !== "pub") {
recv()
}
send()
this.emit("_flushRecv")
}
async _recv() {
if (
this._socket instanceof zmq.Push ||
this._socket instanceof zmq.Publisher
) {
throw new Error("Cannot receive on this socket type.")
}
try {
if (this._recvQueue.length) {
const msg = this._recvQueue.shift()!
process.nextTick(() => this.emit("message", ...msg))
}
{
const msg = await this._socket.receive()
if (this._paused) {
this._recvQueue.push(msg)
} else {
process.nextTick(() => this.emit("message", ...msg))
}
}
} catch (err) {
if (!this._socket.closed && (err as FullError).code !== "EBUSY") {
process.nextTick(() => this.emit("error", err))
}
}
}
async _send() {
if (
this._socket instanceof zmq.Pull ||
this._socket instanceof zmq.Subscriber
) {
throw new Error("Cannot send on this socket type.")
}
if (this._sendQueue.length) {
const [msg, cb] = this._sendQueue.shift()!
try {
await (this._socket as zmq.Writable).send(msg)
if (cb) {
cb()
}
} catch (err) {
if (cb) {
cb(err as Error)
} else {
this.emit("error", err)
}
}
}
}
bind(address: string, cb?: Callback) {
this._socket
.bind(address)
.then(() => {
process.nextTick(() => {
this.emit("bind", address)
if (cb) {
cb()
}
})
})
.catch(err => {
process.nextTick(() => {
if (cb) {
cb(err)
} else {
this.emit("error", err)
}
})
})
return this
}
unbind(address: string, cb?: Callback) {
this._socket
.unbind(address)
.then(() => {
process.nextTick(() => {
this.emit("unbind", address)
if (cb) {
cb()
}
})
})
.catch(err => {
process.nextTick(() => {
if (cb) {
cb(err)
} else {
this.emit("error", err)
}
})
})
return this
}
connect(address: string) {
this._socket.connect(address)
return this
}
disconnect(address: string) {
this._socket.disconnect(address)
return this
}
send(message: zmq.MessageLike[], flags = 0, cb?: Callback) {
flags = flags | 0
this._msg = this._msg.concat(message)
if ((flags & sendOptions.ZMQ_SNDMORE) === 0) {
this._sendQueue.push([this._msg, cb])
this._msg = []
if (!this._paused) {
this.emit("_flushSend")
}
}
return this
}
read() {
throw new Error(
"read() has been removed from compatibility mode; " +
"use on('message', ...) instead.",
)
}
bindSync(...args: Parameters<Socket["bind"]>) {
try {
Object.defineProperty(this, "bindSync", {
value: require("deasync")(this.bind),
})
} catch (err) {
throw new Error(
"bindSync() has been removed from compatibility mode; " +
"use bind() instead, or add 'deasync' to your project dependencies",
)
}
this.bindSync(...args)
}
unbindSync(...args: Parameters<Socket["unbind"]>) {
try {
Object.defineProperty(this, "unbindSync", {
value: require("deasync")(this.unbind),
})
} catch (err) {
throw new Error(
"unbindSync() has been removed from compatibility mode; " +
"use unbind() instead, or add 'deasync' to your project dependencies",
)
}
this.unbindSync(...args)
}
pause() {
this._paused = true
}
resume() {
this._paused = false
this.emit("_flushRecv")
this.emit("_flushSend")
}
close() {
this._socket.close()
return this
}
get closed() {
return this._socket.closed
}
monitor(interval: number, num: number) {
this._count = count++
/* eslint-disable-next-line no-unused-expressions */
this._count
if (interval || num) {
process.emitWarning(
"Arguments to monitor() are ignored in compatibility mode; " +
"all events are read automatically",
)
}
const events = this._socket.events
const read = async () => {
while (!events.closed) {
try {
const event = await events.receive()
let type = event.type as string
let value
let error
switch (event.type) {
case "connect":
break
case "connect:delay":
type = "connect_delay"
break
case "connect:retry":
value = event.interval
type = "connect_retry"
break
case "bind":
type = "listen"
break
case "bind:error":
error = event.error
value = event.error ? event.error.errno : 0
type = "bind_error"
break
case "accept":
break
case "accept:error":
error = event.error
value = event.error ? event.error.errno : 0
type = "accept_error"
break
case "close":
break
case "close:error":
error = event.error
value = event.error ? event.error.errno : 0
type = "close_error"
break
case "disconnect":
break
case "end":
return
default:
continue
}
this.emit(type, value, event.address, error)
} catch (err) {
if (!this._socket.closed) {
this.emit("error", err)
}
}
}
}
read()
return this
}
unmonitor() {
this._socket.events.close()
return this
}
subscribe(filter: string) {
if (this._socket instanceof zmq.Subscriber) {
this._socket.subscribe(filter)
return this
} else {
throw new Error("Subscriber socket required")
}
}
unsubscribe(filter: string) {
if (this._socket instanceof zmq.Subscriber) {
this._socket.unsubscribe(filter)
return this
} else {
throw new Error("Subscriber socket required")
}
}
setsockopt(option: number | keyof typeof shortOptions, value: any) {
option = typeof option !== "number" ? shortOptions[option] : option
switch (option) {
case longOptions.ZMQ_AFFINITY:
this._socket.affinity = value
break
case longOptions.ZMQ_IDENTITY:
;(this._socket as zmq.Router).routingId = value
break
case longOptions.ZMQ_SUBSCRIBE:
;(this._socket as zmq.Subscriber).subscribe(value)
break
case longOptions.ZMQ_UNSUBSCRIBE:
;(this._socket as zmq.Subscriber).unsubscribe(value)
break
case longOptions.ZMQ_RATE:
this._socket.rate = value
break
case longOptions.ZMQ_RECOVERY_IVL:
this._socket.recoveryInterval = value
break
case longOptions.ZMQ_SNDBUF:
;(this._socket as zmq.Writable).sendBufferSize = value
break
case longOptions.ZMQ_RCVBUF:
;(this._socket as zmq.Readable).receiveBufferSize = value
break
case longOptions.ZMQ_LINGER:
this._socket.linger = value
break
case longOptions.ZMQ_RECONNECT_IVL:
this._socket.reconnectInterval = value
break
case longOptions.ZMQ_BACKLOG:
this._socket.backlog = value
break
case longOptions.ZMQ_RECOVERY_IVL_MSEC:
this._socket.recoveryInterval = value
break
case longOptions.ZMQ_RECONNECT_IVL_MAX:
this._socket.reconnectMaxInterval = value
break
case longOptions.ZMQ_MAXMSGSIZE:
this._socket.maxMessageSize = value
break
case longOptions.ZMQ_SNDHWM:
;(this._socket as zmq.Writable).sendHighWaterMark = value
break
case longOptions.ZMQ_RCVHWM:
;(this._socket as zmq.Readable).receiveHighWaterMark = value
break
case longOptions.ZMQ_MULTICAST_HOPS:
;(this._socket as zmq.Writable).multicastHops = value
break
case longOptions.ZMQ_RCVTIMEO:
;(this._socket as zmq.Readable).receiveTimeout = value
break
case longOptions.ZMQ_SNDTIMEO:
;(this._socket as zmq.Writable).sendTimeout = value
break
case longOptions.ZMQ_IPV4ONLY:
this._socket.ipv6 = !value
break
case longOptions.ZMQ_ROUTER_MANDATORY:
;(this._socket as zmq.Router).mandatory = Boolean(value)
break
case longOptions.ZMQ_TCP_KEEPALIVE:
this._socket.tcpKeepalive = value
break
case longOptions.ZMQ_TCP_KEEPALIVE_CNT:
this._socket.tcpKeepaliveCount = value
break
case longOptions.ZMQ_TCP_KEEPALIVE_IDLE:
this._socket.tcpKeepaliveIdle = value
break
case longOptions.ZMQ_TCP_KEEPALIVE_INTVL:
this._socket.tcpKeepaliveInterval = value
break
case longOptions.ZMQ_TCP_ACCEPT_FILTER:
this._socket.tcpAcceptFilter = value
break
case longOptions.ZMQ_DELAY_ATTACH_ON_CONNECT:
this._socket.immediate = Boolean(value)
break
case longOptions.ZMQ_XPUB_VERBOSE:
;(this._socket as zmq.XPublisher).verbosity = value ? "allSubs" : null
break
case longOptions.ZMQ_ROUTER_RAW:
throw new Error("ZMQ_ROUTER_RAW is not supported in compatibility mode")
case longOptions.ZMQ_IPV6:
this._socket.ipv6 = Boolean(value)
break
case longOptions.ZMQ_PLAIN_SERVER:
this._socket.plainServer = Boolean(value)
break
case longOptions.ZMQ_PLAIN_USERNAME:
this._socket.plainUsername = value
break
case longOptions.ZMQ_PLAIN_PASSWORD:
this._socket.plainPassword = value
break
case longOptions.ZMQ_CURVE_SERVER:
this._socket.curveServer = Boolean(value)
break
case longOptions.ZMQ_CURVE_PUBLICKEY:
this._socket.curvePublicKey = value
break
case longOptions.ZMQ_CURVE_SECRETKEY:
this._socket.curveSecretKey = value
break
case longOptions.ZMQ_CURVE_SERVERKEY:
this._socket.curveServerKey = value
break
case longOptions.ZMQ_ZAP_DOMAIN:
this._socket.zapDomain = value
break
case longOptions.ZMQ_HEARTBEAT_IVL:
this._socket.heartbeatInterval = value
break
case longOptions.ZMQ_HEARTBEAT_TTL:
this._socket.heartbeatTimeToLive = value
break
case longOptions.ZMQ_HEARTBEAT_TIMEOUT:
this._socket.heartbeatTimeout = value
break
case longOptions.ZMQ_CONNECT_TIMEOUT:
this._socket.connectTimeout = value
break
case longOptions.ZMQ_ROUTER_HANDOVER:
;(this._socket as zmq.Router).handover = Boolean(value)
break
default:
throw new Error("Unknown option")
}
return this
}
getsockopt(option: number | keyof typeof shortOptions) {
option = typeof option !== "number" ? shortOptions[option] : option
switch (option) {
case longOptions.ZMQ_AFFINITY:
return this._socket.affinity
case longOptions.ZMQ_IDENTITY:
return (this._socket as zmq.Router).routingId
case longOptions.ZMQ_RATE:
return this._socket.rate
case longOptions.ZMQ_RECOVERY_IVL:
return this._socket.recoveryInterval
case longOptions.ZMQ_SNDBUF:
return (this._socket as zmq.Writable).sendBufferSize
case longOptions.ZMQ_RCVBUF:
return (this._socket as zmq.Readable).receiveBufferSize
case longOptions.ZMQ_RCVMORE:
throw new Error("ZMQ_RCVMORE is not supported in compatibility mode")
case longOptions.ZMQ_FD:
throw new Error("ZMQ_FD is not supported in compatibility mode")
case longOptions.ZMQ_EVENTS:
return (
(this._socket.readable ? pollStates.ZMQ_POLLIN : 0) |
(this._socket.writable ? pollStates.ZMQ_POLLOUT : 0)
)
case longOptions.ZMQ_TYPE:
return this._socket.type
case longOptions.ZMQ_LINGER:
return this._socket.linger
case longOptions.ZMQ_RECONNECT_IVL:
return this._socket.reconnectInterval
case longOptions.ZMQ_BACKLOG:
return this._socket.backlog
case longOptions.ZMQ_RECOVERY_IVL_MSEC:
return this._socket.recoveryInterval
case longOptions.ZMQ_RECONNECT_IVL_MAX:
return this._socket.reconnectMaxInterval
case longOptions.ZMQ_MAXMSGSIZE:
return this._socket.maxMessageSize
case longOptions.ZMQ_SNDHWM:
return (this._socket as zmq.Writable).sendHighWaterMark
case longOptions.ZMQ_RCVHWM:
return (this._socket as zmq.Readable).receiveHighWaterMark
case longOptions.ZMQ_MULTICAST_HOPS:
return (this._socket as zmq.Writable).multicastHops
case longOptions.ZMQ_RCVTIMEO:
return (this._socket as zmq.Readable).receiveTimeout
case longOptions.ZMQ_SNDTIMEO:
return (this._socket as zmq.Writable).sendTimeout
case longOptions.ZMQ_IPV4ONLY:
return !this._socket.ipv6
case longOptions.ZMQ_LAST_ENDPOINT:
return this._socket.lastEndpoint
case longOptions.ZMQ_ROUTER_MANDATORY:
return (this._socket as zmq.Router).mandatory ? 1 : 0
case longOptions.ZMQ_TCP_KEEPALIVE:
return this._socket.tcpKeepalive
case longOptions.ZMQ_TCP_KEEPALIVE_CNT:
return this._socket.tcpKeepaliveCount
case longOptions.ZMQ_TCP_KEEPALIVE_IDLE:
return this._socket.tcpKeepaliveIdle
case longOptions.ZMQ_TCP_KEEPALIVE_INTVL:
return this._socket.tcpKeepaliveInterval
case longOptions.ZMQ_DELAY_ATTACH_ON_CONNECT:
return this._socket.immediate ? 1 : 0
case longOptions.ZMQ_XPUB_VERBOSE:
throw new Error("Reading ZMQ_XPUB_VERBOSE is not supported")
case longOptions.ZMQ_ROUTER_RAW:
throw new Error("ZMQ_ROUTER_RAW is not supported in compatibility mode")
case longOptions.ZMQ_IPV6:
return this._socket.ipv6 ? 1 : 0
case longOptions.ZMQ_MECHANISM:
switch (this._socket.securityMechanism) {
case "plain":
return 1
case "curve":
return 2
case "gssapi":
return 3
default:
return 0
}
case longOptions.ZMQ_PLAIN_SERVER:
return this._socket.plainServer ? 1 : 0
case longOptions.ZMQ_PLAIN_USERNAME:
return this._socket.plainUsername
case longOptions.ZMQ_PLAIN_PASSWORD:
return this._socket.plainPassword
case longOptions.ZMQ_CURVE_SERVER:
return this._socket.curveServer ? 1 : 0
case longOptions.ZMQ_CURVE_PUBLICKEY:
return this._socket.curvePublicKey
case longOptions.ZMQ_CURVE_SECRETKEY:
return this._socket.curveSecretKey
case longOptions.ZMQ_CURVE_SERVERKEY:
return this._socket.curveServerKey
case longOptions.ZMQ_ZAP_DOMAIN:
return this._socket.zapDomain
case longOptions.ZMQ_HEARTBEAT_IVL:
return this._socket.heartbeatInterval
case longOptions.ZMQ_HEARTBEAT_TTL:
return this._socket.heartbeatTimeToLive
case longOptions.ZMQ_HEARTBEAT_TIMEOUT:
return this._socket.heartbeatTimeout
case longOptions.ZMQ_CONNECT_TIMEOUT:
return this._socket.connectTimeout
default:
throw new Error("Unknown option")
}
}
}
for (const key in shortOptions) {
if (!shortOptions.hasOwnProperty(key)) {
continue
}
if (Socket.prototype.hasOwnProperty(key)) {
continue
}
Object.defineProperty(Socket.prototype, key, {
get(this: Socket) {
return this.getsockopt(shortOptions[key as keyof typeof shortOptions])
},
set(this: Socket, val: string | Buffer) {
if ("string" === typeof val) {
val = Buffer.from(val, "utf8")
}
return this.setsockopt(
shortOptions[key as keyof typeof shortOptions],
val,
)
},
})
}
function createSocket(type: SocketType, options: {[key: string]: any} = {}) {
const sock = new Socket(type)
for (const key in options) {
if (options.hasOwnProperty(key)) {
sock[key] = options[key]
}
}
return sock
}
function curveKeypair() {
const {publicKey, secretKey} = zmq.curveKeyPair()
return {public: publicKey, secret: secretKey}
}
function proxy(frontend: Socket, backend: Socket, capture?: Socket) {
switch (`${frontend.type}/${backend.type}`) {
case "push/pull":
case "pull/push":
case "xpub/xsub":
frontend.on("message", (...args: zmq.MessageLike[]) => {
backend.send(args)
})
if (capture) {
backend.on("message", (...args: zmq.MessageLike[]) => {
frontend.send(args)
capture.send(args)
})
} else {
backend.on("message", (...args: zmq.MessageLike[]) => {
frontend.send(args)
})
}
break
case "router/dealer":
case "xrep/xreq":
frontend.on("message", (...args: zmq.MessageLike[]) => {
backend.send(args)
})
if (capture) {
backend.on("message", (...args: zmq.MessageLike[]) => {
frontend.send(args)
capture.send(args.slice(2))
})
} else {
backend.on("message", (...args: zmq.MessageLike[]) => {
frontend.send(args)
})
}
break
default:
throw new Error(
"This socket type order is not supported in compatibility mode",
)
}
}
const version = zmq.version
export {
version,
Context,
Socket,
createSocket as socket,
createSocket,
curveKeypair,
proxy,
shortOptions as options,
}
/* Unfortunately there is no easy way to include these in the resulting
TS definitions. */
Object.assign(module.exports, longOptions)
Object.assign(module.exports, types)
Object.assign(module.exports, pollStates)
Object.assign(module.exports, sendOptions)
Object.assign(module.exports, socketStates)
Object.assign(module.exports, capabilities)