Skip to content

Commit 269a4a5

Browse files
committed
dirty: assets-controller
1 parent b61595c commit 269a4a5

34 files changed

Lines changed: 13841 additions & 8 deletions

packages/assets-controllers/src/AssetsController/AssetsController.ts

Lines changed: 1519 additions & 0 deletions
Large diffs are not rendered by default.

packages/assets-controllers/src/AssetsController/README.md

Lines changed: 928 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import type { ChainId, DataRequest, DataResponse } from '../types';
2+
3+
// ============================================================================
4+
// DATA SOURCE BASE TYPES
5+
// ============================================================================
6+
7+
/**
8+
* Subscription request from AssetsController.
9+
*/
10+
export interface SubscriptionRequest {
11+
request: DataRequest;
12+
subscriptionId: string;
13+
isUpdate: boolean;
14+
}
15+
16+
/**
17+
* Base state for all data sources.
18+
*/
19+
export interface DataSourceState {
20+
/** Currently active chains (supported AND available) */
21+
activeChains: ChainId[];
22+
}
23+
24+
// ============================================================================
25+
// ABSTRACT DATA SOURCE
26+
// ============================================================================
27+
28+
/**
29+
* Abstract base class for data sources.
30+
*
31+
* Data sources communicate with AssetsController via Messenger:
32+
* - Register actions that AssetsController can call
33+
* - Publish events that AssetsController subscribes to
34+
*/
35+
export abstract class AbstractDataSource<
36+
Name extends string,
37+
State extends DataSourceState = DataSourceState,
38+
> {
39+
protected readonly name: Name;
40+
protected state: State;
41+
42+
/** Active subscriptions by ID */
43+
protected readonly activeSubscriptions: Map<
44+
string,
45+
{ cleanup: () => void; chains: ChainId[] }
46+
> = new Map();
47+
48+
constructor(name: Name, initialState: State) {
49+
this.name = name;
50+
this.state = initialState;
51+
}
52+
53+
/**
54+
* Get the data source name/ID.
55+
*/
56+
getName(): Name {
57+
return this.name;
58+
}
59+
60+
/**
61+
* Get currently active chains (supported AND available).
62+
*/
63+
async getActiveChains(): Promise<ChainId[]> {
64+
return this.state.activeChains;
65+
}
66+
67+
/**
68+
* Subscribe to updates for the given request.
69+
*/
70+
abstract subscribe(request: SubscriptionRequest): Promise<void>;
71+
72+
/**
73+
* Unsubscribe from updates.
74+
*/
75+
async unsubscribe(subscriptionId: string): Promise<void> {
76+
const subscription = this.activeSubscriptions.get(subscriptionId);
77+
if (subscription) {
78+
subscription.cleanup();
79+
this.activeSubscriptions.delete(subscriptionId);
80+
}
81+
}
82+
83+
/**
84+
* Update active chains and notify listeners only if changed.
85+
*/
86+
protected updateActiveChains(
87+
chains: ChainId[],
88+
publishEvent: (chains: ChainId[]) => void,
89+
): void {
90+
const previousChains = new Set(this.state.activeChains);
91+
const newChains = new Set(chains);
92+
93+
// Check if chains have actually changed
94+
const hasChanges =
95+
previousChains.size !== newChains.size ||
96+
chains.some((chain) => !previousChains.has(chain));
97+
98+
// Always update state
99+
this.state.activeChains = chains;
100+
101+
// Only publish event if there are actual changes
102+
if (hasChanges) {
103+
publishEvent(chains);
104+
}
105+
}
106+
107+
/**
108+
* Add a chain to active chains.
109+
*/
110+
protected addActiveChain(
111+
chainId: ChainId,
112+
publishEvent: (chains: ChainId[]) => void,
113+
): void {
114+
if (!this.state.activeChains.includes(chainId)) {
115+
this.state.activeChains = [...this.state.activeChains, chainId];
116+
publishEvent(this.state.activeChains);
117+
}
118+
}
119+
120+
/**
121+
* Remove a chain from active chains.
122+
*/
123+
protected removeActiveChain(
124+
chainId: ChainId,
125+
publishEvent: (chains: ChainId[]) => void,
126+
): void {
127+
if (this.state.activeChains.includes(chainId)) {
128+
this.state.activeChains = this.state.activeChains.filter(
129+
(c) => c !== chainId,
130+
);
131+
publishEvent(this.state.activeChains);
132+
}
133+
}
134+
135+
/**
136+
* Destroy the data source and clean up resources.
137+
*/
138+
destroy(): void {
139+
for (const subscription of this.activeSubscriptions.values()) {
140+
subscription.cleanup();
141+
}
142+
this.activeSubscriptions.clear();
143+
}
144+
}

0 commit comments

Comments
 (0)