feat(rt+auth): batched input publish boi so 4 (het crackle) + auto-login loopback khong can mat khau

- fx_realtime: write_input gom FXRT_IN_SLOTS(4) frame vao _in_pending, flush
  ghi 1 lan + h.in_write += n (publish atomic -> bridge take=4 luon, het deficit)
- plugins pump: flush_input_stale(0.004) dau vong lap -> input le khong ket
- auth: _is_loopback(127.*/::1/localhost) -> get_current_user khong token = admin
  tu DB (must_change_password=False); POST /auth/local auto-login loopback, LAN 403
- ws fx-realtime: loopback khong token cho phep, remote thieu token -> close 4401
- UI: checkAuthStatus khong savedToken -> thu localLogin, thanh cong vao DAW,
  that bai -> modal login nhu cu; cache-buster v=202608212400
This commit is contained in:
2026-08-23 12:00:05 +07:00
parent 0acc3ee7ee
commit 9bb9a234b0
7 changed files with 126 additions and 23 deletions
+19 -2
View File
@@ -1711,7 +1711,7 @@ async function fxRtStart() {
fxRt.sessionId = st.session_id;
fxRtGuiPushShm();
try {
await ctx.audioWorklet.addModule(`${API_BASE_URL}/static/js/sf-fx-realtime.js?v=202608212300`);
await ctx.audioWorklet.addModule(`${API_BASE_URL}/static/js/sf-fx-realtime.js?v=202608212400`);
fxRt.node = new AudioWorkletNode(ctx, 'sf-fx-realtime', { numberOfInputs: 1, numberOfOutputs: 1, outputChannelCount: [2] });
const u = new URL(API_BASE_URL);
const wsProto = u.protocol === 'https:' ? 'wss://' : 'ws://';
@@ -19382,6 +19382,23 @@ const App = () => {
const checkAuthStatus = async () => {
const savedToken = localStorage.getItem('sonic_token');
if (!savedToken) {
// Standalone (loopback): auto-login không cần mật khẩu. LAN client:
// /auth/local trả 403 → hiện modal đăng nhập như cũ.
try {
const res = await window.SonicAPI.localLogin();
if (res && res.access_token) {
localStorage.setItem('sonic_token', res.access_token);
localStorage.setItem('sonic_user', JSON.stringify(res.user));
setCurrentUser(res.user);
setIsMandatoryLogin(false);
setAuthModalOpen(false);
(async () => {
const restored = await restoreLastSessionProject();
if (!restored) await restoreTempProjectIfFresh();
})();
return;
}
} catch (e) {}
setIsMandatoryLogin(true);
setAuthMode('login');
setAuthModalOpen(true);
@@ -23662,7 +23679,7 @@ const App = () => {
fxRtTracks[key] = entry;
fxRtGuiPushShm();
try {
await ctx.audioWorklet.addModule(`${API_BASE_URL}/static/js/sf-fx-realtime.js?v=202608212300`);
await ctx.audioWorklet.addModule(`${API_BASE_URL}/static/js/sf-fx-realtime.js?v=202608212400`);
const node = new AudioWorkletNode(ctx, 'sf-fx-realtime', { numberOfInputs: 1, numberOfOutputs: 1, outputChannelCount: [2] });
entry.node = node;
const u = new URL(API_BASE_URL);
File diff suppressed because one or more lines are too long
+1
View File
@@ -35,6 +35,7 @@ window.API_BASE_URL = (window.API_BASE_URL || window.location.origin).replace(/\
window.SonicAPI = {
login: (username, password) => apiRequest('/api/v1/auth/login', { method: 'POST', body: JSON.stringify({ username, password }) }),
localLogin: () => apiRequest('/api/v1/auth/local', { method: 'POST' }),
register: (username, email, password) => apiRequest('/api/v1/auth/register', { method: 'POST', body: JSON.stringify({ username, email, password }) }),
changePassword: (old_password, new_password) => apiRequest('/api/v1/auth/change-password', { method: 'POST', body: JSON.stringify({ old_password, new_password }) }),
getProfile: () => apiRequest('/api/v1/auth/profile', { method: 'GET' }),