ulwanski/unix-dgram-socket

View on GitHub
src/UnixDgramSocket.ts

Summary

Maintainability
A
0 mins
Test Coverage
A
95%
/* tslint:disable:no-var-requires */
import * as fs from "fs";
import {EventEmitter} from "events";
import {SocketException} from "./SocketException";
const lib = require('../build/Release/unix_dgram');

export class UnixDgramSocket extends EventEmitter {
    public static readonly payloadEncoding = 'utf8';
    protected fd: any;
    protected connected: boolean = false;

    public constructor() {
        super();

        this.fd = lib.socket(lib.AF_UNIX, lib.SOCK_DGRAM, 0, (size: number, data: Buffer, path: string | null) => {
            this.emit('message', data, { dataSize: size, remoteSocket: path });
        }, () => {
            this.emit('writable');
        });

        if (this.fd < 0) {
            throw new SocketException(this.fd, 'socket');
        }
    }

    public bind(socketPath: string): void {
        const result: number = lib.bind(this.fd, this.cleanupSocketFile(socketPath));
        if (result < 0) {
            this.emit('error', new SocketException(result, 'bind'));
        } else {
            this.emit('listening', socketPath);
        }
    }

    public send(data: Buffer | string, socketPath?: string): boolean {
        let result: number;

        if (typeof data === 'string') {
            data = Buffer.from(data, UnixDgramSocket.payloadEncoding);
        }

        if (socketPath) {
            result = lib.sendto(this.fd, data, 0, data.length, socketPath);
        } else {
            result = lib.send(this.fd, data);
        }

        if (result < 0) {
            this.emit('error', new SocketException(result, 'send'));
        } else if (result === 1) {
            this.emit('congestion', data);
        }

        return (result >= 0);
    }

    public close(): void {
        const result: number = lib.close(this.fd);
        if (result < 0) {
            this.emit('error', new SocketException(result, 'close'));
        }
        this.fd = -1;
    }

    /*
     The connect() system call connects the socket referred to by the file
     descriptor sockfd to the address specified by addr. If the socket sockfd
     is of type SOCK_DGRAM, then addr is the address to which datagrams
     are sent by default, and the only address from which datagrams are received.
     If the socket is of type SOCK_STREAM or SOCK_SEQPACKET, this call attempts
     to make a connection to the socket that is bound to the address specified by addr.

     Generally, connection-based protocol sockets may successfully
     connect() only once; connectionless protocol sockets may use
     connect() multiple times to change their association.
     Connectionless sockets may dissolve the association by connecting to an address with
     the sa_family member of sockaddr set to AF_UNSPEC (supported on Linux
     since kernel 2.2).
     */
    public connect(socketPath: string) {
        const result: number = lib.connect(this.fd, socketPath);
        if (result < 0) {
            this.emit('error', new SocketException(result, 'connect'));
        } else {
            this.connected = true;
            this.emit('connect', socketPath);
        }
    }

    protected cleanupSocketFile(socketPath: string): string {
        if (fs.existsSync(socketPath)) {
            const stat: fs.Stats = fs.statSync(socketPath);

            if (stat.isSocket()) {
                fs.unlinkSync(fs.realpathSync(socketPath));
            }
        }

        return socketPath;
    }
}