diff --git a/applet.js b/applet.js index ff495d8..aaf3c9d 100644 --- a/applet.js +++ b/applet.js @@ -6,6 +6,7 @@ const Mainloop = imports.mainloop; const Soup = imports.gi.Soup; const St = imports.gi.St; const Settings = imports.ui.settings; +const Json = imports.gi.Json; function MyApplet(metadata, orientation, panel_height, instance_id) { this._init(metadata, orientation, panel_height, instance_id); @@ -30,8 +31,16 @@ MyApplet.prototype = { this.settings.bindProperty( Settings.BindingDirection.IN, - "token", - "token", + "username", + "username", + this.onSettingsChanged, + null + ); + + this.settings.bindProperty( + Settings.BindingDirection.IN, + "password", + "password", this.onSettingsChanged, null ); @@ -46,20 +55,10 @@ MyApplet.prototype = { this._player = null; this._audioBuffer = new Uint8Array(0); this._playbackBuffer = []; + this._accessToken = null; global.log("[Voice Assistant] Applet initialized"); - this._initSockets(); - }, - - onSettingsChanged: function() { - global.log("[Voice Assistant] Settings changed, reinitializing sockets"); - if (this._streamSocket) { - this._streamSocket.close(Soup.WebsocketCloseCode.NORMAL, null); - } - if (this._nodeSocket) { - this._nodeSocket.close(Soup.WebsocketCloseCode.NORMAL, null); - } - this._initSockets(); + this._authenticate(); }, _setCustomIcon: function(iconPath) { @@ -75,12 +74,56 @@ MyApplet.prototype = { } }, + onSettingsChanged: function() { + global.log("[Voice Assistant] Settings changed, re-authenticating"); + this._closeExistingSockets(); + this._authenticate(); + }, + + _authenticate: function() { + let session = new Soup.Session(); + let message = Soup.Message.new( + 'POST', + `https://${this.baseUrl}/auth/login` + ); + + let body = JSON.stringify({ + username: this.username, + password: this.password + }); + + let bytes = GLib.Bytes.new(body); + + message.set_request_body_from_bytes('application/json', bytes); + + session.send_and_read_async(message, GLib.PRIORITY_DEFAULT, null, (session, result) => { + try { + let bytes = session.send_and_read_finish(result); + if (message.get_status() === 200) { + let data = JSON.parse(new TextDecoder().decode(bytes.get_data())); + this._accessToken = data.access_token; + global.log("[Voice Assistant] Authentication successful"); + this._initSockets(); + } else { + global.logError("[Voice Assistant] Authentication failed: " + message.get_status()); + } + } catch (e) { + global.logError("[Voice Assistant] Error during authentication: " + e.message); + } + }); + }, + _initSockets: function() { + if (!this._accessToken) { + global.logError("[Voice Assistant] No access token available. Cannot initialize sockets."); + return; + } + global.log("[Voice Assistant] Initializing WebSockets"); let maxPayloadSize = 10 * 1024 * 1024; // 10 MB in bytes - const STREAM_SOCKET_URL = `wss://${this.baseUrl}/node/v1/stream?token=${this.token}`; - const NODE_SOCKET_URL = `wss://${this.baseUrl}/node/v1?token=${this.token}`; + const STREAM_SOCKET_URL = `wss://${this.baseUrl}/node/v1/stream?token=${this._accessToken}`; + const NODE_SOCKET_URL = `wss://${this.baseUrl}/node/v1?token=${this._accessToken}`; // Initialize Node WebSocket try { @@ -128,14 +171,21 @@ MyApplet.prototype = { } }, + _closeExistingSockets: function() { + if (this._streamSocket) { + this._streamSocket.close(Soup.WebsocketCloseCode.NORMAL, null); + this._streamSocket = null; + } + if (this._nodeSocket) { + this._nodeSocket.close(Soup.WebsocketCloseCode.NORMAL, null); + this._nodeSocket = null; + } + }, + _onSocketError: function(socket, error) { global.logError("[Voice Assistant] WebSocket error: " + error.message); - try { - this._streamSocket.close(); - this._nodeSocket.close(); - } finally { - this._initSockets(); - } + this._closeExistingSockets(); + this._authenticate(); }, _onNodeMessage: function(connection, type, message) { @@ -317,14 +367,7 @@ MyApplet.prototype = { on_applet_removed_from_panel: function() { global.log("[Voice Assistant] Applet removed from panel"); this._stopRecording(); - if (this._streamSocket) { - this._streamSocket.close(Soup.WebsocketCloseCode.NORMAL, null); - global.log("[Voice Assistant] Record WebSocket closed"); - } - if (this._nodeSocket) { - this._nodeSocket.close(Soup.WebsocketCloseCode.NORMAL, null); - global.log("[Voice Assistant] Node WebSocket closed"); - } + this._closeExistingSockets(); if (this._player) { this._player.force_exit(); global.log("[Voice Assistant] Audio player terminated"); diff --git a/settings-schema.json b/settings-schema.json index 8e94ff2..152b2a6 100644 --- a/settings-schema.json +++ b/settings-schema.json @@ -2,11 +2,16 @@ "baseUrl": { "type": "entry", "default": "hana.neonaialpha.com", - "description": "Base URL for HANA Websocket" + "description": "Base URL for the Voice Assistant service" }, - "token": { + "username": { "type": "entry", - "default": "", - "description": "Valid token for authentication" + "default": "neon", + "description": "Username for authentication" + }, + "password": { + "type": "entry", + "default": "neon", + "description": "Password for authentication" } }