8 Commits

Author SHA1 Message Date
Salad Dais
8989843042 v0.3.2 2021-05-04 15:42:27 +00:00
Salad Dais
a217a30133 Log message after addon hooks have run
This used to be the behaviour, but switching from queueing to
immediately adding messages to the log removed the implicit delay
2021-05-04 03:01:18 +00:00
Salad Dais
8514d7bae8 Update readme 2021-05-04 00:10:17 +00:00
Salad Dais
d9084c3332 Include licenses in Windows bundles 2021-05-04 00:09:07 +00:00
Salad Dais
0f35cc00d5 Allow manually triggering windows build 2021-05-03 23:40:00 +00:00
Salad Dais
a6a7ce8fa3 Correct codecov threshold 2021-05-03 23:36:59 +00:00
Salad Dais
269a1e163b Don't fail commits on coverage dropping 2021-05-03 23:33:33 +00:00
Salad Dais
eb2b6ee870 Package a zip for Windows when a release is made 2021-05-03 23:20:40 +00:00
14 changed files with 185 additions and 25 deletions

46
.github/workflows/bundle_windows.yml vendored Normal file
View File

@@ -0,0 +1,46 @@
# Have to manually unzip this (it gets double zipped) and add it
# onto the release after it gets created. Don't want actions with repo write.
name: Bundle Windows EXE
on:
# Only trigger on release creation
release:
types:
- created
workflow_dispatch:
jobs:
build:
runs-on: windows-latest
strategy:
matrix:
python-version: [3.9]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e .
pip install cx_freeze
- name: Bundle with cx_Freeze
run: |
python setup_cxfreeze.py build_exe
pip install pip-licenses
pip-licenses --format=plain-vertical --with-license-file --no-license-path --output-file=lib_licenses.txt
python setup_cxfreeze.py finalize_cxfreeze
- name: Upload the artifact
uses: actions/upload-artifact@v2
with:
name: hippolyzer-gui-windows-${{ github.sha }}
path: ./dist/**

View File

@@ -6,6 +6,8 @@ on:
release:
types:
- created
workflow_dispatch:
# based on https://github.com/pypa/gh-action-pypi-publish

View File

@@ -24,6 +24,9 @@ with low-level SL details. See the [Local Animation addon example](https://githu
![Screenshot of proxy GUI](https://github.com/SaladDais/Hippolyzer/blob/master/static/screenshot.png?raw=true)
## Setup
### From Source
* Python 3.8 or above is **required**. If you're unable to upgrade your system Python package due to
being on a stable distro, you can use [pyenv](https://github.com/pyenv/pyenv) to create
a self-contained Python install with the appropriate version.
@@ -34,6 +37,11 @@ with low-level SL details. See the [Local Animation addon example](https://githu
* * Under Windows it's `<virtualenv_dir>\Scripts\activate.bat`
* Run `pip install hippolyzer`, or run `pip install -e .` in a cloned repo to install an editable version
### Binary Windows Builds
Binary Windows builds are available on the [Releases page](https://github.com/SaladDais/Hippolyzer/releases/).
I don't extensively test these, building from source is recommended.
## Proxy
A proxy is provided with both a CLI and Qt-based interface. The proxy application wraps a
@@ -291,8 +299,6 @@ If you are a viewer developer, please put them in a viewer.
## Potential Changes
* Make package-able for PyPI
* GitHub action to build binary packages and pull together licenses bundle
* AISv3 wrapper?
* Higher level wrappers for common things? I don't really need these, so only if people want to write them.
* Highlight matched portion of message in log view, if applicable

11
codecov.yml Normal file
View File

@@ -0,0 +1,11 @@
coverage:
precision: 1
round: down
range: "50...80"
status:
project:
default:
# Do not fail PRs if the code coverage drops.
target: 0%
threshold: 100%
base: auto

View File

@@ -8,7 +8,6 @@ import json
import logging
import pathlib
import multiprocessing
import os
import re
import signal
import socket
@@ -24,7 +23,7 @@ from hippolyzer.apps.model import MessageLogModel, MessageLogHeader, RegionListM
from hippolyzer.apps.proxy import start_proxy
from hippolyzer.lib.base import llsd
from hippolyzer.lib.base.datatypes import UUID
from hippolyzer.lib.base.helpers import bytes_unescape, bytes_escape
from hippolyzer.lib.base.helpers import bytes_unescape, bytes_escape, get_resource_filename
from hippolyzer.lib.base.message.llsd_msg_serializer import LLSDMessageSerializer
from hippolyzer.lib.base.message.message import Block
from hippolyzer.lib.base.message.msgtypes import MsgType
@@ -44,11 +43,10 @@ from hippolyzer.lib.proxy.templates import CAP_TEMPLATES
LOG = logging.getLogger(__name__)
BASE_PATH = os.path.dirname(os.path.abspath(__file__))
MAIN_WINDOW_UI_PATH = os.path.join(BASE_PATH, "proxy_mainwindow.ui")
MESSAGE_BUILDER_UI_PATH = os.path.join(BASE_PATH, "message_builder.ui")
ADDON_DIALOG_UI_PATH = os.path.join(BASE_PATH, "addon_dialog.ui")
FILTER_DIALOG_UI_PATH = os.path.join(BASE_PATH, "filter_dialog.ui")
MAIN_WINDOW_UI_PATH = get_resource_filename("apps/proxy_mainwindow.ui")
MESSAGE_BUILDER_UI_PATH = get_resource_filename("apps/message_builder.ui")
ADDON_DIALOG_UI_PATH = get_resource_filename("apps/addon_dialog.ui")
FILTER_DIALOG_UI_PATH = get_resource_filename("apps/filter_dialog.ui")
def show_error_message(error_msg, parent=None):

View File

@@ -1,6 +1,7 @@
from __future__ import annotations
import functools
import pkg_resources
import re
import weakref
from pprint import PrettyPrinter
@@ -133,3 +134,7 @@ def bytes_unescape(val: bytes) -> bytes:
def bytes_escape(val: bytes) -> bytes:
# Try to keep newlines as-is
return re.sub(rb"(?<!\\)\\n", b"\n", codecs.escape_encode(val)[0]) # type: ignore
def get_resource_filename(resource_filename: str):
return pkg_resources.resource_filename("hippolyzer", resource_filename)

View File

@@ -22,6 +22,8 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import os
msg_tmpl = open(os.path.join(os.path.dirname(__file__), 'message_template.msg'))
with open(os.path.join(os.path.dirname(__file__), 'message.xml'), "rb") as _f:
from hippolyzer.lib.base.helpers import get_resource_filename
msg_tmpl = open(get_resource_filename("lib/base/message/data/message_template.msg"))
with open(get_resource_filename("lib/base/message/data/message.xml"), "rb") as _f:
msg_details = _f.read()

View File

@@ -1703,7 +1703,7 @@ class BaseSubfieldSerializer(abc.ABC):
"""Guess at which template a val might correspond to"""
if dataclasses.is_dataclass(val):
val = dataclasses.asdict(val) # noqa
if isinstance(val, bytes):
if isinstance(val, (bytes, bytearray)):
template_checker = cls._template_sizes_match
elif isinstance(val, dict):
template_checker = cls._template_keys_match

View File

@@ -5,7 +5,6 @@ import multiprocessing
import os
import re
import sys
import pkg_resources
import queue
import typing
import uuid
@@ -20,6 +19,7 @@ from mitmproxy.addons import core, clientplayback
from mitmproxy.http import HTTPFlow
import OpenSSL
from hippolyzer.lib.base.helpers import get_resource_filename
from hippolyzer.lib.base.multiprocessing_utils import ParentProcessWatcher
orig_sethostflags = OpenSSL.SSL._lib.X509_VERIFY_PARAM_set_hostflags # noqa
@@ -230,7 +230,7 @@ def create_proxy_master(host, port, flow_context: HTTPFlowContext): # pragma: n
os.path.join(opts.confdir, "config.yml"),
)
# Use SL's CA bundle so LL's CA certs won't cause verification errors
ca_bundle = pkg_resources.resource_filename("hippolyzer.lib.base", "network/data/ca-bundle.crt")
ca_bundle = get_resource_filename("lib/base/network/data/ca-bundle.crt")
opts.update(
ssl_verify_upstream_trusted_ca=ca_bundle,
listen_host=host,

View File

@@ -129,13 +129,14 @@ class InterceptingLLUDPProxyProtocol(BaseLLUDPProxyProtocol):
LOG.exception("Failed in region message handler")
message_logger = self.session_manager.message_logger
if message_logger:
message_logger.log_lludp_message(self.session, region, message)
handled = AddonManager.handle_lludp_message(
self.session, region, message
)
if message_logger:
message_logger.log_lludp_message(self.session, region, message)
if handled:
return

View File

@@ -1,10 +1,9 @@
import dataclasses
from typing import *
import pkg_resources
import hippolyzer.lib.base.serialization as se
from hippolyzer.lib.base.datatypes import UUID
from hippolyzer.lib.base.helpers import get_resource_filename
from hippolyzer.lib.proxy.templates import AssetType
@@ -64,5 +63,5 @@ class VFS:
return self._data_fh.read(block.size)
_static_path = pkg_resources.resource_filename("hippolyzer.lib.proxy", "data/static_index.db2")
_static_path = get_resource_filename("lib/proxy/data/static_index.db2")
STATIC_VFS = VFS(_static_path)

View File

@@ -25,7 +25,7 @@ from setuptools import setup, find_packages
here = path.abspath(path.dirname(__file__))
version = '0.3.1'
version = '0.3.2'
with open(path.join(here, 'README.md')) as readme_fh:
readme = readme_fh.read()

View File

@@ -1,7 +1,91 @@
import sys
import setuptools # noqa
import os
import shutil
from distutils.core import Command
from pathlib import Path
from cx_Freeze import setup, Executable
# We don't need any of these and they make the archive huge.
TO_DELETE = [
"lib/PySide2/Qt3DRender.pyd",
"lib/PySide2/Qt53DRender.dll",
"lib/PySide2/Qt5Charts.dll",
"lib/PySide2/Qt5Location.dll",
"lib/PySide2/Qt5Pdf.dll",
"lib/PySide2/Qt5Quick.dll",
"lib/PySide2/Qt5WebEngineCore.dll",
"lib/PySide2/QtCharts.pyd",
"lib/PySide2/QtMultimedia.pyd",
"lib/PySide2/QtOpenGLFunctions.pyd",
"lib/PySide2/QtOpenGLFunctions.pyi",
"lib/PySide2/d3dcompiler_47.dll",
"lib/PySide2/opengl32sw.dll",
"lib/PySide2/translations",
"lib/aiohttp/_find_header.c",
"lib/aiohttp/_frozenlist.c",
"lib/aiohttp/_helpers.c",
"lib/aiohttp/_http_parser.c",
"lib/aiohttp/_http_writer.c",
"lib/aiohttp/_websocket.c",
# Improve this to work with different versions.
"lib/aiohttp/python39.dll",
"lib/lazy_object_proxy/python39.dll",
"lib/lxml/python39.dll",
"lib/markupsafe/python39.dll",
"lib/multidict/python39.dll",
"lib/numpy/core/python39.dll",
"lib/numpy/fft/python39.dll",
"lib/numpy/linalg/python39.dll",
"lib/numpy/random/python39.dll",
"lib/python39.dll",
"lib/recordclass/python39.dll",
"lib/regex/python39.dll",
"lib/test",
"lib/yarl/python39.dll",
]
COPY_TO_ZIP = [
"LICENSE.txt",
"README.md",
"NOTICE.md",
# Must have been generated with pip-licenses before. Many dependencies
# require their license to be distributed with their binaries.
"lib_licenses.txt",
]
BASE_DIR = Path(__file__).parent.absolute()
class FinalizeCXFreezeCommand(Command):
description = "Prepare cx_Freeze build dirs and create a zip"
user_options = []
def initialize_options(self) -> None:
pass
def finalize_options(self) -> None:
pass
def run(self):
(BASE_DIR / "dist").mkdir(exist_ok=True)
for path in (BASE_DIR / "build").iterdir():
if path.name.startswith("exe.") and path.is_dir():
for cleanse_suffix in TO_DELETE:
cleanse_path = path / cleanse_suffix
shutil.rmtree(cleanse_path, ignore_errors=True)
try:
os.unlink(cleanse_path)
except:
pass
for to_copy in COPY_TO_ZIP:
shutil.copy(BASE_DIR / to_copy, path / to_copy)
zip_path = BASE_DIR / "dist" / path.name
shutil.make_archive(zip_path, "zip", path)
options = {
"build_exe": {
"packages": [
@@ -12,7 +96,8 @@ options = {
# exclude packages that are not really needed
"excludes": [
"tkinter",
]
],
"include_msvcr": True,
}
}
@@ -26,8 +111,11 @@ executables = [
setup(
name="hippolyzer_gui",
version="0.1",
version="0.3.2",
description="Hippolyzer GUI",
options=options,
executables=executables,
cmdclass={
"finalize_cxfreeze": FinalizeCXFreezeCommand,
}
)

View File

@@ -1,16 +1,18 @@
import pkg_resources
import os
import unittest
from hippolyzer.lib.base.mesh import LLMeshSerializer, MeshAsset
import hippolyzer.lib.base.serialization as se
BASE_PATH = os.path.dirname(os.path.abspath(__file__))
class TestMesh(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
# Use a rigged cube SLM from the upload process as a test file
slm_file = pkg_resources.resource_filename(__name__, "test_resources/testslm.slm")
slm_file = os.path.join(BASE_PATH, "test_resources", "testslm.slm")
with open(slm_file, "rb") as f:
cls.slm_bytes = f.read()