mempool/frontend/src/app/services/navigation.service.ts

111 lines
3.8 KiB
TypeScript
Raw Normal View History

2022-10-12 22:13:29 +00:00
import { Injectable } from '@angular/core';
2024-06-15 00:22:33 +02:00
import { Router, NavigationEnd, ActivatedRouteSnapshot } from '@angular/router';
2022-10-12 22:13:29 +00:00
import { BehaviorSubject } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import { StateService } from './state.service';
2024-07-12 09:29:21 +00:00
import { RelativeUrlPipe } from '../shared/pipes/relative-url/relative-url.pipe';
2022-10-12 22:13:29 +00:00
@Injectable({
providedIn: 'root'
})
export class NavigationService {
subnetPaths = new BehaviorSubject<Record<string,string>>({});
2024-06-15 00:22:33 +02:00
networkModules = {
bitcoin: {
subnets: [
{ name: 'mainnet', path: '' },
2024-06-16 10:50:31 +02:00
{ name: 'testnet', path: this.stateService.env.ROOT_NETWORK === 'testnet' ? '/' : '/testnet' },
{ name: 'testnet4', path: this.stateService.env.ROOT_NETWORK === 'testnet4' ? '/' : '/testnet4' },
{ name: 'signet', path: this.stateService.env.ROOT_NETWORK === 'signet' ? '/' : '/signet' },
2024-06-15 00:22:33 +02:00
],
},
liquid: {
subnets: [
{ name: 'liquid', path: '' },
{ name: 'liquidtestnet', path: '/testnet' },
],
}
};
networks = Object.keys(this.networkModules);
initialLoad = true;
2022-10-12 22:13:29 +00:00
constructor(
private stateService: StateService,
private router: Router,
2024-07-12 09:29:21 +00:00
private relativeUrlPipe: RelativeUrlPipe,
2022-10-12 22:13:29 +00:00
) {
this.router.events.pipe(
filter(event => event instanceof NavigationEnd),
map(() => this.router.routerState.snapshot.root),
).subscribe((state) => {
2024-07-12 09:29:21 +00:00
if (this.enforceSubnetRestrictions(state)) {
this.updateSubnetPaths(state);
}
if (this.initialLoad) {
this.initialLoad = false;
}
this.updateSubnetPaths(state);
2022-10-12 22:13:29 +00:00
});
}
2024-07-12 09:29:21 +00:00
enforceSubnetRestrictions(root: ActivatedRouteSnapshot): boolean {
let route = root;
while (route) {
if (route.data.onlySubnet && !route.data.onlySubnet.includes(this.stateService.network)) {
this.router.navigate([this.relativeUrlPipe.transform('')]);
return false;
}
route = route.firstChild;
}
return true;
}
2024-03-17 18:22:38 +09:00
// For each network (bitcoin/liquid), find and save the longest url path compatible with the current route
2022-10-12 22:13:29 +00:00
updateSubnetPaths(root: ActivatedRouteSnapshot): void {
let path = '';
const networkPaths = {};
let route = root;
// traverse the router state tree until all network paths are set, or we reach the end of the tree
2024-06-15 00:22:33 +02:00
while (!this.networks.reduce((acc, network) => acc && !!networkPaths[network], true) && route) {
2022-10-12 22:13:29 +00:00
// 'networkSpecific' paths may correspond to valid routes on other networks, but aren't directly compatible
// (e.g. we shouldn't link a mainnet transaction page to the same txid on testnet or liquid)
if (route.data?.networkSpecific) {
2024-06-15 00:22:33 +02:00
this.networks.forEach(network => {
2022-10-12 22:13:29 +00:00
if (networkPaths[network] == null) {
networkPaths[network] = path;
}
});
}
// null or empty networks list is shorthand for "compatible with every network"
if (route.data?.networks?.length) {
// if the list is non-empty, only those networks are compatible
2024-06-15 00:22:33 +02:00
this.networks.forEach(network => {
2022-10-12 22:13:29 +00:00
if (!route.data.networks.includes(network)) {
if (networkPaths[network] == null) {
networkPaths[network] = path;
}
}
});
}
if (route.url?.length) {
path = [path, ...route.url.map(segment => segment.path).filter(path => {
2024-05-06 15:40:32 +00:00
return path.length && !['testnet', 'testnet4', 'signet'].includes(path);
2022-10-12 22:13:29 +00:00
})].join('/');
}
route = route.firstChild;
}
const subnetPaths = {};
2024-06-15 00:22:33 +02:00
Object.entries(this.networkModules).forEach(([key, network]) => {
2022-10-12 22:13:29 +00:00
network.subnets.forEach(subnet => {
subnetPaths[subnet.name] = subnet.path + (networkPaths[key] != null ? networkPaths[key] : path);
});
});
this.subnetPaths.next(subnetPaths);
}
isInitialLoad(): boolean {
return this.initialLoad;
}
2022-10-12 22:13:29 +00:00
}