From 6cefa7392c407af36683d9ab88acb0815143459d Mon Sep 17 00:00:00 2001 From: Fritz Heiden Date: Sat, 12 Apr 2025 16:35:03 +0200 Subject: [PATCH] feat: persisting remotes and commands in database --- data/command.go | 75 +++++++++ data/remote.go | 7 + data/remote_database.go | 200 +++++++++++++++++++++++ main/main.go | 20 +++ management/remote_manager.go | 50 ++++++ server/remote_api_handler.go | 103 ++++++++++++ www/src/data/command.js | 18 +- www/src/data/serializer.js | 37 ++++- www/src/modals/create-command-modal.jsx | 8 +- www/src/modals/create-remote-modal.jsx | 1 + www/src/modals/import-commands-modal.jsx | 4 + www/src/services/remotes-service.js | 117 +++++++------ 12 files changed, 576 insertions(+), 64 deletions(-) create mode 100644 data/command.go create mode 100644 data/remote.go create mode 100644 data/remote_database.go create mode 100644 management/remote_manager.go create mode 100644 server/remote_api_handler.go diff --git a/data/command.go b/data/command.go new file mode 100644 index 0000000..a65afa4 --- /dev/null +++ b/data/command.go @@ -0,0 +1,75 @@ +package data + +const SAMSUNG_PROTOCOL = "samsung" +const NEC_PROTOCOL = "nec" +const ONKYO_PROTOCOL = "onkyo" +const APPLE_PROTOCOL = "apple" +const DENON_PROTOCOL = "denon" +const SHARP_PROTOCOL = "sharp" +const PANASONIC_PROTOCOL = "panasonic" +const KASEIKYO_PROTOCOL = "kaseikyo" +const JVC_PROTOCOL = "jvc" +const LG_PROTOCOL = "lg" +const SONY_PROTOCOL = "sony" +const RC5_PROTOCOL = "rc5" +const RC6_PROTOCOL = "rc6" +const UNIVERSAL_PULSE_DISTANCE_PROTOCOL = "universal_pulse_distance" +const UNIVERSAL_PULSE_WIDTH_PROTOCOL = "universal_pulse_width" +const UNIVERSAL_PULSE_DISTANCE_WIDTH_PROTOCOL = "universal_pulse_distance_width" +const HASH_PROTOCOL = "hash" +const PRONTO_PROTOCOL = "pronto" +const BOSE_WAVE_PROTOCOL = "bose_wave" +const BANG_OLUFSEN_PROTOCOL = "bang_olufsen" +const LEGO_PROTOCOL = "lego" +const FAST_PROTOCOL = "fast" +const WHYNTER_PROTOCOL = "whynter" +const MAGIQUEST_PROTOCOL = "magiquest" + +const POWER_COMMAND_TYPE = "power" +const INPUT_COMMAND_TYPE = "input" +const ONE_COMMAND_TYPE = "1" +const TWO_COMMAND_TYPE = "2" +const THREE_COMMAND_TYPE = "3" +const FOUR_COMMAND_TYPE = "4" +const FIVE_COMMAND_TYPE = "5" +const SIX_COMMAND_TYPE = "6" +const SEVEN_COMMAND_TYPE = "7" +const EIGHT_COMMAND_TYPE = "8" +const NINE_COMMAND_TYPE = "9" +const ZERO_COMMAND_TYPE = "0" +const VOLUME_UP_COMMAND_TYPE = "volume_up" +const VOLUME_DOWN_COMMAND_TYPE = "volume_down" +const MUTE_COMMAND_TYPE = "mute" +const CHANNEL_UP_COMMAND_TYPE = "channel_up" +const CHANNEL_DOWN_COMMAND_TYPE = "channel_down" +const MENU_COMMAND_TYPE = "menu" +const HOME_COMMAND_TYPE = "home" +const SETTINGS_COMMAND_TYPE = "settings" +const OPTIONS_COMMAND_TYPE = "options" +const UP_COMMAND_TYPE = "up" +const DOWN_COMMAND_TYPE = "down" +const LEFT_COMMAND_TYPE = "left" +const RIGHT_COMMAND_TYPE = "right" +const ENTER_COMMAND_TYPE = "enter" +const INFO_COMMAND_TYPE = "info" +const RETURN_COMMAND_TYPE = "return" +const EXIT_COMMAND_TYPE = "exit" +const RED_COMMAND_TYPE = "red" +const GREEN_COMMAND_TYPE = "green" +const YELLOW_COMMAND_TYPE = "yellow" +const BLUE_COMMAND_TYPE = "blue" +const REWIND_COMMAND_TYPE = "rewind" +const PLAY_COMMAND_TYPE = "play" +const PAUSE_COMMAND_TYPE = "pause" +const STOP_COMMAND_TYPE = "stop" +const FORWARD_COMMAND_TYPE = "forward" +const OTHER_COMMAND_TYPE = "other" + +type Command struct { + Id string `json:"id"` + Protocol string `json:"protocol"` + CommandNumber int `json:"commandNumber"` + Device int `json:"device"` + CommandType string `json:"commandType"` + Title string `json:"title"` +} diff --git a/data/remote.go b/data/remote.go new file mode 100644 index 0000000..4ba5e6c --- /dev/null +++ b/data/remote.go @@ -0,0 +1,7 @@ +package data + +type Remote struct { + Id string `json:"id"` + Title string `json:"title"` + Commands []Command `json:"commands"` +} diff --git a/data/remote_database.go b/data/remote_database.go new file mode 100644 index 0000000..0b676fe --- /dev/null +++ b/data/remote_database.go @@ -0,0 +1,200 @@ +package data + +import ( + "database/sql" + "fmt" + "path/filepath" + + gonanoid "github.com/matoous/go-nanoid" +) + +type RemoteDatabase struct { + Connection *sql.DB + databaseDirectory string +} + +func (db *RemoteDatabase) Initialize() error { + connection, error := sql.Open("sqlite3", filepath.Join(db.databaseDirectory, "remotes.db")) + if error != nil { + return error + } + db.Connection = connection + + _, error = db.Connection.Exec(`PRAGMA foreign_keys = ON;`) + if error != nil { + return fmt.Errorf("error enabling foreign keys: %s", error) + } + + _, error = db.Connection.Exec(` + CREATE TABLE IF NOT EXISTS Remotes ( + id TEXT PRIMARY KEY, + title TEXT NOT NULL + );`) + if error != nil { + return fmt.Errorf("error creating remotes table: %s", error) + } + + _, error = db.Connection.Exec(` + CREATE TABLE IF NOT EXISTS Commands ( + id TEXT PRIMARY KEY, + protocol TEXT, + commandNumber INTEGER, + device INTEGER, + commandType TEXT, + title TEXT + );`) + if error != nil { + return fmt.Errorf("error creating commands table: %s", error) + } + + _, error = db.Connection.Exec(` + CREATE TABLE IF NOT EXISTS RemoteCommands ( + remote_id TEXT NOT NULL, + command_id TEXT NOT NULL, + PRIMARY KEY (remote_id, command_id), + FOREIGN KEY (remote_id) REFERENCES Remotes(id) ON DELETE CASCADE, + FOREIGN KEY (command_id) REFERENCES Commands(id) ON DELETE CASCADE + );`) + if error != nil { + return fmt.Errorf("error creating remote-commands table: %s", error) + } + return nil +} + +func (db *RemoteDatabase) Close() error { + return db.Connection.Close() +} + +func (db *RemoteDatabase) CreateRemote(remote Remote) (string, error) { + remoteId, err := gonanoid.Nanoid(8) + if err != nil { + return "", err + } + queryString := "INSERT INTO Remotes (id, title) VALUES (?, ?)" + _, err = db.Connection.Exec(queryString, remoteId, remote.Title) + if err != nil { + return "", err + } + commandIds := []string{} + for _, command := range remote.Commands { + commandIds = append(commandIds, command.Id) + } + err = db.CreateRemoteCommands(remoteId, commandIds) + if err != nil { + return "", err + } + return remoteId, nil +} + +func (db *RemoteDatabase) CreateRemoteCommands(remoteId string, commandIds []string) error { + for _, commandId := range commandIds { + queryString := "INSERT INTO RemoteCommands (remote_id, command_id) VALUES (?, ?)" + _, err := db.Connection.Exec(queryString, remoteId, commandId) + if err != nil { + return err + } + } + return nil +} + +func (db *RemoteDatabase) GetRemotes() ([]Remote, error) { + rows, error := db.Connection.Query("SELECT id, title FROM Remotes") + if error != nil { + return nil, fmt.Errorf("error querying remotes: %s", error) + } + defer rows.Close() + + remotes := []Remote{} + for rows.Next() { + var remote Remote + error = rows.Scan(&remote.Id, &remote.Title) + if error != nil { + return nil, fmt.Errorf("error scanning remote: %s", error) + } + remotes = append(remotes, remote) + } + return remotes, nil +} + +func (db *RemoteDatabase) DeleteRemote(remoteId string) error { + queryString := "DELETE FROM Remotes WHERE id = ?" + _, error := db.Connection.Exec(queryString, remoteId) + if error != nil { + return fmt.Errorf("error deleting remote %s: %s", remoteId, error) + } + return nil +} + +func (db *RemoteDatabase) GetCommandsByRemoteId(remoteId string) ([]Command, error) { + rows, error := db.Connection.Query("SELECT id, protocol, commandNumber, device, commandType, title FROM Commands WHERE id IN (SELECT command_id FROM RemoteCommands WHERE remote_id = ?)", remoteId) + if error != nil { + return nil, fmt.Errorf("error querying commands for remote %s: %s", remoteId, error) + } + defer rows.Close() + + commands := []Command{} + for rows.Next() { + var command Command + error = rows.Scan(&command.Id, &command.Protocol, &command.CommandNumber, &command.Device, &command.CommandType, &command.Title) + if error != nil { + return nil, fmt.Errorf("error scanning command: %s", error) + } + commands = append(commands, command) + } + return commands, nil +} + +func (db *RemoteDatabase) CreateCommand(command Command) (string, error) { + commandId, err := gonanoid.Nanoid(8) + if err != nil { + return "", err + } + queryString := "INSERT INTO Commands (id, protocol, commandNumber, device, commandType, title) VALUES (?, ?, ?, ?, ?, ?)" + _, err = db.Connection.Exec(queryString, commandId, command.Protocol, command.CommandNumber, command.Device, command.CommandType, command.Title) + if err != nil { + return "", err + } + return commandId, nil +} + +func (db *RemoteDatabase) CreateCommands(commands []Command) error { + for _, command := range commands { + _, err := db.CreateCommand(command) + if err != nil { + return err + } + } + return nil +} + +func (db *RemoteDatabase) GetCommands() ([]Command, error) { + rows, error := db.Connection.Query("SELECT id, protocol, commandNumber, device, commandType, title FROM Commands") + if error != nil { + return nil, fmt.Errorf("error querying commands: %s", error) + } + defer rows.Close() + + commands := []Command{} + for rows.Next() { + var command Command + error = rows.Scan(&command.Id, &command.Protocol, &command.CommandNumber, &command.Device, &command.CommandType, &command.Title) + if error != nil { + return nil, fmt.Errorf("error scanning command: %s", error) + } + commands = append(commands, command) + } + return commands, nil +} + +func (db *RemoteDatabase) DeleteCommand(commandId string) error { + queryString := "DELETE FROM Commands WHERE id = ?" + _, error := db.Connection.Exec(queryString, commandId) + if error != nil { + return fmt.Errorf("error deleting command %s: %s", commandId, error) + } + return nil +} + +func (db *RemoteDatabase) SetDirectory(directory string) { + db.databaseDirectory = directory +} diff --git a/main/main.go b/main/main.go index 1f609bb..dc56c27 100644 --- a/main/main.go +++ b/main/main.go @@ -39,6 +39,15 @@ func main() { } defer deviceDatabase.Close() + remoteDatabase := data.RemoteDatabase{} + remoteDatabase.SetDirectory(configuration.DatabaseDirectory) + err = remoteDatabase.Initialize() + if err != nil { + log.Error().Err(err).Msg("failed to initialize remote database") + os.Exit(1) + } + defer remoteDatabase.Close() + userManager := management.UserManager{} err = userManager.Initialize(&userDatabase) if err != nil { @@ -51,6 +60,12 @@ func main() { log.Error().Err(err).Msg("failed to initialize device manager") } + remoteManager := management.RemoteManager{} + err = remoteManager.Initialize(&remoteDatabase) + if err != nil { + log.Error().Err(err).Msg("failed to initialize remote manager") + } + webServer := server.WebServer{} webServer.SetWebAppDirectoryPath("www") webServer.SetPort(configuration.Port) @@ -71,6 +86,11 @@ func main() { deviceApiHandler.SetRouter(webServer.Router()) deviceApiHandler.Initialize(&authenticator) + remoteApiHandler := server.RemoteApiHandler{} + remoteApiHandler.SetRemoteManager(&remoteManager) + remoteApiHandler.SetRouter(webServer.Router()) + remoteApiHandler.Initialize(&authenticator) + webSocketServer := server.WebsocketServer{} webSocketServer.SetRouter(webServer.Router()) webSocketServer.Initialize(&authenticator) diff --git a/management/remote_manager.go b/management/remote_manager.go new file mode 100644 index 0000000..4fb8919 --- /dev/null +++ b/management/remote_manager.go @@ -0,0 +1,50 @@ +package management + +import ( + d "playback-device-server/data" +) + +type RemoteManager struct { + remoteDatabase *d.RemoteDatabase +} + +func (rm *RemoteManager) Initialize(remoteDatabase *d.RemoteDatabase) error { + rm.remoteDatabase = remoteDatabase + return nil +} + +func (rm *RemoteManager) CreateRemote(remote d.Remote) (string, error) { + return rm.remoteDatabase.CreateRemote(remote) +} + +func (rm *RemoteManager) GetRemotes() ([]d.Remote, error) { + remotes, err := rm.remoteDatabase.GetRemotes() + if err != nil { + return nil, err + } + return remotes, nil +} + +func (rm *RemoteManager) DeleteRemote(remoteID string) error { + return rm.remoteDatabase.DeleteRemote(remoteID) +} + +func (rm *RemoteManager) CreateCommand(command d.Command) (string, error) { + return rm.remoteDatabase.CreateCommand(command) +} + +func (rm *RemoteManager) CreateCommands(commands []d.Command) error { + return rm.remoteDatabase.CreateCommands(commands) +} + +func (rm *RemoteManager) GetCommands() ([]d.Command, error) { + return rm.remoteDatabase.GetCommands() +} + +func (rm *RemoteManager) SetRemoteDatabase(remoteDatabase *d.RemoteDatabase) { + rm.remoteDatabase = remoteDatabase +} + +func (rm *RemoteManager) DeleteCommand(commandID string) error { + return rm.remoteDatabase.DeleteCommand(commandID) +} diff --git a/server/remote_api_handler.go b/server/remote_api_handler.go new file mode 100644 index 0000000..14c4456 --- /dev/null +++ b/server/remote_api_handler.go @@ -0,0 +1,103 @@ +package server + +import ( + d "playback-device-server/data" + m "playback-device-server/management" + + "github.com/labstack/echo/v4" +) + +type RemoteApiHandler struct { + router *echo.Echo + remoteManager *m.RemoteManager +} + +func (r *RemoteApiHandler) Initialize(authenticator *Authenticator) { + r.router.Use(authenticator.Authenticate("/api/remotes", []string{})) + remotesApi := r.router.Group("/api/remotes") + remotesApi.GET("", r.handleGetRemotes) + remotesApi.POST("", r.handleCreateRemote) + remotesApi.DELETE("/:id", r.handleDelteRemote) + + r.router.Use(authenticator.Authenticate("/api/commands", []string{})) + commandsApi := r.router.Group("/api/commands") + commandsApi.GET("", r.handleGetCommands) + commandsApi.POST("", r.handleCreateCommands) + commandsApi.DELETE("/:id", r.handleDeleteCommand) + +} + +func (r *RemoteApiHandler) handleCreateRemote(context echo.Context) error { + remote := d.Remote{} + if err := context.Bind(&remote); err != nil { + SendError(400, context, err.Error()) + return nil + } + id, err := r.remoteManager.CreateRemote(remote) + if err != nil { + SendError(500, context, err.Error()) + return err + } + remote.Id = id + return context.JSON(200, remote) +} + +func (r *RemoteApiHandler) handleGetRemotes(context echo.Context) error { + remotes, err := r.remoteManager.GetRemotes() + if err != nil { + SendError(500, context, err.Error()) + return err + } + return context.JSON(200, remotes) +} + +func (r *RemoteApiHandler) handleDelteRemote(context echo.Context) error { + id := context.Param("id") + err := r.remoteManager.DeleteRemote(id) + if err != nil { + SendError(500, context, err.Error()) + return err + } + return context.JSON(200, "") +} + +func (r *RemoteApiHandler) handleCreateCommands(context echo.Context) error { + commands := []d.Command{} + if err := context.Bind(&commands); err != nil { + SendError(400, context, err.Error()) + return nil + } + err := r.remoteManager.CreateCommands(commands) + if err != nil { + SendError(500, context, err.Error()) + return err + } + return context.JSON(200, "") +} + +func (r *RemoteApiHandler) handleGetCommands(context echo.Context) error { + commands, err := r.remoteManager.GetCommands() + if err != nil { + SendError(500, context, err.Error()) + return err + } + return context.JSON(200, commands) +} + +func (r *RemoteApiHandler) handleDeleteCommand(context echo.Context) error { + id := context.Param("id") + err := r.remoteManager.DeleteCommand(id) + if err != nil { + SendError(500, context, err.Error()) + return err + } + return context.JSON(200, "") +} + +func (r *RemoteApiHandler) SetRouter(router *echo.Echo) { + r.router = router +} + +func (r *RemoteApiHandler) SetRemoteManager(remoteManager *m.RemoteManager) { + r.remoteManager = remoteManager +} diff --git a/www/src/data/command.js b/www/src/data/command.js index 57679e8..137cb4f 100644 --- a/www/src/data/command.js +++ b/www/src/data/command.js @@ -1,11 +1,14 @@ function Command({ - id, - protocol, - commandNumber, - device, - commandType, - title, + id = "", + protocol = "", + commandNumber = -1, + device = -1, + commandType = "", + title = "", } = {}) { + if (typeof commandNumber !== "number") + throw new Error("Command number must be a number"); + if (typeof device !== "number") throw new Error("Device must be a number"); let _id = id; let _protocol = protocol; let _commandNumber = commandNumber; @@ -34,6 +37,8 @@ function Command({ } function setCommandNumber(commandNumber) { + if (typeof commandNumber !== "number") + throw new Error("Command number must be a number"); _commandNumber = commandNumber; } @@ -42,6 +47,7 @@ function Command({ } function setDevice(device) { + if (typeof device !== "number") throw new Error("Device must be a number"); _device = device; } diff --git a/www/src/data/serializer.js b/www/src/data/serializer.js index 28f1dcf..5bd8239 100644 --- a/www/src/data/serializer.js +++ b/www/src/data/serializer.js @@ -31,20 +31,46 @@ const Serializer = (function () { if (!objects) return []; return objects.map((object) => deserializeIntegration(object)); } - + + function serializeCommand(command) { + return { + id: command.getId(), + protocol: command.getProtocol(), + commandNumber: command.getCommandNumber(), + device: command.getDevice(), + commandType: command.getCommandType(), + title: command.getTitle(), + }; + } + + function serializeCommands(commands) { + if (!commands) return []; + return commands.map((command) => serializeCommand(command)); + } + function deserializeCommand(object) { return new Command(object); } - + function deserializeCommands(objects) { if (!objects) return []; return objects.map((object) => deserializeCommand(object)); } - + + function serializeRemote(remote) { + return { + id: remote.getId(), + title: remote.getTitle(), + commands: remote.getCommands().map((command) => ({ + id: command.getId(), + })), + }; + } + function deserializeRemote(object) { return new Remote(object); } - + function deserializeRemotes(objects) { if (!objects) return []; return objects.map((object) => deserializeRemote(object)); @@ -57,8 +83,11 @@ const Serializer = (function () { deserializeDevices, deserializeIntegration, deserializeIntegrations, + serializeCommand, + serializeCommands, deserializeCommand, deserializeCommands, + serializeRemote, deserializeRemote, deserializeRemotes, }; diff --git a/www/src/modals/create-command-modal.jsx b/www/src/modals/create-command-modal.jsx index dd15e0a..71cad47 100644 --- a/www/src/modals/create-command-modal.jsx +++ b/www/src/modals/create-command-modal.jsx @@ -24,7 +24,9 @@ function CreateCommandModal(props) { ); const isDeviceValid = createMemo(() => device() !== "" && !isNaN(device())); const isCommandTypeValid = createMemo(() => commandType() !== ""); - const isTitleValid = createMemo(() => title().length >= MIN_TITLE_LENGTH); + const isTitleValid = createMemo( + () => title() === "" || title().length >= MIN_TITLE_LENGTH + ); const isFormValid = createMemo( () => @@ -41,8 +43,8 @@ function CreateCommandModal(props) { command = await RemotesService.createCommand( new Command({ protocol: protocol(), - commandNumber: commandNumber(), - device: device(), + commandNumber: parseInt(commandNumber()), + device: parseInt(device()), commandType: commandType(), title: title(), }) diff --git a/www/src/modals/create-remote-modal.jsx b/www/src/modals/create-remote-modal.jsx index 60824c7..4b369dd 100644 --- a/www/src/modals/create-remote-modal.jsx +++ b/www/src/modals/create-remote-modal.jsx @@ -37,6 +37,7 @@ function CreateRemoteModal(props) { ); } catch (e) { setError(e.message); + console.error(e); return; } resetFields(); diff --git a/www/src/modals/import-commands-modal.jsx b/www/src/modals/import-commands-modal.jsx index 960d28f..ce88198 100644 --- a/www/src/modals/import-commands-modal.jsx +++ b/www/src/modals/import-commands-modal.jsx @@ -360,7 +360,11 @@ function ImportCommandsModal(props) { let protocol = valueMapping()[PROTOCOL_FIELD][row[protocolField]]; if (!protocol) return null; let commandNumber = row[commandNumberField]; + if (isNaN(commandNumber)) return null; + commandNumber = parseInt(commandNumber); let device = row[deviceField]; + if (isNaN(device)) return null; + device = parseInt(device); let commandType = valueMapping()[COMMAND_TYPE_FIELD][row[commandTypeField]]; if (!commandType) return null; diff --git a/www/src/services/remotes-service.js b/www/src/services/remotes-service.js index e0b2a09..dfa620e 100644 --- a/www/src/services/remotes-service.js +++ b/www/src/services/remotes-service.js @@ -1,78 +1,93 @@ import Command from "../data/command"; import Serializer from "../data/serializer"; +import Net from "../tools/net"; -function RemotesService() { - let _commands = [ - new Command({ - id: 1, - protocol: "samsung", - commandNumber: 1, - device: 7, - commandType: "power", - title: "Power Samsung", - }), - new Command({ - id: 2, - protocol: "samsung", - commandNumber: 2, - device: 7, - commandType: "input", - title: "Input Samsung", - }), - new Command({ - id: 3, - protocol: "samsung", - commandNumber: 3, - device: 7, - commandType: "volume_up", - title: "Volume Up Samsung", - }), - ]; +function RemoteService() { let remotes = []; async function getRemotes() { - return [].concat(remotes); + let response = await Net.sendRequest({ + method: "GET", + url: "/api/remotes", + }); + + if (response.status !== 200) { + let responseData = JSON.parse(response.data); + throw new Error(responseData.error); + } + + let remoteObjects = JSON.parse(response.data); + return Serializer.deserializeRemotes(remoteObjects); } async function createRemote(remote) { - let id = Math.random().toString(36).substr(2, 9); - remote.setId(id); - remotes.push(remote); - return remote; + let remoteObject = Serializer.serializeRemote(remote); + let response = await Net.sendJsonRequest({ + method: "POST", + url: "/api/remotes", + data: remoteObject, + }); + + if (response.status !== 200) { + let responseData = JSON.parse(response.data); + throw new Error(responseData.error); + } } async function deleteRemote(remoteId) { - let index = remotes.findIndex((remote) => remote.getId() === remoteId); - if (index >= 0) { - remotes.splice(index, 1); + let response = await Net.sendRequest({ + method: "DELETE", + url: "/api/remotes/" + remoteId, + }); + + if (response.status !== 200) { + let responseData = JSON.parse(response.data); + throw new Error(responseData.error); } } async function getCommands() { - return [].concat(_commands); + let response = await Net.sendRequest({ + method: "GET", + url: "/api/commands", + }); + + if (response.status !== 200) { + let responseData = JSON.parse(response.data); + throw new Error(responseData.error); + } + + let commandObjects = JSON.parse(response.data); + return Serializer.deserializeCommands(commandObjects); } async function createCommand(command) { - let id = Math.random().toString(36).substr(2, 9); - command.setId(id); - _commands.push(command); - return command; + return createCommands([command]); } async function createCommands(commands) { - if (!commands || commands.length === 0) return []; - commands.forEach((command) => { - let id = Math.random().toString(36).substr(2, 9); - command.setId(id); - _commands.push(command); + let commandObjects = Serializer.serializeCommands(commands); + let response = await Net.sendJsonRequest({ + method: "POST", + url: "/api/commands", + data: commandObjects, }); - return commands; + + if (response.status !== 200) { + let responseData = JSON.parse(response.data); + throw new Error(responseData.error); + } } async function deleteCommand(commandId) { - let index = _commands.findIndex((command) => command.getId() === commandId); - if (index >= 0) { - _commands.splice(index, 1); + let response = await Net.sendRequest({ + method: "DELETE", + url: "/api/commands/" + commandId, + }); + + if (response.status !== 200) { + let responseData = JSON.parse(response.data); + throw new Error(responseData.error); } } @@ -87,6 +102,6 @@ function RemotesService() { }; } -RemotesService = new RemotesService(); +RemoteService = new RemoteService(); -export default RemotesService; +export default RemoteService;