tes.service.ts 21.3 KB
Newer Older
1
import { Injectable, EventEmitter } from '@angular/core';
Chris Hines's avatar
Chris Hines committed
2
import { HttpClientModule, HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
Chris Hines's avatar
Chris Hines committed
3
import { Observable, Subject, BehaviorSubject, of, from } from 'rxjs';
4
5
import { fromEvent, throwError, Subscription, merge } from 'rxjs';
import { catchError, map, tap, filter } from 'rxjs/operators';
Chris Hines's avatar
Chris Hines committed
6
import { Job } from './job';
7
import { AppAction, Strudelapp, StrudelappInstance } from './strudelapp';
Chris Hines's avatar
Chris Hines committed
8
import { Computesite, Health } from './computesite';
9
import { APIServer } from './apiserver';
Chris Hines's avatar
Chris Hines committed
10
import { Identity, AuthToken, KeyCert, SshAuthzServer } from './identity';
11
12
import { BatchInterface } from './batchinterface';
import { ComputesitesService } from './computesites.service';
13
import { StrudelappsService } from './strudelapps.service';
Chris Hines's avatar
Chris Hines committed
14
import { timer } from 'rxjs/observable/timer';
Chris Hines's avatar
Chris Hines committed
15
import { repeat, takeUntil } from 'rxjs/operators';
Chris Hines's avatar
Chris Hines committed
16
import { LocationStrategy, Location } from '@angular/common';
Chris Hines's avatar
Chris Hines committed
17
import { ActivatedRoute, Router } from '@angular/router';
Chris Hines's avatar
Chris Hines committed
18
19
import { ModaldialogComponent } from './modaldialog/modaldialog.component';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material';
Chris Hines's avatar
Chris Hines committed
20
21
import { AuthorisationService } from './authorisation.service';
import { environment } from '../environments/environment';
Chris Hines's avatar
Chris Hines committed
22
import { BackendSelectionService } from './backend-selection.service';
Chris Hines's avatar
Chris Hines committed
23

Chris Hines's avatar
Chris Hines committed
24
25
/** The TES service contains ways to start Tunnels, and Execute programs
Its also responsible for querying a compute site for running jobs */
Chris Hines's avatar
Chris Hines committed
26
27


28

Chris Hines's avatar
Chris Hines committed
29
30
31
@Injectable({
  providedIn: 'root',
})
Chris Hines's avatar
Chris Hines committed
32
export class TesService {
33
34
35
36
public Base: string;
//public Base=environment.tesurl;
//private twsproxy = environment.twsurl;
private twsproxy: string;
Chris Hines's avatar
Chris Hines committed
37
// public Base='http://localhost:5000';
38
public statusMsg: BehaviorSubject<any>;
Chris Hines's avatar
Chris Hines committed
39
public jobs: any[];
Chris Hines's avatar
Chris Hines committed
40
// public joblist: BehaviorSubject<{ [id: string ]: Job[]}>;
Chris Hines's avatar
Chris Hines committed
41
42
//public joblist: BehaviorSubject<Job[]>;
//public userhealth: BehaviorSubject<Health[]>;
Chris Hines's avatar
Chris Hines committed
43

Chris Hines's avatar
Chris Hines committed
44
private timerSubscription: any;
Chris Hines's avatar
Chris Hines committed
45
private appwindow: any;
46
47
public apiserver: BehaviorSubject<APIServer>;
public apiservers: BehaviorSubject<APIServer[]>;
48
private updateJobSub: Subscription;
Chris Hines's avatar
Chris Hines committed
49
50
private updateUserHealthSub: Subscription;
private cachetincidents: BehaviorSubject<Health[]>;
51
private nextUpdate: Subscription;
52
private cancelRequests$: Subject<boolean>;
53
public identitySubject: BehaviorSubject<Identity>;
Chris Hines's avatar
Chris Hines committed
54
public appSubject: BehaviorSubject<Strudelapp>;
Chris Hines's avatar
Chris Hines committed
55
private openapps: any[];
56

57
// public batchinterface: {[id: string] : BatchInterface};
Chris Hines's avatar
Chris Hines committed
58

59
  constructor(private http: HttpClient,
Chris Hines's avatar
Chris Hines committed
60
              public dialog: MatDialog,
Chris Hines's avatar
Chris Hines committed
61
62
              private computesitesService: ComputesitesService,
              private authorisationService: AuthorisationService,
Chris Hines's avatar
Chris Hines committed
63
              private strudelappsService: StrudelappsService,
Chris Hines's avatar
Chris Hines committed
64
              private backendSelectionService: BackendSelectionService,
Chris Hines's avatar
Chris Hines committed
65
              private location: Location ) {
Chris Hines's avatar
Chris Hines committed
66
67

    // this.joblist = new BehaviorSubject<{[id: string]: Job[]}>({});
Chris Hines's avatar
Chris Hines committed
68
69
70
    //this.joblist = new BehaviorSubject<Job[]>([]);
    //this.cachetincidents = new BehaviorSubject<Health[]>([]);
    //this.userhealth = new BehaviorSubject<Health[]>([{'stat':'ok','msg':''}])
Chris Hines's avatar
Chris Hines committed
71
    this.apiserver = new BehaviorSubject<APIServer>(null);
72
    this.apiservers = new BehaviorSubject<APIServer[]>([]);
73
    this.cancelRequests$ = new Subject<boolean>();
Chris Hines's avatar
Chris Hines committed
74
    this.openapps = [];
Chris Hines's avatar
Chris Hines committed
75
76
    //this.identitySubject = new BehaviorSubject<Identity>(null);
    //this.appSubject = new BehaviorSubject<Strudelapp>(null);
Chris Hines's avatar
Chris Hines committed
77

78
      this.backendSelectionService.apiserver.subscribe( (value) => { if (value != null) {this.twsproxy = value.tws ; this.Base = value.tes }});
Chris Hines's avatar
Chris Hines committed
79
    timer(500).pipe(repeat()).subscribe(() => this.checkWindows());
80
    // this.batchinterface = {};
Chris Hines's avatar
Chris Hines committed
81
    // this.computesitesService.identities.subscribe(identities => this.startPolling(identities));
Chris Hines's avatar
Chris Hines committed
82
83
 }

Chris Hines's avatar
Chris Hines committed
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
public checkWindows() {
  var app: any;
  this.openapps.forEach( (app,index) => {
    if (app.window.closed) {
      if (app.job.state == 'RUNNING') {
        let dialogRef = this.dialog.open(ModaldialogComponent, {
          width: '600px',
          data: app.job,
        });
        //dialogRef.afterClosed().subscribe((job) => {if (job !== null) { console.log('terminate'); console.log(job);}})
        dialogRef.afterClosed().subscribe((job) => {if (job !== null) { this.cancel(job)}});
      }
      this.openapps.splice(index,1);
    }
  })
}

Chris Hines's avatar
Chris Hines committed
101
102
103
public setStatusMsg(statusMsg: BehaviorSubject<any>) {
  this.statusMsg = statusMsg;
}
104

Chris Hines's avatar
Chris Hines committed
105
 private buildParams(app: Strudelapp, identity: Identity, batchinterface: BatchInterface, appinst?: any): string {
106
   let params = new URLSearchParams();
Chris Hines's avatar
Chris Hines committed
107
108
109
   let id = identity.copy_skip_catalog();
   id.site.appCatalog = null;

Chris Hines's avatar
Chris Hines committed
110
111
112
   if (appinst!== null)  {
     params.set('appinstance',JSON.stringify(appinst));
   }
113
114
   params.set('app',JSON.stringify(app));
   params.set('interface',JSON.stringify(batchinterface));
Chris Hines's avatar
Chris Hines committed
115
   params.set('identity',JSON.stringify(id));
116
   return params.toString();
Chris Hines's avatar
Chris Hines committed
117
118
 }

119

120
 updateJoblist(resp, identity: Identity) {
121
122
123
124
125
126
127
128
     // resp contains a javascript represnetiation of a list of jobs
     // We want to update the joblist BUT we don't want to create new Job objects
     // instead we want to reuse existing job objects removing any which are no longer valid
     // and adding any new ones. We also want the list sorted from largest jobid to smallest (oldest job)
     // The sort is lexographic since sometimes jobids are a string rather than a number
   
   var joblist: Job[] = []
   var jobquery: Job[] = <Job[]>resp;
Chris Hines's avatar
Chris Hines committed
129
   var lastjoblist: Job[] = identity.joblist.value;
130
131
   var qjobids: any[] = [];
   var jobids: any[] = [];
Chris Hines's avatar
Chris Hines committed
132
133
134
   var j: Job;
   var newjob: Job;
   var idx: number;
135
136
137
138
139
140
141

   for (j of jobquery) {
       qjobids.push(j.jobid);
   }
   for (j of lastjoblist) {
       if (qjobids.indexOf(j.jobid) != -1) {
           if (jobids.indexOf(j.jobid) == -1) {
Chris Hines's avatar
Chris Hines committed
142
143
144
145
146
147
               idx = qjobids.indexOf(j.jobid)
               newjob = jobquery[idx]
               // These values in the job may change, but we need to keep using the old object
               j.state  = newjob.state;
               j.endtime = newjob.endtime;
               j.batch_host = newjob.batch_host;
148
149
150
151
               joblist.push(j);
               jobids.push(j.jobid);
           }
       }
152
   }
153
154
155
156
157
158
159
160
   for (j of jobquery) {
       if (jobids.indexOf(j.jobid) == -1) {
           joblist.push(j);
           jobids.push(j.jobid);
       }
   }
       
   for (j of joblist) {
161
162
     if (j.app === undefined || j.app == null) {
       j.app = this.strudelappsService.getApp(j.appname,identity.site.appCatalog.value);
163
164
165
166
167
168
169
170
171
     }
     if (j.identity == undefined) {
        j.identity = identity;
     }
     if (j.connectionState == undefined) {
         j.connectionState = 0;
     }
   }
   joblist = joblist.sort((a,b) =>  (a.jobid < b.jobid)? 1:-1);
Chris Hines's avatar
Chris Hines committed
172
   identity.joblist.next(joblist);
Chris Hines's avatar
Chris Hines committed
173
   //this.statusMsg.next(null);
174
175
 }

Chris Hines's avatar
Chris Hines committed
176
177
 private getBatchInterfaceError(error: any) {
   console.error(error);
178
179
 }

180
181


Chris Hines's avatar
Chris Hines committed
182
183
 private getCachetIncidentsError(error: any, identity: Identity) {
   return this.getJobsError(error, identity)
Chris Hines's avatar
Chris Hines committed
184
 }
185

Chris Hines's avatar
Chris Hines committed
186
187
 
 public cancelHealthRequests() {
188
    this.cancelRequests$.next(true);
Chris Hines's avatar
Chris Hines committed
189
190
 }

Chris Hines's avatar
Chris Hines committed
191
 private getUserHealthError(error: any, identity: Identity) {
192
   identity.accountalerts.next([]);
Chris Hines's avatar
Chris Hines committed
193
194
   this.statusMsg.next("There was an error checking your user account");
   //return this.getJobsError(error,identity)
Chris Hines's avatar
Chris Hines committed
195
196
 }

Chris Hines's avatar
Chris Hines committed
197
198
 private getJobsError(error: any, identity: Identity) {
   identity.joblist.next([]);
Chris Hines's avatar
Chris Hines committed
199
   if (error.status == 0) {
Chris Hines's avatar
Chris Hines committed
200
     this.statusMsg.next("A network error occurred. Please try again later");
Chris Hines's avatar
Chris Hines committed
201
     return
202
   }
203
   console.error(error);
204
   if (error.status == 401) {
Chris Hines's avatar
Chris Hines committed
205
     this.statusMsg.next("Login expired. Please log in again.");
206
     this.authorisationService.updateAgentContents();
Chris Hines's avatar
Chris Hines committed
207
     return
208
   }
209
210
211
212
213
214
   if (error.status == 400) {
       if (error.error !== undefined && error.error.message !== undefined) {
        this.statusMsg.next(error.error.message);
       }
       return
   }
Chris Hines's avatar
Chris Hines committed
215
216
 }

Chris Hines's avatar
Chris Hines committed
217
218
219
220
 getJobs(identity: Identity) {
  let headers = new HttpHeaders();
  let options = { headers: headers, withCredentials: true};
  // remove from the job list any jobs for identities that we don't know about
Chris Hines's avatar
Chris Hines committed
221
  let oldjobs = identity.joblist.value;
222
223
224
  let bi = new BatchInterface();
  bi.cancelcmd = identity.site.cancelcmd;
  bi.statcmd = identity.site.statcmd;
225
226
227
228
229
  let params = new URLSearchParams();
  params.set('statcmd',JSON.stringify(identity.site.statcmd));
  params.set('host',JSON.stringify(identity.site.host));
  params.set('username',JSON.stringify(identity.username));
  
230
  this.updateJobSub = this.http.get<Job[]>(this.Base+'/stat'+'?'+params.toString(),options)
231
                .subscribe(resp => this.updateJoblist(resp, identity),
Chris Hines's avatar
Chris Hines committed
232
                           error => this.getJobsError(error, identity));
Chris Hines's avatar
Chris Hines committed
233
234
}

Chris Hines's avatar
Chris Hines committed
235
236
237
238
239
240
241
242
243
getUserHealth(identity: Identity)  {
  let headers = new HttpHeaders();
  let options = { headers: headers, withCredentials: true};
  // remove from the job list any jobs for identities that we don't know about
  let params = new URLSearchParams();
  if (identity === undefined || identity === null) {
    return
  }
  if (identity.site.userhealth === undefined) {
244
    identity.accountalerts.next([]);
Chris Hines's avatar
Chris Hines committed
245
246
247
248
249
250
251
    return
  }
  params.set('statcmd',JSON.stringify(identity.site.userhealth));
  params.set('host',JSON.stringify(identity.site.host));
  params.set('username',JSON.stringify(identity.username));
  
  this.updateUserHealthSub = this.http.get<Health[]>(this.Base+'/stat'+'?'+params.toString(),options)
252
    .pipe(takeUntil(this.cancelRequests$))
Chris Hines's avatar
Chris Hines committed
253
254
255
256
    .subscribe(resp => this.addUserHealth(identity,resp), error => this.getUserHealthError(error,identity));
}

getHealthAlerts(identity: Identity) {
257
258
  //identity.accountalerts.next(null);
  //identity.systemalerts.next([]);
Chris Hines's avatar
Chris Hines committed
259
260
  this.getCachetIncidents(identity);
  this.getUserHealth(identity);
Chris Hines's avatar
Chris Hines committed
261
262
263
264
265
266
267
268
269
}

getCachetIncidents(identity: Identity) {
  let headers = new HttpHeaders();
  let options = { headers: headers, withCredentials: false};
  // remove from the job list any jobs for identities that we don't know about
  let params = new URLSearchParams();

  if (identity.site.cacheturis === undefined ||  identity.site.cacheturis.length == 0) {
270
    identity.systemalerts.next([]);
Chris Hines's avatar
Chris Hines committed
271
272
273
274
    return
  }
  for (let uri of identity.site.cacheturis) {
    this.http.get(uri,options)
275
      .pipe(takeUntil(this.cancelRequests$))
Chris Hines's avatar
Chris Hines committed
276
      .subscribe(resp => this.addCachetIncidents(identity,resp), error => this.getCachetIncidentsError(error,identity));
Chris Hines's avatar
Chris Hines committed
277
278
279
  }
}

Chris Hines's avatar
Chris Hines committed
280
addCachetIncidents(identity,resp) {
281
282
  console.log('got an sa response');
  /*let ci = identity.systemalerts.value;
283
284
  if (ci == null) {
    ci = []
285
286
  }*/
  let ci = [];
Chris Hines's avatar
Chris Hines committed
287
288
289
290
291
292
293
294
295
  for (let i of resp.data) {
    if (i.status == 3 || i.status == 4) {
      continue;
    }
    let h = new Health();
    h.stat = 'error';
    h.msg = i.message;
    ci.push(h);
  }
296
  identity.systemalerts.next(ci);
297
298
299
  console.log('update system alerts for ',identity.displayName());
  console.log(identity.systemalerts.value);
  console.log(identity.systemalerts);
Chris Hines's avatar
Chris Hines committed
300
301
302
}

addUserHealth(identity,resp) {
303
  /*let ci = identity.accountalerts.value;
304
305
  if (ci == null) {
    ci = []
306
307
  }*/
  let ci = []
Chris Hines's avatar
Chris Hines committed
308
  for (let i of resp) {
Chris Hines's avatar
Chris Hines committed
309
310
311
    let h = new Health();
    h.stat = i.stat;
    h.msg = i.message;
312
313
314
    if (i.title != undefined) {
      h.title = i.title;
    }
Chris Hines's avatar
Chris Hines committed
315
316
317
    if (i.type != undefined) {
      h.type = i.type;
      h.data = i.data;
Chris Hines's avatar
Chris Hines committed
318
    }
Chris Hines's avatar
Chris Hines committed
319
    ci.push(h);
Chris Hines's avatar
Chris Hines committed
320
  }
321
  console.log('update account alerts for ',identity.displayName());
322
  identity.accountalerts.next(ci);
323
324
  console.log(identity.accountalerts.value);
  console.log(identity.accountalerts);
Chris Hines's avatar
Chris Hines committed
325
326
327
328
}



329
 public getconfig(app: Strudelapp, identity: Identity): Observable<any> {
Chris Hines's avatar
Chris Hines committed
330
331
332
   let headers = new HttpHeaders();
   let options = { headers: headers, withCredentials: true};
   return this.http.get<any>(identity.site.url+'getconfig/'+app.name,options)
Chris Hines's avatar
Chris Hines committed
333
                                        // .pipe(catchError(this.handleError))
Chris Hines's avatar
Chris Hines committed
334
335
}

Chris Hines's avatar
Chris Hines committed
336
337
 submissionError(error: any) {
   if (error.status != 0) {
338
339
340
341
342
       if ('error' in error && 'message' in error.error) {
         this.statusMsg.next(error.error.message);
       } else {
         this.statusMsg.next('Job submission failed');
       }
Chris Hines's avatar
Chris Hines committed
343
344
   }
 }
345
346
347
348
349
350
351
352
353
354
 cancelError(error: any) {
     console.log('error canceling job',error);
   if (error.status != 0) {
       if ('error' in error && 'message' in error.error) {
         this.statusMsg.next(error.error.message);
       } else {
         this.statusMsg.next('Job submission failed');
       }
   }
 }
Chris Hines's avatar
Chris Hines committed
355
356
357

 buildBody(app: Strudelapp, appparams?: string) {
   return JSON.stringify({'app': app, 'appparams': appparams});
Chris Hines's avatar
Chris Hines committed
358
359
 }

360
 submit(app: Strudelapp, identity: Identity, batchinterface: BatchInterface, appparams?: any) {
Chris Hines's avatar
Chris Hines committed
361
362
   let headers = new HttpHeaders();
   let options = { headers: headers, withCredentials: true};
363
   this.statusMsg.next('Submitting job');
Chris Hines's avatar
Chris Hines committed
364
   let paramstr = this.buildParams(app,identity,batchinterface);
Chris Hines's avatar
Chris Hines committed
365
   // let body = this.buildBody(app,appparams)
366
367
368
369
370
371
372
   let keys = JSON.stringify(this.authorisationService.getKeys());
   let loggedin = JSON.stringify(this.authorisationService.loggedInAuthZ.value);
   let ids = [];
     for (let id of this.computesitesService.ftidentities.value) {
         ids.push(id.copy_skip_catalog())
     }
   let body = {'app': app, 'appparams': appparams, 'keys': keys, 'ids': JSON.stringify(JSON.stringify(ids))}
Chris Hines's avatar
Chris Hines committed
373
   this.http.post<any>(this.Base+'/submit'+'?'+paramstr, body, options)
374
                                          .subscribe(resp => {
Chris Hines's avatar
Chris Hines committed
375
376
377
                                                              this.statusMsg.next(null)
                                                            },
                                                    error => this.submissionError(error));
Chris Hines's avatar
Chris Hines committed
378
379
 }

Chris Hines's avatar
Chris Hines committed
380
381
 submitted(resp: any, identity: Identity ) {
   this.getJobs(identity);
382
383
 }

384
 cancel(job: Job) {
Chris Hines's avatar
Chris Hines committed
385
386
   let headers = new HttpHeaders();
   let options = { headers: headers, withCredentials: true};
Chris Hines's avatar
Chris Hines committed
387
   // this.statusMsg.next(null);
Chris Hines's avatar
Chris Hines committed
388
   let data = {};
389
390
391
392
   let bi = new BatchInterface();
   bi.statcmd = job.identity.site.statcmd;
   bi.cancelcmd = job.identity.site.cancelcmd;
   let paramstr = this.buildParams(job.app,job.identity,bi);
393
   this.http.delete<any>(this.Base+'/cancel/'+job.jobid+'?'+paramstr, options)
394
395
         .subscribe(resp => this.submitted(resp,job.identity),
                    error => this.cancelError(error));
Chris Hines's avatar
Chris Hines committed
396
397
398
399
400
401
 }

 public watchAppwindow(appwindow, dialogRef) {
   if (appwindow.closed) {
     dialogRef.close();
   }
Chris Hines's avatar
Chris Hines committed
402
403
 }

404
 public getAppInstance(job: Job, action: AppAction) {
Chris Hines's avatar
Chris Hines committed
405
406
407
   let username = job.identity.username;
   let loginhost = job.identity.site.host;
   let batchhost = job.batch_host;
Chris Hines's avatar
Chris Hines committed
408
   let jobid = job.jobid;
Chris Hines's avatar
Chris Hines committed
409
   let params = new URLSearchParams;
410
411
   let headers = new HttpHeaders();
   let options = { headers: headers, withCredentials: true};
412
   params.set('cmd',JSON.stringify(action.paramscmd));
Chris Hines's avatar
Chris Hines committed
413
414
   let paramstr = params.toString();
   job.connectionState = 1;
Chris Hines's avatar
Chris Hines committed
415
   this.http.get<string>(this.Base+'/appinstance/'+username+'/'+loginhost+'/'+batchhost+'/'+jobid+'?'+paramstr, options)
Chris Hines's avatar
Chris Hines committed
416
                // .pipe(catchError(this.handleError))
417
     .subscribe(resp =>  { job.appinst = resp; if (action.client != null) { this.createTunnel(job, action) } else { job.connectionState = 0} },
418
             error => { this.handleAppInstanceError(job,error) })
Chris Hines's avatar
Chris Hines committed
419
420
421
422
423
424
425
426
   // let paramstr = this.buildParams(job.app,job.identity,this.batchinterface[job.identity.repr()]);
   // let headers = new HttpHeaders();
   // let options = { headers: headers, withCredentials: true};
   // this.http.get<any>(this.Base+'/getappinst/'+paramstr,options)
   //                                      .pipe(catchError(this.handleError))
   //                                      .subscribe(resp =>  { job.appinst = <StrudelappInstance>resp; this.openAppWindow(job);});
 }

427
 public createTunnel(job: Job, action: AppAction) {
Chris Hines's avatar
Chris Hines committed
428
429
430
431
432
433
   let username = job.identity.username;
   let loginhost = job.identity.site.host;
   let batchhost = job.batch_host;
   let params = new URLSearchParams;
   let headers = new HttpHeaders();
   job.connectionState = 2;
434
435
436
437
438

     //    let sleepDuration = 20;
     //var now = new Date().getTime();
     //while(new Date().getTime() < now + sleepDuration){ /* do nothing */ }

Chris Hines's avatar
Chris Hines committed
439
   let options = { headers: headers, withCredentials: true};
440
   //params.set('cmd',JSON.stringify(action.paramscmd));
Chris Hines's avatar
Chris Hines committed
441
442
   let paramstr = params.toString();
   this.http.post<string>(this.Base+'/createtunnel/'+username+'/'+loginhost+'/'+batchhost+'?'+paramstr, job.appinst, options)
443
                .subscribe(() =>  { this.getAppUrl(job, action) } )
Chris Hines's avatar
Chris Hines committed
444
 }
Chris Hines's avatar
Chris Hines committed
445

446
 public getAppUrl(job: Job, action: AppAction) {
Chris Hines's avatar
Chris Hines committed
447
448
449
   let params = new URLSearchParams;
   let headers = new HttpHeaders();
   let options = { headers: headers, withCredentials: true};
450
451
   let pseudoapp = {'client':{'redir':action.client.redir}};
   params.set('app',JSON.stringify(pseudoapp));
Chris Hines's avatar
Chris Hines committed
452
453
454
455
456
   params.set('appinst',JSON.stringify(job.appinst));
   let paramstr = params.toString();
   job.connectionState = 3;
   this.http.get<string>(this.Base+'/appurl?'+paramstr,options)
                .pipe(catchError(this.handleError))
Chris Hines's avatar
Chris Hines committed
457
                .subscribe(resp => {  job.connectionState = 0; this.openAppWindow(resp,job)});
Chris Hines's avatar
Chris Hines committed
458
459
460
461


 }

462
463
 public getInterface(job: Job, action: AppAction) {
   this.getAppInstance(job, action);
Chris Hines's avatar
Chris Hines committed
464
465
 }

Chris Hines's avatar
Chris Hines committed
466
 public openAppWindow(url: any, job: Job) {
467
468
469
     var re = /^https:\/\/([a-z0-9\.-]+)\/?/;
     let twshost = this.twsproxy.replace(re,"$1");
     let windowloc = url.replace(/\{twsproxy\}/g,this.twsproxy).replace(/twshost/g,twshost);
Chris Hines's avatar
Chris Hines committed
470
471
472

     let appwindow = window.open(windowloc);
     if (appwindow == null) {
473
474
475
         this.statusMsg.next('It looks like a window failed to open. Please check your popup blocker settings (Strudel 2 needs to be able to open a window to your application');
         return;
     }
Chris Hines's avatar
Chris Hines committed
476
477
     if (appwindow.closed) {
       return
478
     }
Chris Hines's avatar
Chris Hines committed
479
480
     this.openapps.push({'window':appwindow,'job':job})
     
Chris Hines's avatar
Chris Hines committed
481
482
 }

483
 public connect(job: Job, action: AppAction, appinst?: any) {
Chris Hines's avatar
Chris Hines committed
484
485
   let headers = new HttpHeaders();
   let options = { headers: headers, withCredentials: true};
486
   this.getInterface(job,action); // getInterface will subsequently called getAppInstance, which will call createTunnel, which will openAppWindow
Chris Hines's avatar
Chris Hines committed
487
 }
Chris Hines's avatar
Chris Hines committed
488

Chris Hines's avatar
Chris Hines committed
489
490
491
492



public postAgentData(keyCert: KeyCert) {
493
494
495
496
  let headers = new HttpHeaders();
  let options = { headers: headers, withCredentials: true};

  this.statusMsg.next("Authorising ...")
Chris Hines's avatar
Chris Hines committed
497
  let data = {'key': keyCert.key, 'cert': keyCert.cert};
Chris Hines's avatar
Chris Hines committed
498
  return this.http.post<any>(this.Base+'/sshagent',data,options)
Chris Hines's avatar
Chris Hines committed
499
                      .pipe(catchError(this.handleError))
Chris Hines's avatar
Chris Hines committed
500

501
502
}

Chris Hines's avatar
Chris Hines committed
503
public postMkDir(id: Identity, path: string, name: string ) {
504
505
  let headers = new HttpHeaders();
  let options = { headers: headers, withCredentials: true};
Chris Hines's avatar
Chris Hines committed
506
507
508
509
  let params = new URLSearchParams;
  params.set('identity',JSON.stringify(id));
  params.set('path',JSON.stringify(path));

510
  return this.http.post<any>(this.Base+'/mkdir?'+params.toString(),name, options);
511
512
}

Chris Hines's avatar
Chris Hines committed
513
public getSftpData(id: Identity, path: string, cd: string ) {
514
515
  let headers = new HttpHeaders();
  let options = { headers: headers, withCredentials: true};
Chris Hines's avatar
Chris Hines committed
516
517
518
519
  let params = new URLSearchParams;
  params.set('identity',JSON.stringify(id));
  params.set('path',JSON.stringify(path));
  params.set('cd',JSON.stringify(cd));
520

Chris Hines's avatar
Chris Hines committed
521
  return this.http.get<any>(this.Base+'/ls?'+params.toString(),options)
522
                      // .pipe(catchError(this.handleError))
523

Chris Hines's avatar
Chris Hines committed
524
525
}

Chris Hines's avatar
Chris Hines committed
526
527


528
529
public getstatusMsgSubject(): BehaviorSubject<any> {
  return this.statusMsg;
Chris Hines's avatar
Chris Hines committed
530
531
}

Chris Hines's avatar
Chris Hines committed
532
533
534
535
536
private httperror(errorstr: string) {
  var re = /login expired/gi;
  let searchresult = errorstr.search(re);
  if (searchresult != -1) {
    this.statusMsg.next("Some authentication tokens have expired, you may need to log in again");
537
    console.error(errorstr);
Chris Hines's avatar
Chris Hines committed
538
    this.authorisationService.updateAgentContents();
Chris Hines's avatar
Chris Hines committed
539
  }
540
  console.error(errorstr);
Chris Hines's avatar
Chris Hines committed
541
}
Chris Hines's avatar
Chris Hines committed
542

Chris Hines's avatar
Chris Hines committed
543
544
545
546
547
548
549
550
551
// private networkError(error: HttpErrorResponse) {
//   if (error.error instanceof ErrorEvent) {
//     console.log('network error contacting TES backend');
//   } else {
//     return error;
//   }
// }


552
private handleAppInstanceError(job: Job, error: any) {
Chris Hines's avatar
Chris Hines committed
553
    console.log(error);
554
    job.connectionState=0;
555
556
557
558
    if (error.status == 0) {
      this.statusMsg.next('It appears we had a timeout learning about your '+job.name+'. Its possible '+job.identity.site.name+' is experiencing issues');
      return;
    }
Chris Hines's avatar
Chris Hines committed
559
560
    if (error.error !== undefined && error.error.message !== undefined) {
        this.statusMsg.next(error.error.message);
Chris Hines's avatar
Chris Hines committed
561
562
    } else if (error.error !== undefined && error.error.error !== undefined) {
      this.statusMsg.next(error.error.error.msg);
563
564
565
566
567
    } else {
        this.statusMsg.next(error);
    }
}

Chris Hines's avatar
Chris Hines committed
568
private handleError(error: HttpErrorResponse) {
569
570
  console.error('in handleError');
  console.error(error);
Chris Hines's avatar
Chris Hines committed
571
572
573
574
575
576
577
578
  if (error.error instanceof ErrorEvent) {
    // A client-side or network error occurred. Handle it accordingly.
    return throwError("Hmm, that didn't work. If you're using a local connection, please make sure Strudel-TES is running.");
  } else {
    // Not sure if this code works correctly. It should update identities in case the error is
    // that the user isn't allowed to run the job

    var re = /identity/gi;
Chris Hines's avatar
Chris Hines committed
579
580
581
582
583
584
585
586
587
    if (error.error.message != undefined) {
      let searchresult = error.error.message.search(re);
      if (searchresult != -1) {
        // this.getIdentities();
        return throwError('login expired, refreshing');
      }
      return throwError(error.error.message)
    } else {
      return throwError('An error occured but I\'m not sure exactly what. Please try again latter or contact the sys admins');
Chris Hines's avatar
Chris Hines committed
588
    }
Chris Hines's avatar
Chris Hines committed
589
590
591
    // this.statusMsg.next("There was an error submitting that job. The backend gave me the message: " + error.error.message);

  }
Chris Hines's avatar
Chris Hines committed
592
}
Chris Hines's avatar
Chris Hines committed
593
594
595



Chris Hines's avatar
Chris Hines committed
596
}