UNPKG

pxt-common-packages

Version:
189 lines (169 loc) 7.04 kB
namespace net { export const SOCK_STREAM = 1 export const AF_INET = 2 export const MAX_PACKET = 4000 export const TCP_MODE = 0 export const UDP_MODE = 1 export const TLS_MODE = 2 export class ControllerSocket implements net.Socket { _buffer: Buffer; _socknum: number; _timeout: number; _closed: boolean; _openHandler: () => void; _closeHandler: () => void; _errorHandler: (msg: string) => void; _messageHandler: (data: Buffer) => void; /** A simplified implementation of the Python 'socket' class, for connecting through an interface to a remote device */ constructor(private controller: Controller, private host: string | Buffer, private port: number, private conntype: number = null) { if (this.conntype === null) { this.conntype = net.TCP_MODE } this._buffer = hex`` this._socknum = this.controller.socket() this.setTimeout(0) } /** Connect the socket to the 'address' (which can be 32bit packed IP or a hostname string). 'conntype' is an extra that may indicate SSL or not, depending on the underlying interface */ public connect() { if (!this.controller.socketConnect(this._socknum, this.host, this.port, this.conntype)) { this.error(`failed to connect to ${this.host}`) return; } this._buffer = hex`` if (this._openHandler) this._openHandler(); } /** Send some data to the socket */ public send(data: string | Buffer) { //console.log("sock wr: " + data) this.controller.socketWrite(this._socknum, net.dataAsBuffer(data)) } private error(msg: string) { if (this._errorHandler) this._errorHandler(msg) } onOpen(handler: () => void): void { this._openHandler = handler; } onClose(handler: () => void): void { this._closeHandler = handler; } onError(handler: (msg: string) => void): void { this._errorHandler = handler; } private flushReadBuffer() { while (!this._closed && this._messageHandler) { const buf = this.read() if (buf.length) { this._messageHandler(buf) } else { break } } } onMessage(handler: (data: Buffer) => void): void { if (this._messageHandler === undefined) { const src = this.controller.dataAvailableSrc(this._socknum) const value = this.controller.dataAvailableValue(this._socknum) if (src > 0 && value > 0) { this.flushReadBuffer() control.internalOnEvent(src, value, () => this.flushReadBuffer()) } else { control.runInParallel(() => { while (!this._closed) { this.flushReadBuffer() pause(200) } }) } } this._messageHandler = handler || null; } /** Attempt to return as many bytes as we can up to but not including '\r\n' */ public readLine(): string { // print("Socket readline") let stamp = monotonic() while (this._buffer.indexOf(hex`0d0a`) < 0) { // there's no line already in there, read some more let avail = Math.min(this.controller.socketAvailable(this._socknum), MAX_PACKET) if (avail > 0) { this._buffer = this._buffer.concat(this.controller.socketRead(this._socknum, avail)) } else if (avail < 0 || (this._timeout > 0 && monotonic() - stamp > this._timeout)) { // Make sure to close socket so that we don't exhaust sockets. this.close() throw "Didn't receive full response, failing out" } else { pause(20) } } const pos = this._buffer.indexOf(hex`0d0a`) const pref = this._buffer.slice(0, pos) this._buffer = this._buffer.slice(pos + 2) // print("rd: " + this._buffer.length + " / " + pref.length + " :" + pref.toString()) return pref.toString() } /** Read up to 'size' bytes from the socket, this may be buffered internally! If 'size' isn't specified, return everything in the buffer. */ public read(size: number = 0): Buffer { // print("Socket read", size) if (size == 0) { if (this._buffer.length == 0) { let avail = Math.min(this.controller.socketAvailable(this._socknum), MAX_PACKET) if (avail > 0) this._buffer = this.controller.socketRead(this._socknum, avail) if (avail < 0) this.close() } let ret = this._buffer this._buffer = hex`` return ret } let stamp = monotonic() let to_read = size - this._buffer.length let received = [] while (to_read > 0) { // print("Bytes to read:", to_read) let avail = Math.min(this.controller.socketAvailable(this._socknum), MAX_PACKET) if (avail > 0) { stamp = monotonic() let recv = this.controller.socketRead(this._socknum, Math.min(to_read, avail)) received.push(recv) to_read -= recv.length } else { pause(20) } if (avail < 0 || (this._timeout > 0 && monotonic() - stamp > this._timeout)) { break } } // print(received) received.unshift(this._buffer) this._buffer = pins.concatBuffers(received) let ret = null if (this._buffer.length == size) { ret = this._buffer this._buffer = hex`` } else { ret = this._buffer.slice(0, size) this._buffer = this._buffer.slice(size) } return ret } /** Set the read timeout for sockets, if value is 0 it will block */ public setTimeout(value: number) { this._timeout = value } /** Close the socket, after reading whatever remains */ public close() { this._closed = true; this._buffer = hex`` this.controller.socketClose(this._socknum) if (this._closeHandler) this._closeHandler(); } } }