Skip to content

Commit

Permalink
Merge pull request #143 from TheCacophonyProject/test-rec-tweak
Browse files Browse the repository at this point in the history
made tsc file and added some better state handling
  • Loading branch information
gferraro authored Aug 28, 2024
2 parents 0acbf35 + e530fda commit b90ff8f
Show file tree
Hide file tree
Showing 8 changed files with 389 additions and 214 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,10 @@ api/types.js
api/types.js.map
static/js/camera.js
static/js/camera.js.map
static/js/audiorecording.js
static/js/audiorecording.js.map
go.work
go.work.sum
node_modules
package-lock.json
package.json
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ build: install-packr install-typescript
install-typescript:
npm install -g typescript
npm install -g rollup
npm i @types/jquery
npx tsc

.PHONY: release
Expand Down
8 changes: 5 additions & 3 deletions api/audiorecording.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,18 @@ func (api *ManagementAPI) AudioRecordingStatus(w http.ResponseWriter, r *http.Re
return
}

var result int
err = tc2AgentDbus.Call("org.cacophony.TC2Agent.audiostatus", 0).Store(&result)
var status int
var mode int
err = tc2AgentDbus.Call("org.cacophony.TC2Agent.audiostatus", 0).Store(&mode, &status)
if err != nil {
log.Println(err)
http.Error(w, "Failed to request test audio recoding", http.StatusInternalServerError)
return
}
rp2040status := map[string]int{"mode": mode, "status": status}

w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(result)
json.NewEncoder(w).Encode(rp2040status)

}

Expand Down
112 changes: 68 additions & 44 deletions cmd/managementd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,14 @@ const (
)

var (
haveClients = make(chan bool)
version = "<not set>"
sockets = make(map[int64]*WebsocketRegistration)
socketsLock sync.RWMutex
headerInfo *headers.HeaderInfo
frameCh = make(chan *FrameData, 4)
currentFrame = -1
log *logrus.Logger
haveClients = make(chan bool)
version = "<not set>"
sockets = make(map[int64]*WebsocketRegistration)
socketsLock sync.RWMutex
headerInfo *headers.HeaderInfo
frameCh = make(chan *FrameData, 4)
connected atomic.Bool
log *logrus.Logger
)

type Args struct {
Expand Down Expand Up @@ -253,7 +253,10 @@ func main() {
listener.Close()

err = handleConn(conn)
frameCh <- &FrameData{Disconnected: true}
log.Printf("camera connection ended with: %v", err)
connected.Store(false)

}
}()

