Skip to content

Commit

Permalink
#183 ensure theme is present when needed.
Browse files Browse the repository at this point in the history
#176 experimental web server in ESP
2.2.7 release
  • Loading branch information
dave committed Feb 15, 2022
1 parent 8cfd586 commit 3178ccf
Show file tree
Hide file tree
Showing 21 changed files with 5,510 additions and 31 deletions.
6 changes: 3 additions & 3 deletions tcMenuGenerator/packager-all-platforms.md
Expand Up @@ -38,19 +38,19 @@ Ensure you are in the tcMenuGenerator/target directory.

cp classes/img/tcMenuDesigner.ico .

jpackage --type app-image -n tcMenuDesigner -p jfx/deps --input jfx/app --resource-dir .\classes\img\ --icon tcMenuDesigner.ico --app-version 2.2.6 --verbose --java-options "-Dprism.lcdtext=false" --add-modules "jdk.crypto.cryptoki" -m com.thecoderscorner.tcmenu.menuEditorUI/com.thecoderscorner.menu.editorui.cli.TcMenuDesignerCmd
jpackage --type app-image -n tcMenuDesigner -p jfx/deps --input jfx/app --resource-dir .\classes\img\ --icon tcMenuDesigner.ico --app-version 2.2.7 --verbose --java-options "-Dprism.lcdtext=false" --add-modules "jdk.crypto.cryptoki" -m com.thecoderscorner.tcmenu.menuEditorUI/com.thecoderscorner.menu.editorui.cli.TcMenuDesignerCmd

## Packaging - build for Debian / Ubuntu using package command

Ensure you are in the tcMenuGenerator/target directory.

jpackage -n tcMenuDesigner -p jfx/deps --input jfx/app --icon ./classes/img/menu-icon.png --verbose --license-file ../../LICENSE --linux-app-category Development --linux-menu-group "Development;Utility;" --java-options "-Dprism.lcdtext=false" --app-version 2.2.6 --add-modules "jdk.crypto.cryptoki" -m com.thecoderscorner.tcmenu.menuEditorUI/com.thecoderscorner.menu.editorui.cli.TcMenuDesignerCmd
jpackage -n tcMenuDesigner -p jfx/deps --input jfx/app --icon ./classes/img/menu-icon.png --verbose --license-file ../../LICENSE --linux-app-category Development --linux-menu-group "Development;Utility;" --java-options "-Dprism.lcdtext=false" --app-version 2.2.7 --add-modules "jdk.crypto.cryptoki" -m com.thecoderscorner.tcmenu.menuEditorUI/com.thecoderscorner.menu.editorui.cli.TcMenuDesignerCmd

## Packaging - macOS build all versions

Ensure you are in the tcMenuGenerator/target directory.

jpackage -n tcMenuDesigner -p jfx/deps --input jfx/app --icon ./classes/img/AppIcon.icns --verbose --license-file ../../LICENSE --vendor TheCodersCorner --app-version 2.2.6 --add-modules "jdk.crypto.cryptoki" --java-options "-Dprism.lcdtext=false" --verbose -m com.thecoderscorner.tcmenu.menuEditorUI/com.thecoderscorner.menu.editorui.cli.TcMenuDesignerCmd
jpackage -n tcMenuDesigner -p jfx/deps --input jfx/app --icon ./classes/img/AppIcon.icns --verbose --license-file ../../LICENSE --vendor TheCodersCorner --app-version 2.2.7 --add-modules "jdk.crypto.cryptoki" --java-options "-Dprism.lcdtext=false" --verbose -m com.thecoderscorner.tcmenu.menuEditorUI/com.thecoderscorner.menu.editorui.cli.TcMenuDesignerCmd

To allow for CLI on macOS: alias tcmenu=/Applications/tcMenuDesigner.app/Contents/MacOS/tcMenuDesigner

Expand Down
2 changes: 1 addition & 1 deletion tcMenuGenerator/pom.xml
Expand Up @@ -12,7 +12,7 @@
<name>menuEditorUI</name>
<groupId>com.thecoderscorner.tcmenu</groupId>
<description>JavaFX based menu editor UI</description>
<version>2.2.6-SNAPSHOT</version>
<version>2.2.7</version>

