Spaces:
Running
Running
File size: 6,055 Bytes
1bc149f 27e40c0 1bc149f 27e40c0 1bc149f 27e40c0 1bc149f 27e40c0 1bc149f 27e40c0 1bc149f 27e40c0 1bc149f 27e40c0 1bc149f 27e40c0 1bc149f 27e40c0 1bc149f 27e40c0 1bc149f 88bf46c 27e40c0 88bf46c 27e40c0 88bf46c 27e40c0 88bf46c 27e40c0 88bf46c 27e40c0 88bf46c 27e40c0 88bf46c 27e40c0 88bf46c 27e40c0 88bf46c 1bc149f |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
import { Injectable } from '@angular/core';
import { environment } from '../../../environments/environment';
import {BehaviorSubject, Observable, OperatorFunction, shareReplay, throwError, timer} from 'rxjs';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { StateModel } from '../models/state.model';
import { AuthenticationService } from './authentication.service';
import { catchError, retry } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class AppStateService {
private readonly _apiUrl = environment.apiUrl;
private readonly _state = new BehaviorSubject<StateModel>({
leaderboards: [],
submissions: [],
datasets: [],
tasks: [],
controlPanelSubmissions: [],
adminSessionStatus: '',
});
public readonly state$ = this._state.asObservable();
constructor(public http: HttpClient, public authService: AuthenticationService) {
console.log(this._apiUrl);
this.refreshTasks();
this.refreshDatasets();
this.refreshLeaderboards();
this.refreshSubmissions();
authService.$authStatus.subscribe((status: string) => {
this._setState({
...this.getState(),
adminSessionStatus: status,
});
});
}
private _setState(state: StateModel): void {
this._state.next(state);
}
public getState(): StateModel {
return this._state.getValue();
}
private makeRequest<T>(request: Observable<T>, stateKey?: keyof StateModel, callback?: (data: any) => void) {
let obs = request.pipe(
this.retryStrategy(),
shareReplay(1),
catchError(this.handleRequestError.bind(this))
);
obs.subscribe(
(data) => {
if (callback) {
callback(data);
} else if (stateKey) {
this._setState({
...this.getState(),
[stateKey]: data
});
}
}
);
return obs;
}
private handleRequestError(error: any): Observable<never> {
let errorMessage = 'An unknown error occurred!';
if (error.error instanceof ErrorEvent) {
errorMessage = `Client Error: ${error.error.message}`;
} else {
switch (error.status) {
case 400:
errorMessage = `Bad Request: ${error.message}`;
break;
case 401:
errorMessage = 'Unauthorized: Please log in again.';
this.authService.logout();
break;
case 404:
errorMessage = `Not Found: The requested resource was not found.`;
break;
case 500:
errorMessage = `Internal Server Error: Please try again later.`;
break;
case 503:
errorMessage = `Service Unavailable: Please try again later.`;
break;
default:
errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
break;
}
}
// Rethrow the error so it can be handled globally
return throwError(() => new Error(errorMessage));
}
// Improved retry strategy with exponential backoff and jitter
private retryStrategy<T>() {
return <OperatorFunction<T, T>>((source) =>
source.pipe(
retry({
count: 3, // Maximum of 3 retry attempts
delay: (error, retryCount) => {
if (![500, 503].includes(error.status)) {
// Do not retry for errors other than 500 and 503
return throwError(() => error);
}
// Exponential backoff with jitter
const jitter = Math.random() * 500; // Jitter value between 0-500ms
const backoffDelay = Math.pow(2, retryCount) * 1000 + jitter; // Exponential backoff
console.log(`Retrying request after ${backoffDelay}ms (attempt #${retryCount})`);
return timer(backoffDelay);
}
})
)
);
}
// ========================
// Public API
// ========================
public submit(
modelName: string,
modelLink: string,
teamName: string,
contactEmail: string,
task: string,
dataset: string,
isPublic: boolean,
fileContent: string
) {
return this.makeRequest(
this.http.post<Object>(`${this._apiUrl}/submission/${task}/${dataset}`, {
modelName,
modelLink,
teamName,
contactEmail,
isPublic,
fileContent,
})
);
}
public refreshTasks() {
return this.makeRequest(this.http.get(this._apiUrl + '/tasks'), 'tasks');
}
public refreshDatasets() {
return this.makeRequest(this.http.get(this._apiUrl + '/datasets'), 'datasets');
}
public refreshLeaderboards() {
return this.makeRequest(this.http.get(this._apiUrl + '/leaderboards'), 'leaderboards');
}
public refreshSubmissions() {
return this.makeRequest(this.http.get(this._apiUrl + '/submissions'), 'submissions');
}
public authenticate(password: string) {
let obs = this.authService.login(password);
obs.subscribe(
next => {
console.log('Login successful');
this._setState({
...this.getState(),
adminSessionStatus: 'authenticated',
});
});
return obs;
}
public refreshControlPanel() {
const headers = this.authService.getAuthHeaders();
return this.makeRequest(
this.http.get(`${this._apiUrl}/control-panel-submissions`, { headers }),
'controlPanelSubmissions'
);
}
public updateSubmission(entry: any) {
const headers = this.authService.getAuthHeaders();
return this.makeRequest(
this.http.put(`${this._apiUrl}/submission/${entry.id}`, entry, { headers }),
undefined,
() => this.refreshControlPanel() // Refresh control panel after update
);
}
public deleteSubmission(id: number) {
const headers = this.authService.getAuthHeaders();
return this.makeRequest(
this.http.delete(`${this._apiUrl}/submission/${id}`, { headers }),
undefined,
() => this.refreshControlPanel() // Refresh control panel after deletion
);
}
}
|