-
Chris Hines authoredChris Hines authored
browser-window.service.ts 5.67 KiB
/*
* The browser window service deals with opening a new window
* once all the tunnels are setup.
* It also monitors for that window being closed and displays a dialog
* in case it is (prompting to terminate the process)
* Temination occurs by setting an rxjs Subject which must be subscribe to
* by launcher-dialog which will in turn call TES service cancel
*/
import { Injectable } from '@angular/core';
import { Job } from './job';
import { AppAction, Strudelapp, StrudelappInstance } from './strudelapp';
import {BackendSelectionService} from './backend-selection.service';
import {repeat, take, takeUntil, filter, catchError, map, tap} from 'rxjs/operators';
import {timer, interval, Subject, BehaviorSubject, of} from 'rxjs';
import { ModaldialogComponent } from './modaldialog/modaldialog.component';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material';
import {NotificationsService } from './notifications.service';
import { HttpClientModule, HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { SettingsService } from './settings.service';
import { environment } from '../environments/environment';
@Injectable({
providedIn: 'root'
})
export class BrowserWindowService {
private twsproxy: string;
private Base: string;
private authdone$: Subject<boolean>;
private openapps: any[];
public cancelJob$: Subject<Job>;
constructor(private backendSelectionService: BackendSelectionService,
public dialog: MatDialog,
private notifications: NotificationsService,
private http: HttpClient,
private settingsService: SettingsService) {
this.backendSelectionService.apiserver.subscribe( (value) => { if (value != null) {this.twsproxy = value.tws ; this.Base = value.tes }});
this.authdone$ = new Subject<boolean>();
this.openapps = [];
this.cancelJob$ = new Subject<Job>();
timer(500).pipe(repeat()).subscribe(() => this.checkWindows());
timer(environment.loginterval).pipe(repeat()).subscribe(() => this.logUsage());
}
private windowLoaded(window: any, location: string): boolean {
try {
if (window.location.toString() == location) {
return true;
}
return false;
} catch {
return true;
}
}
public openAppWindow( job: Job, url: any, basicAuth: boolean, action: AppAction, appinst: any ) {
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);
var authwindow = null;
console.log('openAppWindow entered');
if (basicAuth) {
let authwindowloc = windowloc.replace(/^https:\/\//,'https://'+appinst.username+':'+appinst.password+'@');
authwindow = window.open(authwindowloc);
this.authdone$.pipe(take(1)).subscribe( () => { authwindow.close() ; this.finishAppWindow(windowloc,job,action) });
interval(500).pipe(takeUntil(this.authdone$),filter((v) => this.windowLoaded(authwindow, authwindowloc))).subscribe( () => this.authdone$.next(true));
return
}
if (action.postData !== undefined && action.postData !== null) {
let params = {}
for (let k in action.postData) {
params[k] = action.postData[k].replace(/\{password\}/g,appinst.password).replace(/\{username\}/g,appinst.username);
}
this.openWindowWithPostRequest(windowloc,params);
return
}
this.finishAppWindow(windowloc,job, action);
}
public openWindowWithPostRequest(url: string, params: any) {
var winName='MyWindow';
var form = document.createElement("form");
form.setAttribute("method", "post");
form.setAttribute("action", url);
form.setAttribute("target",winName);
for (var i in params) {
if (params.hasOwnProperty(i)) {
var input = document.createElement('input');
input.type = 'hidden';
input.name = i;
input.value = params[i];
form.appendChild(input);
}
}
document.body.appendChild(form);
window.open('', winName);
form.target = winName;
form.submit();
document.body.removeChild(form);
}
public logUsage() {
var app: any;
if (this.settingsService.logging) {
this.openapps.forEach( (app,index) => {
if (!app.window.closed) {
if (app.job.state == 'RUNNING') {
this.http.get<any>(environment.logserver+"/"+app.job.identity.site.name+"/"+app.job.identity.username+"/"+app.job.app.name+"/"+app.job.jobid).pipe( //We're expecting 404 not founds
catchError((e) => {return of([]);})
).subscribe((_) => {return})
}
}
})
}
}
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) {
this.cancelJob$.next(job);
}});
}
this.openapps.splice(index,1);
}
})
}
public finishAppWindow(windowloc: any, job:Job, action: AppAction) {
let appwindow = window.open(windowloc);
if (appwindow == null) {
this.notifications.notify('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;
}
if (appwindow.closed) {
return
}
if (action.name == "Connect") { // actions like viewing logs don't cause us to monitor for the window closing. Only actions like connecting to desktops/jupyter labs
this.openapps.push({'window':appwindow,'job':job})
}
}
}