Giter Club home page Giter Club logo

glowdtf's Introduction

GlowDTF

GlowDTF is a tech demo for controlling GDTF lighting fixtures over Art-Net.

GDTF stands for General Device Type Fixture. It is an open file format to describe the functionality of lighting fixtures in the entertainment industry, like LED bars, scanners or moving heads. You can find more details in the GDTF Resources below.

GlowDTF allows you to patch GDTF 1.1 (DIN SPEC 15800:2020-07) fixtures and control their Channel Functions with a simple slider interface. The DMX values are broadcast to the local network over Art-Net.

The application consists of a browser frontend written in React/TypeScript and a Kotlin/JVM server. The GDTF parser is machine-generated in Java from the official XML Schema with xjc/JAXB.

Being a tech demo, GlowDTF should not be relied upon to work in production situations. Since there are no security measures, you should only use GlowDTF in a secure local network. There are no plans for continued development. However, if you find any unexpected behavior or just want to tell us what you think about our demo, feel free to open an issue anyway.

How To Run

  • Make sure you have Java 11 or higher installed (How To)
    • If not, you can install it for example from Adoptium
  • Download the jar file from our Releases
  • Run the jar by double-clicking on it, or if your prefer the command line:
java -jar glowdtf-0.0.1-dev-all.jar
  • You should see the Javalin server start up in the terminal. Open the browser and navigate to http://localhost:7000. You should see the empty GlowDTF main screen.

Things to Try Out

Add a GDTF

  • Open the patch by clicking on the button in the upper right
  • Navigate to the "Fixture Types" tab and click "Add GDTF"
  • Select a GDTF file and confirm
  • The GDTF file will show up in the table. Click on it to see Details on the right.
  • Click "Show ModeMaster Dependencies" below the DMX channel list to show the dependency graph (only visible if there are ModeMaster dependencies). You can drag the nodes around and zoom with the mouse wheel.

Patch a Fixture

  • Switch to the "Fixtures" tab in the patch and click "Add New Fixtures". Make your settings and confirm with "Add Fixtures". Your fixtures should show up in the Fixture table.
  • To go back to the main screen, click the Exit button in the upper left

Control the Fixture

  • On the main screen, select a fixture in the table on the left. Its channel functions show up as sliders on the right. Drag them to change the DMX output.
  • The DMX values are output via Art-Net to the address 255.255.255.255 (local network broadcast address), so should reach all devices in your local network. The Art-Net universes are numbered from 0 to 32767 and can be set in the Fixture Patch.
  • The channel function sliders react to out-of-range and ModeMaster values. If their name is written in gray but the slider is enabled, the current value of the channel is outside the range of the channel function. If the slider is completely disabled, its ModeMaster needs to be set appropriately.

Quitting GlowDTF

  • On the main screen, click the "Close" Button in the upper right corner. All added Fixture Types and Fixtures will be lost.

Unimplemented Features

As GlowDTF focuses on rudimentary DMX control, there are many things in GDTF that are not supported:

  • Channel Sets and Physical Values
  • Wheels
  • Color Management
  • 3D Models
  • Kinematic Geometry Chains
  • Protocols other than DMX over Art-Net
  • ...

GDTF Resources

  • GDTF Share - Offical Website for GDTF. Database contains many GDTF files for download after registration and the Builder allows you to create your own GDTF files.
  • GDTF Forum - Official Forum. Best place to ask questions regarding GDTF.
  • DIN SPEC 15800:2020-07 - Standard document, free download with registration.
  • mvrdevelopment/spec - Repository for GDTF Development. If you find an issue with the standard document (or the Builder?), open an issue here. You can also find the XML Schema here.
  • GDTF Wiki - This Wiki on the official GDTF site has an up-to-date main page. Older pages from GDTF 1.0 days can still be found with the search. They sometimes contain background info that you won't find anywhere else.
    Note that the library for parsing GDTF and MVR mentioned here is currently available only upon request and I don't know about its licensing.

Developer Documentation

Information on how to build and develop can be found in the CONTRIBUTING.md. Additional in-depth notes on the design are in the folder /dev-docs.

glowdtf's People

Contributors

dependabot[bot] avatar doriansnowball avatar firionus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

glowdtf's Issues

Patch Error Handling

