Home Reference Source Test

src/plugin/dgram.js

  1. import dgram from 'dgram'
  2.  
  3. import Plugin from './plugin'
  4.  
  5. /**
  6. * Status flags
  7. * @private
  8. */
  9. const STATUS = {
  10. IS_NOT_INITIALIZED: -1,
  11. IS_CONNECTING: 0,
  12. IS_OPEN: 1,
  13. IS_CLOSING: 2,
  14. IS_CLOSED: 3,
  15. }
  16.  
  17. /**
  18. * Default options for open method
  19. * @private
  20. */
  21. const defaultOpenOptions = {
  22. host: 'localhost',
  23. port: 41234,
  24. exclusive: false,
  25. }
  26.  
  27. /**
  28. * Default options for send method
  29. * @private
  30. */
  31. const defaultSendOptions = {
  32. host: 'localhost',
  33. port: 41235,
  34. }
  35.  
  36. /**
  37. * Default options
  38. * @private
  39. */
  40. const defaultOptions = {
  41. type: 'udp4',
  42. open: defaultOpenOptions,
  43. send: defaultSendOptions,
  44. }
  45.  
  46. /**
  47. * Helper method to merge nested objects
  48. * @private
  49. */
  50. function mergeOptions(base, custom) {
  51. return {
  52. ...defaultOptions,
  53. ...base,
  54. ...custom,
  55. open: { ...defaultOptions.open, ...base.open, ...custom.open },
  56. send: { ...defaultOptions.send, ...base.send, ...custom.send },
  57. }
  58. }
  59.  
  60. /**
  61. * OSC plugin for simple OSC messaging via udp client
  62. * and udp server
  63. */
  64. export default class DatagramPlugin extends Plugin {
  65. /**
  66. * Create an OSC Plugin instance with given options. Defaults to
  67. * localhost:41234 for server and localhost:41235 for client messaging
  68. * @param {object} [options] Custom options
  69. * @param {string} [options.type='udp4'] 'udp4' or 'udp6'
  70. * @param {string} [options.open.host='localhost'] Hostname of udp server to bind to
  71. * @param {number} [options.open.port=41234] Port of udp server to bind to
  72. * @param {boolean} [options.open.exclusive=false] Exclusive flag
  73. * @param {string} [options.send.host='localhost'] Hostname of udp client for messaging
  74. * @param {number} [options.send.port=41235] Port of udp client for messaging
  75. *
  76. * @example
  77. * const plugin = new OSC.DatagramPlugin({ send: { port: 9912 } })
  78. * const osc = new OSC({ plugin: plugin })
  79. */
  80. constructor(options = {}) {
  81. super()
  82.  
  83. // `dgram` gets replaced with an undefined value in builds targeting
  84. // browser environments
  85. if (!dgram) {
  86. throw new Error('DatagramPlugin can not be used in browser context')
  87. }
  88.  
  89. /**
  90. * @type {object} options
  91. * @private
  92. */
  93. this.options = mergeOptions({}, options)
  94.  
  95. /**
  96. * @type {object} socket
  97. * @private
  98. */
  99. this.socket = dgram.createSocket(this.options.type)
  100. /**
  101. * @type {number} socketStatus
  102. * @private
  103. */
  104. this.socketStatus = STATUS.IS_NOT_INITIALIZED
  105.  
  106. // register events
  107. this.socket.on('message', (message, rinfo) => {
  108. this.notify(message, rinfo)
  109. })
  110.  
  111. this.socket.on('error', (error) => {
  112. this.notify('error', error)
  113. })
  114.  
  115. /**
  116. * @type {function} notify
  117. * @private
  118. */
  119. this.notify = () => {}
  120. }
  121.  
  122. /**
  123. * Internal method to hook into osc library's
  124. * EventHandler notify method
  125. * @param {function} fn Notify callback
  126. * @private
  127. */
  128. registerNotify(fn) {
  129. this.notify = fn
  130. }
  131.  
  132. /**
  133. * Returns the current status of the connection
  134. * @return {number} Status ID
  135. */
  136. status() {
  137. return this.socketStatus
  138. }
  139.  
  140. /**
  141. * Bind a udp socket to a hostname and port
  142. * @param {object} [customOptions] Custom options
  143. * @param {string} [customOptions.host='localhost'] Hostname of udp server to bind to
  144. * @param {number} [customOptions.port=41234] Port of udp server to bind to
  145. * @param {boolean} [customOptions.exclusive=false] Exclusive flag
  146. */
  147. open(customOptions = {}) {
  148. const options = { ...this.options.open, ...customOptions }
  149. const { port, exclusive } = options
  150.  
  151. this.socketStatus = STATUS.IS_CONNECTING
  152.  
  153. this.socket.bind({
  154. address: options.host,
  155. port,
  156. exclusive,
  157. }, () => {
  158. this.socketStatus = STATUS.IS_OPEN
  159. this.notify('open')
  160. })
  161. }
  162.  
  163. /**
  164. * Close udp socket
  165. */
  166. close() {
  167. this.socketStatus = STATUS.IS_CLOSING
  168.  
  169. this.socket.close(() => {
  170. this.socketStatus = STATUS.IS_CLOSED
  171. this.notify('close')
  172. })
  173. }
  174.  
  175. /**
  176. * Send an OSC Packet, Bundle or Message. Use options here for
  177. * custom port and hostname, otherwise the global options will
  178. * be taken
  179. * @param {Uint8Array} binary Binary representation of OSC Packet
  180. * @param {object} [customOptions] Custom options for udp socket
  181. * @param {string} [customOptions.host] Hostname of udp client
  182. * @param {number} [customOptions.port] Port of udp client
  183. */
  184. send(binary, customOptions = {}) {
  185. const options = { ...this.options.send, ...customOptions }
  186. const { port, host } = options
  187.  
  188. this.socket.send(Buffer.from(binary), 0, binary.byteLength, port, host)
  189. }
  190. }