mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-01-29 15:43:58 +00:00
Handle case when server is unavailable, Ref: #146
This commit is contained in:
parent
ed84799ed1
commit
0cc0b765b5
@ -40,7 +40,7 @@ import { ProjectService } from './services/project.service';
|
||||
import { SymbolService } from "./services/symbol.service";
|
||||
import { ServerService } from "./services/server.service";
|
||||
import { IndexedDbService } from "./services/indexed-db.service";
|
||||
import { HttpServer } from "./services/http-server.service";
|
||||
import { HttpServer, ServerErrorHandler } from "./services/http-server.service";
|
||||
import { SnapshotService } from "./services/snapshot.service";
|
||||
import { ProgressDialogService } from "./common/progress-dialog/progress-dialog.service";
|
||||
import { NodeService } from "./services/node.service";
|
||||
@ -80,13 +80,20 @@ import { ProgressComponent } from './common/progress/progress.component';
|
||||
import { ProgressService } from "./common/progress/progress.service";
|
||||
import { version } from "./version";
|
||||
import { ToasterErrorHandler } from "./toaster-error-handler";
|
||||
import { environment } from "../environments/environment";
|
||||
import { RavenState } from "./raven-state-communicator";
|
||||
|
||||
|
||||
Raven
|
||||
.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', {
|
||||
release: version
|
||||
})
|
||||
.install();
|
||||
if (environment.production) {
|
||||
Raven
|
||||
.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', {
|
||||
shouldSendCallback: () => {
|
||||
return RavenState.shouldSend;
|
||||
},
|
||||
release: version
|
||||
})
|
||||
.install();
|
||||
}
|
||||
|
||||
|
||||
@NgModule({
|
||||
@ -166,7 +173,8 @@ Raven
|
||||
SymbolsDataSource,
|
||||
SelectionManager,
|
||||
InRectangleHelper,
|
||||
DrawingsDataSource
|
||||
DrawingsDataSource,
|
||||
ServerErrorHandler
|
||||
],
|
||||
entryComponents: [
|
||||
AddServerDialogComponent,
|
||||
|
@ -31,11 +31,11 @@ describe('RavenErrorHandler', () => {
|
||||
it('should handle error', () => {
|
||||
settingsService.set('crash_reports', true);
|
||||
environment.production = true;
|
||||
expect(handler.shouldSend()()).toBeTruthy();
|
||||
expect(handler.shouldSend()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not handle when crash reports are disabled', () => {
|
||||
settingsService.set('crash_reports', false);
|
||||
expect(handler.shouldSend()()).toBeFalsy();
|
||||
expect(handler.shouldSend()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
@ -1,24 +1,21 @@
|
||||
import * as Raven from 'raven-js';
|
||||
|
||||
import { ErrorHandler, Inject, Injector } from "@angular/core";
|
||||
|
||||
import { SettingsService } from "./services/settings.service";
|
||||
import { environment } from "../environments/environment";
|
||||
import { RavenState } from "./raven-state-communicator";
|
||||
|
||||
|
||||
export class RavenErrorHandler implements ErrorHandler {
|
||||
constructor(@Inject(Injector) protected injector: Injector) {}
|
||||
|
||||
handleError(err: any): void {
|
||||
Raven.setShouldSendCallback(this.shouldSend());
|
||||
RavenState.shouldSend = this.shouldSend();
|
||||
|
||||
console.error(err.originalError || err);
|
||||
}
|
||||
|
||||
shouldSend() {
|
||||
return () => {
|
||||
const settingsService: SettingsService = this.injector.get(SettingsService);
|
||||
return environment.production && settingsService.get('crash_reports');
|
||||
};
|
||||
const settingsService: SettingsService = this.injector.get(SettingsService);
|
||||
return environment.production && settingsService.get('crash_reports');
|
||||
}
|
||||
}
|
||||
|
5
src/app/raven-state-communicator.ts
Normal file
5
src/app/raven-state-communicator.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export class RavenStateCommunicator {
|
||||
public shouldSend = true;
|
||||
};
|
||||
|
||||
export var RavenState = new RavenStateCommunicator();
|
@ -5,6 +5,7 @@ import { HttpClient } from "@angular/common/http";
|
||||
import { ApplianceService } from './appliance.service';
|
||||
import { Server } from '../models/server';
|
||||
import { HttpServer } from './http-server.service';
|
||||
import { AppTestingModule } from "../testing/app-testing/app-testing.module";
|
||||
|
||||
|
||||
|
||||
@ -16,7 +17,8 @@ describe('ApplianceService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
HttpClientTestingModule
|
||||
HttpClientTestingModule,
|
||||
AppTestingModule
|
||||
],
|
||||
providers: [
|
||||
ApplianceService,
|
||||
|
@ -5,6 +5,7 @@ import { HttpClient } from "@angular/common/http";
|
||||
import { Server } from '../models/server';
|
||||
import { HttpServer } from './http-server.service';
|
||||
import { getTestServer } from './testing';
|
||||
import { AppTestingModule } from "../testing/app-testing/app-testing.module";
|
||||
|
||||
class MyType {
|
||||
id: number;
|
||||
@ -20,7 +21,8 @@ describe('HttpServer', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
HttpClientTestingModule
|
||||
HttpClientTestingModule,
|
||||
AppTestingModule
|
||||
],
|
||||
providers: [
|
||||
HttpServer
|
||||
|
@ -1,8 +1,11 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {HttpHeaders, HttpClient, HttpParams} from '@angular/common/http';
|
||||
import { HttpHeaders, HttpClient, HttpParams, HttpErrorResponse } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
import {Server} from "../models/server";
|
||||
import { catchError } from "rxjs/operators";
|
||||
|
||||
import 'rxjs/add/observable/throw'
|
||||
|
||||
|
||||
/* tslint:disable:interface-over-type-literal */
|
||||
@ -40,57 +43,104 @@ export type HeadersOptions = {
|
||||
/* tslint:enable:interface-over-type-literal */
|
||||
|
||||
|
||||
export class ServerError extends Error {
|
||||
public originalError: Error;
|
||||
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
static fromError(message: string, originalError: Error) {
|
||||
const serverError = new ServerError(message);
|
||||
serverError.originalError = originalError;
|
||||
return serverError;
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class ServerErrorHandler {
|
||||
handleError(error: HttpErrorResponse) {
|
||||
let err: Error = error;
|
||||
|
||||
if (error.name === 'HttpErrorResponse' && error.status === 0) {
|
||||
err = ServerError.fromError("Server is unreachable", error);
|
||||
}
|
||||
|
||||
return Observable.throw(err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class HttpServer {
|
||||
|
||||
constructor(private http: HttpClient) { }
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
private errorHandler: ServerErrorHandler
|
||||
) { }
|
||||
|
||||
get<T>(server: Server, url: string, options?: JsonOptions): Observable<T> {
|
||||
options = this.getJsonOptions(options);
|
||||
const intercepted = this.getOptionsForServer<JsonOptions>(server, url, options);
|
||||
return this.http.get<T>(intercepted.url, intercepted.options as JsonOptions);
|
||||
return this.http
|
||||
.get<T>(intercepted.url, intercepted.options as JsonOptions)
|
||||
.pipe(catchError<T, any>(this.errorHandler.handleError));
|
||||
}
|
||||
|
||||
getText(server: Server, url: string, options?: TextOptions): Observable<string> {
|
||||
options = this.getTextOptions(options);
|
||||
const intercepted = this.getOptionsForServer<TextOptions>(server, url, options);
|
||||
return this.http.get(intercepted.url, intercepted.options as TextOptions);
|
||||
return this.http
|
||||
.get(intercepted.url, intercepted.options as TextOptions)
|
||||
.pipe(catchError(this.errorHandler.handleError));
|
||||
}
|
||||
|
||||
post<T>(server: Server, url: string, body: any | null, options?: JsonOptions): Observable<T> {
|
||||
options = this.getJsonOptions(options);
|
||||
const intercepted = this.getOptionsForServer(server, url, options);
|
||||
return this.http.post<T>(intercepted.url, body, intercepted.options);
|
||||
return this.http
|
||||
.post<T>(intercepted.url, body, intercepted.options)
|
||||
.pipe(catchError<T, any>(this.errorHandler.handleError));
|
||||
}
|
||||
|
||||
put<T>(server: Server, url: string, body: any, options?: JsonOptions): Observable<T> {
|
||||
options = this.getJsonOptions(options);
|
||||
const intercepted = this.getOptionsForServer(server, url, options);
|
||||
return this.http.put<T>(intercepted.url, body, intercepted.options);
|
||||
return this.http
|
||||
.put<T>(intercepted.url, body, intercepted.options)
|
||||
.pipe(catchError<T, any>(this.errorHandler.handleError));
|
||||
}
|
||||
|
||||
delete<T>(server: Server, url: string, options?: JsonOptions): Observable<T> {
|
||||
options = this.getJsonOptions(options);
|
||||
const intercepted = this.getOptionsForServer(server, url, options);
|
||||
return this.http.delete<T>(intercepted.url, intercepted.options);
|
||||
return this.http
|
||||
.delete<T>(intercepted.url, intercepted.options)
|
||||
.pipe(catchError<T, any>(this.errorHandler.handleError));
|
||||
}
|
||||
|
||||
patch<T>(server: Server, url: string, body: any, options?: JsonOptions): Observable<T> {
|
||||
options = this.getJsonOptions(options);
|
||||
const intercepted = this.getOptionsForServer(server, url, options);
|
||||
return this.http.patch<T>(intercepted.url, body, intercepted.options);
|
||||
return this.http
|
||||
.patch<T>(intercepted.url, body, intercepted.options)
|
||||
.pipe(catchError<T, any>(this.errorHandler.handleError));
|
||||
}
|
||||
|
||||
head<T>(server: Server, url: string, options?: JsonOptions): Observable<T> {
|
||||
options = this.getJsonOptions(options);
|
||||
const intercepted = this.getOptionsForServer(server, url, options);
|
||||
return this.http.head<T>(intercepted.url, intercepted.options);
|
||||
return this.http
|
||||
.head<T>(intercepted.url, intercepted.options)
|
||||
.pipe(catchError<T, any>(this.errorHandler.handleError));
|
||||
}
|
||||
|
||||
options<T>(server: Server, url: string, options?: JsonOptions): Observable<T> {
|
||||
options = this.getJsonOptions(options);
|
||||
const intercepted = this.getOptionsForServer(server, url, options);
|
||||
return this.http.options<T>(intercepted.url, intercepted.options);
|
||||
return this.http
|
||||
.options<T>(intercepted.url, intercepted.options)
|
||||
.pipe(catchError<T, any>(this.errorHandler.handleError));
|
||||
}
|
||||
|
||||
private getJsonOptions(options: JsonOptions): JsonOptions {
|
||||
|
@ -8,6 +8,7 @@ import { Server } from '../models/server';
|
||||
import { Node } from '../cartography/models/node';
|
||||
import { Port } from '../models/port';
|
||||
import { getTestServer } from './testing';
|
||||
import { AppTestingModule } from "../testing/app-testing/app-testing.module";
|
||||
|
||||
describe('LinkService', () => {
|
||||
let httpClient: HttpClient;
|
||||
@ -19,7 +20,8 @@ describe('LinkService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
HttpClientTestingModule
|
||||
HttpClientTestingModule,
|
||||
AppTestingModule
|
||||
],
|
||||
providers: [
|
||||
HttpServer,
|
||||
|
@ -5,11 +5,11 @@ import { HttpTestingController, HttpClientTestingModule } from '@angular/common/
|
||||
import { HttpServer } from './http-server.service';
|
||||
import { Server } from '../models/server';
|
||||
import { Node } from '../cartography/models/node';
|
||||
import { Port } from '../models/port';
|
||||
import { getTestServer } from './testing';
|
||||
import { NodeService } from './node.service';
|
||||
import { Appliance } from '../models/appliance';
|
||||
import { Project } from '../models/project';
|
||||
import { AppTestingModule } from "../testing/app-testing/app-testing.module";
|
||||
|
||||
describe('NodeService', () => {
|
||||
let httpClient: HttpClient;
|
||||
@ -21,7 +21,8 @@ describe('NodeService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
HttpClientTestingModule
|
||||
HttpClientTestingModule,
|
||||
AppTestingModule
|
||||
],
|
||||
providers: [
|
||||
HttpServer,
|
||||
|
@ -10,6 +10,7 @@ import { SettingsService } from "./settings.service";
|
||||
import { MockedSettingsService } from "./settings.service.spec";
|
||||
import { Observable } from "rxjs/Observable";
|
||||
import { Project } from "../models/project";
|
||||
import { AppTestingModule } from "../testing/app-testing/app-testing.module";
|
||||
|
||||
|
||||
/**
|
||||
@ -47,7 +48,8 @@ describe('ProjectService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
HttpClientTestingModule
|
||||
HttpClientTestingModule,
|
||||
AppTestingModule
|
||||
],
|
||||
providers: [
|
||||
HttpServer,
|
||||
|
@ -4,11 +4,10 @@ import { HttpClient } from '@angular/common/http';
|
||||
import { HttpTestingController, HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { HttpServer } from './http-server.service';
|
||||
import { Server } from '../models/server';
|
||||
import { Node } from '../cartography/models/node';
|
||||
import { Port } from '../models/port';
|
||||
import { getTestServer } from './testing';
|
||||
import { SnapshotService } from './snapshot.service';
|
||||
import { Snapshot } from '../models/snapshot';
|
||||
import { AppTestingModule } from "../testing/app-testing/app-testing.module";
|
||||
|
||||
|
||||
describe('SnapshotService', () => {
|
||||
@ -21,7 +20,8 @@ describe('SnapshotService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
HttpClientTestingModule
|
||||
HttpClientTestingModule,
|
||||
AppTestingModule
|
||||
],
|
||||
providers: [
|
||||
HttpServer,
|
||||
|
@ -7,6 +7,7 @@ import { Server } from '../models/server';
|
||||
import { getTestServer } from './testing';
|
||||
import { SymbolService } from './symbol.service';
|
||||
import { Symbol } from '../cartography/models/symbol';
|
||||
import { AppTestingModule } from "../testing/app-testing/app-testing.module";
|
||||
|
||||
|
||||
describe('SymbolService', () => {
|
||||
@ -19,7 +20,8 @@ describe('SymbolService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
HttpClientTestingModule
|
||||
HttpClientTestingModule,
|
||||
AppTestingModule
|
||||
],
|
||||
providers: [
|
||||
HttpServer,
|
||||
|
@ -8,6 +8,7 @@ import { Node } from '../cartography/models/node';
|
||||
import { Port } from '../models/port';
|
||||
import { getTestServer } from './testing';
|
||||
import { VersionService } from './version.service';
|
||||
import { AppTestingModule } from "../testing/app-testing/app-testing.module";
|
||||
|
||||
|
||||
describe('VersionService', () => {
|
||||
@ -20,7 +21,8 @@ describe('VersionService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
HttpClientTestingModule
|
||||
HttpClientTestingModule,
|
||||
AppTestingModule
|
||||
],
|
||||
providers: [
|
||||
HttpServer,
|
||||
|
14
src/app/testing/app-testing/app-testing.module.ts
Normal file
14
src/app/testing/app-testing/app-testing.module.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ServerErrorHandler } from "../../services/http-server.service";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule
|
||||
],
|
||||
declarations: [],
|
||||
providers: [
|
||||
ServerErrorHandler
|
||||
]
|
||||
})
|
||||
export class AppTestingModule { }
|
@ -3,6 +3,8 @@ import { ToasterService } from "./services/toaster.service";
|
||||
import { MockedToasterService } from "./services/toaster.service.spec";
|
||||
import { ToasterErrorHandler } from "./toaster-error-handler";
|
||||
import { RavenErrorHandler } from "./raven-error-handler";
|
||||
import { SettingsService } from "./services/settings.service";
|
||||
import { MockedSettingsService } from "./services/settings.service.spec";
|
||||
|
||||
|
||||
describe('ToasterErrorHandler', () => {
|
||||
@ -13,6 +15,7 @@ describe('ToasterErrorHandler', () => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{ provide: ToasterService, useClass: MockedToasterService },
|
||||
{ provide: SettingsService, useClass: MockedSettingsService },
|
||||
RavenErrorHandler,
|
||||
ToasterErrorHandler,
|
||||
]
|
||||
|
@ -8,8 +8,7 @@ export class ToasterErrorHandler extends RavenErrorHandler {
|
||||
super.handleError(err);
|
||||
|
||||
const toasterService = this.injector.get(ToasterService);
|
||||
const error = err.originalError || err;
|
||||
toasterService.error(error.message);
|
||||
toasterService.error(err.message);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6526,8 +6526,8 @@ range-parser@^1.0.3, range-parser@^1.2.0, range-parser@~1.2.0:
|
||||
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
|
||||
|
||||
raven-js@^3.24.1:
|
||||
version "3.25.1"
|
||||
resolved "https://registry.yarnpkg.com/raven-js/-/raven-js-3.25.1.tgz#05df39b41af140e3b2fa34e2c522e2b4f99a98be"
|
||||
version "3.26.3"
|
||||
resolved "https://registry.yarnpkg.com/raven-js/-/raven-js-3.26.3.tgz#0efb49969b5b11ab965f7b0d6da4ca102b763cb0"
|
||||
|
||||
raven@^2.6.0:
|
||||
version "2.6.1"
|
||||
|
Loading…
x
Reference in New Issue
Block a user