onQueue('provisioning'); } public static function for(VpnPeer $peer): self { return new self($peer->public_key, $peer->allowed_ip, $peer->enabled); } public function handle(WireguardHub $hub): void { // Read the CURRENT desired state rather than the one captured at // dispatch time. A retried block job would otherwise undo an unblock // that happened in the meantime, and nothing would ever put it back: // SyncVpnPeers only observes, it never re-applies intent. $peer = VpnPeer::withTrashed()->where('public_key', $this->publicKey)->first(); // No row, or a revoked one, means the peer must be off the hub. The // constructor payload only matters when the row is already gone. $enabled = $peer === null ? $this->enabled && $this->allowedIp !== null : (! $peer->trashed() && $peer->enabled); $ip = $peer?->allowed_ip ?? $this->allowedIp; if ($enabled && $ip !== null) { $hub->addPeer($this->publicKey, $ip); } else { $hub->removePeer($this->publicKey); } if ($peer === null) { return; } // The tombstone has served its purpose once the hub has dropped the peer. if ($peer->trashed()) { $peer->forceDelete(); return; } // Reflect the change immediately instead of waiting for the next sync, // so the console does not sit on "wird angewendet" for a whole minute. $peer->update(['present' => $enabled, 'observed_at' => now()]); } }