11import { NMOSDeviceRuntimeOptions , NMOSNodeRuntimeOptions } from './types'
2- import { Axios } from 'axios'
32import is04endpoints from '../schema/is04/index'
43import is05endpoints from '../schema/is05/index'
54import { z , ZodError } from 'zod'
6- import _ from 'lodash'
5+ import _ , { type get } from 'lodash'
6+ import superagent , { type SuperAgent , type SuperAgentStatic } from 'superagent'
7+ import nodeapiBaseV13 from '../schema/is04/v1.3/zod/nodeapi-base.json'
8+ import nodeapiBaseV12 from '../schema/is04/v1.2/zod/nodeapi-base.json'
9+ import nodeapiSelfV13 from '../schema/is04/v1.3/zod/_node'
10+ import nodeapiSelfV12 from '../schema/is04/v1.2/zod/_node'
11+ import nodeapiDevicesV13 from '../schema/is04/v1.3/zod/_devices'
12+ import nodeapiDevicesV12 from '../schema/is04/v1.2/zod/_devices'
13+ import nodeapiSourcesV13 from '../schema/is04/v1.3/zod/_sources'
14+ import nodeapiSourcesV12 from '../schema/is04/v1.2/zod/_sources'
15+ import nodeapiFlowsV13 from '../schema/is04/v1.3/zod/_flows'
16+ import nodeapiFlowsV12 from '../schema/is04/v1.2/zod/_flows'
17+ import nodeapiSendersV13 from '../schema/is04/v1.3/zod/_senders'
18+ import nodeapiSendersV12 from '../schema/is04/v1.2/zod/_senders'
19+ import nodeapiReceiversV13 from '../schema/is04/v1.3/zod/_receivers'
20+ import nodeapiReceiversV12 from '../schema/is04/v1.2/zod/_receivers'
721
822type IS04Endpoints = typeof is04endpoints
923export type IS04EndpointTypes = keyof typeof is04endpoints
@@ -14,141 +28,160 @@ export type IS05EndpointTypes = keyof typeof is05endpoints
1428export type IS05EndpointType < T extends IS05EndpointTypes > = z . infer < IS05Endpoints [ T ] >
1529
1630export class NMOSNodeRuntime {
17- private runtime : Axios
1831 private options : NMOSNodeRuntimeOptions
1932
33+ private protocol : 'http' | 'https'
34+ private host : string
35+ private port : number
36+ private basePath : string
37+ private is04Version : 'v1.0' | 'v1.1' | 'v1.2' | 'v1.3' | undefined
38+ private timeout : number = 2000
39+ private insecureHTTPParser : boolean = true
40+
2041 constructor ( options : NMOSNodeRuntimeOptions ) {
2142 this . options = options
22- this . runtime = new Axios ( {
23- baseURL : `${ options . protocol } ://${ options . host } :${ options . port } ${ options . basePath } ` ,
24- timeout : 1000 ,
25- headers : {
26- 'Content-Type' : 'application/json' ,
27- } ,
28- } )
43+ this . protocol = options . protocol
44+ this . host = options . host
45+ this . port = options . port
46+ this . basePath = options . basePath
47+ this . timeout = options . timeout || 2000
48+ this . insecureHTTPParser = options . insecureHTTPParser || true
2949 }
3050
31- async get < T extends IS04EndpointTypes > ( path : T , options : Record < string , string > = { } ) : Promise < z . infer < typeof is04endpoints [ T ] > > {
32- const endpoint = is04endpoints [ path ]
33- const resolvedPath = path . replace ( / { ( [ ^ } ] * ) } / g, ( _ , key ) => options [ key ] )
34- const result = await this . runtime . get < IS04EndpointType < T > > ( resolvedPath )
51+ setIS04Version ( version : 'v1.0' | 'v1.1' | 'v1.2' | 'v1.3' ) {
52+ this . is04Version = version
53+ }
3554
36- if ( result . status !== 200 ) {
37- throw new Error ( 'Failed to fetch data from: ' + resolvedPath )
38- }
55+ async probeNodeApiSupport ( ) : Promise < ( 'v1.0' | 'v1.1' | 'v1.2' | 'v1.3' ) [ ] > {
56+ const response = await this . get ( `${ this . protocol } ://${ this . host } :${ this . port } ${ this . basePath } /node` )
57+ const firstParse = z
58+ . array ( z . string ( ) )
59+ . parse ( response . body )
60+ . map ( ( s ) => s . replace ( / \/ $ / , '' ) )
61+
62+ return firstParse as ( 'v1.0' | 'v1.1' | 'v1.2' | 'v1.3' ) [ ]
63+ }
3964
40- if ( typeof result . data === 'string' ) {
41- try {
42- result . data = JSON . parse ( result . data )
43- } catch ( error ) {
44- console . error ( error )
45- throw new Error ( 'Failed to parse JSON' )
46- }
65+ requireIS04Version ( ) {
66+ if ( ! this . is04Version ) {
67+ throw new Error ( 'IS04 version not set' )
4768 }
69+ }
4870
49- if ( this . options . strict ) {
50- return await endpoint . parseAsync ( result . data )
51- } else {
52- const parse = await endpoint . safeParseAsync ( result . data )
71+ get ( url : string ) {
72+ return superagent . get ( url ) . timeout ( this . timeout ) . disableTLSCerts ( ) . accept ( 'json' )
73+ }
5374
54- if ( ! parse . success ) {
55- parse . error . errors . forEach ( ( error ) => {
56- console . error ( 'Validation error [' + path + ']' , error . path . join ( '.' ) + ': ' + error . message , 'received' , _ . get ( result . data , error . path . join ( '.' ) ) )
57- } )
58- }
75+ async nodeSelfGet ( ) {
76+ this . requireIS04Version ( )
77+ const httpRes = await this . get ( `${ this . protocol } ://${ this . host } :${ this . port } ${ this . basePath } /node/${ this . is04Version } /self` )
78+
79+ if ( this . is04Version === 'v1.3' ) {
80+ const safe = nodeapiSelfV13 . parse ( httpRes . body )
81+ return safe
82+ }
5983
60- return parse . data as z . infer < typeof endpoint >
84+ if ( this . is04Version === 'v1.2' ) {
85+ const safe = nodeapiSelfV12 . parse ( httpRes . body )
86+ // do polyfill here....
87+ return safe
6188 }
89+
90+ throw new Error ( 'Unknown IS04 version' )
6291 }
63- }
6492
65- export class NMOSConnectionRuntime {
66- private runtime : Axios
67- private options : NMOSDeviceRuntimeOptions
93+ async nodeDevicesGet ( ) {
94+ this . requireIS04Version ( )
95+ const httpRes = await this . get ( `${ this . protocol } ://${ this . host } :${ this . port } ${ this . basePath } /node/${ this . is04Version } /devices` )
96+
97+ if ( this . is04Version === 'v1.3' ) {
98+ const safe = nodeapiDevicesV13 . parse ( httpRes . body )
99+ return safe
100+ }
68101
69- constructor ( options : NMOSDeviceRuntimeOptions ) {
70- this . options = options
71- this . runtime = new Axios ( {
72- baseURL : `${ options . baseUrl } ` ,
73- timeout : 1000 ,
74- headers : {
75- 'Content-Type' : 'application/json' ,
76- } ,
77- } )
102+ if ( this . is04Version === 'v1.2' ) {
103+ const safe = nodeapiDevicesV12 . parse ( httpRes . body )
104+ return safe
105+ }
106+
107+ throw new Error ( 'Unknown IS04 version' )
78108 }
79109
80- async execute < T extends IS05EndpointTypes > ( method : 'patch' | 'get' , path : T , options : Record < string , string > = { } ) {
81- const endpoint = is05endpoints [ path ]
82- const resolvedPath = path . replace ( / { ( [ ^ } ] * ) } / g, ( _ , key ) => options [ key ] )
83110
84- if ( method !== 'get' && method !== 'patch' ) {
85- throw new Error ( 'unknwon method ' + method )
111+ async nodeSourcesGet ( ) {
112+ this . requireIS04Version ( )
113+ const httpRes = await this . get ( `${ this . protocol } ://${ this . host } :${ this . port } ${ this . basePath } /node/${ this . is04Version } /sources` )
114+
115+ if ( this . is04Version === 'v1.3' ) {
116+ const safe = nodeapiSourcesV13 . parse ( httpRes . body )
117+ return safe
86118 }
87119
88- const result = method === 'get' ? await this . runtime . get < IS05EndpointType < T > > ( resolvedPath ) : method === 'patch' ? await this . runtime . patch < IS05EndpointType < T > > ( resolvedPath ) : undefined
89-
90- if ( ! result ) {
91- throw new Error ( 'Unknown error' )
120+ if ( this . is04Version === 'v1.2' ) {
121+ const safe = nodeapiSourcesV12 . parse ( httpRes . body )
122+ return safe
92123 }
93124
94- if ( result . status !== 200 ) {
95- throw new Error ( 'Failed to fetch data from: ' + resolvedPath )
125+ throw new Error ( 'Unknown IS04 version' )
126+ }
127+
128+
129+ async nodeFlowsGet ( ) {
130+ this . requireIS04Version ( )
131+ const httpRes = await this . get ( `${ this . protocol } ://${ this . host } :${ this . port } ${ this . basePath } /node/${ this . is04Version } /flows` )
132+
133+ if ( this . is04Version === 'v1.3' ) {
134+ const safe = nodeapiFlowsV13 . parse ( httpRes . body )
135+ return safe
96136 }
97137
98- try {
99- if ( typeof result . data === 'string' ) {
100- try {
101- result . data = JSON . parse ( result . data )
102- } catch ( error ) {
103- console . error ( error )
104- throw new Error ( 'Failed to parse JSON' )
105- }
106- }
107-
108- const parse = await endpoint . safeParseAsync ( result . data )
109-
110- if ( ! parse . success ) {
111- parse . error . errors . forEach ( ( error ) => {
112- console . error ( 'Validation error [' + path + ']' , error . path . join ( '.' ) + ': ' + error . message , 'received' , _ . get ( result . data , error . path . join ( '.' ) ) )
113- } )
114-
115- if ( this . options . strict ) {
116- console . error ( 'Strict mode enabled, failed to parse data' )
117- throw new ZodError ( parse . error . issues )
118- }
119- }
120-
121- return parse . data as z . infer < typeof endpoint >
122-
123- } catch ( error ) {
124- console . error ( 'error' , error )
138+ if ( this . is04Version === 'v1.2' ) {
139+ const safe = nodeapiFlowsV12 . parse ( httpRes . body )
140+ return safe
125141 }
126- }
127142
128- async get < T extends IS05EndpointTypes > ( path : T , options : Record < string , string > = { } ) {
129- this . execute ( 'get' , path , options )
143+ throw new Error ( 'Unknown IS04 version' )
130144 }
131145
132- async patch < T extends IS05EndpointTypes > ( path : T , options : Record < string , string > = { } ) {
133- this . execute ( 'patch' , path , options )
146+ async nodeSendersGet ( ) {
147+ this . requireIS04Version ( )
148+ const httpRes = await this . get ( `${ this . protocol } ://${ this . host } :${ this . port } ${ this . basePath } /node/${ this . is04Version } /senders` )
149+
150+ if ( this . is04Version === 'v1.3' ) {
151+ const safe = nodeapiSendersV13 . parse ( httpRes . body )
152+ return safe
153+ }
154+
155+ if ( this . is04Version === 'v1.2' ) {
156+ const safe = nodeapiSendersV12 . parse ( httpRes . body )
157+ return safe
158+ }
159+
160+ throw new Error ( 'Unknown IS04 version' )
134161 }
135- }
136162
163+ async nodeReceiversGet ( ) {
164+ this . requireIS04Version ( )
165+ const httpRes = await this . get ( `${ this . protocol } ://${ this . host } :${ this . port } ${ this . basePath } /node/${ this . is04Version } /receivers` )
137166
167+ if ( this . is04Version === 'v1.3' ) {
168+ const safe = nodeapiReceiversV13 . parse ( httpRes . body )
169+ return safe
170+ }
138171
172+ if ( this . is04Version === 'v1.2' ) {
173+ const safe = nodeapiReceiversV12 . parse ( httpRes . body )
174+ return safe
175+ }
139176
140- export class NMOSConnectionAPI extends NMOSConnectionRuntime {
141- constructor ( {
142- baseUrl = '' ,
143- strict = true ,
144- } : Partial < NMOSDeviceRuntimeOptions > ) {
145- super ( {
146- baseUrl,
147- strict,
148- } )
177+ throw new Error ( 'Unknown IS04 version' )
149178 }
179+
180+
150181}
151182
183+
184+
152185export class NMOSNodeAPI extends NMOSNodeRuntime {
153186 constructor ( {
154187 dialect = null ,
@@ -158,6 +191,7 @@ export class NMOSNodeAPI extends NMOSNodeRuntime {
158191 basePath = '/x-nmos' ,
159192 strict = true ,
160193 insecureHTTPParser = true ,
194+ timeout = 2000 ,
161195 } : Partial < NMOSNodeRuntimeOptions > ) {
162196 super ( {
163197 dialect,
@@ -167,6 +201,7 @@ export class NMOSNodeAPI extends NMOSNodeRuntime {
167201 basePath,
168202 strict,
169203 insecureHTTPParser,
204+ timeout,
170205 } )
171206 }
172207}
0 commit comments