Skip to content

Commit

Permalink
fix: improved logging for failed sync (#1885)
Browse files Browse the repository at this point in the history
Co-authored-by: Sebastian <sebastian.leidig@gmail.com>
  • Loading branch information
TheSlimvReal and sleidig authored Jun 5, 2023
1 parent 7114bbb commit cb7aea3
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 30 deletions.
10 changes: 10 additions & 0 deletions src/app/core/session/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { AuthUser } from "../session-service/auth-user";
* See {@link AuthProvider} for available options.
*/
export abstract class AuthService {
static readonly LAST_AUTH_KEY = "LAST_REMOTE_LOGIN";

/**
* Authenticate a user with credentials.
* @param username The username of the user
Expand All @@ -30,4 +32,12 @@ export abstract class AuthService {
* Clear the local session of the currently logged-in user.
*/
abstract logout(): Promise<void>;

/**
* Log timestamp of last successful authentication
* @protected
*/
protected logSuccessfulAuth() {
localStorage.setItem(AuthService.LAST_AUTH_KEY, new Date().toISOString());
}
}
14 changes: 9 additions & 5 deletions src/app/core/session/auth/couchdb/couchdb-auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import { firstValueFrom } from "rxjs";
import { AppSettings } from "../../../app-config/app-settings";
import { AuthUser } from "../../session-service/auth-user";
import { tap } from "rxjs/operators";

@Injectable()
export class CouchdbAuthService extends AuthService {
Expand All @@ -25,11 +26,13 @@ export class CouchdbAuthService extends AuthService {

authenticate(username: string, password: string): Promise<AuthUser> {
return firstValueFrom(
this.http.post<AuthUser>(
`${AppSettings.DB_PROXY_PREFIX}/_session`,
{ name: username, password: password },
{ withCredentials: true }
)
this.http
.post<AuthUser>(
`${AppSettings.DB_PROXY_PREFIX}/_session`,
{ name: username, password: password },
{ withCredentials: true }
)
.pipe(tap(() => this.logSuccessfulAuth()))
);
}

Expand All @@ -41,6 +44,7 @@ export class CouchdbAuthService extends AuthService {
)
).then((res: any) => {
if (res.userCtx.name) {
this.logSuccessfulAuth();
return res.userCtx;
} else {
throw new HttpErrorResponse({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export class KeycloakAuthService extends AuthService {
KeycloakAuthService.REFRESH_TOKEN_KEY,
token.refresh_token
);
this.logSuccessfulAuth();
const parsedToken = parseJwt(this.accessToken);
return {
name: parsedToken.username,
Expand Down
5 changes: 0 additions & 5 deletions src/app/core/session/session-service/remote-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import { AuthUser } from "./auth-user";
*/
@Injectable()
export class RemoteSession extends SessionService {
static readonly LAST_LOGIN_KEY = "LAST_REMOTE_LOGIN";
/** remote (!) PouchDB */
private readonly database: PouchDatabase;
private currentDBUser: AuthUser;
Expand All @@ -58,10 +57,6 @@ export class RemoteSession extends SessionService {
try {
const user = await this.authService.authenticate(username, password);
await this.handleSuccessfulLogin(user);
localStorage.setItem(
RemoteSession.LAST_LOGIN_KEY,
new Date().toISOString()
);
this.loginState.next(LoginState.LOGGED_IN);
} catch (error) {
const httpError = error as HttpErrorResponse;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,16 +267,13 @@ describe("SyncedSessionService", () => {
expect(sessionService.checkPassword("TestUser", "wrongPW")).toBeFalse();
});

it("should restart the sync if it is canceled at one point", fakeAsync(() => {
let errorCallback, completeCallback, pauseCallback;
it("should restart the sync if it fails at one point", fakeAsync(() => {
let errorCallback, pauseCallback;
const syncHandle = {
on: (action, callback) => {
if (action === "error") {
errorCallback = callback;
}
if (action === "complete") {
completeCallback = callback;
}
if (action === "paused") {
pauseCallback = callback;
}
Expand All @@ -299,21 +296,16 @@ describe("SyncedSessionService", () => {
errorCallback();
expect(syncSpy).toHaveBeenCalled();

// complete -> sync should restart
syncSpy.calls.reset();
completeCallback();
expect(syncSpy).toHaveBeenCalled();

// pause -> no restart required
syncSpy.calls.reset();
pauseCallback();
expect(syncSpy).not.toHaveBeenCalled();

// logout + complete -> no restart
// logout + error -> no restart
syncSpy.calls.reset();
sessionService.logout();
tick();
completeCallback();
errorCallback();
expect(syncSpy).not.toHaveBeenCalled();
}));

Expand Down
14 changes: 10 additions & 4 deletions src/app/core/session/session-service/synced-session.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,16 +226,22 @@ export class SyncedSessionService extends SessionService {
// replication was resumed: either because new things to sync or because connection is available again. info contains the direction
this.syncState.next(SyncState.STARTED);
})
.on("error", this.handleStoppedSync("error"))
.on("complete", this.handleStoppedSync("complete"));
.on("error", this.handleFailedSync())
.on("complete", (info) => {
this.loggingService.info(
`Live sync completed: ${JSON.stringify(info)}`
);
this.syncState.next(SyncState.COMPLETED);
});
}

private handleStoppedSync(reason: string) {
private handleFailedSync() {
return (info) => {
if (this.isLoggedIn()) {
this.syncState.next(SyncState.FAILED);
const lastAuth = localStorage.getItem(AuthService.LAST_AUTH_KEY);
this.loggingService.warn(
`Live sync stopped "${reason}": ${JSON.stringify(info)}`
`Live sync failed (last auth ${lastAuth}): ${JSON.stringify(info)}`
);
this.liveSync();
}
Expand Down
4 changes: 2 additions & 2 deletions src/app/core/support/support/support.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { SyncState } from "../../session/session-states/sync-state.enum";
import { SwUpdate } from "@angular/service-worker";
import { LOCATION_TOKEN, WINDOW_TOKEN } from "../../../utils/di-tokens";
import { TEST_USER } from "../../../utils/mocked-testing.module";
import { RemoteSession } from "../../session/session-service/remote-session";
import { ConfirmationDialogService } from "../../confirmation-dialog/confirmation-dialog.service";
import { HttpClient } from "@angular/common/http";
import { SyncedSessionService } from "../../session/session-service/synced-session.service";
Expand All @@ -23,6 +22,7 @@ import { NoopAnimationsModule } from "@angular/platform-browser/animations";
import { PouchDatabase } from "../../database/pouch-database";
import { BackupService } from "../../admin/services/backup.service";
import { DownloadService } from "../../export/download-service/download.service";
import { AuthService } from "../../session/auth/auth.service";

describe("SupportComponent", () => {
let component: SupportComponent;
Expand Down Expand Up @@ -93,7 +93,7 @@ describe("SupportComponent", () => {
const lastSync = new Date("2022-01-01").toISOString();
localStorage.setItem(SyncedSessionService.LAST_SYNC_KEY, lastSync);
const lastRemoteLogin = new Date("2022-01-02").toISOString();
localStorage.setItem(RemoteSession.LAST_LOGIN_KEY, lastRemoteLogin);
localStorage.setItem(AuthService.LAST_AUTH_KEY, lastRemoteLogin);

await component.ngOnInit();

Expand Down
5 changes: 3 additions & 2 deletions src/app/core/support/support/support.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { LOCATION_TOKEN, WINDOW_TOKEN } from "../../../utils/di-tokens";
import { SyncState } from "../../session/session-states/sync-state.enum";
import { SwUpdate } from "@angular/service-worker";
import * as Sentry from "@sentry/browser";
import { RemoteSession } from "../../session/session-service/remote-session";
import { ConfirmationDialogService } from "../../confirmation-dialog/confirmation-dialog.service";
import { HttpClient } from "@angular/common/http";
import { SyncedSessionService } from "../../session/session-service/synced-session.service";
Expand All @@ -17,6 +16,7 @@ import { PouchDatabase } from "../../database/pouch-database";
import { MatTooltipModule } from "@angular/material/tooltip";
import { BackupService } from "../../admin/services/backup.service";
import { DownloadService } from "../../export/download-service/download.service";
import { AuthService } from "../../session/auth/auth.service";

@Component({
selector: "app-support",
Expand Down Expand Up @@ -80,7 +80,7 @@ export class SupportComponent implements OnInit {

private initLastRemoteLogin() {
this.lastRemoteLogin =
localStorage.getItem(RemoteSession.LAST_LOGIN_KEY) || "never";
localStorage.getItem(AuthService.LAST_AUTH_KEY) || "never";
}

private initStorageInfo() {
Expand Down Expand Up @@ -131,6 +131,7 @@ export class SupportComponent implements OnInit {
swLog: this.swLog,
storageInfo: this.storageInfo,
dbInfo: this.dbInfo,
timestamp: new Date().toISOString(),
},
});
Sentry.showReportDialog({
Expand Down

0 comments on commit cb7aea3

Please sign in to comment.