Expand Down Expand Up @@ -282,7 +285,7 @@ func handleConn(conn net.Conn) error {
var frame *cptvframe.Frame = cptvframe.NewFrame(headerInfo)
var frames int = 0
var lastFrame *FrameData

connected.Store(true)
for {
_, err := io.ReadFull(reader, rawFrame)
if err != nil {
Expand Down Expand Up @@ -353,6 +356,10 @@ func WebsocketServer(ws *websocket.Conn) {
LastHeartbeatAt: time.Now(),
AtomicLock: 0,
}
if !connected.Load() {
_ = websocket.Message.Send(ws, "disconnected")
}

socketsLock.Unlock()
if firstSocket {
log.Print("Get new client register")
Expand Down Expand Up @@ -389,40 +396,56 @@ func sendFrameToSockets() {
lastFrame = <-frameCh

if len(sockets) != 0 {
// Make the frame info
buffer := bytes.NewBuffer(make([]byte, 0))
frameInfo := FrameInfo{
Camera: map[string]interface{}{"ResX": headerInfo.ResX(), "ResY": headerInfo.ResY()},
Telemetry: lastFrame.Frame.Status,
Tracks: lastFrame.Tracks,
}
frameInfoJson, _ := json.Marshal(frameInfo)
frameInfoLen := len(frameInfoJson)
// Write out the length of the frameInfo json as a u16
_ = binary.Write(buffer, binary.LittleEndian, uint16(frameInfoLen))
_ = binary.Write(buffer, binary.LittleEndian, frameInfoJson)
for _, row := range lastFrame.Frame.Pix {
_ = binary.Write(buffer, binary.LittleEndian, row)
}
// Send the buffer back to the client
frameBytes := buffer.Bytes()
socketsLock.RLock()
for uuid, socket := range sockets {
go func(socket *WebsocketRegistration, uuid int64, frameNum int) {
// If the socket is busy sending the previous frame,
// don't block, just move on to the next socket.
if atomic.CompareAndSwapUint32(&socket.AtomicLock, 0, 1) {
_ = websocket.Message.Send(socket.Socket, frameBytes)
atomic.StoreUint32(&socket.AtomicLock, 0)
} else {
// Locked, skip this frame to let client catch up.
log.Println("Skipping frame for", uuid, frameNum)
}
}(socket, uuid, frameNum)
if lastFrame.Disconnected {
socketsLock.RLock()
for uuid, socket := range sockets {
go func(socket *WebsocketRegistration, uuid int64, frameNum int) {
// If the socket is busy sending the previous frame,
// don't block, just move on to the next socket.
if atomic.CompareAndSwapUint32(&socket.AtomicLock, 0, 1) {
_ = websocket.Message.Send(socket.Socket, "disconnected")
atomic.StoreUint32(&socket.AtomicLock, 0)
} else {
time.Sleep(100 * time.Millisecond)
}
}(socket, uuid, frameNum)
}
socketsLock.RUnlock()
} else {
// Make the frame info
buffer := bytes.NewBuffer(make([]byte, 0))
frameInfo := FrameInfo{
Camera: map[string]interface{}{"ResX": headerInfo.ResX(), "ResY": headerInfo.ResY()},
Telemetry: lastFrame.Frame.Status,
Tracks: lastFrame.Tracks,
}
frameInfoJson, _ := json.Marshal(frameInfo)
frameInfoLen := len(frameInfoJson)
// Write out the length of the frameInfo json as a u16
_ = binary.Write(buffer, binary.LittleEndian, uint16(frameInfoLen))
_ = binary.Write(buffer, binary.LittleEndian, frameInfoJson)
for _, row := range lastFrame.Frame.Pix {
_ = binary.Write(buffer, binary.LittleEndian, row)
}
// Send the buffer back to the client
frameBytes := buffer.Bytes()
socketsLock.RLock()
for uuid, socket := range sockets {
go func(socket *WebsocketRegistration, uuid int64, frameNum int) {
// If the socket is busy sending the previous frame,
// don't block, just move on to the next socket.
if atomic.CompareAndSwapUint32(&socket.AtomicLock, 0, 1) {
_ = websocket.Message.Send(socket.Socket, frameBytes)
atomic.StoreUint32(&socket.AtomicLock, 0)
} else {
// Locked, skip this frame to let client catch up.
log.Println("Skipping frame for", uuid, frameNum)
}
}(socket, uuid, frameNum)
}
socketsLock.RUnlock()
frameNum = lastFrame.Frame.Status.FrameCount
}
socketsLock.RUnlock()
frameNum = lastFrame.Frame.Status.FrameCount

var socketsToRemove []int64
socketsLock.RLock()
for uuid, socket := range sockets {
Expand Down Expand Up @@ -452,6 +475,7 @@ func sendFrameToSockets() {
}

type FrameData struct {
Frame *cptvframe.Frame
Tracks []map[string]interface{}
Disconnected bool
Frame *cptvframe.Frame
Tracks []map[string]interface{}
}
56 changes: 33 additions & 23 deletions static/js/about.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ async function readAutoUpdate() {
var res = await fetch("/api/auto-update", { headers: authHeaders });
if (res.ok) {
resJson = await res.json();
document.getElementById('auto-update-checkbox').checked = resJson.autoUpdate;
document.getElementById("auto-update-checkbox").checked =
resJson.autoUpdate;
}
}

Expand Down Expand Up @@ -122,15 +123,20 @@ async function updateSaltState() {
var data = JSON.parse(await response.text());

if (data.RunningUpdate) {
document.getElementById("salt-update-button").setAttribute("disabled", true);
document.getElementById("salt-update-button").textContent = "Running Salt Update...";
document
.getElementById("salt-update-button")
.setAttribute("disabled", true);
document.getElementById("salt-update-button").textContent =
"Running Salt Update...";
setTimeout(updateSaltState, 2000);
} else {
enableSaltButton();
}

document.getElementById("salt-update-progress").textContent = data.UpdateProgressPercentage;
document.getElementById("salt-update-progress-text").textContent = data.UpdateProgressStr;
document.getElementById("salt-update-progress").textContent =
data.UpdateProgressPercentage;
document.getElementById("salt-update-progress-text").textContent =
data.UpdateProgressStr;
document.getElementById("running-salt-command").textContent =
data.RunningUpdate ? "Yes" : "No";
document.getElementById("running-salt-arguements").textContent =
Expand All @@ -156,7 +162,8 @@ async function updateSaltState() {

function enableSaltButton() {
document.getElementById("salt-update-button").removeAttribute("disabled");
document.getElementById("salt-update-button").textContent = "Run Salt Update...";
document.getElementById("salt-update-button").textContent =
"Run Salt Update...";
}

var runningSaltUpdate = true;
Expand Down Expand Up @@ -202,16 +209,18 @@ function pollSaltUpdateState() {
}

function getEnvironmentState() {
fetch('/api/salt-grains', {
headers: authHeaders
fetch("/api/salt-grains", {
headers: authHeaders,
})
.then(response => response.json())
.then(data => {
.then((response) => response.json())
.then((data) => {
if (data.environment) {
document.getElementById('environment-select').value = data.environment;
document.getElementById("environment-select").value = data.environment;
}
})
.catch(error => console.error('Error fetching environment state:', error));
})
.catch((error) =>
console.error("Error fetching environment state:", error)
);
}

async function setEnvironment() {
Expand All @@ -221,22 +230,23 @@ async function setEnvironment() {
}
$("#set-environment-button").attr("disabled", true);
$("#set-environment-button").html("Setting Environment");
const selectedEnvironment = document.getElementById('environment-select').value;
const selectedEnvironment =
document.getElementById("environment-select").value;
headers = authHeaders;
headers.append('Content-Type', 'application/json');
headers.append("Content-Type", "application/json");
try {
var response = await fetch('/api/salt-grains', {
method: 'POST',
headers: headers,
body: JSON.stringify({ environment: selectedEnvironment })
})
var response = await fetch("/api/salt-grains", {
method: "POST",
headers: headers,
body: JSON.stringify({ environment: selectedEnvironment }),
});
if (response.ok) {
alert('Environment set successfully');
alert("Environment set successfully");
} else {
alert('Failed to set environment');
alert("Failed to set environment");
}
} catch (error) {
console.error('Error setting environment:', error);
console.error("Error setting environment:", error);
}
$("#set-environment-button").attr("disabled", false);
$("#set-environment-button").html("Set Environment");
Expand Down
Loading

0 comments on commit b90ff8f

Please sign in to comment.