generated from thinkode/modelRepository
Compare commits
3 Commits
037735fb85
...
b69097e2a4
| Author | SHA1 | Date | |
|---|---|---|---|
| b69097e2a4 | |||
| c3c604d871 | |||
| 1052dcc8d5 |
@@ -9,17 +9,17 @@
|
||||
import Show from './components/Show/Show.svelte';
|
||||
import GeneralConsole from './components/Console/GeneralConsole.svelte';
|
||||
import RoundIconButton from './components/General/RoundIconButton.svelte';
|
||||
import { showInformation, needProjectSave, peripherals } from './stores';
|
||||
import { generateToast, showInformation, needProjectSave, peripherals } from './stores';
|
||||
import { SaveProject } from '../wailsjs/go/main/App.js';
|
||||
import { construct_svelte_component } from 'svelte/internal';
|
||||
import { EventsOn } from '../wailsjs/runtime'
|
||||
import { CreateProject, GetPeripherals } from "../wailsjs/go/main/App";
|
||||
import { WindowSetTitle } from "../wailsjs/runtime/runtime"
|
||||
import { get } from "svelte/store"
|
||||
import ToastNotification from './components/General/ToastNotification.svelte';
|
||||
|
||||
// Handle the event when a new peripheral is detected
|
||||
EventsOn('PERIPHERAL_ARRIVAL', function(peripheralInfo){
|
||||
console.log("Hardware has been added to the system");
|
||||
// When a new peripheral is detected, add it to the map and:
|
||||
// - Pass the isDetected key to true
|
||||
// - Set the isSaved key to the last value
|
||||
@@ -31,6 +31,8 @@
|
||||
peripherals[peripheralInfo.SerialNumber] = peripheralInfo
|
||||
return {...peripherals}
|
||||
})
|
||||
console.log("Hardware has been added to the system");
|
||||
generateToast('info', 'bxs-hdd', 'Your <b>' + peripheralInfo.Name + '</b> device has been detected')
|
||||
})
|
||||
|
||||
// Handle the event when a peripheral is removed from the system
|
||||
@@ -49,6 +51,7 @@
|
||||
storedPeripherals[peripheralInfo.SerialNumber].isDetected = false
|
||||
return {...storedPeripherals}
|
||||
})
|
||||
generateToast('warning', 'bxs-hdd', 'Your <b>' + peripheralInfo.Name + '</b> device has been removed')
|
||||
})
|
||||
|
||||
// Set the window title
|
||||
@@ -67,8 +70,10 @@
|
||||
SaveProject().then((filePath) => {
|
||||
needProjectSave.set(false)
|
||||
console.log("Project has been saved to " + filePath)
|
||||
generateToast('info', 'bxs-save', 'The project has been saved')
|
||||
}).catch((error) => {
|
||||
console.error(`Unable to save the project: ${error}`)
|
||||
generateToast('danger', 'bx-error', 'Unable to save the project: ' + error)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -79,8 +84,9 @@
|
||||
})
|
||||
|
||||
// Request the list of peripherals
|
||||
// TODO: Handle the error here
|
||||
GetPeripherals()
|
||||
GetPeripherals().catch((error) => {
|
||||
generateToast('danger', 'bx-error', 'Unable to get the list of peripherals: ' + error)
|
||||
})
|
||||
|
||||
// Handle window shortcuts
|
||||
document.addEventListener('keydown', function(event) {
|
||||
@@ -116,6 +122,7 @@
|
||||
{:else if selectedMenu === "console"}
|
||||
<GeneralConsole />
|
||||
{/if}
|
||||
<ToastNotification/>
|
||||
</main>
|
||||
|
||||
<style>
|
||||
|
||||
94
frontend/src/components/General/ToastNotification.svelte
Normal file
94
frontend/src/components/General/ToastNotification.svelte
Normal file
@@ -0,0 +1,94 @@
|
||||
<script lang=ts>
|
||||
import { time } from 'svelte-i18n';
|
||||
import {messages, colors} from '../../stores.js';
|
||||
|
||||
let timers = {};
|
||||
|
||||
function removeToast(id) {
|
||||
// Supprime un toast par son ID
|
||||
$messages = $messages.filter(message => message.id !== id);
|
||||
clearTimeout(timers[id]);
|
||||
}
|
||||
|
||||
$: {
|
||||
// Ajoute un timer pour supprimer automatiquement les toasts
|
||||
for (const message of $messages) {
|
||||
if (!timers[message.id]) {
|
||||
timers[message.id] = setTimeout(() => removeToast(message.id), 5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="notificationsPanel">
|
||||
{#each $messages as message}
|
||||
<div class="toastMessage" style="background-color: {$colors.second}; color: {$colors.white}" on:mouseup={() => removeToast(message.id)}>
|
||||
<div class="toastIndicator" style="background-color:{(message.type == 'danger') ? $colors.nok : (message.type == 'warning') ? $colors.orange : $colors.third};"></div>
|
||||
<p><i class='bx {message.icon}'></i> {@html message.text}</p>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
p{
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
.toastIndicator{
|
||||
width: 10px;
|
||||
border-top-left-radius: 0.5em;
|
||||
border-bottom-left-radius: 0.5em;
|
||||
}
|
||||
|
||||
.toastMessage:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.toastMessage{
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
white-space: normal;
|
||||
z-index: 150;
|
||||
display: flex;
|
||||
opacity: 0.8;
|
||||
border-radius: 0.5em;
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1), /* Ombre principale douce */
|
||||
0px 1px 3px rgba(0, 0, 0, 0.06); /* Ombre plus subtile */
|
||||
animation: fade-in 0.3s ease-out, fade-out 0.3s ease-in 4.7s;
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 0.9;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-out {
|
||||
from {
|
||||
opacity: 0.9;
|
||||
transform: translateY(0);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
}
|
||||
|
||||
.notificationsPanel{
|
||||
max-width: 50em;
|
||||
align-items: flex-end;
|
||||
position: fixed;
|
||||
bottom: 1rem;
|
||||
right: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
z-index: 1000;
|
||||
}
|
||||
</style>
|
||||
@@ -2,7 +2,7 @@
|
||||
import DeviceCard from "./DeviceCard.svelte";
|
||||
import Tab from "../General/Tab.svelte";
|
||||
import { _ } from 'svelte-i18n'
|
||||
import { needProjectSave, peripherals } from "../../stores";
|
||||
import { generateToast, needProjectSave, peripherals } from "../../stores";
|
||||
import { get } from "svelte/store"
|
||||
import { AddOS2LPeripheral, RemovePeripheral, ConnectFTDI, ActivateFTDI, DeactivateFTDI, DisconnectFTDI, SetDeviceFTDI, AddPeripheral } from "../../../wailsjs/go/main/App";
|
||||
import RoundedButton from "../General/RoundedButton.svelte";
|
||||
@@ -62,6 +62,7 @@
|
||||
$needProjectSave = true
|
||||
}).catch((error) => {
|
||||
console.log("Unable to add the peripheral to the project: " + error)
|
||||
generateToast('danger', 'bx-error', 'Unable to add this device to project')
|
||||
})
|
||||
}
|
||||
|
||||
@@ -85,6 +86,7 @@
|
||||
$needProjectSave = true
|
||||
}).catch((error) => {
|
||||
console.log("Unable to remove the peripheral from the project: " + error)
|
||||
generateToast('danger', 'bx-error', 'Unable to remove this device from project')
|
||||
})
|
||||
}
|
||||
|
||||
@@ -97,8 +99,11 @@
|
||||
currentPeriph[os2lDevice.SerialNumber] = os2lDevice
|
||||
return {...currentPeriph}
|
||||
})
|
||||
$needProjectSave = true
|
||||
generateToast('info', 'bx-signal-5', 'Your OS2L peripheral has been created')
|
||||
}).catch(error => {
|
||||
console.log("Unable to add the OS2L peripheral: " + error)
|
||||
generateToast('danger', 'bx-error', 'Unable to create the OS2L peripheral')
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -114,7 +119,7 @@
|
||||
if(!peripheral.isSaved)
|
||||
addPeripheral(peripheral)
|
||||
}}
|
||||
title={peripheral.Name} type={peripheral.ProtocolName} location={peripheral.Location ? peripheral.Location : ""} line1={peripheral.SerialNumber ? "S/N: " + peripheral.SerialNumber : ""} addable={!peripheral.isSaved}/>
|
||||
title={peripheral.Name} type={peripheral.ProtocolName} location={peripheral.Location ? peripheral.Location : ""} line1={"S/N: " + peripheral.SerialNumber} addable={!peripheral.isSaved}/>
|
||||
{/if}
|
||||
{/each}
|
||||
<p style="color: var(--first-color);"><i class='bx bxs-network-chart' ></i> Others</p>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang=ts>
|
||||
import { projectsList, showInformation, needProjectSave, peripherals } from '../../stores.js';
|
||||
import { generateToast, projectsList, showInformation, needProjectSave, peripherals } from '../../stores.js';
|
||||
import RoundedButton from "../General/RoundedButton.svelte";
|
||||
import ProjectPropertiesContent from "./ProjectPropertiesContent.svelte";
|
||||
import DropdownList from "../General/DropdownList.svelte";
|
||||
@@ -23,6 +23,7 @@
|
||||
$projectsList = projects
|
||||
}).catch((error) => {
|
||||
console.error(`Unable to get the projects list: ${error}`)
|
||||
generateToast('danger', 'bx-error', 'Unable to get the projects list')
|
||||
})
|
||||
}
|
||||
|
||||
@@ -51,8 +52,10 @@
|
||||
return {...storedPeripherals}
|
||||
})
|
||||
needProjectSave.set(false)
|
||||
generateToast('info', 'bx-folder-open', 'The project <b>' + projectInfo.ShowInfo.Name + '</b> was opened')
|
||||
}).catch((error) => {
|
||||
console.error(`Unable to open the project: ${error}`)
|
||||
generateToast('danger', 'bx-error', 'Unable to open the project')
|
||||
})
|
||||
}
|
||||
|
||||
@@ -61,6 +64,7 @@
|
||||
CreateProject().then((showInfo) => {
|
||||
$showInformation = showInfo
|
||||
$needProjectSave = true
|
||||
generateToast('info', 'bxs-folder-plus', 'The project was created')
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -68,7 +72,6 @@
|
||||
<!-- Project buttons -->
|
||||
<RoundedButton on:click={initializeNewProject} text={$_("newProjectString")} icon='bxs-plus-square' tooltip={$_("newProjectTooltip")}/>
|
||||
<DropdownList icon='bxs-folder-open' text={$_("openProjectString")} choices={choices} tooltip={$_("openProjectTooltip")} on:click={loadProjectsList} on:selected={openSelectedProject}/>
|
||||
|
||||
<!-- Project tabcontrol -->
|
||||
<Tab { tabs } maxHeight='73vh'/>
|
||||
|
||||
|
||||
@@ -7,6 +7,16 @@ export let needProjectSave = writable(true)
|
||||
// Show settings
|
||||
export let showInformation = writable({})
|
||||
|
||||
// Toasts notifications
|
||||
export let messages = writable([])
|
||||
export function generateToast(type, icon, text){
|
||||
messages.update((value) => {
|
||||
value.push( { id: Date.now(), type: type, icon: icon, text: text } )
|
||||
return value.slice(-5)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// Application colors
|
||||
export const colors = writable({
|
||||
first: "#1B262C",
|
||||
|
||||
1
go.mod
1
go.mod
@@ -7,6 +7,7 @@ toolchain go1.21.3
|
||||
require (
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e
|
||||
github.com/mattrtaylor/go-rtmidi v0.0.0-20220428034745-af795b1c1a79
|
||||
github.com/rs/zerolog v1.33.0
|
||||
github.com/wailsapp/wails/v2 v2.9.1
|
||||
golang.org/x/sys v0.20.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
|
||||
6
go.sum
6
go.sum
@@ -1,10 +1,12 @@
|
||||
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
||||
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
@@ -48,6 +50,9 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
||||
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@@ -85,6 +90,7 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -24,6 +26,7 @@ type FTDIDriver struct {
|
||||
|
||||
// NewFTDIDriver creates a new FTDI finder
|
||||
func NewFTDIDriver() *FTDIDriver {
|
||||
log.Trace().Str("file", "FTDIDriver").Msg("FTDI driver created")
|
||||
return &FTDIDriver{
|
||||
peripherals: make(map[string]Peripheral),
|
||||
}
|
||||
@@ -32,9 +35,10 @@ func NewFTDIDriver() *FTDIDriver {
|
||||
// Initialize initializes the FTDI driver
|
||||
func (d *FTDIDriver) Initialize() error {
|
||||
if goRuntime.GOOS != "windows" {
|
||||
log.Error().Str("file", "FTDIDriver").Str("platform", goRuntime.GOOS).Msg("FTDI driver not compatible with your platform")
|
||||
return fmt.Errorf("<!> The FTDI driver is not compatible with your platform yet (%s)", goRuntime.GOOS)
|
||||
}
|
||||
fmt.Println("FTDI driver initialized")
|
||||
log.Trace().Str("file", "FTDIDriver").Msg("FTDI driver initialized")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -48,11 +52,10 @@ func (d *FTDIDriver) GetPeripheral(peripheralID string) (Peripheral, bool) {
|
||||
// Return the specified peripheral
|
||||
peripheral := d.peripherals[peripheralID]
|
||||
if peripheral == nil {
|
||||
fmt.Println("Unable to get the peripheral with the driver")
|
||||
log.Error().Str("file", "FTDIDriver").Str("peripheralID", peripheralID).Msg("unable to get this peripheral from the FTDI driver")
|
||||
return nil, false
|
||||
}
|
||||
fmt.Println("Peripheral found by the FTDI driver")
|
||||
|
||||
log.Debug().Str("file", "FTDIDriver").Str("peripheralID", peripheralID).Msg("peripheral found by the FTDI driver")
|
||||
return peripheral, true
|
||||
}
|
||||
|
||||
@@ -61,6 +64,7 @@ var findFTDI []byte
|
||||
|
||||
// Scan scans the FTDI peripherals
|
||||
func (d *FTDIDriver) Scan(ctx context.Context) error {
|
||||
log.Trace().Str("file", "FTDIDriver").Msg("FTDI scan triggered")
|
||||
time.Sleep(scanDelay)
|
||||
|
||||
// Create a temporary file
|
||||
@@ -69,61 +73,68 @@ func (d *FTDIDriver) Scan(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(tempFile.Name())
|
||||
log.Trace().Str("file", "FTDIDriver").Msg("has created the FIND executable temp")
|
||||
|
||||
// Write the embedded executable to the temp file
|
||||
if _, err := tempFile.Write(findFTDI); err != nil {
|
||||
return err
|
||||
}
|
||||
tempFile.Close()
|
||||
log.Trace().Str("file", "FTDIDriver").Msg("has written the FIND executable")
|
||||
|
||||
ftdiPeripherals := make(map[string]Peripheral)
|
||||
|
||||
finder := exec.Command(tempFile.Name())
|
||||
log.Trace().Str("file", "FTDIDriver").Msg("has executed the FIND executable")
|
||||
|
||||
stdout, err := finder.StdoutPipe()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to create the stdout pipe: %s", err)
|
||||
return fmt.Errorf("unable to create the stdout pipe: %s", err)
|
||||
}
|
||||
|
||||
stderr, err := finder.StderrPipe()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to create the stderr pipe: %s", err)
|
||||
return fmt.Errorf("unable to create the stderr pipe: %s", err)
|
||||
}
|
||||
|
||||
err = finder.Start()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to find FTDI devices: %s", err)
|
||||
return fmt.Errorf("unable to find FTDI devices: %s", err)
|
||||
}
|
||||
|
||||
scannerErr := bufio.NewScanner(stderr)
|
||||
for scannerErr.Scan() {
|
||||
return fmt.Errorf("Unable to find FTDI devices: %s", scannerErr.Text())
|
||||
return fmt.Errorf("unable to find FTDI devices: %s", scannerErr.Text())
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(stdout)
|
||||
for scanner.Scan() {
|
||||
deviceString := scanner.Text()
|
||||
peripheralString := scanner.Text()
|
||||
// The program output is like '0:1:2' where 0 is the location, 1 is the S/N and 2 is the name
|
||||
deviceInfo := strings.Split(deviceString, ":")
|
||||
peripheralInfo := strings.Split(peripheralString, ":")
|
||||
|
||||
fmt.Println("FTDI device: " + deviceString)
|
||||
log.Debug().Str("file", "FTDIDriver").Str("peripheralName", peripheralInfo[2]).Str("peripheralSN", peripheralInfo[1]).Msg("new FTDI peripheral detected")
|
||||
// Convert the location to an integer
|
||||
location, err := strconv.Atoi(deviceInfo[0])
|
||||
location, err := strconv.Atoi(peripheralInfo[0])
|
||||
if err != nil {
|
||||
log.Warn().Str("file", "FTDIDriver").Str("peripheralName", peripheralInfo[2]).Msg("no location provided for this FTDI peripheral")
|
||||
location = -1
|
||||
}
|
||||
// Add the peripheral to the temporary list
|
||||
peripheral, err := NewFTDIPeripheral(deviceInfo[2], deviceInfo[1], location)
|
||||
peripheral, err := NewFTDIPeripheral(peripheralInfo[2], peripheralInfo[1], location)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to create the FTDI peripheral: %v", err)
|
||||
}
|
||||
ftdiPeripherals[deviceInfo[1]] = peripheral
|
||||
ftdiPeripherals[peripheralInfo[1]] = peripheral
|
||||
log.Trace().Str("file", "FTDIDriver").Str("peripheralName", peripheralInfo[2]).Msg("successfully added the FTDI peripheral to the driver")
|
||||
}
|
||||
// Compare with the current peripherals to detect arrivals/removals
|
||||
removedList, addedList := comparePeripherals(d.peripherals, ftdiPeripherals)
|
||||
// Emit the events
|
||||
emitPeripheralsEvents(ctx, removedList, PeripheralRemoval)
|
||||
log.Info().Str("file", "FTDIDriver").Msg("FTDI remove list emitted to the front")
|
||||
emitPeripheralsEvents(ctx, addedList, PeripheralArrival)
|
||||
log.Info().Str("file", "FTDIDriver").Msg("FTDI add list emitted to the front")
|
||||
// Store the new peripherals list
|
||||
d.peripherals = ftdiPeripherals
|
||||
return nil
|
||||
|
||||
@@ -5,7 +5,9 @@ import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"os"
|
||||
"os/exec"
|
||||
"sync"
|
||||
@@ -38,16 +40,19 @@ type FTDIPeripheral struct {
|
||||
|
||||
// NewFTDIPeripheral creates a new FTDI peripheral
|
||||
func NewFTDIPeripheral(name string, serialNumber string, location int) (*FTDIPeripheral, error) {
|
||||
log.Info().Str("file", "FTDIPeripheral").Str("name", name).Str("s/n", serialNumber).Int("location", location).Msg("FTDI peripheral created")
|
||||
// Create a temporary file
|
||||
tempFile, err := os.CreateTemp("", "dmxSender*.exe")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Trace().Str("file", "FTDIPeripheral").Str("s/n", serialNumber).Msg("FTDI sender temp created")
|
||||
|
||||
// Write the embedded executable to the temp file
|
||||
if _, err := tempFile.Write(dmxSender); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Trace().Str("file", "FTDIPeripheral").Str("s/n", serialNumber).Msg("FTDI sender written")
|
||||
|
||||
tempFile.Close()
|
||||
|
||||
@@ -65,35 +70,40 @@ func NewFTDIPeripheral(name string, serialNumber string, location int) (*FTDIPer
|
||||
// Connect connects the FTDI peripheral
|
||||
func (p *FTDIPeripheral) Connect() error {
|
||||
// Connect if no connection is already running
|
||||
fmt.Println(p.dmxSender)
|
||||
log.Trace().Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("connecting FTDI peripheral...")
|
||||
if p.dmxSender == nil {
|
||||
log.Debug().Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("no instance of dmxSender for this FTDI")
|
||||
|
||||
// Executing the command
|
||||
p.dmxSender = exec.Command(p.programName, fmt.Sprintf("%d", p.location))
|
||||
log.Trace().Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("no instance of dmxSender for this FTDI")
|
||||
|
||||
var err error
|
||||
p.stdout, err = p.dmxSender.StdoutPipe()
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to create the stdout pipe: %v", err)
|
||||
log.Err(err).Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("unable to create the stdout pipe")
|
||||
return fmt.Errorf("unable to create the stdout pipe: %v", err)
|
||||
}
|
||||
|
||||
p.stdin, err = p.dmxSender.StdinPipe()
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to create the stdin pipe: %v", err)
|
||||
log.Err(err).Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("unable to create the stdin pipe")
|
||||
return fmt.Errorf("unable to create the stdin pipe: %v", err)
|
||||
}
|
||||
|
||||
p.stderr, err = p.dmxSender.StderrPipe()
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to create the stderr pipe: %v", err)
|
||||
log.Err(err).Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("unable to create the stderr pipe")
|
||||
return fmt.Errorf("unable to create the stderr pipe: %v", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
scanner := bufio.NewScanner(p.stderr)
|
||||
for scanner.Scan() {
|
||||
// Traitez chaque ligne lue depuis stderr
|
||||
fmt.Printf("Erreur : %s\n", scanner.Text())
|
||||
log.Err(fmt.Errorf(scanner.Text())).Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("error detected in dmx sender")
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Printf("Error reading from stderr: %v", err)
|
||||
log.Err(err).Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("error reading from stderr")
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -102,17 +112,12 @@ func (p *FTDIPeripheral) Connect() error {
|
||||
defer p.wg.Done()
|
||||
err = p.dmxSender.Run()
|
||||
if err != nil {
|
||||
// Affiche l'erreur (cela inclut également les erreurs de retour du programme)
|
||||
fmt.Printf("Erreur lors de l'exécution : %v\n", err)
|
||||
|
||||
// Vérifie si l'erreur est liée au code de retour
|
||||
log.Err(err).Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("error while execution of dmw sender")
|
||||
if exitError, ok := err.(*exec.ExitError); ok {
|
||||
// Récupère et affiche le code de retour
|
||||
fmt.Printf("Le programme s'est terminé avec le code : %d\n", exitError.ExitCode())
|
||||
fmt.Println(p.stderr)
|
||||
log.Warn().Str("file", "FTDIPeripheral").Int("exitCode", exitError.ExitCode()).Str("s/n", p.serialNumber).Msg("dmx sender exited with code")
|
||||
}
|
||||
} else {
|
||||
fmt.Println("Le programme s'est terminé avec succès.")
|
||||
log.Debug().Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("dmx sender exited successfully")
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -121,74 +126,72 @@ func (p *FTDIPeripheral) Connect() error {
|
||||
|
||||
// Disconnect disconnects the FTDI peripheral
|
||||
func (p *FTDIPeripheral) Disconnect() error {
|
||||
log.Trace().Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("disconnecting FTDI peripheral...")
|
||||
if p.dmxSender != nil {
|
||||
log.Debug().Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("dmxsender is defined for this FTDI")
|
||||
_, err := io.WriteString(p.stdin, string([]byte{0x04, 0x00, 0x00, 0x00}))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to disconnect: %v", err)
|
||||
log.Err(err).Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("unable to write command to sender")
|
||||
return fmt.Errorf("unable to disconnect: %v", err)
|
||||
}
|
||||
p.stdin.Close()
|
||||
p.stdout.Close()
|
||||
p.dmxSender = nil
|
||||
err = os.Remove(p.programName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to delete the temporary file: %v", err)
|
||||
log.Warn().Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("unable to delete the dmx sender temporary file")
|
||||
return fmt.Errorf("unable to delete the temporary file: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Unable to disconnect: not connected")
|
||||
// if p.dmxSender != nil {
|
||||
// err := p.dmxSender.Process.Kill()
|
||||
// if err != nil {
|
||||
// return fmt.Errorf("Unable to disconnect: %v", err)
|
||||
// }
|
||||
// p.stdin.Close()
|
||||
// p.stdout.Close()
|
||||
// p.dmxSender = nil
|
||||
// err = os.Remove(p.programName)
|
||||
// if err != nil {
|
||||
// return fmt.Errorf("Unable to delete the temporary file: %v", err)
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
// return fmt.Errorf("Unable to disconnect: not connected")
|
||||
log.Warn().Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("error while disconnecting: not connected")
|
||||
return fmt.Errorf("unable to disconnect: not connected")
|
||||
}
|
||||
|
||||
// Activate activates the FTDI peripheral
|
||||
func (p *FTDIPeripheral) Activate() error {
|
||||
if p.dmxSender != nil {
|
||||
log.Debug().Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("dmxsender is defined for this FTDI")
|
||||
_, err := io.WriteString(p.stdin, string([]byte{0x01, 0x00, 0x00, 0x00}))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to activate: %v", err)
|
||||
log.Err(err).Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("unable to write command to sender")
|
||||
return fmt.Errorf("unable to activate: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Unable to activate: not connected")
|
||||
log.Warn().Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("error while activating: not connected")
|
||||
return fmt.Errorf("unable to activate: not connected")
|
||||
}
|
||||
|
||||
// Deactivate deactivates the FTDI peripheral
|
||||
func (p *FTDIPeripheral) Deactivate() error {
|
||||
if p.dmxSender != nil {
|
||||
log.Debug().Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("dmxsender is defined for this FTDI")
|
||||
_, err := io.WriteString(p.stdin, string([]byte{0x02, 0x00, 0x00, 0x00}))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to deactivate: %v", err)
|
||||
log.Err(err).Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("unable to write command to sender")
|
||||
return fmt.Errorf("unable to deactivate: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Unable to deactivate: not connected")
|
||||
log.Warn().Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("error while deactivating: not connected")
|
||||
return fmt.Errorf("unable to deactivate: not connected")
|
||||
}
|
||||
|
||||
// SetDeviceProperty sends a command to the specified device
|
||||
func (p *FTDIPeripheral) SetDeviceProperty(uint32, channelNumber uint32, channelValue byte) error {
|
||||
if p.dmxSender != nil {
|
||||
fmt.Println(channelValue)
|
||||
log.Debug().Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("dmxsender is defined for this FTDI")
|
||||
commandString := []byte{0x03, 0x01, 0x00, 0xff, 0x03, 0x02, 0x00, channelValue}
|
||||
_, err := io.WriteString(p.stdin, string(commandString))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to set device property: %v", err)
|
||||
log.Err(err).Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("unable to write command to sender")
|
||||
return fmt.Errorf("unable to set device property: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Unable to set device property: not connected")
|
||||
log.Warn().Str("file", "FTDIPeripheral").Str("s/n", p.serialNumber).Msg("error while setting device property: not connected")
|
||||
return fmt.Errorf("unable to set device property: not connected")
|
||||
}
|
||||
|
||||
// GetInfo gets all the peripheral information
|
||||
|
||||
@@ -8,27 +8,9 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/mattrtaylor/go-rtmidi"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
/*
|
||||
DMXConnect
|
||||
DMXUSBProtocol.go
|
||||
|
||||
Copyright (c) Valentin Boulanger
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// MIDIDriver represents how the protocol is defined
|
||||
type MIDIDriver struct {
|
||||
peripherals map[string]Peripheral // The list of peripherals
|
||||
@@ -36,6 +18,7 @@ type MIDIDriver struct {
|
||||
|
||||
// NewMIDIDriver creates a new DMXUSB protocol
|
||||
func NewMIDIDriver() *MIDIDriver {
|
||||
log.Trace().Str("file", "MIDIDriver").Msg("MIDI driver created")
|
||||
return &MIDIDriver{
|
||||
peripherals: make(map[string]Peripheral),
|
||||
}
|
||||
@@ -43,7 +26,7 @@ func NewMIDIDriver() *MIDIDriver {
|
||||
|
||||
// Initialize initializes the MIDI driver
|
||||
func (d *MIDIDriver) Initialize() error {
|
||||
fmt.Println("MIDI driver initialized")
|
||||
log.Trace().Str("file", "MIDIDriver").Msg("MIDI driver initialized")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -55,10 +38,12 @@ func (d *MIDIDriver) GetName() string {
|
||||
// GetPeripheral gets the peripheral that correspond to the specified ID
|
||||
func (d *MIDIDriver) GetPeripheral(peripheralID string) (Peripheral, bool) {
|
||||
// Return the specified peripheral
|
||||
peripheral := d.peripherals[peripheralID]
|
||||
if peripheral == nil {
|
||||
peripheral, found := d.peripherals[peripheralID]
|
||||
if !found {
|
||||
log.Error().Str("file", "MIDIDriver").Str("peripheralID", peripheralID).Msg("unable to get this peripheral in the MIDI driver")
|
||||
return nil, false
|
||||
}
|
||||
log.Trace().Str("file", "MIDIDriver").Str("peripheralID", peripheralID).Msg("MIDI peripheral found in the driver")
|
||||
return peripheral, true
|
||||
}
|
||||
|
||||
@@ -86,36 +71,46 @@ func splitStringAndNumber(input string) (string, int, error) {
|
||||
// Scan scans the interfaces compatible with the MIDI protocol
|
||||
func (d *MIDIDriver) Scan(ctx context.Context) error {
|
||||
midiPeripherals := make(map[string]Peripheral)
|
||||
fmt.Println("Opening MIDI scanner port...")
|
||||
log.Trace().Str("file", "MIDIDriver").Msg("opening MIDI scanner port...")
|
||||
midiScanner, err := rtmidi.NewMIDIInDefault()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error when opening the MIDI scanner: %s", err)
|
||||
log.Err(err).Str("file", "MIDIDriver").Msg("unable to open the MIDI scanner port...")
|
||||
return fmt.Errorf("unable to open the MIDI scanner: %s", err)
|
||||
}
|
||||
defer midiScanner.Close()
|
||||
fmt.Println("Scanning MIDI devices...")
|
||||
midiScanner.SetCallback(func(m rtmidi.MIDIIn, b []byte, f float64) {
|
||||
|
||||
})
|
||||
log.Trace().Str("file", "MIDIDriver").Msg("scanning MIDI peripherals...")
|
||||
devicesCount, err := midiScanner.PortCount()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error when scanning MIDI devices: %s", err)
|
||||
log.Err(err).Str("file", "MIDIDriver").Msg("unable to scan MIDI peripherals...")
|
||||
return fmt.Errorf("unable to scan MIDI peripherals: %s", err)
|
||||
}
|
||||
for i := 0; i < devicesCount; i++ {
|
||||
portName, err := midiScanner.PortName(i)
|
||||
if err != nil {
|
||||
log.Warn().Str("file", "MIDIPeripheral").Msg("found peripheral without a correct name, set it to unknown")
|
||||
portName = "Unknown device 0"
|
||||
}
|
||||
// Separate data
|
||||
name, location, err := splitStringAndNumber(portName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to get information from the string: %s", err)
|
||||
log.Err(err).Str("file", "MIDIDriver").Str("description", portName).Msg("invalid peripheral description")
|
||||
return fmt.Errorf("invalid pripheral description: %s", err)
|
||||
}
|
||||
fmt.Printf("New MIDI device found: %s on %i\n", name, location)
|
||||
log.Info().Str("file", "MIDIDriver").Str("name", name).Int("location", location).Msg("MIDI peripheral found")
|
||||
// Add the peripheral to the temporary list
|
||||
midiPeripherals[portName] = NewMIDIPeripheral(name, location)
|
||||
sn := strings.ToLower(strings.Replace(name, " ", "_", -1))
|
||||
midiPeripherals[sn] = NewMIDIPeripheral(name, location, sn)
|
||||
}
|
||||
// Compare with the current peripherals to detect arrivals/removals
|
||||
removedList, addedList := comparePeripherals(d.peripherals, midiPeripherals)
|
||||
// Emit the events
|
||||
emitPeripheralsEvents(ctx, removedList, PeripheralRemoval)
|
||||
log.Info().Str("file", "MIDIDriver").Msg("MIDI remove list emitted to the front")
|
||||
emitPeripheralsEvents(ctx, addedList, PeripheralArrival)
|
||||
log.Info().Str("file", "MIDIDriver").Msg("MIDI add list emitted to the front")
|
||||
// Store the new peripherals list
|
||||
d.peripherals = midiPeripherals
|
||||
return nil
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
package hardware
|
||||
|
||||
import "github.com/rs/zerolog/log"
|
||||
|
||||
// MIDIPeripheral contains the data of a MIDI peripheral
|
||||
type MIDIPeripheral struct {
|
||||
name string // The name of the peripheral
|
||||
location int // The location of the peripheral
|
||||
name string // The name of the peripheral
|
||||
location int // The location of the peripheral
|
||||
serialNumber string // The S/N of the peripheral
|
||||
}
|
||||
|
||||
// NewMIDIPeripheral creates a new MIDI peripheral
|
||||
func NewMIDIPeripheral(name string, location int) *MIDIPeripheral {
|
||||
func NewMIDIPeripheral(name string, location int, serialNumber string) *MIDIPeripheral {
|
||||
log.Trace().Str("file", "MIDIPeripheral").Str("name", name).Str("s/n", serialNumber).Int("location", location).Msg("MIDI peripheral created")
|
||||
return &MIDIPeripheral{
|
||||
name: name,
|
||||
location: location,
|
||||
name: name,
|
||||
location: location,
|
||||
serialNumber: serialNumber,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,5 +49,6 @@ func (p *MIDIPeripheral) GetInfo() PeripheralInfo {
|
||||
return PeripheralInfo{
|
||||
Name: p.name,
|
||||
ProtocolName: "MIDI",
|
||||
SerialNumber: p.serialNumber,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// OS2LDriver represents how the protocol is defined
|
||||
@@ -13,6 +16,7 @@ type OS2LDriver struct {
|
||||
|
||||
// NewOS2LDriver creates a new OS2L driver
|
||||
func NewOS2LDriver() *OS2LDriver {
|
||||
log.Trace().Str("file", "OS2LDriver").Msg("OS2L driver created")
|
||||
return &OS2LDriver{
|
||||
peripherals: make(map[string]Peripheral),
|
||||
}
|
||||
@@ -20,22 +24,25 @@ func NewOS2LDriver() *OS2LDriver {
|
||||
|
||||
// Initialize initializes the MIDI driver
|
||||
func (d *OS2LDriver) Initialize() error {
|
||||
fmt.Println("OS2L driver initialized")
|
||||
log.Trace().Str("file", "OS2LDriver").Msg("OS2L driver initialized")
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreatePeripheral creates a new OS2L peripheral
|
||||
func (d *OS2LDriver) CreatePeripheral(ctx context.Context) (Peripheral, error) {
|
||||
// Create a random serial number for this peripheral
|
||||
randomSerialNumber := fmt.Sprintf("%08x", rand.Intn(1<<32))
|
||||
randomSerialNumber := strings.ToUpper(fmt.Sprintf("%08x", rand.Intn(1<<32)))
|
||||
log.Trace().Str("file", "OS2LDriver").Str("serialNumber", randomSerialNumber).Msg("OS2L peripheral created")
|
||||
peripheral := NewOS2LPeripheral("OS2L", randomSerialNumber)
|
||||
d.peripherals[randomSerialNumber] = peripheral
|
||||
log.Info().Str("file", "OS2LDriver").Str("serialNumber", randomSerialNumber).Msg("OS2L peripheral created and registered")
|
||||
return peripheral, nil
|
||||
}
|
||||
|
||||
// RemovePeripheral removes an OS2L dev
|
||||
func (d *OS2LDriver) RemovePeripheral(serialNumber string) error {
|
||||
delete(d.peripherals, serialNumber)
|
||||
log.Info().Str("file", "OS2LDriver").Str("serialNumber", serialNumber).Msg("OS2L peripheral removed")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -47,10 +54,12 @@ func (d *OS2LDriver) GetName() string {
|
||||
// GetPeripheral gets the peripheral that correspond to the specified ID
|
||||
func (d *OS2LDriver) GetPeripheral(peripheralID string) (Peripheral, bool) {
|
||||
// Return the specified peripheral
|
||||
peripheral := d.peripherals[peripheralID]
|
||||
if peripheral == nil {
|
||||
peripheral, found := d.peripherals[peripheralID]
|
||||
if !found {
|
||||
log.Error().Str("file", "OS2LDriver").Str("peripheralID", peripheralID).Msg("unable to get this peripheral in the OS2L driver")
|
||||
return nil, false
|
||||
}
|
||||
log.Trace().Str("file", "OS2LDriver").Str("peripheralID", peripheralID).Msg("OS2L peripheral found in the driver")
|
||||
return peripheral, true
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package hardware
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// OS2LPeripheral contains the data of an OS2L peripheral
|
||||
type OS2LPeripheral struct {
|
||||
@@ -10,6 +12,7 @@ type OS2LPeripheral struct {
|
||||
|
||||
// NewOS2LPeripheral creates a new OS2L peripheral
|
||||
func NewOS2LPeripheral(name string, serialNumber string) *OS2LPeripheral {
|
||||
log.Trace().Str("file", "OS2LPeripheral").Str("name", name).Str("s/n", serialNumber).Msg("OS2L peripheral created")
|
||||
return &OS2LPeripheral{
|
||||
name: name,
|
||||
serialNumber: serialNumber,
|
||||
@@ -18,25 +21,25 @@ func NewOS2LPeripheral(name string, serialNumber string) *OS2LPeripheral {
|
||||
|
||||
// Connect connects the MIDI peripheral
|
||||
func (p *OS2LPeripheral) Connect() error {
|
||||
fmt.Println("OS2L peripheral connected")
|
||||
log.Info().Str("file", "OS2LPeripheral").Msg("OS2L peripheral connected")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Disconnect disconnects the MIDI peripheral
|
||||
func (p *OS2LPeripheral) Disconnect() error {
|
||||
fmt.Println("OS2L peripheral disconnected")
|
||||
log.Info().Str("file", "OS2LPeripheral").Msg("OS2L peripheral disconnected")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Activate activates the MIDI peripheral
|
||||
func (p *OS2LPeripheral) Activate() error {
|
||||
fmt.Println("OS2L peripheral activated")
|
||||
log.Info().Str("file", "OS2LPeripheral").Msg("OS2L peripheral activated")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Deactivate deactivates the MIDI peripheral
|
||||
func (p *OS2LPeripheral) Deactivate() error {
|
||||
fmt.Println("OS2L peripheral deactivated")
|
||||
log.Info().Str("file", "OS2LPeripheral").Msg("OS2L peripheral deactivated")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/lxn/win"
|
||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||
"golang.org/x/sys/windows"
|
||||
@@ -37,6 +39,7 @@ type HardwareManager struct {
|
||||
|
||||
// NewHardwareManager creates a new HardwareManager
|
||||
func NewHardwareManager() *HardwareManager {
|
||||
log.Trace().Str("package", "hardware").Msg("Hardware instance created")
|
||||
return &HardwareManager{
|
||||
drivers: make(map[string]PeripheralDriver),
|
||||
peripherals: make([]Peripheral, 0),
|
||||
@@ -44,13 +47,17 @@ func NewHardwareManager() *HardwareManager {
|
||||
}
|
||||
}
|
||||
|
||||
// Start starts to finding new device events
|
||||
// Start starts to find new peripheral events
|
||||
func (h *HardwareManager) Start(ctx context.Context) error {
|
||||
cb := windows.NewCallback(h.wndProc)
|
||||
log.Trace().Str("file", "hardware").Msg("wndProc callback set")
|
||||
|
||||
inst := win.GetModuleHandle(nil)
|
||||
cn, err := syscall.UTF16PtrFromString("DMXConnect device watcher")
|
||||
log.Trace().Str("file", "hardware").Msg("got windows API instance")
|
||||
|
||||
cn, err := syscall.UTF16PtrFromString("DMXConnect peripheral watcher")
|
||||
if err != nil {
|
||||
log.Err(err).Str("file", "hardware").Msg("failed to convert window class name to UTF16")
|
||||
return fmt.Errorf("failed to convert window class name to UTF16: %w", err)
|
||||
}
|
||||
wc := win.WNDCLASSEX{
|
||||
@@ -58,12 +65,18 @@ func (h *HardwareManager) Start(ctx context.Context) error {
|
||||
LpfnWndProc: cb,
|
||||
LpszClassName: cn,
|
||||
}
|
||||
log.Trace().Str("file", "hardware").Msg("windows API class created")
|
||||
|
||||
wc.CbSize = uint32(unsafe.Sizeof(wc))
|
||||
if win.RegisterClassEx(&wc) == 0 {
|
||||
log.Err(syscall.GetLastError()).Str("file", "hardware").Msg("failed to register window class")
|
||||
return fmt.Errorf("failed to register window class: %w", syscall.GetLastError())
|
||||
}
|
||||
log.Trace().Str("file", "hardware").Msg("window class registered")
|
||||
|
||||
wName, err := syscall.UTF16PtrFromString("usbevent.exe")
|
||||
if err != nil {
|
||||
log.Err(err).Str("file", "hardware").Msg("failed to convert window class name to UTF16")
|
||||
return fmt.Errorf("failed to convert window name to UTF16: %w", err)
|
||||
}
|
||||
wdw := win.CreateWindowEx(
|
||||
@@ -80,14 +93,18 @@ func (h *HardwareManager) Start(ctx context.Context) error {
|
||||
wc.HInstance,
|
||||
nil)
|
||||
if wdw == 0 {
|
||||
log.Err(syscall.GetLastError()).Str("file", "hardware").Msg("failed to create window")
|
||||
return fmt.Errorf("failed to create window: %w", syscall.GetLastError())
|
||||
}
|
||||
log.Trace().Str("file", "hardware").Msg("window created successfully")
|
||||
|
||||
_ = win.ShowWindow(wdw, win.SW_HIDE)
|
||||
win.UpdateWindow(wdw)
|
||||
log.Trace().Str("file", "hardware").Msg("window shown and updated")
|
||||
|
||||
// To continuously get the devices events from Windows
|
||||
go func() {
|
||||
defer log.Debug().Str("file", "hardware").Msg("peripheral watcher goroutine exited")
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
@@ -105,13 +122,17 @@ func (h *HardwareManager) Start(ctx context.Context) error {
|
||||
|
||||
// To handle the peripheral changed
|
||||
go func() {
|
||||
defer log.Debug().Str("file", "hardware").Msg("peripheral getter goroutine exited")
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-h.deviceChangedEvent:
|
||||
fmt.Println("This is the list of devices")
|
||||
h.Scan(ctx)
|
||||
log.Debug().Str("file", "hardware").Msg("peripheral change event, triggering scan...")
|
||||
err := h.Scan(ctx)
|
||||
if err != nil {
|
||||
log.Err(err).Str("file", "hardware").Msg("unable to scan peripherals")
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -122,26 +143,29 @@ func (h *HardwareManager) Start(ctx context.Context) error {
|
||||
func (h *HardwareManager) GetDriver(driverName string) (PeripheralDriver, error) {
|
||||
driver, exists := h.drivers[driverName]
|
||||
if !exists {
|
||||
log.Error().Str("file", "hardware").Str("driverName", driverName).Msg("unable to get the driver")
|
||||
return nil, fmt.Errorf("Unable to locate the '%s' driver", driverName)
|
||||
}
|
||||
log.Debug().Str("file", "hardware").Str("driverName", driverName).Msg("got driver")
|
||||
return driver, nil
|
||||
}
|
||||
|
||||
// RegisterDriver registers a new peripherals driver
|
||||
func (h *HardwareManager) RegisterDriver(driver PeripheralDriver) {
|
||||
h.drivers[driver.GetName()] = driver
|
||||
fmt.Printf("Success registered the %s driver\n", driver.GetName())
|
||||
log.Info().Str("file", "hardware").Str("driverName", driver.GetName()).Msg("driver registered")
|
||||
}
|
||||
|
||||
// GetPeripheral gets the peripheral object from the parent driver
|
||||
func (h *HardwareManager) GetPeripheral(driverName string, peripheralID string) (Peripheral, bool) {
|
||||
// Get the driver
|
||||
parentDriver := h.drivers[driverName]
|
||||
parentDriver, found := h.drivers[driverName]
|
||||
// If no driver found, return false
|
||||
if parentDriver == nil {
|
||||
fmt.Println("Unable to get the driver")
|
||||
if !found {
|
||||
log.Error().Str("file", "hardware").Str("driverName", driverName).Msg("unable to get the driver")
|
||||
return nil, false
|
||||
}
|
||||
log.Trace().Str("file", "hardware").Str("driverName", parentDriver.GetName()).Msg("driver got")
|
||||
// Contact the driver to get the device
|
||||
return parentDriver.GetPeripheral(peripheralID)
|
||||
}
|
||||
@@ -149,14 +173,15 @@ func (h *HardwareManager) GetPeripheral(driverName string, peripheralID string)
|
||||
// Scan scans all the peripherals for the registered finders
|
||||
func (h *HardwareManager) Scan(ctx context.Context) error {
|
||||
if len(h.drivers) == 0 {
|
||||
return fmt.Errorf("No peripherals driver registered")
|
||||
log.Warn().Str("file", "hardware").Msg("no driver registered")
|
||||
return fmt.Errorf("no driver registered")
|
||||
}
|
||||
for _, driver := range h.drivers {
|
||||
finder := driver
|
||||
driverCopy := driver
|
||||
go func() {
|
||||
err := driver.Scan(ctx)
|
||||
err := driverCopy.Scan(ctx)
|
||||
if err != nil {
|
||||
fmt.Printf("Unable to scan peripherals with the %s driver: %s\n", finder.GetName(), err)
|
||||
log.Err(err).Str("file", "hardware").Str("driverName", driverCopy.GetName()).Msg("unable to scan peripheral")
|
||||
return
|
||||
}
|
||||
}()
|
||||
@@ -170,9 +195,10 @@ func (h *HardwareManager) wndProc(hwnd windows.HWND, msg uint32, wParam, lParam
|
||||
// Trigger the devices scan when the last DEVICE_CHANGE event is received
|
||||
if debounceTimer != nil {
|
||||
debounceTimer.Stop()
|
||||
log.Trace().Str("file", "hardware").Msg("scan debounce timer stopped")
|
||||
}
|
||||
debounceTimer = time.AfterFunc(debounceDuration, func() {
|
||||
fmt.Printf("Devices list has changed, refresh the devices list\n")
|
||||
log.Debug().Str("file", "hardware").Msg("peripheral changed")
|
||||
h.deviceChangedEvent <- struct{}{}
|
||||
})
|
||||
}
|
||||
@@ -183,6 +209,7 @@ func (h *HardwareManager) wndProc(hwnd windows.HWND, msg uint32, wParam, lParam
|
||||
func emitPeripheralsEvents(ctx context.Context, peripheralsList map[string]Peripheral, peripheralEvent PeripheralEvent) {
|
||||
for _, peripheral := range peripheralsList {
|
||||
runtime.EventsEmit(ctx, string(peripheralEvent), peripheral.GetInfo())
|
||||
log.Trace().Str("file", "hardware").Str("event", string(peripheralEvent)).Msg("emit peripheral event")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,9 +222,11 @@ func comparePeripherals(oldPeripherals map[string]Peripheral, newPeripherals map
|
||||
for key, value := range oldPeripherals {
|
||||
oldList[key] = value
|
||||
}
|
||||
log.Trace().Str("file", "hardware").Any("oldList", oldList).Msg("peripheral oldList comparison")
|
||||
for key, value := range newPeripherals {
|
||||
newList[key] = value
|
||||
}
|
||||
log.Trace().Str("file", "hardware").Any("newList", newList).Msg("peripheral newList comparison")
|
||||
// Remove in these lists all the commons peripherals
|
||||
for key := range newList {
|
||||
if _, exists := oldList[key]; exists {
|
||||
@@ -206,7 +235,7 @@ func comparePeripherals(oldPeripherals map[string]Peripheral, newPeripherals map
|
||||
}
|
||||
}
|
||||
// Now the old list contains the removed peripherals, and the new list contains the added peripherals
|
||||
fmt.Printf("%s\n", oldList)
|
||||
fmt.Printf("%s\n", newList)
|
||||
log.Trace().Str("file", "hardware").Any("oldList", oldList).Msg("peripheral oldList computed")
|
||||
log.Trace().Str("file", "hardware").Any("newList", newList).Msg("peripheral newList computed")
|
||||
return oldList, newList
|
||||
}
|
||||
|
||||
21
main.go
21
main.go
@@ -2,8 +2,14 @@ package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"time"
|
||||
|
||||
"os"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/wailsapp/wails/v2"
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
||||
)
|
||||
@@ -12,6 +18,16 @@ import (
|
||||
var assets embed.FS
|
||||
|
||||
func main() {
|
||||
// Configure the logger
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{
|
||||
Out: os.Stderr,
|
||||
TimeFormat: "2006-01-02 15:04:05",
|
||||
})
|
||||
zerolog.TimestampFunc = func() time.Time {
|
||||
return time.Now().Local()
|
||||
}
|
||||
zerolog.SetGlobalLevel(zerolog.TraceLevel)
|
||||
|
||||
// Create an instance of the app structure
|
||||
app := NewApp()
|
||||
|
||||
@@ -28,9 +44,10 @@ func main() {
|
||||
Bind: []interface{}{
|
||||
app,
|
||||
},
|
||||
LogLevel: logger.ERROR,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
println("Error:", err.Error())
|
||||
log.Err(err).Str("file", "main").Msg("unable to start the application")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,13 @@ package main
|
||||
import (
|
||||
"changeme/hardware"
|
||||
"fmt"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// GetPeripherals gets all the peripherals connected
|
||||
func (a *App) GetPeripherals() error {
|
||||
log.Debug().Str("file", "peripherals").Msg("getting peripherals...")
|
||||
return a.hardwareManager.Scan(a.ctx)
|
||||
}
|
||||
|
||||
@@ -15,10 +18,13 @@ func (a *App) AddPeripheral(protocolName string, peripheralID string) error {
|
||||
// Get the device from its finder
|
||||
p, found := a.hardwareManager.GetPeripheral(protocolName, peripheralID)
|
||||
if !found {
|
||||
return fmt.Errorf("Unable to localize the peripheral %s", peripheralID)
|
||||
log.Error().Str("file", "peripheral").Str("protocolName", protocolName).Str("periphID", peripheralID).Msg("unable to found the specified peripheral")
|
||||
return fmt.Errorf("unable to found the peripheral ID '%s'", peripheralID)
|
||||
}
|
||||
// Add the peripheral ID to the project
|
||||
a.projectInfo.PeripheralsInfo[peripheralID] = p.GetInfo()
|
||||
log.Info().Str("file", "peripheral").Str("protocolName", protocolName).Str("periphID", peripheralID).Msg("peripheral added to project")
|
||||
|
||||
// TODO: Connect the peripheral
|
||||
return nil
|
||||
}
|
||||
@@ -28,6 +34,7 @@ func (a *App) RemovePeripheral(protocolName string, peripheralID string) error {
|
||||
// TODO: Disconnect the peripheral
|
||||
// Remove the peripheral ID from the project
|
||||
delete(a.projectInfo.PeripheralsInfo, peripheralID)
|
||||
log.Info().Str("file", "peripheral").Str("protocolName", protocolName).Str("periphID", peripheralID).Msg("peripheral removed from project")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -36,14 +43,20 @@ func (a *App) AddOS2LPeripheral() (hardware.PeripheralInfo, error) {
|
||||
// Get the OS2L driver
|
||||
os2lDriver, err := a.hardwareManager.GetDriver("OS2L")
|
||||
if err != nil {
|
||||
log.Err(err).Str("file", "peripheral").Msg("unable to found the OS2L driver")
|
||||
return hardware.PeripheralInfo{}, err
|
||||
}
|
||||
log.Trace().Str("file", "peripheral").Msg("OS2L driver got")
|
||||
|
||||
// Create a new OS2L peripheral with this driver
|
||||
os2lPeripheral, err := os2lDriver.CreatePeripheral(a.ctx)
|
||||
if err != nil {
|
||||
return hardware.PeripheralInfo{}, nil
|
||||
log.Err(err).Str("file", "peripheral").Msg("unable to create the OS2L peripheral")
|
||||
return hardware.PeripheralInfo{}, err
|
||||
}
|
||||
|
||||
os2lInfo := os2lPeripheral.GetInfo()
|
||||
log.Info().Str("file", "peripheral").Str("s/n", os2lInfo.SerialNumber).Msg("OS2L peripheral created, adding to project")
|
||||
// Add this new peripheral to the project
|
||||
return os2lInfo, a.AddPeripheral(os2lDriver.GetName(), os2lInfo.SerialNumber)
|
||||
}
|
||||
|
||||
72
project.go
72
project.go
@@ -3,7 +3,9 @@ package main
|
||||
import (
|
||||
"changeme/hardware"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
@@ -24,31 +26,42 @@ func (a *App) GetProjects() ([]ProjectMetaData, error) {
|
||||
|
||||
f, err := os.Open(projectsDirectory)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to open the projects directory: %v", err)
|
||||
return nil, err
|
||||
log.Err(err).Str("file", "project").Msg("unable to open the projects directory")
|
||||
return nil, fmt.Errorf("unable to open the projects directory: %v", err)
|
||||
}
|
||||
log.Trace().Str("file", "project").Str("projectsDirectory", projectsDirectory).Msg("projects directory opened")
|
||||
|
||||
files, err := f.Readdir(0)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to read the projects directory: %v", err)
|
||||
return nil, err
|
||||
log.Err(err).Str("file", "project").Msg("unable to read the projects directory")
|
||||
return nil, fmt.Errorf("unable to read the projects directory: %v", err)
|
||||
}
|
||||
log.Trace().Str("file", "project").Any("projectsFiles", files).Msg("project files got")
|
||||
|
||||
for _, fileInfo := range files {
|
||||
// Open the file and get the show name
|
||||
fileData, err := os.ReadFile(filepath.Join(projectsDirectory, fileInfo.Name()))
|
||||
if err == nil {
|
||||
projectObject := ProjectInfo{}
|
||||
err = yaml.Unmarshal(fileData, &projectObject)
|
||||
if err == nil {
|
||||
// Add the SaveFile property
|
||||
projects = append(projects, ProjectMetaData{
|
||||
Name: projectObject.ShowInfo.Name,
|
||||
Save: fileInfo.Name(),
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
log.Warn().Str("file", "project").Str("projectFile", fileInfo.Name()).Msg("unable to open the project file")
|
||||
continue
|
||||
}
|
||||
log.Trace().Str("file", "project").Str("projectFile", fileInfo.Name()).Any("fileData", fileData).Msg("project file read")
|
||||
|
||||
projectObject := ProjectInfo{}
|
||||
err = yaml.Unmarshal(fileData, &projectObject)
|
||||
if err != nil {
|
||||
log.Warn().Str("file", "project").Str("projectFile", fileInfo.Name()).Msg("project has invalid format")
|
||||
continue
|
||||
}
|
||||
log.Trace().Str("file", "project").Str("projectFile", fileInfo.Name()).Msg("project file unmarshalled")
|
||||
|
||||
// Add the SaveFile property
|
||||
projects = append(projects, ProjectMetaData{
|
||||
Name: projectObject.ShowInfo.Name,
|
||||
Save: fileInfo.Name(),
|
||||
})
|
||||
}
|
||||
log.Info().Str("file", "project").Any("projectsList", projects).Msg("got the projects list")
|
||||
return projects, nil
|
||||
}
|
||||
|
||||
@@ -62,6 +75,7 @@ func (a *App) CreateProject() ShowInfo {
|
||||
Avatar: "appicon.png",
|
||||
Comments: "Write your comments here",
|
||||
}
|
||||
log.Info().Str("file", "project").Any("showInfo", a.projectInfo.ShowInfo).Msg("project has been created")
|
||||
return a.projectInfo.ShowInfo
|
||||
}
|
||||
|
||||
@@ -69,20 +83,24 @@ func (a *App) CreateProject() ShowInfo {
|
||||
func (a *App) GetProjectInfo(projectFile string) (ProjectInfo, error) {
|
||||
// Open the project file
|
||||
projectPath := filepath.Join(projectsDirectory, projectFile)
|
||||
log.Trace().Str("file", "project").Str("projectPath", projectPath).Msg("project path is created")
|
||||
content, err := os.ReadFile(projectPath)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to read the project file: %v", err)
|
||||
return ProjectInfo{}, err
|
||||
log.Err(err).Str("file", "project").Str("projectFile", projectFile).Msg("Unable to read the project file")
|
||||
return ProjectInfo{}, fmt.Errorf("unable to read the project file: %v", err)
|
||||
}
|
||||
log.Trace().Str("file", "project").Str("projectPath", projectPath).Msg("project file read")
|
||||
a.projectInfo = ProjectInfo{}
|
||||
err = yaml.Unmarshal(content, &a.projectInfo)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to get the project information: %v", err)
|
||||
return ProjectInfo{}, err
|
||||
log.Err(err).Str("file", "project").Str("projectFile", projectFile).Msg("Unable to get the project information")
|
||||
return ProjectInfo{}, fmt.Errorf("unable to get the project information: %v", err)
|
||||
}
|
||||
log.Trace().Str("file", "project").Str("projectPath", projectPath).Msg("project information got")
|
||||
// Load it into the app
|
||||
a.projectSave = projectFile
|
||||
// Return the show information
|
||||
log.Info().Str("file", "project").Any("projectInfo", a.projectInfo).Msg("got the project information")
|
||||
return a.projectInfo, nil
|
||||
}
|
||||
|
||||
@@ -99,44 +117,56 @@ func (a *App) ChooseAvatarPath() (string, error) {
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
log.Err(err).Str("file", "project").Msg("unable to open the avatar dialog")
|
||||
return "", err
|
||||
}
|
||||
log.Debug().Str("file", "project").Msg("avatar dialog is opened")
|
||||
// Copy the avatar to the application avatars path
|
||||
avatarPath := filepath.Join(avatarsDirectory, filepath.Base(filePath))
|
||||
log.Trace().Str("file", "project").Str("avatarPath", avatarPath).Msg("avatar path is created")
|
||||
_, err = copy(filePath, avatarPath)
|
||||
if err != nil {
|
||||
log.Err(err).Str("file", "project").Str("avatarsDirectory", avatarsDirectory).Str("fileBase", filepath.Base(filePath)).Msg("unable to copy the avatar file")
|
||||
return "", err
|
||||
}
|
||||
log.Info().Str("file", "project").Str("avatarFileName", filepath.Base(filePath)).Msg("got the new avatar file")
|
||||
return filepath.Base(filePath), nil
|
||||
}
|
||||
|
||||
// UpdateShowInfo updates the show information
|
||||
func (a *App) UpdateShowInfo(showInfo ShowInfo) {
|
||||
fmt.Printf("%s\n", showInfo)
|
||||
a.projectInfo.ShowInfo = showInfo
|
||||
log.Info().Str("file", "project").Any("showInfo", showInfo).Msg("show information was updated")
|
||||
}
|
||||
|
||||
// SaveProject saves the project
|
||||
func (a *App) SaveProject() (string, error) {
|
||||
log.Printf("Saving the project %s to %s", a.projectInfo.ShowInfo.Name, a.projectSave)
|
||||
// If there is no save file, create a new one with the show name
|
||||
if a.projectSave == "" {
|
||||
date := time.Now()
|
||||
a.projectSave = fmt.Sprintf("%04d%02d%02d%02d%02d%02d%s", date.Year(), date.Month(), date.Day(), date.Hour(), date.Minute(), date.Second(), projectExtension)
|
||||
log.Debug().Str("file", "project").Str("newProjectSave", a.projectSave).Msg("projectSave is null, getting a new one")
|
||||
}
|
||||
data, err := yaml.Marshal(a.projectInfo)
|
||||
if err != nil {
|
||||
log.Err(err).Str("file", "project").Any("projectInfo", a.projectInfo).Msg("unable to format the project information")
|
||||
return "", err
|
||||
}
|
||||
log.Trace().Str("file", "project").Any("projectInfo", a.projectInfo).Msg("projectInfo has been marshalled")
|
||||
// Create the project directory if not exists
|
||||
err = os.MkdirAll(projectsDirectory, os.ModePerm)
|
||||
if err != nil {
|
||||
log.Err(err).Str("file", "project").Str("projectsDirectory", projectsDirectory).Msg("unable to create the projects directory")
|
||||
return "", err
|
||||
}
|
||||
log.Trace().Str("file", "project").Str("projectsDirectory", projectsDirectory).Msg("projects directory has been created")
|
||||
|
||||
err = os.WriteFile(filepath.Join(projectsDirectory, a.projectSave), data, os.ModePerm)
|
||||
if err != nil {
|
||||
log.Err(err).Str("file", "project").Str("projectsDirectory", projectsDirectory).Str("projectSave", a.projectSave).Msg("unable to save the project")
|
||||
return "", err
|
||||
}
|
||||
log.Info().Str("file", "project").Str("projectFileName", a.projectSave).Msg("project has been saved")
|
||||
return a.projectSave, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user