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, Observer} from 'rxjs';
25 import {EventService, EgEvent} from './event.service';
27 // Global vars from opensrf.js
28 // These are availavble at runtime, but are not exported.
29 declare var OpenSRF, OSRF_TRANSPORT_TYPE_WS;
31 export class NetRequest {
35 observer: Observer<any>;
37 // If set, this will be used instead of a one-off OpenSRF.ClientSession.
39 // True if we're using a single-use local session
42 // Last Event encountered by this request.
43 // Most callers will not need to import Event since the parsed
44 // event will be available here.
47 constructor(service: string, method: string, params: any[], session?: any) {
48 this.service = service;
52 this.session = session;
53 this.localSession = false;
55 this.session = new OpenSRF.ClientSession(service);
60 export interface AuthExpiredEvent {
61 // request is set when the auth expiration was determined as a
62 // by-product of making an API call.
65 // True if this environment (e.g. browser tab) was notified of the
66 // expired auth token from an external source (e.g. another browser tab).
67 viaExternal?: boolean;
70 @Injectable({providedIn: 'root'})
71 export class NetService {
73 permFailed$: EventEmitter<NetRequest>;
74 authExpired$: EventEmitter<AuthExpiredEvent>;
76 // If true, permission failures are emitted via permFailed
77 // and the active request is marked as superseded.
78 permFailedHasHandler: Boolean = false;
81 private egEvt: EventService
83 this.permFailed$ = new EventEmitter<NetRequest>();
84 this.authExpired$ = new EventEmitter<AuthExpiredEvent>();
87 // Standard request call -- Variadic params version
88 request(service: string, method: string, ...params: any[]): Observable<any> {
89 return this.requestWithParamList(service, method, params);
92 // Array params version
93 requestWithParamList(service: string,
94 method: string, params: any[]): Observable<any> {
95 return this.requestCompiled(
96 new NetRequest(service, method, params));
99 // Request with pre-compiled NetRequest
100 requestCompiled(request: NetRequest): Observable<any> {
101 return Observable.create(
103 request.observer = observer;
104 this.sendCompiledRequest(request);
109 // Send the compiled request to the server via WebSockets
110 sendCompiledRequest(request: NetRequest): void {
111 OpenSRF.Session.transport = OSRF_TRANSPORT_TYPE_WS;
112 console.debug(`Net: request ${request.method}`);
114 request.session.request({
115 async : true, // WS only operates in async mode
116 method : request.method,
117 params : request.params,
120 // TODO: teach opensrf.js to call cleanup() inside
121 // disconnect() and teach Pcrud to call cleanup()
122 // as needed to avoid long-lived session data bloat.
123 if (request.localSession) {
124 request.session.cleanup();
127 // A superseded request will be complete()'ed by the
128 // superseder at a later time.
129 if (!request.superseded) {
130 request.observer.complete();
134 this.dispatchResponse(request, r.recv().content());
136 onerror : errmsg => {
137 const msg = `${request.method} failed! See server logs. ${errmsg}`;
139 request.observer.error(msg);
141 onmethoderror : (req, statCode, statMsg) => {
143 `${request.method} failed! stat=${statCode} msg=${statMsg}`;
146 if (request.service === 'open-ils.pcrud'
147 && Number(statCode) === 401) {
148 // 401 is the PCRUD equivalent of a NO_SESSION event
149 this.authExpired$.emit({request: request});
152 request.observer.error(msg);
158 // Relay response object to the caller for typical/successful
159 // responses. Applies special handling to response events that
160 // require global attention.
161 private dispatchResponse(request, response): void {
162 request.evt = this.egEvt.parse(response);
165 switch (request.evt.textcode) {
168 console.debug(`Net emitting event: ${request.evt}`);
169 request.observer.error(request.evt.toString());
170 this.authExpired$.emit({request: request});
174 if (this.permFailedHasHandler) {
175 console.debug(`Net emitting event: ${request.evt}`);
176 request.superseded = true;
177 this.permFailed$.emit(request);
183 // Pass the response to the caller.
184 request.observer.next(response);