import {stream_common} from './_stream_common.jsy' export function net_common(hub, plugin, protocol, asURL) :: var _common_ if null == asURL :: let path_prefix = {'.':'/', '/':''} asURL = function () :: let {address, port, path} = this if address :: return `${protocol}://${address}:${port}` else if path :: let pre = path_prefix[path[0]] || '/./' return `${protocol}://${pre}${path}` let conn_info_base = @{} toString: asURL, asURL, protocol from(addr, port, self={__proto__: this}) :: if null != port :: self.host = self.address = addr self.port = port else self.path = addr return self hub.registerProtocols @ [protocol, `${protocol}:`], url => plugin.connect @ _common_.unpackConnectURL(url) Object.assign @ plugin, @{} with_url_options(options) :: // merges options onto this.url_options return plugin.url_options = @{} ... plugin.url_options, ... options // shared implementation between net/tcp and tls implementations return _common_ = @{} __proto__: stream_common(hub), createSocketChannel(sock, channel_id) :: sock.setNoDelay(true) let channel = this.createStreamChannel(sock, sock, channel_id || protocol) return Object.defineProperties @ channel, @{} sock: @{} enumerable: true, get() :: return sock conn_info: @{} enumerable: true, value() :: let res = conn_info_base.from(sock.localAddress, sock.localPort) res.remote = conn_info_base.from(sock.remoteAddress, sock.remotePort) return res bindChannel(...args) :: let channel = this.createSocketChannel(...args) channel.init() return channel createClient(channel_id, _impl_) :: return new Promise @ (resolve, reject) => :: _impl_ @ function() :: let sock = this.setKeepAlive(true) let channel = _common_.bindChannel(sock, channel_id) resolve(channel) .on @ 'error', reject createServer(channel_id, onPeer, _impl_) :: let svr = _impl_ @ sock => :: sock = sock.unref().setKeepAlive(false) let channel = _common_.bindChannel(sock, channel_id) on_peer(channel) let on_peer = this.bindOnPeer(svr, onPeer) svr.conn_info = function (asPromise) :: let addr = svr.address() if null != addr :: let res = conn_info_base.from @ addr.address || addr, addr.port return asPromise ? Promise.resolve(res) : res else if asPromise :: return new Promise @ (resolve, reject) => :: svr.once @ 'listening', @=> resolve @ svr.conn_info(false) svr.once @ 'error', reject else return null return svr bindOnPeer(svr, onPeer) :: if 'function' === typeof onPeer :: return onPeer return ! onPeer ? Boolean : channel => svr.emit @ onPeer, channel unpackConnectURL(conn_url) :: if 'string' === typeof conn_url.href :: conn_url = this.unpackURLParams(conn_url) let options = @{} ... conn_url, ... plugin.url_options return plugin.on_url_connect ? plugin.on_url_connect(options, url) : options unpackURLParams(url) :: if 'string' !== typeof url.href :: return let {hostname:host, port, pathname: path} = url if host :: return @{} host, port else if path :: if path.startsWith('/.') :: path = path.slice(1) return @{} path