Skip to main content

unifly_api/command/
mod.rs

1// ── Command API ──
2//
3// All write operations flow through a unified `Command` enum.
4// The controller routes each variant to the appropriate API backend
5// (Integration API preferred, Session API for session-only operations).
6
7pub mod requests;
8
9use crate::core_error::CoreError;
10use crate::model::{
11    AclRule, Client, Device, DnsPolicy, EntityId, FirewallPolicy, FirewallZone, MacAddress,
12    Network, TrafficMatchingList, Voucher, WifiBroadcast,
13};
14
15pub use requests::{
16    ApplyPortEntry, ApplyPortsRequest, CreateAclRuleRequest, CreateDnsPolicyRequest,
17    CreateFirewallGroupRequest, CreateFirewallPolicyRequest, CreateFirewallZoneRequest,
18    CreateNatPolicyRequest, CreateNetworkRequest, CreateRemoteAccessVpnServerRequest,
19    CreateSiteToSiteVpnRequest, CreateTrafficMatchingListRequest, CreateVouchersRequest,
20    CreateVpnClientProfileRequest, CreateWifiBroadcastRequest, CreateWireGuardPeerRequest,
21    PortSpec, TrafficFilterSpec, UpdateAclRuleRequest, UpdateDnsPolicyRequest,
22    UpdateFirewallGroupRequest, UpdateFirewallPolicyRequest, UpdateFirewallZoneRequest,
23    UpdateNatPolicyRequest, UpdateNetworkRequest, UpdateRemoteAccessVpnServerRequest,
24    UpdateSiteToSiteVpnRequest, UpdateTrafficMatchingListRequest, UpdateVpnClientProfileRequest,
25    UpdateWifiBroadcastRequest, UpdateWireGuardPeerRequest,
26};
27
28/// A command envelope sent through the command channel.
29/// Contains the command and a oneshot response channel.
30pub(crate) struct CommandEnvelope {
31    pub command: Command,
32    pub response_tx: tokio::sync::oneshot::Sender<Result<CommandResult, CoreError>>,
33}
34
35/// All possible write operations against a UniFi controller.
36#[derive(Debug, Clone)]
37pub enum Command {
38    // ── Device operations ────────────────────────────────────────────
39    AdoptDevice {
40        mac: MacAddress,
41        ignore_device_limit: bool,
42    },
43    RemoveDevice {
44        id: EntityId,
45    },
46    RestartDevice {
47        id: EntityId,
48    },
49    LocateDevice {
50        mac: MacAddress,
51        enable: bool,
52    },
53    UpgradeDevice {
54        mac: MacAddress,
55        firmware_url: Option<String>,
56    },
57    ProvisionDevice {
58        mac: MacAddress,
59    },
60    SpeedtestDevice,
61    PowerCyclePort {
62        device_id: EntityId,
63        port_idx: u32,
64    },
65
66    // ── Client operations ────────────────────────────────────────────
67    BlockClient {
68        mac: MacAddress,
69    },
70    UnblockClient {
71        mac: MacAddress,
72    },
73    KickClient {
74        mac: MacAddress,
75    },
76    ForgetClient {
77        mac: MacAddress,
78    },
79    AuthorizeGuest {
80        client_id: EntityId,
81        time_limit_minutes: Option<u32>,
82        data_limit_mb: Option<u64>,
83        rx_rate_kbps: Option<u64>,
84        tx_rate_kbps: Option<u64>,
85    },
86    UnauthorizeGuest {
87        client_id: EntityId,
88    },
89    SetClientFixedIp {
90        mac: MacAddress,
91        ip: std::net::Ipv4Addr,
92        network_id: EntityId,
93    },
94    RemoveClientFixedIp {
95        mac: MacAddress,
96        network_id: Option<EntityId>,
97    },
98
99    // ── Network CRUD ─────────────────────────────────────────────────
100    CreateNetwork(CreateNetworkRequest),
101    UpdateNetwork {
102        id: EntityId,
103        update: UpdateNetworkRequest,
104    },
105    DeleteNetwork {
106        id: EntityId,
107        force: bool,
108    },
109
110    // ── WiFi CRUD ────────────────────────────────────────────────────
111    CreateWifiBroadcast(CreateWifiBroadcastRequest),
112    UpdateWifiBroadcast {
113        id: EntityId,
114        update: UpdateWifiBroadcastRequest,
115    },
116    DeleteWifiBroadcast {
117        id: EntityId,
118        force: bool,
119    },
120
121    // ── Firewall ─────────────────────────────────────────────────────
122    CreateFirewallPolicy(CreateFirewallPolicyRequest),
123    UpdateFirewallPolicy {
124        id: EntityId,
125        update: UpdateFirewallPolicyRequest,
126    },
127    DeleteFirewallPolicy {
128        id: EntityId,
129    },
130    PatchFirewallPolicy {
131        id: EntityId,
132        enabled: Option<bool>,
133        logging: Option<bool>,
134    },
135    ReorderFirewallPolicies {
136        zone_pair: (EntityId, EntityId),
137        before_system_ids: Vec<EntityId>,
138        after_system_ids: Vec<EntityId>,
139    },
140    CreateFirewallZone(CreateFirewallZoneRequest),
141    UpdateFirewallZone {
142        id: EntityId,
143        update: UpdateFirewallZoneRequest,
144    },
145    DeleteFirewallZone {
146        id: EntityId,
147    },
148
149    // ── Firewall Groups (Session) ────────────────────────────────────
150    CreateFirewallGroup(CreateFirewallGroupRequest),
151    UpdateFirewallGroup {
152        id: EntityId,
153        update: UpdateFirewallGroupRequest,
154    },
155    DeleteFirewallGroup {
156        id: EntityId,
157    },
158
159    // ── NAT ──────────────────────────────────────────────────────────
160    CreateNatPolicy(CreateNatPolicyRequest),
161    UpdateNatPolicy {
162        id: EntityId,
163        update: UpdateNatPolicyRequest,
164    },
165    DeleteNatPolicy {
166        id: EntityId,
167    },
168
169    // ── VPN (Legacy) ────────────────────────────────────────────────
170    CreateSiteToSiteVpn(CreateSiteToSiteVpnRequest),
171    UpdateSiteToSiteVpn {
172        id: EntityId,
173        update: UpdateSiteToSiteVpnRequest,
174    },
175    DeleteSiteToSiteVpn {
176        id: EntityId,
177    },
178    CreateRemoteAccessVpnServer(CreateRemoteAccessVpnServerRequest),
179    UpdateRemoteAccessVpnServer {
180        id: EntityId,
181        update: UpdateRemoteAccessVpnServerRequest,
182    },
183    DeleteRemoteAccessVpnServer {
184        id: EntityId,
185    },
186    CreateVpnClientProfile(CreateVpnClientProfileRequest),
187    UpdateVpnClientProfile {
188        id: EntityId,
189        update: UpdateVpnClientProfileRequest,
190    },
191    DeleteVpnClientProfile {
192        id: EntityId,
193    },
194    CreateWireGuardPeer {
195        server_id: EntityId,
196        peer: CreateWireGuardPeerRequest,
197    },
198    UpdateWireGuardPeer {
199        server_id: EntityId,
200        peer_id: EntityId,
201        update: UpdateWireGuardPeerRequest,
202    },
203    DeleteWireGuardPeer {
204        server_id: EntityId,
205        peer_id: EntityId,
206    },
207    RestartVpnClientConnection {
208        id: EntityId,
209    },
210
211    // ── ACL ──────────────────────────────────────────────────────────
212    CreateAclRule(CreateAclRuleRequest),
213    UpdateAclRule {
214        id: EntityId,
215        update: UpdateAclRuleRequest,
216    },
217    DeleteAclRule {
218        id: EntityId,
219    },
220    ReorderAclRules {
221        ordered_ids: Vec<EntityId>,
222    },
223
224    // ── DNS ──────────────────────────────────────────────────────────
225    CreateDnsPolicy(CreateDnsPolicyRequest),
226    UpdateDnsPolicy {
227        id: EntityId,
228        update: UpdateDnsPolicyRequest,
229    },
230    DeleteDnsPolicy {
231        id: EntityId,
232    },
233
234    // ── Traffic matching lists ───────────────────────────────────────
235    CreateTrafficMatchingList(CreateTrafficMatchingListRequest),
236    UpdateTrafficMatchingList {
237        id: EntityId,
238        update: UpdateTrafficMatchingListRequest,
239    },
240    DeleteTrafficMatchingList {
241        id: EntityId,
242    },
243
244    // ── Hotspot / Vouchers ───────────────────────────────────────────
245    CreateVouchers(CreateVouchersRequest),
246    DeleteVoucher {
247        id: EntityId,
248    },
249    PurgeVouchers {
250        filter: String,
251    },
252
253    // ── Site settings (Session) ─────────────────────────────────────────
254    SetDpiEnabled {
255        enabled: bool,
256    },
257
258    // ── System (Session) ──────────────────────────────────────────────
259    ArchiveAlarm {
260        id: EntityId,
261    },
262    ArchiveAllAlarms,
263    CreateSite {
264        name: String,
265        description: String,
266    },
267    DeleteSite {
268        name: String,
269    },
270    CreateBackup,
271    DeleteBackup {
272        filename: String,
273    },
274    RebootController,
275    PoweroffController,
276    InviteAdmin {
277        name: String,
278        email: String,
279        role: String,
280    },
281    RevokeAdmin {
282        id: EntityId,
283    },
284    UpdateAdmin {
285        id: EntityId,
286        role: Option<String>,
287    },
288}
289
290/// Result of a command execution.
291#[derive(Debug)]
292pub enum CommandResult {
293    Ok,
294    CreatedId(EntityId),
295    Device(Device),
296    Client(Client),
297    Network(Network),
298    WifiBroadcast(WifiBroadcast),
299    FirewallPolicy(FirewallPolicy),
300    FirewallZone(FirewallZone),
301    AclRule(AclRule),
302    DnsPolicy(DnsPolicy),
303    Vouchers(Vec<Voucher>),
304    TrafficMatchingList(TrafficMatchingList),
305}