3 * constructor(private net : NetService) {
5 * this.net.request(service, method, param1 [, param2, ...])
7 * (res) => console.log('received one resopnse: ' + res),
8 * (err) => console.error('recived request error: ' + err),
9 * () => console.log('request complete')
14 * // Example translating a net request into a promise.
15 * this.net.request(service, method, param1)
16 * .toPromise().then(result => console.log(result));
20 * Each response is relayed via Observable.next(). The interface is
21 * the same for streaming and atomic requests.
23 import {Injectable, EventEmitter} from '@angular/core';
24 import {Observable} from 'rxjs/Observable';
25 import {Observer} from 'rxjs/Observer';
26 import {EventService, EgEvent} from './event.service';
28 // Global vars from opensrf.js
29 // These are availavble at runtime, but are not exported.
30 declare var OpenSRF, OSRF_TRANSPORT_TYPE_WS;
32 export class NetRequest {
36 observer: Observer<any>;
38 // If set, this will be used instead of a one-off OpenSRF.ClientSession.
40 // True if we're using a single-use local session
43 // Last Event encountered by this request.
44 // Most callers will not need to import Event since the parsed
45 // event will be available here.
48 constructor(service: string, method: string, params: any[], session?: any) {
49 this.service = service;
53 this.session = session;
54 this.localSession = false;
56 this.session = new OpenSRF.ClientSession(service);
61 export interface AuthExpiredEvent {
62 // request is set when the auth expiration was determined as a
63 // by-product of making an API call.
66 // True if this environment (e.g. browser tab) was notified of the
67 // expired auth token from an external source (e.g. another browser tab).
68 viaExternal?: boolean;
71 @Injectable({providedIn: 'root'})
72 export class NetService {
74 permFailed$: EventEmitter<NetRequest>;
75 authExpired$: EventEmitter<AuthExpiredEvent>;
77 // If true, permission failures are emitted via permFailed$
78 // and the active request is marked as superseded.
79 permFailedHasHandler: Boolean = false;
82 private egEvt: EventService
84 this.permFailed$ = new EventEmitter<NetRequest>();
85 this.authExpired$ = new EventEmitter<AuthExpiredEvent>();
88 // Standard request call -- Variadic params version
89 request(service: string, method: string, ...params: any[]): Observable<any> {
90 return this.requestWithParamList(service, method, params);
93 // Array params version
94 requestWithParamList(service: string,
95 method: string, params: any[]): Observable<any> {
96 return this.requestCompiled(
97 new NetRequest(service, method, params));
100 // Request with pre-compiled NetRequest
101 requestCompiled(request: NetRequest): Observable<any> {
102 return Observable.create(
104 request.observer = observer;
105 this.sendCompiledRequest(request);
110 // Send the compiled request to the server via WebSockets
111 sendCompiledRequest(request: NetRequest): void {
112 OpenSRF.Session.transport = OSRF_TRANSPORT_TYPE_WS;
113 console.debug(`Net: request ${request.method}`);
115 request.session.request({
116 async : true, // WS only operates in async mode
117 method : request.method,
118 params : request.params,
121 // TODO: teach opensrf.js to call cleanup() inside
122 // disconnect() and teach Pcrud to call cleanup()
123 // as needed to avoid long-lived session data bloat.
124 if (request.localSession) {
125 request.session.cleanup();
128 // A superseded request will be complete()'ed by the
129 // superseder at a later time.
130 if (!request.superseded) {
131 request.observer.complete();
135 this.dispatchResponse(request, r.recv().content());
137 onerror : errmsg => {
138 const msg = `${request.method} failed! See server logs. ${errmsg}`;
140 request.observer.error(msg);
142 onmethoderror : (req, statCode, statMsg) => {
144 `${request.method} failed! stat=${statCode} msg=${statMsg}`;
147 if (request.service === 'open-ils.pcrud'
148 && Number(statCode) === 401) {
149 // 401 is the PCRUD equivalent of a NO_SESSION event
150 this.authExpired$.emit({request: request});
153 request.observer.error(msg);
159 // Relay response object to the caller for typical/successful
160 // responses. Applies special handling to response events that
161 // require global attention.
162 private dispatchResponse(request, response): void {
163 request.evt = this.egEvt.parse(response);
166 switch (request.evt.textcode) {
169 console.debug(`Net emitting event: ${request.evt}`);
170 request.observer.error(request.evt.toString());
171 this.authExpired$.emit({request: request});
175 if (this.permFailedHasHandler) {
176 console.debug(`Net emitting event: ${request.evt}`);
177 request.superseded = true;
178 this.permFailed$.emit(request);
184 // Pass the response to the caller.
185 request.observer.next(response);