If Fixtures can be added to the Patch but result in potentially unwanted outcomes (overlapping DMX channels, for example, or overlapping FIDs/names), everything should work as well as possible but show clear warnings in the UI.

Nice Display of Fixture Type Details

Show full info for GDTFs in Fixture Type Tab in Patch, such as a nice display for DMX modes, full metadata, etc. See sketches in #1

Tracking ToDo:

  • Nice of DMX Mode Channels
    • Multi-Column Layout
  • Full Metadata
    • Description
    • Fixture Type ID
    • LongName/ShortName
    • RefFT
    • Current and previous Revisions with Text, Date and UserID
  • Check Sketches in #1
  • Graph of Channel Function Dependencies (only show the ones involved in dependencies - overview of all is on main page)
  • Ideally: ModeMaster points from slave to master, but there is a bar next to the parent that shows the ModeMaster range. Each node is rectangular. There is a label on each edge that shows the ModeMaster range numerically.

Dropped:

  • Warnings during GDTF initialization (would require significant refactor on server)

Notes on Node/Edge Graph Visualization Libraries:

Issue Triage Guide

We should have an issue triage guide where we lay down rules how to handle new issues. Possible Points:

  • step-by-step so we don't forget things
  • bugs need to be reproduced
  • features need UX assessment
  • assign priority and milestone
  • assign tags
  • assign to project
  • what steps to write down in the issue and when to assign yourself

Implement Ping API (Client-Side)

The new API design is found in /dev-docs and uses a three-way handshake.

Blocked by #30

  • Test against Server
  • Implement client-side to make tests pass

GlowDTF Release

  • Recommend Adoptium Temurin instead of Azul
  • Check open Issues
  • Do a build according to my own documentation and see if it works across Linux and Windows nicely
    • It works, but when double clicking on Windows with Adoptium 17, it opens in the background. This makes it a hassle to close.
  • Add a Close Button to the GUI
    • Implementation
    • API Docs
    • User Docs
  • Release Tag 0.1.0
  • Clean Build
  • Make a GitHub Release with the jar
  • Add Link to Releases in README

Enable Absent "universe" and "address" in updateFixtures JSON

Currently, when a fixture is updated and there is no change to the "universe" or "address" field, a null value is serialized. This is valid, but it would be nicer if the fields were completely absent.

This is currently not possible in Klaxon so we first need to add a feature upstream. While there already is the "serializeNull" feature, it does not work if we need to use a custom converter (as we have to in this case).

This issue is very low priority as the overhead is not too large, patch changes don't occur often and we may change JSON package in the future anyway.

Maximum WebSocket Message Size & Patching Many Fixtures

Steps to Reproduce

patch 512 fixtures of some type

Observed Behavior

Server closes connection because message is too large

Expected Behavior

Up to a certain reasonable point, let's say 1024 fixtures for two universes, I want to be able to patch many fixtures at once.

Implement Patch

Implement Fixture Patch as a list of all fixtures in the current show.

A Fixture consists of the following fields:

  • uuid*
    • Assigned upon patching of Fixture, immutable
    • 128-bit
  • fid
    • Fixture Identifier
    • u32, freely chosen by the user
    • equivalent to the CustomId in the MVR specification
  • attributes
    • an object, where the name of the attribute are the keys and the values are the values
    • internally, each attribute may have multiple sources associated with it (programmer, cues) that are mixed according to different rules
    • values may be described by effects (which really are functions, depending on time, position of fixture, interactive input and previous internal state)
    • maybe make different APIs for requesting current value of attribute and where it comes from to simplify and reduce overhead
  • name
    • string, freely chosen by user
  • fixtureTypeId
    • Fixture Type Unique ID, see Fixture Types
  • dmxMode
    • string
    • must be found in fixtureType
  • universe
    • Art-Net portAddress universe unique ID
  • startAddress
    • first DMX address in assigned universe
    • 9-bit uint, therefore value-limited u16 or i16

Use HTTP to Check whether Server is Available