<properties>
<timestamp>${maven.build.timestamp}</timestamp>
Expand Down
@@ -1,5 +1,6 @@
package com.thecoderscorner.menu.editorui.cli;

import com.thecoderscorner.menu.editorui.util.StringHelper;
import picocli.CommandLine;

import java.io.ByteArrayOutputStream;
Expand All @@ -22,6 +23,10 @@ public enum CreationMode {ESP_ASYNC, AVR_WEBSERVER}
private File srcDir;
@CommandLine.Option(names = {"-a", "--want-maps"}, defaultValue = "false", description = "Keep map files in output")
private boolean wantMaps;
@CommandLine.Option(names = {"-l", "--debug"}, defaultValue = "false", description = "Add log statements around each operation")
private boolean debugLog;
@CommandLine.Option(names = {"-o", "--output"}, defaultValue = "", description = "Optionally provide the output file name")
private String outputFile;

@Override
public Integer call() throws Exception {
Expand All @@ -37,6 +42,11 @@ public Integer call() throws Exception {

sbVariables.append("#include <Arduino.h>").append(LINE_BREAK);
sbVariables.append("#include <ESPAsyncWebServer.h>").append(LINE_BREAK).append(LINE_BREAK);

if(debugLog && creationMode == CreationMode.ESP_ASYNC) {
sbVariables.append("const char LOG_TAG_WS[] = \"web\";").append(LINE_BREAK);
}

sbVariables.append("// Generated by tcMenu Designer wrap-ws command on ").append(LocalDateTime.now()).append(LINE_BREAK);
sbVariables.append("// use tcmenu wrap-ws cli command to regenerate ").append(LINE_BREAK).append(LINE_BREAK);

Expand Down Expand Up @@ -94,15 +104,22 @@ public Integer call() throws Exception {
sbFunctions.append("}").append(LINE_BREAK);
sbFunctions.append(LINE_BREAK);
sbFunctions.append("// Add the following forward-definition to your code if you're calling this yourself");
sbFunctions.append(LINE_BREAK);
sbFunctions.append("// void prepareWebServer(AsyncWebServer& server); ");
sbFunctions.append(LINE_BREAK);

System.out.println("Writing esp_ws.cpp to " + srcDir + ". Approx memory requirement for data is " + entireSize);
Path outputPath;
if (!StringHelper.isStringEmptyOrNull(outputFile)) {
outputPath = Paths.get(outputFile);
} else {
outputPath = srcDir.toPath().resolve("esp_ws.cpp");
}
Files.writeString(outputPath, sbVariables + sbFunctions.toString(), StandardOpenOption.CREATE);

System.out.println("Written file " + outputPath + ". Approx memory requirement for data is " + entireSize);
System.out.println("If you need to use this directly in your project, forward declare as follows:");
System.out.println(" void prepareWebServer(AsyncWebServer& server);");

Files.writeString(srcDir.toPath().resolve("esp_ws.cpp"), sbVariables + sbFunctions.toString(),
StandardOpenOption.CREATE);
return 0;
}

Expand Down Expand Up @@ -133,24 +150,39 @@ private String writeServeLogicFor(String theLocalPath, String varName, boolean b
private String writeServeLogicEspAsync(String theLocalPath, String varName, String mime, boolean binary, boolean gzipped) {
String requestProcessing;
if(gzipped) {
requestProcessing = " auto* resp = request->beginResponse_P(200, \"" + mime + "\", " + varName + ", sizeof(" + varName +"));" + LINE_BREAK +
requestProcessing = possibleDebugStatement("start", varName) +
" auto* resp = request->beginResponse_P(200, \"" + mime + "\", " + varName + ", sizeof(" + varName +"));" + LINE_BREAK +
" resp->addHeader(\"Content-Encoding\", \"gzip\");" + LINE_BREAK +
" resp->addHeader(\"Cache-Control\", \"max-age=2592000\");" + LINE_BREAK +
" request->send(resp);" + LINE_BREAK;
" request->send(resp);" + LINE_BREAK +
possibleDebugStatement("end", varName);

} else if(binary) {
requestProcessing = " auto* resp = request->beginResponse_P(200, \"" + mime + "\", " + varName + ", sizeof(" + varName +"));" + LINE_BREAK +
requestProcessing = possibleDebugStatement("start", varName) +
" auto* resp = request->beginResponse_P(200, \"" + mime + "\", " + varName + ", sizeof(" + varName +"));" + LINE_BREAK +
" resp->addHeader(\"Cache-Control\", \"max-age=2592000\");" + LINE_BREAK +
" request->send(resp);" + LINE_BREAK;
" request->send(resp);" + LINE_BREAK +
possibleDebugStatement("end", varName);

} else {
requestProcessing = " request->send_P(200, \"" + mime + "\", " + varName + ");";
requestProcessing = possibleDebugStatement("start", varName)+
" request->send_P(200, \"" + mime + "\", " + varName + ");" + LINE_BREAK +
possibleDebugStatement("end", varName);
}

return " server.on(\"" + theLocalPath + "\", HTTP_GET, [](AsyncWebServerRequest *request) {" + LINE_BREAK +
requestProcessing + LINE_BREAK +
requestProcessing +
" });" + LINE_BREAK;
}

private String possibleDebugStatement(String key, String text) {
if(!debugLog) return "";
return switch(creationMode) {
case ESP_ASYNC -> " ESP_LOGI(LOG_TAG_WS, \"" + key + " " + text + "\");";
case AVR_WEBSERVER -> " serdebugF(\""+ key + " " + text + "\");";
} + LINE_BREAK;
}

private String mimeTypeFor(String p) {
String strPath = p.toLowerCase();

Expand Down
Expand Up @@ -7,6 +7,7 @@

package com.thecoderscorner.menu.editorui.generator.ui;

import com.thecoderscorner.menu.editorui.dialog.BaseDialogSupport;
import com.thecoderscorner.menu.editorui.dialog.SelectAuthenticatorTypeDialog;
import com.thecoderscorner.menu.editorui.dialog.SelectEepromTypeDialog;
import com.thecoderscorner.menu.editorui.generator.CodeGeneratorOptions;
Expand Down Expand Up @@ -49,7 +50,7 @@
import static javafx.collections.FXCollections.observableArrayList;

public class GenerateCodeDialog {
private final static String DEFAULT_THEME_ID = "b186c809-d9ef-4ca8-9d4b-e4780a041ccc"; // manual theme, works for most displays
private final static String DEFAULT_THEME_ID = "2026a7f2-0d5b-43f5-9f98-4f0eacac4c0e"; // manual theme, works for most displays

private final System.Logger logger = System.getLogger(getClass().getSimpleName());

Expand Down Expand Up @@ -402,6 +403,18 @@ private void onCancel(ActionEvent actionEvent) {
}

private void onGenerateCode(ActionEvent actionEvent) {
if(currentDisplay.getItem().isThemeNeeded() && currentTheme.getItem().getId().equals(DEFAULT_THEME_ID)) {
var alert = new Alert(Alert.AlertType.WARNING, "No theme selected", ButtonType.CLOSE);
alert.setTitle("Theme Configuration Error");
alert.setHeaderText("Selected display requires a theme");
alert.setContentText("Displays need configuration to work properly, this is provided by the theme. " +
"We strongly recommend you start with one of our core themes and modify it to meet your needs." +
"However, advanced users could start with the manual theme.");

BaseDialogSupport.getJMetro().setScene(alert.getDialogPane().getScene());
alert.showAndWait();
return;
}
saveCodeGeneratorChanges();
runner.startCodeGeneration(mainStage, platformCombo.getSelectionModel().getSelectedItem(),
Paths.get(project.getFileName()).getParent().toString(),
Expand Down
2 changes: 1 addition & 1 deletion tcMenuJavaApi/pom.xml
Expand Up @@ -11,7 +11,7 @@
<groupId>com.thecoderscorner.tcmenu</groupId>
<artifactId>tcMenuJavaAPI</artifactId>
<name>tcMenuJavaAPI</name>
<version>2.2.6-SNAPSHOT</version>
<version>2.2.7</version>
<description>A series of domain and serialisation components for the TcMenu library</description>
<url>https://www.thecoderscorner.com/products/arduino-libraries/tc-menu/</url>

Expand Down
Expand Up @@ -2,6 +2,7 @@

import java.util.List;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArrayList;

/**
Expand Down
Expand Up @@ -5,6 +5,7 @@
import java.nio.file.Path;
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.Callable;

import static java.lang.System.Logger.Level.*;

Expand Down Expand Up @@ -40,7 +41,7 @@ public boolean authenticate(String user, UUID uuid) {
}

@Override
public synchronized boolean addAuthentication(String user, UUID uuid) {
public boolean addAuthentication(String user, UUID uuid) {
try {
synchronized (properties) {
properties.setProperty(user, uuid.toString());
Expand Down
Expand Up @@ -13,6 +13,7 @@
import com.thecoderscorner.menu.remote.protocol.ApiPlatform;
import com.thecoderscorner.menu.remote.protocol.CorrelationId;

import java.lang.System.Logger.Level;
import java.time.Clock;
import java.util.UUID;
import java.util.concurrent.ScheduledExecutorService;
Expand All @@ -33,7 +34,6 @@ public class MenuManagerServer implements NewServerConnectionListener {
private final MenuAuthenticator authenticator;
private final AtomicBoolean successfulLogin = new AtomicBoolean(false);
private final Clock clock;
private final AtomicBoolean pairingMode = new AtomicBoolean(false);
private ScheduledFuture<?> hbSchedule;

public MenuManagerServer(ScheduledExecutorService executorService, MenuTree tree, ServerConnectionManager serverManager,
Expand All @@ -57,18 +57,18 @@ public void stop() {
try {
serverManager.stop();
} catch (Exception e) {
logger.log(System.Logger.Level.ERROR, "Server manager threw error during stop", e);
logger.log(Level.ERROR, "Server manager threw error during stop", e);
}
}

private void checkHeartbeats() {
for (var socket : serverManager.getServerConnections()) {
if((clock.millis() - socket.lastReceivedHeartbeat()) > (socket.getHeartbeatFrequency() * 3L)) {
logger.log(System.Logger.Level.WARNING, "HB timeout, no received message within frequency");
logger.log(Level.WARNING, "HB timeout, no received message within frequency");
socket.closeConnection();
}
else if((clock.millis() - socket.lastTransmittedHeartbeat()) > socket.getHeartbeatFrequency()) {
logger.log(System.Logger.Level.INFO, "Sending HB due to inactivity");
logger.log(Level.INFO, "Sending HB due to inactivity");
socket.sendCommand(new MenuHeartbeatCommand(socket.getHeartbeatFrequency(), HeartbeatMode.NORMAL));
}
}
Expand All @@ -82,18 +82,21 @@ public void connectionCreated(ServerConnection connection) {

private void messageReceived(ServerConnection conn, MenuCommand cmd) {
try {
if(pairingMode.get()) return; // nothing further is done on a pairing connection.
if(conn.isPairing()) {
logger.log(Level.INFO, "Connection is in pairing mode, ignoring " + cmd);
return; // nothing further is done on a pairing connection.
}
switch(cmd.getCommandType()) {
case JOIN: {
var join = (MenuJoinCommand) cmd;
if (authenticator != null && !authenticator.authenticate(join.getMyName(), join.getAppUuid())) {
logger.log(System.Logger.Level.WARNING, "Invalid credentials from " + join.getMyName());
logger.log(Level.WARNING, "Invalid credentials from " + join.getMyName());
conn.sendCommand(new MenuAcknowledgementCommand(CorrelationId.EMPTY_CORRELATION, AckStatus.INVALID_CREDENTIALS));
conn.closeConnection();
}
else {
successfulLogin.set(true);
logger.log(System.Logger.Level.WARNING, "Successful login from " + join.getMyName());
logger.log(Level.WARNING, "Successful login from " + join.getMyName());
conn.sendCommand(new MenuAcknowledgementCommand(CorrelationId.EMPTY_CORRELATION, AckStatus.SUCCESS));
conn.sendCommand(new MenuBootstrapCommand(MenuBootstrapCommand.BootType.START));

Expand All @@ -120,7 +123,7 @@ private void messageReceived(ServerConnection conn, MenuCommand cmd) {
}
case CHANGE_INT_FIELD:
if(!successfulLogin.get()) {
logger.log(System.Logger.Level.WARNING, "Un-authenticated change command ignored");
logger.log(Level.WARNING, "Un-authenticated change command ignored");
return;
}
handleIncomingChange(conn, (MenuChangeCommand) cmd);
Expand All @@ -132,7 +135,7 @@ private void messageReceived(ServerConnection conn, MenuCommand cmd) {
}

private void startPairingMode(ServerConnection conn, MenuPairingCommand cmd) {
pairingMode.set(true);
conn.enablePairingMode();
var success = authenticator.addAuthentication(cmd.getName(), cmd.getUuid());
var determinedStatus = success ? AckStatus.SUCCESS : AckStatus.INVALID_CREDENTIALS;
conn.sendCommand(new MenuAcknowledgementCommand(CorrelationId.EMPTY_CORRELATION, determinedStatus));
Expand All @@ -148,7 +151,7 @@ public void updateMenuItem(MenuItem item, Object newValue) {
}

public void menuItemDidUpdate(MenuItem item) {
logger.log(System.Logger.Level.INFO, "Sending item update for " + item);
logger.log(Level.INFO, "Sending item update for " + item);
var state = tree.getMenuState(item);
if(state == null) return;

Expand Down
Expand Up @@ -13,4 +13,6 @@ public interface ServerConnection {
boolean isConnected();
void registerConnectionListener(BiConsumer<ServerConnection, Boolean> connectionListener);
void registerMessageHandler(BiConsumer<ServerConnection, MenuCommand> messageHandler);
boolean isPairing();
void enablePairingMode();
}
Expand Up @@ -30,6 +30,7 @@ public class SocketServerConnection extends SharedStreamConnection implements Se
private final AtomicReference<BiConsumer<ServerConnection, MenuCommand>> messageHandler = new AtomicReference<>();
private final AtomicReference<BiConsumer<ServerConnection, Boolean>> connectionListener = new AtomicReference<>();
private final Thread readThread;
private final AtomicBoolean pairingMode = new AtomicBoolean(false);

public SocketServerConnection(Socket socket, MenuCommandProtocol protocol, Clock clock) {
super(protocol);
Expand Down Expand Up @@ -115,6 +116,16 @@ public void registerMessageHandler(BiConsumer<ServerConnection, MenuCommand> mes
this.messageHandler.set(messageHandler);
}

@Override
public boolean isPairing() {
return this.pairingMode.get();
}

@Override
public void enablePairingMode() {
this.pairingMode.set(true);
}

@Override
protected void getAtLeastBytes(ByteBuffer inputBuffer, int len, StreamRemoteConnector.ReadMode mode) throws IOException {
if(mode == StreamRemoteConnector.ReadMode.ONLY_WHEN_EMPTY && inputBuffer.remaining() >= len) return;
Expand Down
Expand Up @@ -10,6 +10,7 @@
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.time.Clock;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
Expand All @@ -31,6 +32,7 @@ public class WebSocketServerConnection implements ServerConnection {
private final AtomicInteger heartbeatFrequency = new AtomicInteger(1500);
private final Object socketLock = new Object();
private final Object handlerLock = new Object();
private final AtomicBoolean pairingMode = new AtomicBoolean(false);

public WebSocketServerConnection(WebSocket socket, MenuCommandProtocol protocol, Clock clock) {
this.socket = socket;
Expand Down Expand Up @@ -101,6 +103,16 @@ public void registerMessageHandler(BiConsumer<ServerConnection, MenuCommand> mes
}
}

@Override
public boolean isPairing() {
return this.pairingMode.get();
}

@Override
public void enablePairingMode() {
this.pairingMode.set(true);
}

public void informClosed() {
synchronized (handlerLock) {
var l = this.connectionListener.get();
Expand Down
4 changes: 3 additions & 1 deletion tcMenuJavaApi/src/test/resources/auth.properties
@@ -1,3 +1,5 @@
#TcMenu Auth properties
#Thu Dec 30 17:10:02 GMT 2021
#Sun Feb 13 15:25:51 GMT 2022
Untitled=1df939bb-467c-42fc-b604-484dd31641e2
Daves\ Amp\ Web=453eab49-d3df-4250-a39d-720b43dc9193
DavesSim=e0a5ffca-bd6e-464c-b631-af7652ab4560

0 comments on commit 3178ccf

Please sign in to comment.