Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
aaa1e9b0c3
|
|||
|
8e976f39bb
|
|||
|
9734c18c4f
|
|||
|
71476c9196
|
|||
|
d259bd4839
|
|||
|
1f9632b396
|
|||
|
6ecd46dcec
|
|||
|
0b5c8e4e68
|
|||
|
42e7c2cf3b
|
|||
|
e23c5abdd9
|
|||
|
fea9389a14
|
|||
|
20c0e10767
|
|||
|
7618300619
|
|||
|
98092d3c77
|
|||
|
2d8e050d61
|
|||
|
dc6f0cae29
|
|||
|
2f00c39aba
|
|||
|
92204ba16a
|
@@ -71,16 +71,13 @@ jobs:
|
||||
- name: Install system dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y patchelf libopusfile0 ffmpeg espeak-ng
|
||||
sudo apt-get install -y patchelf libopusfile0 ffmpeg espeak-ng wine nsis
|
||||
|
||||
- name: Setup Task
|
||||
uses: https://git.quad4.io/actions/setup-task@0ab1b2a65bc55236a3bc64cde78f80e20e8885c2 # v1
|
||||
with:
|
||||
version: "3.46.3"
|
||||
|
||||
- name: Sync versions
|
||||
run: python scripts/sync_version.py
|
||||
|
||||
- name: Install dependencies
|
||||
run: task install
|
||||
|
||||
@@ -90,24 +87,39 @@ jobs:
|
||||
- name: Build Python wheel
|
||||
run: task wheel
|
||||
|
||||
- name: Build Electron App (Universal)
|
||||
run: pnpm run dist-prebuilt
|
||||
- name: Build Electron Apps (Linux and Windows)
|
||||
run: task build-electron-all
|
||||
|
||||
- name: Prepare release assets
|
||||
run: |
|
||||
mkdir -p release-assets
|
||||
# Collect artifacts
|
||||
find dist -type f \( -name "*-linux*.AppImage" -o -name "*-linux*.deb" \) -exec cp {} release-assets/ \;
|
||||
find python-dist -type f -name "*.whl" -exec cp {} release-assets/ \;
|
||||
# Collect artifacts from dist/
|
||||
# Linux artifacts
|
||||
find dist -maxdepth 1 -type f \( -name "*-linux*.AppImage" -o -name "*-linux*.deb" \) -exec cp {} release-assets/ \;
|
||||
# Windows artifacts
|
||||
find dist -maxdepth 1 -type f \( -name "*-win*.exe" \) -exec cp {} release-assets/ \;
|
||||
# Python artifacts
|
||||
find python-dist -maxdepth 1 -type f -name "*.whl" -exec cp {} release-assets/ \;
|
||||
|
||||
# Generate checksums
|
||||
cd release-assets
|
||||
for file in *; do
|
||||
if [ -f "$file" ] && [[ "$file" != *.sha256 ]]; then
|
||||
sha256sum "$file" | tee "${file}.sha256"
|
||||
fi
|
||||
done
|
||||
|
||||
# Generate release notes (outside release-assets directory)
|
||||
cd ..
|
||||
echo "## SHA256 Checksums" > release-body.md
|
||||
echo "" >> release-body.md
|
||||
for file in *; do
|
||||
if [ -f "$file" ] && [ "$file" != "release-body.md" ] && [[ "$file" != *.sha256 ]]; then
|
||||
sha256sum "$file" | tee "${file}.sha256"
|
||||
echo "\`$(cat "${file}.sha256")\`" >> release-body.md
|
||||
for file in release-assets/*; do
|
||||
if [ -f "$file" ] && [[ "$file" != *.sha256 ]] && [[ "$file" != *release-body.md* ]]; then
|
||||
filename=$(basename "$file")
|
||||
if [ -f "release-assets/${filename}.sha256" ]; then
|
||||
# Extract just the filename and its sha256 (format: <sha256> <filename>)
|
||||
echo "\`$(cat "release-assets/${filename}.sha256")\`" >> release-body.md
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -132,8 +144,13 @@ jobs:
|
||||
gitea_token: ${{ secrets.GITEA_TOKEN }}
|
||||
title: ${{ steps.version.outputs.version }}
|
||||
tag: ${{ steps.version.outputs.version }}
|
||||
files: "release-assets/*"
|
||||
bodyFile: "release-assets/release-body.md"
|
||||
files: |
|
||||
release-assets/*.AppImage
|
||||
release-assets/*.deb
|
||||
release-assets/*.exe
|
||||
release-assets/*.whl
|
||||
release-assets/*.sha256
|
||||
body_path: "release-body.md"
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
|
||||
66
.gitea/workflows/ci.yml
Normal file
66
.gitea/workflows/ci.yml
Normal file
@@ -0,0 +1,66 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "*"
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
UV_LINK_MODE: copy
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: https://git.quad4.io/actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
- name: Setup Node.js
|
||||
uses: https://git.quad4.io/actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
- name: Setup Python
|
||||
uses: https://git.quad4.io/actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
- name: Setup Task
|
||||
uses: https://git.quad4.io/actions/setup-task@0ab1b2a65bc55236a3bc64cde78f80e20e8885c2 # v1
|
||||
with:
|
||||
version: "3.46.3"
|
||||
- name: Setup uv
|
||||
run: |
|
||||
task setup-uv
|
||||
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||||
- name: Setup Python environment
|
||||
run: task setup-python-env
|
||||
- name: Install Node dependencies
|
||||
run: task node_modules
|
||||
- name: Lint
|
||||
run: task lint
|
||||
|
||||
build-frontend:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: https://git.quad4.io/actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
- name: Setup Node.js
|
||||
uses: https://git.quad4.io/actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
- name: Setup Task
|
||||
uses: https://git.quad4.io/actions/setup-task@0ab1b2a65bc55236a3bc64cde78f80e20e8885c2 # v1
|
||||
with:
|
||||
version: "3.46.3"
|
||||
- name: Install dependencies
|
||||
run: task node_modules
|
||||
- name: Determine version
|
||||
id: version
|
||||
run: |
|
||||
SHORT_SHA=$(git rev-parse --short HEAD)
|
||||
echo "version=${SHORT_SHA}" >> $GITHUB_OUTPUT
|
||||
- name: Build frontend
|
||||
run: task build-frontend
|
||||
env:
|
||||
VITE_APP_VERSION: ${{ steps.version.outputs.version }}
|
||||
15
README.md
15
README.md
@@ -2,7 +2,7 @@
|
||||
|
||||
A [Reticulum MeshChat](https://github.com/liamcottle/reticulum-meshchat) fork from the future.
|
||||
|
||||
<video src="showcase/showcase-video-call.mp4" controls="controls" style="max-width: 100%;"></video>
|
||||
<video src="https://strg.0rbitzer0.net/view/62926a2a-0a9a-4f44-a5f6-000dd60deac1.mp4" controls="controls" style="max-width: 100%;"></video>
|
||||
|
||||
This project is seperate from the original Reticulum MeshChat project, and is not affiliated with the original project.
|
||||
|
||||
@@ -31,18 +31,23 @@ This project is seperate from the original Reticulum MeshChat project, and is no
|
||||
<summary>Telephony & Calling</summary>
|
||||
|
||||
### Phone
|
||||
|
||||

|
||||
|
||||
### Active Call
|
||||
|
||||

|
||||
|
||||
### Call Ended
|
||||
|
||||

|
||||
|
||||
### Voicemail
|
||||
|
||||

|
||||
|
||||
### Ringtone Settings
|
||||
|
||||

|
||||
|
||||
</details>
|
||||
@@ -51,6 +56,7 @@ This project is seperate from the original Reticulum MeshChat project, and is no
|
||||
<summary>Networking & Visualization</summary>
|
||||
|
||||
### Network Visualiser
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -60,9 +66,11 @@ This project is seperate from the original Reticulum MeshChat project, and is no
|
||||
<summary>Page Archives</summary>
|
||||
|
||||
### Archives Browser
|
||||
|
||||

|
||||
|
||||
### Viewing Archived Page
|
||||
|
||||

|
||||
|
||||
</details>
|
||||
@@ -71,9 +79,11 @@ This project is seperate from the original Reticulum MeshChat project, and is no
|
||||
<summary>Tools & Identities</summary>
|
||||
|
||||
### Tools
|
||||
|
||||

|
||||
|
||||
### Identity Management
|
||||
|
||||

|
||||
|
||||
</details>
|
||||
@@ -88,7 +98,6 @@ This project is seperate from the original Reticulum MeshChat project, and is no
|
||||
- [ ] RNS Tunnel - tunnel your regular services over RNS to another MeshchatX user.
|
||||
- [ ] RNS Filesync - P2P file sync
|
||||
- [ ] RNS Page Node
|
||||
- [x] Micron Editor (w/ [micron-parser](https://github.com/RFnexus/micron-parser) by [RFnexus](https://github.com/RFnexus))
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -135,7 +144,7 @@ All tasks support environment variable overrides. For example:
|
||||
|
||||
### Python Packaging
|
||||
|
||||
The backend uses Poetry with `pyproject.toml` for dependency management and packaging. Before building, run `python3 scripts/sync_version.py` (or `task sync-version`) to ensure the generated `src/version.py` reflects the version from `package.json` that the Electron artifacts use. This keeps the CLI release metadata, wheel packages, and other bundles aligned.
|
||||
The backend uses Poetry with `pyproject.toml` for dependency management and packaging. `package.json` is the source of truth for the project version. When you run `task install` (or any task that builds/runs the app), the version is automatically synced to `pyproject.toml` and `src/version.py`. This keeps the CLI release metadata, wheel packages, and other bundles aligned with the Electron build.
|
||||
|
||||
#### Build Artifact Locations
|
||||
|
||||
|
||||
64
Taskfile.yml
64
Taskfile.yml
@@ -50,9 +50,35 @@ tasks:
|
||||
cmds:
|
||||
- task --list
|
||||
|
||||
setup-uv:
|
||||
desc: Install uv
|
||||
cmds:
|
||||
- curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
|
||||
setup-python-env:
|
||||
desc: Setup Python environment using uv
|
||||
cmds:
|
||||
- uv venv
|
||||
- uv pip install ruff poetry
|
||||
|
||||
lint-python:
|
||||
desc: Lint Python code using ruff
|
||||
cmds:
|
||||
- uv run ruff check .
|
||||
- uv run ruff format --check .
|
||||
|
||||
lint-frontend:
|
||||
desc: Lint frontend code
|
||||
cmds:
|
||||
- "{{.NPM}} run lint"
|
||||
|
||||
lint:
|
||||
desc: Run all linters
|
||||
deps: [lint-frontend, lint-python]
|
||||
|
||||
install:
|
||||
desc: Install all dependencies (syncs version, installs node modules and python deps)
|
||||
deps: [sync-version, node_modules, python]
|
||||
desc: Install all dependencies (installs node modules and python deps)
|
||||
deps: [node_modules, python]
|
||||
|
||||
node_modules:
|
||||
desc: Install Node.js dependencies
|
||||
@@ -109,6 +135,30 @@ tasks:
|
||||
- "{{.NPM}} run electron-postinstall"
|
||||
- "{{.NPM}} run dist -- --win portable"
|
||||
|
||||
build-electron-linux:
|
||||
desc: Build Linux Electron app with prebuilt backend
|
||||
deps: [build-frontend]
|
||||
cmds:
|
||||
- "{{.NPM}} run electron-postinstall"
|
||||
- "{{.NPM}} run build-backend"
|
||||
- "{{.NPM}} run dist -- --linux AppImage deb"
|
||||
|
||||
build-electron-windows:
|
||||
desc: Build Windows Electron apps (portable and installer)
|
||||
deps: [build-frontend]
|
||||
cmds:
|
||||
- "{{.NPM}} run electron-postinstall"
|
||||
- "{{.NPM}} run build-backend"
|
||||
- "{{.NPM}} run dist -- --win portable nsis"
|
||||
|
||||
build-electron-all:
|
||||
desc: Build all Electron apps (Linux and Windows)
|
||||
deps: [build-frontend]
|
||||
cmds:
|
||||
- "{{.NPM}} run electron-postinstall"
|
||||
- "{{.NPM}} run build-backend"
|
||||
- "{{.NPM}} run dist -- --linux AppImage deb --win portable nsis"
|
||||
|
||||
dist:
|
||||
desc: Build distribution (defaults to AppImage)
|
||||
cmds:
|
||||
@@ -143,18 +193,14 @@ tasks:
|
||||
- rm -rf dist
|
||||
- rm -rf python-dist
|
||||
- rm -rf meshchatx/public
|
||||
- rm -rf build-dir
|
||||
- task: android-clean
|
||||
|
||||
sync-version:
|
||||
desc: Sync version numbers across project files
|
||||
cmds:
|
||||
- "{{.PYTHON}} scripts/sync_version.py"
|
||||
|
||||
fix:
|
||||
desc: Format and fix linting issues (Python and frontend)
|
||||
cmds:
|
||||
- "{{.PYTHON}} -m poetry run ruff format ./"
|
||||
- "{{.PYTHON}} -m poetry run ruff check --fix ./"
|
||||
- uv run ruff format ./
|
||||
- uv run ruff check --fix ./
|
||||
- "{{.NPM}} run format"
|
||||
- "{{.NPM}} run lint:fix"
|
||||
|
||||
|
||||
15
cx_setup.py
15
cx_setup.py
@@ -8,12 +8,17 @@ from meshchatx.src.version import __version__
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
PUBLIC_DIR = ROOT / "meshchatx" / "public"
|
||||
|
||||
include_files = [
|
||||
(str(PUBLIC_DIR), "public"),
|
||||
("logo", "logo"),
|
||||
]
|
||||
include_files = []
|
||||
|
||||
if (ROOT / "bin").exists():
|
||||
if PUBLIC_DIR.exists() and PUBLIC_DIR.is_dir():
|
||||
include_files.append((str(PUBLIC_DIR), "public"))
|
||||
|
||||
logo_dir = ROOT / "logo"
|
||||
if logo_dir.exists() and logo_dir.is_dir():
|
||||
include_files.append(("logo", "logo"))
|
||||
|
||||
bin_dir = ROOT / "bin"
|
||||
if bin_dir.exists() and bin_dir.is_dir():
|
||||
include_files.append(("bin", "bin"))
|
||||
|
||||
packages = [
|
||||
|
||||
@@ -91,6 +91,9 @@ from meshchatx.src.version import __version__ as app_version
|
||||
# https://cx-freeze.readthedocs.io/en/latest/faq.html#using-data-files
|
||||
# bearer:disable python_lang_path_traversal
|
||||
def get_file_path(filename):
|
||||
# Remove trailing slashes for path joining consistency
|
||||
filename = filename.rstrip("/\\")
|
||||
|
||||
if getattr(sys, "frozen", False):
|
||||
datadir = os.path.dirname(sys.executable)
|
||||
return os.path.join(datadir, filename)
|
||||
@@ -1706,6 +1709,15 @@ class ReticulumMeshChat:
|
||||
},
|
||||
)
|
||||
|
||||
# allow serving manifest.json and service-worker.js directly at root
|
||||
@routes.get("/manifest.json")
|
||||
async def manifest(request):
|
||||
return web.FileResponse(get_file_path("public/manifest.json"))
|
||||
|
||||
@routes.get("/service-worker.js")
|
||||
async def service_worker(request):
|
||||
return web.FileResponse(get_file_path("public/service-worker.js"))
|
||||
|
||||
# serve ping
|
||||
@routes.get("/api/v1/status")
|
||||
async def status(request):
|
||||
@@ -5969,6 +5981,8 @@ class ReticulumMeshChat:
|
||||
response.headers["Content-Type"] = "text/css; charset=utf-8"
|
||||
elif path.endswith(".json"):
|
||||
response.headers["Content-Type"] = "application/json; charset=utf-8"
|
||||
elif path.endswith(".wasm"):
|
||||
response.headers["Content-Type"] = "application/wasm"
|
||||
elif path.endswith(".html"):
|
||||
response.headers["Content-Type"] = "text/html; charset=utf-8"
|
||||
return response
|
||||
@@ -6048,9 +6062,15 @@ class ReticulumMeshChat:
|
||||
)
|
||||
|
||||
app.add_routes(routes)
|
||||
app.add_routes(
|
||||
[web.static("/", get_file_path("public/"))],
|
||||
) # serve anything in public folder
|
||||
|
||||
# serve anything else from public folder
|
||||
# we use add_static here as it's more robust for serving directories
|
||||
public_dir = get_file_path("public")
|
||||
if os.path.exists(public_dir):
|
||||
app.router.add_static("/", public_dir, name="static", follow_symlinks=True)
|
||||
else:
|
||||
print(f"Warning: Static files directory not found at {public_dir}")
|
||||
|
||||
app.on_shutdown.append(
|
||||
self.shutdown,
|
||||
) # need to force close websockets and stop reticulum now
|
||||
|
||||
@@ -1459,11 +1459,6 @@ export default {
|
||||
isCallInputFocused: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
destinationHash() {
|
||||
this.selectedSuggestionIndex = -1;
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isMicMuted() {
|
||||
return this.activeCall?.is_mic_muted ?? false;
|
||||
@@ -1533,6 +1528,11 @@ export default {
|
||||
return suggestions.slice(0, 8);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
destinationHash() {
|
||||
this.selectedSuggestionIndex = -1;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getConfig();
|
||||
this.getAudioProfiles();
|
||||
|
||||
@@ -51,11 +51,13 @@
|
||||
isMobileView && showEditor ? 'hidden' : '',
|
||||
]"
|
||||
>
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<div
|
||||
ref="previewRef"
|
||||
class="flex-1 overflow-auto text-zinc-100 p-4 font-mono text-sm whitespace-pre-wrap break-words nodeContainer"
|
||||
v-html="renderedContent"
|
||||
></div>
|
||||
<!-- eslint-enable vue/no-v-html -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,4 +3,4 @@ Auto-generated helper so Python tooling and the Electron build
|
||||
share the same version string.
|
||||
"""
|
||||
|
||||
__version__ = '3.3.0'
|
||||
__version__ = "3.3.2"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "reticulum-meshchatx",
|
||||
"version": "3.3.0",
|
||||
"version": "3.3.2",
|
||||
"description": "A simple mesh network communications app powered by the Reticulum Network Stack",
|
||||
"homepage": "https://git.quad4.io/RNS-Things/MeshChatX",
|
||||
"author": "Sudo-Ivan",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "reticulum-meshchatx"
|
||||
version = "3.3.0"
|
||||
version = "3.3.2"
|
||||
description = "A simple mesh network communications app powered by the Reticulum Network Stack"
|
||||
authors = [
|
||||
{name = "Sudo-Ivan"}
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
"""Update project version references to stay aligned with the Electron build.
|
||||
|
||||
Reads `package.json`, writes the same version into `src/version.py`, and
|
||||
updates the `[tool.poetry] version` field inside `pyproject.toml`. Run this
|
||||
before any Python packaging commands so the wheel version matches the
|
||||
Electron artifacts.
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
PACKAGE_JSON = ROOT / "package.json"
|
||||
VERSION_PY = ROOT / "meshchatx" / "src" / "version.py"
|
||||
PYPROJECT_TOML = ROOT / "pyproject.toml"
|
||||
|
||||
|
||||
def read_package_version() -> str:
|
||||
with PACKAGE_JSON.open() as handle:
|
||||
return json.load(handle)["version"]
|
||||
|
||||
|
||||
def write_version_module(version: str) -> None:
|
||||
content = (
|
||||
'"""\n'
|
||||
"Auto-generated helper so Python tooling and the Electron build\n"
|
||||
"share the same version string.\n"
|
||||
'"""\n\n'
|
||||
f"__version__ = {version!r}\n"
|
||||
)
|
||||
if VERSION_PY.exists() and VERSION_PY.read_text() == content:
|
||||
return
|
||||
VERSION_PY.write_text(content)
|
||||
|
||||
|
||||
def update_poetry_version(version: str) -> None:
|
||||
if not PYPROJECT_TOML.exists():
|
||||
return
|
||||
content = PYPROJECT_TOML.read_text()
|
||||
|
||||
def replacer(match):
|
||||
return f"{match.group(1)}{version}{match.group(2)}"
|
||||
|
||||
new_content, replaced = re.subn(
|
||||
r'(?m)^(version\s*=\s*")[^"]*(")',
|
||||
replacer,
|
||||
content,
|
||||
count=1,
|
||||
)
|
||||
if replaced == 0:
|
||||
msg = "failed to update version in pyproject.toml"
|
||||
raise RuntimeError(msg)
|
||||
if new_content != content:
|
||||
PYPROJECT_TOML.write_text(new_content)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
version = read_package_version()
|
||||
write_version_module(version)
|
||||
update_poetry_version(version)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Binary file not shown.
Reference in New Issue
Block a user