fastled 1.2.79__tar.gz → 1.2.80__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fastled-1.2.79 → fastled-1.2.80}/PKG-INFO +1 -1
- {fastled-1.2.79 → fastled-1.2.80}/compiler/compile.py +29 -51
- fastled-1.2.80/compiler/debug.sh +6 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/init_runtime.py +3 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/paths.py +3 -2
- {fastled-1.2.79 → fastled-1.2.80}/compiler/run.py +2 -2
- {fastled-1.2.79 → fastled-1.2.80}/compiler/server.py +36 -4
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/__init__.py +7 -2
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/client_server.py +12 -1
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/open_browser.py +5 -3
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/server_flask.py +39 -5
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/server_start.py +21 -8
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled.egg-info/PKG-INFO +1 -1
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled.egg-info/SOURCES.txt +1 -1
- fastled-1.2.79/compiler/init_runtime2.py +0 -79
- {fastled-1.2.79 → fastled-1.2.80}/.aiderignore +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/.dockerignore +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/.github/workflows/build_multi_docker_image.yml +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/.github/workflows/build_webpage.yml +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/.github/workflows/lint.yml +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/.github/workflows/publish_release.yml +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/.github/workflows/template_build_docker_image.yml +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/.github/workflows/test_build_exe.yml +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/.github/workflows/test_macos.yml +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/.github/workflows/test_ubuntu.yml +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/.github/workflows/test_win.yml +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/.gitignore +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/.pylintrc +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/.vscode/launch.json +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/.vscode/settings.json +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/.vscode/tasks.json +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/Dockerfile +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/LICENSE +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/MANIFEST.in +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/README.md +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/RELEASE.md +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/TODO.md +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/build_exe.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/build_site.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/clean +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/CMakeLists.txt +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/__init__.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/arduino-pre-process.sh +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/build.sh +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/build_archive.sh +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/build_fast.sh +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/code_sync.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/compile_lock.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/entrypoint.sh +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/extra/100dots.html +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/extra/demo_threejs.html +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/extra/micdemo.html +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/extra/mp3upload.html +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/extra/webgl_postprocessing_unreal_bloom.html +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/final_prewarm.sh +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/install-arduino-cli.sh +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/libcompile/CMakeLists.txt +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/pre-process.sh +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/prewarm.sh +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/process-ino.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/process_extended.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/pyproject.toml +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/sketch_hasher.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/compiler/wasm_compiler_flags.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/docker-compose.yml +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/install +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/install_linux.sh +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/lint +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/pyproject.toml +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/requirements.testing.txt +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/setup.cfg +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/setup.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/app.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/assets/example.txt +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/assets/localhost-key.pem +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/assets/localhost.pem +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/cli.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/cli_test.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/cli_test_interactive.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/compile_server.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/compile_server_impl.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/docker_manager.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/filewatcher.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/keyboard.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/keyz.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/live_client.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/parse_args.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/paths.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/print_filter.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/project_init.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/select_sketch_directory.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/server_fastapi.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/server_fastapi_cli.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/settings.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/site/build.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/site/examples.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/sketch.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/spinner.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/string_diff.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/test/can_run_local_docker_tests.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/test/examples.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/types.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/util.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled/web_compile.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled.egg-info/dependency_links.txt +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled.egg-info/entry_points.txt +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled.egg-info/requires.txt +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/src/fastled.egg-info/top_level.txt +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/test +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/integration/test_build_examples.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/integration/test_examples.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/html/index.html +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_api.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_bad_ino.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_cli.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_compile_server.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_docker_linux_on_windows.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_embedded_data.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_filechanger.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_http_server.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_ino/bad/bad.ino +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_ino/bad_platformio/bad_platformio.ino +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_ino/bad_platformio/platformio.ini +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_ino/embedded/data/bigdata.dat +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_ino/embedded/wasm.ino +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_ino/wasm/wasm.ino +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_print_filter.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_project_init.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_server_and_client_seperatly.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_string_diff.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/tests/unit/test_webcompile.py +0 -0
- {fastled-1.2.79 → fastled-1.2.80}/upload_package.sh +0 -0
@@ -21,6 +21,7 @@ import shutil # noqa: E402
|
|
21
21
|
import subprocess # noqa: E402
|
22
22
|
import sys # noqa: E402
|
23
23
|
import traceback # noqa: E402
|
24
|
+
import warnings # noqa: E402
|
24
25
|
from dataclasses import dataclass # noqa: E402
|
25
26
|
from datetime import datetime # noqa: E402
|
26
27
|
from enum import Enum # noqa: E402
|
@@ -51,10 +52,7 @@ _FILE_EXTENSIONS = [".ino", ".h", ".hpp", ".cpp"]
|
|
51
52
|
_FASTLED_OUTPUT_DIR_NAME = "fastled_js"
|
52
53
|
|
53
54
|
|
54
|
-
|
55
|
-
class DateLine:
|
56
|
-
dt: datetime
|
57
|
-
line: str
|
55
|
+
# DateLine class removed as it's no longer needed with streaming timestamps
|
58
56
|
|
59
57
|
|
60
58
|
class BuildMode(Enum):
|
@@ -87,6 +85,8 @@ def copy_files(src_dir: Path, js_src: Path) -> None:
|
|
87
85
|
else:
|
88
86
|
print(f"Copying file: {item}")
|
89
87
|
shutil.copy2(item, js_src / item.name)
|
88
|
+
else:
|
89
|
+
warnings.warn("No files found in the mapped directory.")
|
90
90
|
|
91
91
|
|
92
92
|
def _banner(msg: str) -> str:
|
@@ -172,19 +172,23 @@ def compile(
|
|
172
172
|
)
|
173
173
|
return out
|
174
174
|
|
175
|
-
output_lines = []
|
176
175
|
for attempt in range(1, max_attempts + 1):
|
177
176
|
try:
|
178
177
|
print(f"Attempting compilation (attempt {attempt}/{max_attempts})...")
|
179
178
|
process = _open_process()
|
180
179
|
assert process.stdout is not None
|
180
|
+
|
181
|
+
# Create a new timestamper for this compilation attempt
|
182
|
+
timestamper = StreamingTimestamper()
|
183
|
+
|
184
|
+
# Process and print each line as it comes in with relative timestamp
|
181
185
|
line: str
|
182
186
|
for line in process.stdout:
|
183
|
-
timestamped_line =
|
184
|
-
|
187
|
+
timestamped_line = timestamper.timestamp_line(line)
|
188
|
+
print(timestamped_line)
|
189
|
+
|
185
190
|
process.wait()
|
186
|
-
|
187
|
-
_chunked_print(relative_output)
|
191
|
+
|
188
192
|
if process.returncode == 0:
|
189
193
|
print(_banner(f"Compilation successful on attempt {attempt}"))
|
190
194
|
return 0
|
@@ -264,51 +268,25 @@ def process_ino_files(src_dir: Path) -> None:
|
|
264
268
|
print(_banner("Transform to cpp and insert header operations completed."))
|
265
269
|
|
266
270
|
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
date_str, time_str = parts[:2]
|
274
|
-
rest = " ".join(parts[2:])
|
275
|
-
# Parse with microsecond precision
|
276
|
-
dt = datetime.strptime(f"{date_str} {time_str}", "%Y-%m-%d %H:%M:%S.%f")
|
277
|
-
return DateLine(dt, rest)
|
278
|
-
|
279
|
-
lines = stdout.split("\n")
|
280
|
-
if not lines:
|
281
|
-
return stdout
|
282
|
-
parsed: list[DateLine] = []
|
283
|
-
for line in lines:
|
284
|
-
if not line.strip(): # Skip empty lines
|
285
|
-
continue
|
286
|
-
try:
|
287
|
-
parsed.append(parse(line))
|
288
|
-
except ValueError:
|
289
|
-
print(f"Failed to parse line: {line}")
|
290
|
-
continue
|
291
|
-
|
292
|
-
if not parsed:
|
293
|
-
return stdout
|
271
|
+
class StreamingTimestamper:
|
272
|
+
"""
|
273
|
+
A class that provides streaming relative timestamps for output lines.
|
274
|
+
Instead of processing all lines at the end, this timestamps each line
|
275
|
+
as it's received with a relative time from when the object was created.
|
276
|
+
"""
|
294
277
|
|
295
|
-
|
296
|
-
|
278
|
+
def __init__(self):
|
279
|
+
self.start_time = datetime.now()
|
297
280
|
|
298
|
-
|
299
|
-
|
300
|
-
|
281
|
+
def timestamp_line(self, line: str) -> str:
|
282
|
+
"""
|
283
|
+
Add a relative timestamp to a line of text.
|
284
|
+
The timestamp shows seconds elapsed since the StreamingTimestamper was created.
|
285
|
+
"""
|
286
|
+
now = datetime.now()
|
287
|
+
delta = now - self.start_time
|
301
288
|
seconds = delta.total_seconds()
|
302
|
-
|
303
|
-
outlines.append(line_str)
|
304
|
-
|
305
|
-
return "\n".join(outlines)
|
306
|
-
|
307
|
-
|
308
|
-
def _timestamp_output(line: str) -> str:
|
309
|
-
now = datetime.now()
|
310
|
-
timestamp = now.strftime("%Y-%m-%d %H:%M:%S.%f")
|
311
|
-
return f"{timestamp} {line.rstrip()}"
|
289
|
+
return f"{seconds:3.2f} {line.rstrip()}"
|
312
290
|
|
313
291
|
|
314
292
|
@dataclass
|
@@ -9,10 +9,13 @@ COMPILER_DIR = COMPILER_ROOT / "compiler"
|
|
9
9
|
|
10
10
|
SRC_MAPPED_HOST_COMPLER_DIR = Path("/host/fastled/src/platforms/wasm/compiler")
|
11
11
|
if SRC_MAPPED_HOST_COMPLER_DIR.exists():
|
12
|
+
print(f"Using mapped host compiler directory: {SRC_MAPPED_HOST_COMPLER_DIR}")
|
12
13
|
FASTLED_COMPILER_DIR = SRC_MAPPED_HOST_COMPLER_DIR
|
13
14
|
else:
|
15
|
+
print(f"Using standard host compiler directory: {SRC_MAPPED_HOST_COMPLER_DIR}")
|
14
16
|
FASTLED_COMPILER_DIR = COMPILER_ROOT / "fastled/src/platforms/wasm/compiler"
|
15
17
|
|
18
|
+
|
16
19
|
HERE = Path(__file__).parent
|
17
20
|
|
18
21
|
|
@@ -4,11 +4,12 @@ UPLOAD_DIR = Path("/uploads")
|
|
4
4
|
TEMP_DIR = Path("/tmp")
|
5
5
|
OUTPUT_DIR = Path("/output")
|
6
6
|
|
7
|
-
|
8
7
|
COMPILER_ROOT = Path("/js")
|
8
|
+
FASTLED_SRC = COMPILER_ROOT / "fastled" / "src"
|
9
|
+
|
10
|
+
|
9
11
|
SKETCH_SRC = COMPILER_ROOT / "src"
|
10
12
|
VOLUME_MAPPED_SRC = Path("/host/fastled/src")
|
11
|
-
RSYNC_DEST = COMPILER_ROOT / "fastled" / "src"
|
12
13
|
SKETCH_CACHE_FILE = OUTPUT_DIR / "compile_cache.db"
|
13
14
|
LIVE_GIT_FASTLED_DIR = Path("/git/fastled")
|
14
15
|
|
@@ -7,7 +7,7 @@ from pathlib import Path
|
|
7
7
|
from typing import Tuple
|
8
8
|
|
9
9
|
from code_sync import CodeSync
|
10
|
-
from paths import
|
10
|
+
from paths import FASTLED_SRC, VOLUME_MAPPED_SRC
|
11
11
|
|
12
12
|
_PORT = os.environ.get("PORT", 80)
|
13
13
|
|
@@ -106,7 +106,7 @@ def main() -> int:
|
|
106
106
|
|
107
107
|
code_sync = CodeSync(
|
108
108
|
volume_mapped_src=VOLUME_MAPPED_SRC,
|
109
|
-
rsync_dest=
|
109
|
+
rsync_dest=FASTLED_SRC,
|
110
110
|
)
|
111
111
|
code_sync.sync_source_directory_if_volume_is_mapped()
|
112
112
|
|
@@ -28,10 +28,10 @@ from fastapi import ( # type: ignore
|
|
28
28
|
UploadFile,
|
29
29
|
)
|
30
30
|
from fastapi.responses import FileResponse, RedirectResponse, Response # type: ignore
|
31
|
+
from paths import FASTLED_SRC # The folder where the actual source code is located.
|
31
32
|
from paths import (
|
32
33
|
LIVE_GIT_FASTLED_DIR,
|
33
34
|
OUTPUT_DIR,
|
34
|
-
RSYNC_DEST,
|
35
35
|
SKETCH_CACHE_FILE,
|
36
36
|
TEMP_DIR,
|
37
37
|
UPLOAD_DIR,
|
@@ -131,7 +131,7 @@ class UploadSizeMiddleware(BaseHTTPMiddleware):
|
|
131
131
|
|
132
132
|
_CODE_SYNC = CodeSync(
|
133
133
|
volume_mapped_src=VOLUME_MAPPED_SRC,
|
134
|
-
rsync_dest=
|
134
|
+
rsync_dest=FASTLED_SRC,
|
135
135
|
)
|
136
136
|
|
137
137
|
|
@@ -226,12 +226,12 @@ def sync_live_git_to_target() -> None:
|
|
226
226
|
|
227
227
|
_CODE_SYNC.sync_src_to_target(
|
228
228
|
volume_mapped_src=LIVE_GIT_FASTLED_DIR / "src",
|
229
|
-
rsync_dest=
|
229
|
+
rsync_dest=FASTLED_SRC,
|
230
230
|
callback=on_files_changed,
|
231
231
|
)
|
232
232
|
_CODE_SYNC.sync_src_to_target(
|
233
233
|
volume_mapped_src=LIVE_GIT_FASTLED_DIR / "examples",
|
234
|
-
rsync_dest=
|
234
|
+
rsync_dest=FASTLED_SRC.parent / "examples",
|
235
235
|
callback=on_files_changed,
|
236
236
|
)
|
237
237
|
# Basically a setTimeout() in JS.
|
@@ -598,6 +598,38 @@ def project_init_example(
|
|
598
598
|
)
|
599
599
|
|
600
600
|
|
601
|
+
@app.get("/static/{file_path:path}")
|
602
|
+
async def static_files(file_path: str) -> Response:
|
603
|
+
"""Serve static files."""
|
604
|
+
print(f"Endpoint accessed: /static/{file_path}")
|
605
|
+
|
606
|
+
# Check if path matches the pattern js/fastled/src/...
|
607
|
+
if file_path.startswith("js/fastled/src/"):
|
608
|
+
# Extract the path after "js/fastled/src/"
|
609
|
+
relative_path = file_path[len("js/fastled/src/") :]
|
610
|
+
full_path = FASTLED_SRC / relative_path
|
611
|
+
|
612
|
+
if full_path.exists() and full_path.is_file():
|
613
|
+
content = full_path.read_bytes()
|
614
|
+
# Determine media type based on file extension
|
615
|
+
media_type = "text/plain"
|
616
|
+
if full_path.suffix in [".h", ".cpp"]:
|
617
|
+
media_type = "text/plain"
|
618
|
+
elif full_path.suffix == ".html":
|
619
|
+
media_type = "text/html"
|
620
|
+
elif full_path.suffix == ".js":
|
621
|
+
media_type = "application/javascript"
|
622
|
+
elif full_path.suffix == ".css":
|
623
|
+
media_type = "text/css"
|
624
|
+
|
625
|
+
return Response(content=content, media_type=media_type)
|
626
|
+
|
627
|
+
# If file not found or path doesn't match expected format
|
628
|
+
return Response(
|
629
|
+
content=f"File not found: {file_path}", media_type="text/plain", status_code=404
|
630
|
+
)
|
631
|
+
|
632
|
+
|
601
633
|
@app.get("/info")
|
602
634
|
def info_examples() -> dict:
|
603
635
|
"""Get a list of examples."""
|
@@ -14,7 +14,7 @@ from .types import BuildMode, CompileResult, CompileServerError
|
|
14
14
|
# IMPORTANT! There's a bug in github which will REJECT any version update
|
15
15
|
# that has any other change in the repo. Please bump the version as the
|
16
16
|
# ONLY change in a commit, or else the pypi update and the release will fail.
|
17
|
-
__version__ = "1.2.
|
17
|
+
__version__ = "1.2.80"
|
18
18
|
|
19
19
|
|
20
20
|
class Api:
|
@@ -194,14 +194,19 @@ class Test:
|
|
194
194
|
def spawn_http_server(
|
195
195
|
directory: Path | str = Path("."),
|
196
196
|
port: int | None = None,
|
197
|
+
compile_server_port: int | None = None,
|
197
198
|
open_browser: bool = True,
|
198
199
|
) -> Process:
|
199
200
|
from fastled.open_browser import open_browser_process
|
200
201
|
|
202
|
+
compile_server_port = compile_server_port or -1
|
201
203
|
if isinstance(directory, str):
|
202
204
|
directory = Path(directory)
|
203
205
|
proc: Process = open_browser_process(
|
204
|
-
directory,
|
206
|
+
directory,
|
207
|
+
port=port,
|
208
|
+
compile_server_port=compile_server_port,
|
209
|
+
open_browser=open_browser,
|
205
210
|
)
|
206
211
|
return proc
|
207
212
|
|
@@ -188,6 +188,15 @@ def run_client(
|
|
188
188
|
return DEFAULT_URL
|
189
189
|
|
190
190
|
url = get_url()
|
191
|
+
# parse out the port from the url
|
192
|
+
# use a standard host address parser to grab it
|
193
|
+
import urllib.parse
|
194
|
+
|
195
|
+
parsed_url = urllib.parse.urlparse(url)
|
196
|
+
if parsed_url.port is not None:
|
197
|
+
port = parsed_url.port
|
198
|
+
else:
|
199
|
+
port = 80
|
191
200
|
|
192
201
|
try:
|
193
202
|
|
@@ -214,7 +223,9 @@ def run_client(
|
|
214
223
|
|
215
224
|
browser_proc: Process | None = None
|
216
225
|
if open_web_browser:
|
217
|
-
browser_proc = open_browser_process(
|
226
|
+
browser_proc = open_browser_process(
|
227
|
+
directory / "fastled_js", compile_server_port=port
|
228
|
+
)
|
218
229
|
else:
|
219
230
|
print("\nCompilation successful.")
|
220
231
|
if compile_server:
|
@@ -14,8 +14,7 @@ PYTHON_EXE = sys.executable
|
|
14
14
|
|
15
15
|
|
16
16
|
def _open_http_server_subprocess(
|
17
|
-
fastled_js: Path,
|
18
|
-
port: int,
|
17
|
+
fastled_js: Path, port: int, compile_server_port: int
|
19
18
|
) -> None:
|
20
19
|
print("\n################################################################")
|
21
20
|
print(f"# Opening browser to {fastled_js} on port {port}")
|
@@ -30,6 +29,8 @@ def _open_http_server_subprocess(
|
|
30
29
|
str(fastled_js),
|
31
30
|
"--port",
|
32
31
|
str(port),
|
32
|
+
"--compile-server-port",
|
33
|
+
str(compile_server_port),
|
33
34
|
]
|
34
35
|
# Pass SSL flags if available
|
35
36
|
if ssl:
|
@@ -89,6 +90,7 @@ def wait_for_server(port: int, timeout: int = 10) -> None:
|
|
89
90
|
|
90
91
|
def open_browser_process(
|
91
92
|
fastled_js: Path,
|
93
|
+
compile_server_port: int,
|
92
94
|
port: int | None = None,
|
93
95
|
open_browser: bool = True,
|
94
96
|
) -> Process:
|
@@ -100,7 +102,7 @@ def open_browser_process(
|
|
100
102
|
|
101
103
|
proc = Process(
|
102
104
|
target=_open_http_server_subprocess,
|
103
|
-
args=(fastled_js, port),
|
105
|
+
args=(fastled_js, port, compile_server_port),
|
104
106
|
daemon=True,
|
105
107
|
)
|
106
108
|
proc.start()
|
@@ -2,12 +2,14 @@ import argparse
|
|
2
2
|
from multiprocessing import Process
|
3
3
|
from pathlib import Path
|
4
4
|
|
5
|
+
import requests
|
5
6
|
from livereload import Server
|
6
7
|
|
7
8
|
|
8
9
|
def _run_flask_server(
|
9
10
|
fastled_js: Path,
|
10
11
|
port: int,
|
12
|
+
compile_server_port: int,
|
11
13
|
certfile: Path | None = None,
|
12
14
|
keyfile: Path | None = None,
|
13
15
|
) -> None:
|
@@ -27,10 +29,38 @@ def _run_flask_server(
|
|
27
29
|
# Must be a full path or flask will fail to find the file.
|
28
30
|
fastled_js = fastled_js.resolve()
|
29
31
|
|
32
|
+
print(f"Compile server port is at {compile_server_port}")
|
33
|
+
|
30
34
|
@app.route("/")
|
31
35
|
def serve_index():
|
32
36
|
return send_from_directory(fastled_js, "index.html")
|
33
37
|
|
38
|
+
@app.route("/static/<path:path>")
|
39
|
+
def proxy_static(path):
|
40
|
+
"""Proxy requests to /static/* to the compile server"""
|
41
|
+
from flask import Response, request
|
42
|
+
|
43
|
+
# Forward the request to the compile server
|
44
|
+
target_url = f"http://localhost:{compile_server_port}/static/{path}"
|
45
|
+
|
46
|
+
# Forward the request with the same method, headers, and body
|
47
|
+
resp = requests.request(
|
48
|
+
method=request.method,
|
49
|
+
url=target_url,
|
50
|
+
headers={key: value for key, value in request.headers if key != "Host"},
|
51
|
+
data=request.get_data(),
|
52
|
+
cookies=request.cookies,
|
53
|
+
allow_redirects=True,
|
54
|
+
stream=False,
|
55
|
+
)
|
56
|
+
|
57
|
+
# Create a Flask Response object from the requests response
|
58
|
+
response = Response(
|
59
|
+
resp.raw.read(), status=resp.status_code, headers=dict(resp.headers)
|
60
|
+
)
|
61
|
+
|
62
|
+
return response
|
63
|
+
|
34
64
|
@app.route("/<path:path>")
|
35
65
|
def serve_files(path):
|
36
66
|
response = send_from_directory(fastled_js, path)
|
@@ -83,11 +113,15 @@ def _run_flask_server(
|
|
83
113
|
|
84
114
|
|
85
115
|
def run(
|
86
|
-
port: int,
|
116
|
+
port: int,
|
117
|
+
cwd: Path,
|
118
|
+
compile_server_port: int,
|
119
|
+
certfile: Path | None = None,
|
120
|
+
keyfile: Path | None = None,
|
87
121
|
) -> None:
|
88
122
|
"""Run the Flask server."""
|
89
123
|
try:
|
90
|
-
_run_flask_server(cwd, port, certfile, keyfile)
|
124
|
+
_run_flask_server(cwd, port, compile_server_port, certfile, keyfile)
|
91
125
|
import warnings
|
92
126
|
|
93
127
|
warnings.warn("Flask server has stopped")
|
@@ -128,15 +162,15 @@ def parse_args() -> argparse.Namespace:
|
|
128
162
|
|
129
163
|
def run_flask_server_process(
|
130
164
|
port: int,
|
131
|
-
cwd: Path
|
165
|
+
cwd: Path,
|
166
|
+
compile_server_port: int,
|
132
167
|
certfile: Path | None = None,
|
133
168
|
keyfile: Path | None = None,
|
134
169
|
) -> Process:
|
135
170
|
"""Run the Flask server in a separate process."""
|
136
|
-
cwd = cwd or Path(".")
|
137
171
|
process = Process(
|
138
172
|
target=run,
|
139
|
-
args=(port, cwd, certfile, keyfile),
|
173
|
+
args=(port, cwd, compile_server_port, certfile, keyfile),
|
140
174
|
)
|
141
175
|
process.start()
|
142
176
|
return process
|
@@ -9,7 +9,11 @@ from fastled.server_flask import run_flask_server_process
|
|
9
9
|
|
10
10
|
|
11
11
|
def run_server_process(
|
12
|
-
port: int,
|
12
|
+
port: int,
|
13
|
+
cwd: Path,
|
14
|
+
compile_server_port: int,
|
15
|
+
certfile: Path | None = None,
|
16
|
+
keyfile: Path | None = None,
|
13
17
|
) -> Process:
|
14
18
|
"""Run the server in a separate process."""
|
15
19
|
if True:
|
@@ -17,6 +21,7 @@ def run_server_process(
|
|
17
21
|
process = run_flask_server_process(
|
18
22
|
port=port,
|
19
23
|
cwd=cwd,
|
24
|
+
compile_server_port=compile_server_port,
|
20
25
|
certfile=certfile,
|
21
26
|
keyfile=keyfile,
|
22
27
|
)
|
@@ -45,19 +50,18 @@ def get_asset_path(filename: str) -> Path | None:
|
|
45
50
|
def start_process(
|
46
51
|
path: Path,
|
47
52
|
port: int,
|
48
|
-
|
49
|
-
|
53
|
+
compile_server_port: int,
|
54
|
+
certfile: Path | None = None, # reserved for future use
|
55
|
+
keyfile: Path | None = None, # reserved for future use
|
50
56
|
) -> Process:
|
51
57
|
"""Run the server, using package assets if explicit paths are not provided"""
|
52
58
|
# Use package resources if no explicit path
|
53
|
-
if certfile is None:
|
54
|
-
certfile = get_asset_path("localhost.pem")
|
55
|
-
if keyfile is None:
|
56
|
-
keyfile = get_asset_path("localhost-key.pem")
|
57
59
|
|
58
60
|
# _run_flask_server(path, port, certfile, keyfile)
|
59
61
|
# run_fastapi_server_process(port=port, path=path, certfile=certfile, keyfile=keyfile)
|
60
|
-
proc = run_server_process(
|
62
|
+
proc = run_server_process(
|
63
|
+
port=port, cwd=path, compile_server_port=compile_server_port
|
64
|
+
)
|
61
65
|
# try:
|
62
66
|
# proc.join()
|
63
67
|
# except KeyboardInterrupt:
|
@@ -71,6 +75,7 @@ def start_process(
|
|
71
75
|
class Args:
|
72
76
|
fastled_js: Path
|
73
77
|
port: int
|
78
|
+
compile_server_port: int
|
74
79
|
cert: Path | None
|
75
80
|
key: Path | None
|
76
81
|
|
@@ -89,6 +94,12 @@ def parse_args() -> Args:
|
|
89
94
|
default=5500,
|
90
95
|
help="Port to run the server on (default: 5500)",
|
91
96
|
)
|
97
|
+
parser.add_argument(
|
98
|
+
"--compile-server-port",
|
99
|
+
type=int,
|
100
|
+
required=True,
|
101
|
+
help="Used to forward requests to the compile server",
|
102
|
+
)
|
92
103
|
parser.add_argument(
|
93
104
|
"--cert", type=Path, help="(Optional) Path to SSL certificate (PEM format)"
|
94
105
|
)
|
@@ -99,6 +110,7 @@ def parse_args() -> Args:
|
|
99
110
|
out: Args = Args(
|
100
111
|
fastled_js=args.fastled_js,
|
101
112
|
port=args.port,
|
113
|
+
compile_server_port=args.compile_server_port,
|
102
114
|
cert=args.cert,
|
103
115
|
key=args.key,
|
104
116
|
)
|
@@ -116,6 +128,7 @@ def main() -> None:
|
|
116
128
|
proc = start_process(
|
117
129
|
path=fastled_js,
|
118
130
|
port=port,
|
131
|
+
compile_server_port=args.compile_server_port,
|
119
132
|
certfile=cert,
|
120
133
|
keyfile=key,
|
121
134
|
)
|
@@ -41,10 +41,10 @@ compiler/build_fast.sh
|
|
41
41
|
compiler/code_sync.py
|
42
42
|
compiler/compile.py
|
43
43
|
compiler/compile_lock.py
|
44
|
+
compiler/debug.sh
|
44
45
|
compiler/entrypoint.sh
|
45
46
|
compiler/final_prewarm.sh
|
46
47
|
compiler/init_runtime.py
|
47
|
-
compiler/init_runtime2.py
|
48
48
|
compiler/install-arduino-cli.sh
|
49
49
|
compiler/paths.py
|
50
50
|
compiler/pre-process.sh
|
@@ -1,79 +0,0 @@
|
|
1
|
-
import glob
|
2
|
-
import os
|
3
|
-
import warnings
|
4
|
-
from concurrent.futures import ThreadPoolExecutor
|
5
|
-
from pathlib import Path
|
6
|
-
|
7
|
-
SRC_MAPPED_HOST_COMPLER_DIR = Path("/host/fastled/src/platforms/wasm/compiler")
|
8
|
-
SRC_STANDARD_HOST_COMPILER_DIR = Path(
|
9
|
-
"/js/compiler/fastled/src/platforms/wasm/compiler"
|
10
|
-
)
|
11
|
-
|
12
|
-
COMPILER_TARGET = Path("/js")
|
13
|
-
|
14
|
-
if SRC_MAPPED_HOST_COMPLER_DIR.exists():
|
15
|
-
SRC_COMPILER_DIR = SRC_MAPPED_HOST_COMPLER_DIR
|
16
|
-
else:
|
17
|
-
SRC_COMPILER_DIR = SRC_STANDARD_HOST_COMPILER_DIR
|
18
|
-
|
19
|
-
HERE = Path(__file__).parent
|
20
|
-
|
21
|
-
|
22
|
-
def copy_task(src: str | Path) -> None:
|
23
|
-
src = Path(src)
|
24
|
-
if "entrypoint.sh" in str(src):
|
25
|
-
return
|
26
|
-
link_dst = COMPILER_TARGET / src.name
|
27
|
-
|
28
|
-
# Handle shell scripts
|
29
|
-
if src.suffix == ".sh":
|
30
|
-
os.system(f"dos2unix {src} && chmod +x {src}")
|
31
|
-
|
32
|
-
# if link exists, remove it
|
33
|
-
if link_dst.exists():
|
34
|
-
print(f"Removing existing link {link_dst}")
|
35
|
-
try:
|
36
|
-
os.remove(link_dst)
|
37
|
-
except Exception as e:
|
38
|
-
warnings.warn(f"Failed to remove {link_dst}: {e}")
|
39
|
-
|
40
|
-
if not link_dst.exists():
|
41
|
-
print(f"Linking {src} to {link_dst}")
|
42
|
-
try:
|
43
|
-
os.symlink(str(src), str(link_dst))
|
44
|
-
except FileExistsError:
|
45
|
-
print(f"Target {link_dst} already exists")
|
46
|
-
else:
|
47
|
-
print(f"Target {link_dst} already exists")
|
48
|
-
|
49
|
-
|
50
|
-
def make_links() -> None:
|
51
|
-
# Define file patterns to include
|
52
|
-
patterns = [
|
53
|
-
"*.h",
|
54
|
-
"*.hpp",
|
55
|
-
"*.cpp",
|
56
|
-
"*.py",
|
57
|
-
"*.sh",
|
58
|
-
"*.ino",
|
59
|
-
"*.ini",
|
60
|
-
"*.txt",
|
61
|
-
]
|
62
|
-
|
63
|
-
# Get all matching files in compiler directory
|
64
|
-
files = []
|
65
|
-
for pattern in patterns:
|
66
|
-
files.extend(glob.glob(str(SRC_COMPILER_DIR / pattern)))
|
67
|
-
|
68
|
-
# Process files in parallel using ThreadPoolExecutor
|
69
|
-
with ThreadPoolExecutor(max_workers=16) as executor:
|
70
|
-
executor.map(copy_task, files)
|
71
|
-
|
72
|
-
|
73
|
-
def init_runtime() -> None:
|
74
|
-
os.chdir(str(HERE))
|
75
|
-
make_links()
|
76
|
-
|
77
|
-
|
78
|
-
if __name__ == "__main__":
|
79
|
-
init_runtime()
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|