Currently (feature/patch-ui ff0bbcac), we use reconnecting-websocket to establish a robust WebSocket connection to the Server. However, Firefox has a very strict rate limiter for failed WebSocket connections (https://bugzilla.mozilla.org/show_bug.cgi?id=711793#c0). In the extreme case, we can only check for a WebSocket connection every 60 seconds. So if we try to reconnect every second on Firefox, this is the resulting network traffic:
firefox_reconnecting_websocket_wireshark
The only way to stop this rate limiting is to restart Firefox. Reload does not work. For comparison, Chrome's rate limiting is much less aggressive:
reconnecting_websocket_chrome

However, this means that if we want to support Firefox properly, we need to use a different mechanism than WebSocket connects for checking whether the server is available.

TODO

  • Research how to find out with HTTP whether a server is reachable
    • new API endpoint?
    • or just make a HTTP request to ws?
    • => make a HEAD request to the server. Could only fail if we hit a cache, but I think our server currently forbids browser-side caching.
  • Implement a ConnectionProvider that handles this (class or hook?)
  • check in regular intervals with HTTP whether the server is available
  • if yes, connect WebSocket once or twice
  • if that fails, go back to checking with HTTP
  • communicate the connection state outwards
    • Subscriptions need to be reset when closing
    • Subscriptions need to be made when opening
    • Connection Error Alert needs to be shown when HTTP cannot reach server
    • Connection Error Alert should communicate when the connection is checked (bar going down, countdown, ?)
    • test with Cypress
    • ensure this also works with the frontend dev server

GDTF handling

TODO

  • Implement HTTP POST endpoint for uploading GDTF file from webui
  • parse uploaded GDTF into object via JAXB
  • Extract DMX modes with corresponding channel count, Fixture Name and Manufacturer and FixtureTypeId from GDTF object
  • How to make these properties available in patch stream?
  • Ensure FixtureTypes in ˋPatchˋ cannot be modified from outside
  • Make documentation of auto-generated GDTF classes English instead of German
  • Test upload of GDTF with client mock
  • Allow deletion of FixtureType
  • Check remaining TODOs (ignore TODOs related to streams or other things that will be handled in later PRs)

Calculate GDTF Channel Layout

The channel layout of a DmxMode in a GDTF file is not trivial to calculate, because each DmxChannel can reference a top-level Geometry which could be inherited from by other GeometryReference elements. The DmxChannel then needs to be repeated for every GeometryReference. Each GeometryReference has its own DMX Break and Offset that dictate the DMX Address of the channels that reference its parent.

The calculation needs to be compared to the GDTF Builder (gdtf-share.com). Our implementation should result in the same layout as the GDTF Builder.

Also, the channel count can then be calculated.

All of this should be added to the GdtfWrapper

TODO:

  • Update XSD from upstream
  • Regenerate GDTF sources (should be automatic?)
  • create data structure for channel layout
    • DMX Break
    • DMX Offset
    • Name
    • or split name into different parts?
    • what about originalName?
    • info on controlled attribute?
    • coarse/fine/ultrafine/... -> should be something like 1/3, 2/3, 3/3, or maybe detail: 1, 2, 3, or byte 1, 2, 3, or byte 1/2, 2/2, or byte 1 of 2, 2 of 2
    • possibility: List<List<String?>> (empty offsets are null, otherwise: "LED1 -> GenericLED_Dimmer (1/2)")
    • possibility: List<List<DmxChannel?>>, DmxChannel(val geometry: String, val attribute: String, val reference: String?, val detail: Byte)
  • Use existing Robin Esprite as one example for channel layout (check version of GDTF file! maybe update GDTF file)
  • Document the behaviour of the GDTF Builder with test cases
    • Interleaved Geometry References
      • A1, B1, A2, B2 (A/B are channels, 1/2 are GeometryReferences)
      • A1, A2, B1, B2
      • unfilled spaces
      • single channels
      • overwrite break
        • For Overwrite, use the last Break in the GeometryReference
        • For Break set in Channel, use the first matching Break in GeometryReference from the top
    • Multiple DMX Breaks
  • Write tests where our implementation is compared against the behaviour of the Builder
  • test for Channel names
  • test channel count
  • Make tests pass
  • Test Fail on clashes between channels (Integration Level)
  • Test Fail on missing break -> offset in GeometryReference (Integration Level)
  • Update API Docs
  • Reactivate Snapshot Test and move them to proper Snapshot Testing Tool

Implement Ping API (server-side)

The new API design is found in /dev-docs and uses a three-way handshake.

  • Remove old streamUpdateId from Code
  • Test new API with Java WebSocket Client
  • Implement server-side to make tests pass

Refactor GDTF Initialization

The current implementation has some code smells, like functions with many arguments and deep nesting. This might be helped with dedicated "context objects" that only exist during initialization, which might also make it possible to remove the field originalChannelFunction from GlowChannelFunction that is only needed during initialization.

Also, the error handling should be unified. See this note from #58:

A warnings field in the GdtfWrapper should contain non-fatal warnings about the file. In fact, I think we currently throw for a lot of cases where we could just ignore that specific part of the file. Guideline: Parse as much as possible, while not arbitrarily choosing to perform undefined behavior.

This warnings field should also be shown in the UI.

GlowDTF Preparation

  • Check for bugs due to unstable ordering of Patch HashMaps (they may be the source of strange behavior where channel functions are disabled for nor apparent reason...)
    • Can confirm. Just patch a few more fixtures of two different types and you'll get invalid state
    • Possible Solutions: Change RigState to a Map, Change Patch to a List
    • I think I'll change RigState to a Map, but on Serialization change to List with fixture uuid as field
    • Then I might as well change RigState to a list with fixture uuid as field and save on some of the effort
    • Also need to update statetransition to include uuid
    • Update API docs
  • Hotfix #30 and #31 by sending a WebSocket ping message every minute. Log it on the server.
  • Sometimes Fixture Type doesn't show up when being added. Try this: Add another fixture type, add a fixture with it, go back to fixtureTypes, add Robin Esprite, observe that it only shows up in table after reload
  • Another Memo in Sliders for improved performance?
    • Nah. Maybe if we create another intermediate object to speed up the useMemo comparisons we could get another performance gain. Or if we put each channel value into its own Recoil Atom, or change to MobX/Redux, we could get an improvement here.
  • Don't show button for ModeMaster Dependencies when there are none
  • When adding new fixtures such that the start address of a following fixture is outside the universe, the WS connection is closed and the user does not get any useful message
  • When focussing a text field like Quantity on New Fixture page, you can't escape out of it with escape (likely regression from that escape bug mitigation)
  • Talk to DorianSnowball
  • Update Dependencies
    • Chokidar Warning when running npm update?
  • Open Pull Request to check that everything works
  • Rename repo to GlowDTF
  • Increment FID on creation
  • Clean up the __mocks__ folder - do we need it at all?
  • Word Wrap in Column Layout for Fixture Types (test with Channel Layout Test GDTF and some zoom)
  • Rewrite Documentation from CueGlow to GlowDTF
  • Add Note that there is no security, things are only to be run in a local and protected network
  • remove all references to the name CueGlow in the files (keep around in commit history)
  • Document how to build and release .jar releases
  • Check whether Test Ressources are in built fat jar. If yes, can we remove them to reduce size?
    • Nope, it's just 17 MB of libraries upon libraries...
  • Finish ToDos in README
  • Stop writing logs to a folder in the application context
  • Make new PR into #63

Implement Stream Subscription Handling

Implement the service so that clients can subscribe to streams and other internal services can publish updates.

The handler should follow the schema pictured in the following image:
architecture_stream_handler

TODO

  • Clienthandling (Subscription/Unsubscription)
  • UpdateNotification/Publishing

Blocked By

#3

Implement JSON API Redesign Server-Side

The old JSON API in the HackMD will be replaced by a new API, documented in /dev-docs. This documentation is currently available on the feature/api branch, but not implemented yet.

TODO:

  • Update existing Tests
  • Write new tests where needed
  • Check with Subscription progress to test subscription API

single events to tick off:

  • addFixtures (sent by client/server)
  • updateFixtures (sent by client/server)
  • error (sent by server)
  • removeFixtures (sent by client/server)
  • removeFixtureTypes (sent by client/server)
  • fixtureTypeAdded
  • patchSubscribe (sent by client)
  • patchInitialState (sent by server)
  • patchUnsubscribe (sent by client)
  • addFixtureTypes (sent by server)

Superfluous streamUpdateId should be removed and heartbeat tested

Currently, all stream updates use a field called streamUpdateId to ensure the client can detect out-of-order or dropped streamUpdate's.

However, WebSocket operates over TCP which already ensures all messages are in order. If messages cannot be delivered in order after a certain timeout, the connection will be closed.

Therefore, we do not need to ensure order of our messages. However, we have to disconnect the WebSocket if there is a connection issue.

Server-side

Detecting faulty connection should be implemented server-side via ping/pong.

  • Check this is implemented
  • Adjust ping interval to an appropriate value like 1s
  • Adjust pong timeout before connection is closed to an appropriate value like 2s

Client-side

By default, the client will only disconnect after the TCP timeout. I think this is usually pretty long (minutes?) which is too long for us. We should probably adjust the TCP timeout to an appropriate value for us (like 2s).

Final Testing

We should use Cypress to ensure proper behavior when client and server are disconnected. The server should close the WebSocket properly. The client should close the WebSocket and display the appropriate message to the user and try reconnecting.
Both should happen in an appropriate timeframe like 1 or 2 seconds.

Edit: Still needs some research and there's probably bullshit stated above. See e.g.:

Serve webui

The Kotlin Webserver should serve the react webui

  • automatically build the webui
  • copy from build folder into static ressources
  • serve the files as default

Info Pane While Adding Fixtures

Show an info pane for DMX modes while selecting DMX mode, a fixture list and universe bar while selecting fid/address. See sketches in #1

Create Gradle Command that does not Build Frontend

Currently, during frontend development, I serve the frontend from the create-react-app dev server but forward WebSocket connections to the Kotlin server. But if I restart the Kotlin server, I always have to wait for the npm run build to create an optimized production build. I would like to have a gradle command that does not do any npm building, just starts up the server with whatever static files happen to lay around the dev environment.

Global Hotkeys not Blocked while Alert is Open

tested version: commit 9c40c2

Steps to reproduce

  • Go to Patch -> Fixture Types
  • Add a GDTF file and try to remove it
  • while the confirmation dialog is open, try to use any of the usual hotkeys (like Esc or i)

Observed Behavior

All hotkeys still work as if the dialog wasn't open, e.g. Esc closes out of the Patch.

Expected Behavior

All hotkeys that don't belong to the Dialog should be blocked, e.g. Esc should only close out of the Dialog and i should do nothing.

Additionally, it would be nice if the hotkey hints (behind the button labels) for the disabled hotkeys would disappear.

ToDo

  • Test on Add FixtureType or Depedency Graph Dialog

Defaults for Add Fixture

When adding a fixture, the UI should have good defaults:

  • Fixture Type: last one in that field (if not submitted) or fixture type last added
  • DMX Mode: last one with which this fixture was added
  • Name: Fixture Type Name (Numbering with space if multiple Qty, but not in text field, only in preview)
  • Quantity: 1
  • FID: highest FID + 1
  • Universe/Address: lowest free with enough space for selected above

A first draft for the API is still in hackmd, but we may still want to decide whether HTTP or WS is the better approach here.

Also, Form validation for adding fixtures needs to be added and we should report errors from the server to the user.

Kotlin Algorithm for Finding Free Address

When adding new fixtures, the client needs to assign their DMX Addresses. By default it makes sense to put these in the "next free gap" of the approriate size. I wrote an algorithm in Kotlin to find these gaps:

/**
 * Finds the first gap in [inputList] at or after [target]. The minimum size of the gap can be specified by [gapSize].
 *
 * [inputList] does not have to be sorted.
 */
fun nextGap(inputList: List<Int>, target: Int, gapSize: Int = 1): Int {
    val list = inputList.sorted()
    var firstCandidate = list.binarySearch(target)

    if (firstCandidate < 0) {
        // negative returned index means the targetFid does not exist in Patch yet
        firstCandidate = -firstCandidate-1
    }

    var last: Int = target-1
    var current: Int

    for (i in firstCandidate..list.lastIndex) {
        current = list[i]
        if (current > last + gapSize) {
            return last + 1
        }
        last = current
    }

    return last + 1
}

Note this algorithm does not consider the upper limit of 512 on DMX Addresses, so that needs to be added in an outer layer.

The associated unit test:

    @Test
    fun testFindGapAtOrAfter() {
        val exampleArray = arrayOf(10,11,12,20,21,23)
        exampleArray.shuffle(kotlin.random.Random(42))
        val exampleList = exampleArray.asList()

        // gapSize 1
        assertEquals(1, nextGap(exampleList, 1))
        assertEquals(3, nextGap(exampleList, 3))
        assertEquals(13, nextGap(exampleList, 10))
        assertEquals(13, nextGap(exampleList, 12))
        assertEquals(19, nextGap(exampleList, 19))
        assertEquals(22, nextGap(exampleList, 20))
        assertEquals(22, nextGap(exampleList, 21))
        assertEquals(22, nextGap(exampleList, 22))
        assertEquals(24, nextGap(exampleList, 23))
        assertEquals(24, nextGap(exampleList, 24))

        // bigger gapSize
        assertEquals(1, nextGap(exampleList, 1, 9))
        assertEquals(24, nextGap(exampleList, 1, 10))
        assertEquals(13, nextGap(exampleList, 12, 7))
        assertEquals(24, nextGap(exampleList, 12, 8))
        assertEquals(18, nextGap(exampleList, 18, 2))
        assertEquals(24, nextGap(exampleList, 18, 3))
        assertEquals(24, nextGap(exampleList, 23, 9))
        assertEquals(24, nextGap(exampleList, 24, 9))
    }

Implement Art-Net Output

I have a Java implementation for this based on LibArtnet which just needs to be transpiled to Kotlin and cleaned up

depends on #59

GDTF Channel Function Story

progress on branch feature/gdtf-channel-functions

ToDo:

  • Understand and Specify how to handle Channel Function Control
    • see docs/GDTF.md
  • Implement Channel Function data structures (including serialization)
  • Server-side Tests for Channel Function Data Structures
  • Fatal Errors in GDTF parsing are returned via REST and should be displayed to the user
  • Report Bugs or Issues in GDTF I uncover
    • Issue about Builder producing ChannelFunctions with non-unique DMX end point. Related: standard does not specify this precisely. Mention my algorithm as suggestion for validity. Maybe disallow the special case where for a certain Mode Master Group multiple ChannelFunctions start at the same DMX value but always must exist the same amount of times.
    • Issue about hard to understand DMX Values (What is "Byte Mirroring"? Why aren't there more examples?) Suggest renaming to "Shifting with periodic filling of low values" vs Multiplicative Mapping
    • Forbid using as Mode Master Channel Functions which control a geometry that is referenced by at least two Geometry References if the channel function referencing it as Mode Master is not controlling the same geometry. In other words: A channel function which controls a top level geometry referenced by at least one GeometryReference is only allowed to be a Mode Master if either: There is exactly one Geometry Reference OR the Mode Master controls the same geometry as the depending channel
  • Build UI for Channel Functions
    • Home Screen: Split between Fixture Selection (left) and Channel Function sliders (right)
    • Channel Function sliders display DMX value
    • Channel Functions in same DMXChannel track and exclude each other
    • Channel Function Dependencies enable/disable dependent ChannelFunctions
    • Info on controlled geometry and attribute
    • clearly show which Channel Functions are hot or frozen
    • Info on why Channel Function is hot/frozen
      • e.g. disabled - channel_function_x has to be 12 to 42 to enable this channel function but is 90
      • e.g. excluded - channel is 90 but channel function only goes from 12 to 42
    • should use click-on-slider to include
      • should we use click-on-slider to set mode master to appropriate value? No.
    • ChannelFunctions should be sorted by Features, FeatureGroups and those should be sorted by importance (Dimmer, PanTilt, Color, ..., Control, RawDmx)
    • Show Channel Number for Raw DMX ChF
  • Server-Side State for each Fixture
  • Design API for Fixture State (initial/update? or KISS?)
  • Implement Fixture State API server-side
  • Implement Fixture State API client-side
  • When you add a new fixture type, it sometimes doesn't show up in the list without a reload
  • When you add a fixture, it sometimes doesn't show up in the fixture list on the main page
  • Label Number on the left of ChannelFunction slider isn't visible
  • UI: outOfRange values of sliders render a slider handle far out to the right or left
  • Some simple Cypress Test
  • Remove hardcoded Broadcast IP Address for sending ArtNet. How can we do this as simple as possible?
  • Performance when moving sliders is really bad - why? (Frontend/Backend? Which process slows it down so much?) There seems to be some Queue that builds up somewhere, as lag gets worse the longer you drag on a slider.
  • What happens if we patch beyond 512 channels in a universe?
    • The ArtNet thread crashes and doesn't start up again. Fixed by try/catch with logging and restart every 2 seconds.
  • Better Default FID and Universe/Address (wasn't there an issue for this?)
  • Better validate Patch (should not be possible to patch beyond channel 512 for example)
  • Add cyclic dependency to Fixture State Test

Dropped ToDos:

  • Refactor Channel Function Initialization (I deem it good enough for a release...)
  • Sometimes, some ChannelFunctions are disabled without a displayed reason. This seems to need at least two types of fixture, but I can't reproduce beyond that. (couldn't reproduce)
  • A warnings field in the GdtfWrapper should contain non-fatal warnings about the file. In fact, I think we currently throw for a lot of cases where we could just ignore that specific part of the file. Guideline: Parse as much as possible, while not arbitrarily choosing to perform undefined behavior. (I don't want to refactor the initialization) (moved to #61)

Update to use Kotlin 1.5 features

Kotlin 1.5 released lately and there is at least one feature that may be worth implementing:
Unsigned integer types

We could replace the logic where we check that variables are in a given range at least partially by using unsigned integers.

Make "messageId" in GlowMessage JSON optional

When "messageId" in GlowMessage is set to null, the serialized JSON looks like e.g.

{
"event" : "fixtureTypeAdded", 
"data" : {"fixtureTypeId": "7fb33577-09c9-4bf0-be3b-ef0dc3bef4be"}, 
"messageId" : null
}

Expected Outcome: "messageId" should not appear in JSON

Client-to-Server API

This issue tracks the progress of the development branch feature/api.

Tasks:

  • basic events via WebSocket: add/update/remove fixtures and add/remove fixture types
  • re-design API for more consistency (HackMD is now outdated, documentation moved to repo in branch feature/api)
  • re-design internals for thread safety (not documented yet, on paper and hangs on my wall)
  • make PatchFixture immutable or copy-able (complete patch-state must be copy-able for thread-safety)
  • re-design internal patch API with new external API in mind
  • Move WebSocket Handling from Javalin to our own WebSocket Servlet that spawns our own WebSocketListener for each connection, which in turn creates a stateful JsonHandler for each connection
  • Refactor JsonMessage to GlowMessage, make a nice structure, move JSON-specific things into extra files in json package

Then: Make PR, close this

Rudimentary Patch UI

Implement Patch UI according to Wireframes while leaving out non-essential features.

ToDo

  • Navbar and Tabs
  • Table
  • Add New Fixture Button
  • Patch-State Management "read only"
  • Fixture Type Page
  • Add New Fixture Dialog
  • Add Jest Test Setup that at least allows for basic, low-level Unit Tests (testing algorithms or similar)
  • Test Navigation in Cypress

after implementing API server-side:

  • update dependencies
  • fix version issues due to update
    • does not compile due to node-sass 6 not supported -> changed to node-sass 5
    • remaining issues when doing npm install
  • update npm itself?
  • check how we can apply variables from Blueprint.js in JS or whether we should change to SASS, etc.
  • pull out react-hotkeys-hook and replace with Blueprint.js (they added hooks now)
  • Ensure Hotkey Help Dialog opens by pressing "?" on german keyboard (#51)
  • fix WebSocket connection issue (only in firefox, needs minutes to properly connect, Chrome works) (#52)
  • Connect WebSocket during Startup - if it doesn't work, display Alert
    • Ensure you can't click on anything if Altert is open
    • Ensure Hotkeys don't work while Alert is open => only render main app if connection is open (remove Dialog for this)
    • Ensure Event Listeners will only be added once to webSocketConnection - currently does so for every component that calls the hook
  • Subscribe to Patch Stream
  • Add Fixture Type
  • Delete Fixture Type
  • Add Fixtures
  • Delete Fixtures
  • Test Basic Add/Delete for Fixtures/Fixture Types
  • disallow any type with linting (-> explicit any now creates warning)
  • When not selecting a fixture in Fixture Types it should not display empty but "Select Fixture" or something like that
  • Validate incoming messages -> nah, it all comes from our own server, so we should be fine. If we want to do it in the future, we can use io-ts or something like that
  • Test: When WebSocket connection can't be established or is closed the pop-up appears and prevents all interaction
  • Change Adress format to Universe.Address to avoid sorting issues, etc. -> don't know why I would want this as a user now
  • Make Typing for React Tabulator work
  • Selected Row in Table not highlighted
  • Select Multiple Fixtures in Fixture Patch
  • move state of "no fixture (type) selected" from name="" to Option/Some/undefined/whatever
  • add text label and shortcut to remove button
  • Install a CSS-in-JS solution and use it throughout the code base (Emotion? Other ones?) (pushed to later date when we actually need it)
  • Edit values in Table: FID, Name, Universe, Address
  • Fix Bug:
    • Set Universe to 0, change Universe to empty, change FID, Universe shows up as 0 again
    • Set Universe to 0, change Universe to empty, reload, Universe is 0 again
    • Setting Universe from 0 to empty does not fire a cell edited event
    • MCVE: https://jsfiddle.net/1vnr7byw/ (change Alice and Bob's Toy Count to empty string, observe event is only fired for Bob)
    • Traced to closed but unfixed issue olifolkerd/tabulator#1700
    • Try if it can be solved with a custom editor and/or mutators
    • Proposed Fix: Don't allow setting Universe to empty in UI, only DMX Address which has the same effect
  • test editing
  • test that "removal" of universe/address values works (needs to set to -1 in messaging)
  • Design a Keyboard-only story (no mouse for higher speed)
    • Add Fixture/GDTF
    • Patch Tabs
    • Patch Tables (way too much work and Tabulator isn't an end solution anyway)
    • Optimize add fixture story
    • Tests
  • Make a React element for labels with hotkey hints
    • Fix Unique Key Warnings
  • Check for remaining TODOs
  • Crash when submitting Add Fixture Form without selecting Fixture Type
  • Add Fixtures: Select one Fixture Type, select DMX mode from it, change fixture type, dmx mode selector opens, but click outside, will result in non-valid DMX mode being shown in text field while selected item under the hood is undefined, so by default the first mode of the selected fixture type is used. This should be communicated or be invalid.
  • "Add Fixtures" Validation
    • Validation: integer, min, max, required (for fixture type, mode (automatically done right now - still validate), FID)
    • perform on blur for each field
    • perform for all fields on submit and block submit if invalid
    • color field red and show popover next to it with detailed message if invalid
    • Allow empty Universe and Address which should be added to the Patch as unpatched (-1 in the JSON, empty in UI)
    • Easy Tests
    • Refactors
  • Review code for bad style (cluttered components that do more than one thing, bad naming, ...)

Ommited Features

moved to other issues

  • Search (#43)
  • Undo/Redo (#44)
  • Universe Bar (#45)
  • Info Pane while adding fixtures (#46)
  • FixtureType Details (#47)
  • AutoPatch (#48)
  • Error Handling in Patch UI (#22)
  • Visual Snapshot Testing (#49)
  • "Add Fixture" Defaults (#50)

Mockup

image

Implement EventHandler

Implement the Websocket Endpoint, which handels every incoming message from the client and the websocket state.

TODO

  • JSON Deserialization
  • Webserver Endpoint

Concurrency Tests and Thread-Safety

TODO

  • Patch Thread Safety
    • Test Immutability of Maps returned by Getters
    • Create kinda reliable concurrent tests
    • Make tests pass by locking
    • refactor tests for readability and clarity
  • SubscriptionHandler Thread Safety
  • Client-Server-based Tests
  • Document Locking Strategy and Locking Orders
  • check TODOs

Support Non-American Keyboards

Currently, the plan is to use the Hotkey-support built into Blueprint.js. However, their implementation currently is only valid for US keyboards. For example, the hotkey help dialog should be opened by "?", but on a german keyboard " ' " must be pressed.

Please track palantir/blueprint#4165 for resolving this problem. Alternatively, we can for example consider changing back to react-hotkeys-hook or go to mousetrap/hotkeys libraries directly.

Visual Snapshot Testing

We can use Snapshot Testing with Cypress to ensure our UI does not change. And if it changes, it needs to be accepted by the programmer and the change checked into git.
I think this will be a nice addition once we add more complexity to the UI.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.