Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/source/dev/adapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,9 @@ This generates:
Below is an example of how to define a resource handler configuration for a `MotorAdapter`:

```python
from mxcubeweb.core.models.configmodels import AdapterResourceHandlerConfigModel
from mxcubeweb.core.models.configmodels import ResourceHandlerConfigModel

resource_handler_config = AdapterResourceHandlerConfigModel(
resource_handler_config = ResourceHandlerConfigModel(
commands=[
"set_value",
"get_value",
Expand Down
6 changes: 4 additions & 2 deletions mxcubeweb/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@
from mxcubeweb.core.components.samplechanger import SampleChanger
from mxcubeweb.core.components.sampleview import SampleView
from mxcubeweb.core.components.workflow import Workflow
from mxcubeweb.core.components.log import Log
from mxcubeweb.core.models.configmodels import UIComponentModel
from mxcubeweb.logging_handler import MX3LoggingHandler
from mxcubeweb.core.server.resource_handler import AdapterResourceHandlerFactory
from mxcubeweb.core.server.resource_handler import ResourceHandlerFactory

removeLoggingHandlers()

Expand Down Expand Up @@ -131,7 +132,7 @@ def init(
# re-initializes the application for each test, we thus
# need to remove all AdapterResourceHandlers from the
# factory.
AdapterResourceHandlerFactory.unregister_all()
ResourceHandlerFactory.unregister_all()

logging.getLogger("MX3.HWR").info("Starting MXCuBE-Web...")
MXCUBEApplication.server = server
Expand Down Expand Up @@ -165,6 +166,7 @@ def init(
MXCUBEApplication.sample_view = SampleView(MXCUBEApplication, {})
MXCUBEApplication.workflow = Workflow(MXCUBEApplication, {})
MXCUBEApplication.harvester = Harvester(MXCUBEApplication, {})
MXCUBEApplication.log = Log(MXCUBEApplication, {})

MXCUBEApplication.init_signal_handlers()
# Install server-side UI state storage
Expand Down
4 changes: 2 additions & 2 deletions mxcubeweb/core/adapter/actuator_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
FloatValueModel,
HOActuatorValueChangeModel,
)
from mxcubeweb.core.models.configmodels import AdapterResourceHandlerConfigModel
from mxcubeweb.core.models.configmodels import ResourceHandlerConfigModel
from mxcubeweb.core.util.networkutils import RateLimited

resource_handler_config = AdapterResourceHandlerConfigModel(
resource_handler_config = ResourceHandlerConfigModel(
commands=["get_value", "set_value", "stop"], attributes=["data"]
)

Expand Down
12 changes: 6 additions & 6 deletions mxcubeweb/core/adapter/adapter_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
HOActuatorModel,
HOModel,
)
from mxcubeweb.core.models.configmodels import AdapterResourceHandlerConfigModel
from mxcubeweb.core.models.configmodels import ResourceHandlerConfigModel
from mxcubeweb.core.server.resource_handler import (
AdapterResourceHandlerFactory,
ResourceHandlerFactory,
)

default_resource_handler_config = AdapterResourceHandlerConfigModel(
default_resource_handler_config = ResourceHandlerConfigModel(
commands=[
"set_value",
"get_value",
Expand Down Expand Up @@ -67,10 +67,10 @@ def __init__(self, ho, role, app, resource_handler_config=None):
self.ADAPTER_DICT[cls_name][ho.name] = self

if resource_handler_config:
AdapterResourceHandlerFactory.create_or_get(
ResourceHandlerFactory.create_or_get(
name=cls_name,
url_prefix="/mxcube/api/v0.1/hwobj/" + self._type.lower(),
adapter_dict=self.ADAPTER_DICT[cls_name],
handler_dict=self.ADAPTER_DICT[cls_name],
app=self.app,
exports=resource_handler_config.exports,
commands=resource_handler_config.commands,
Expand Down Expand Up @@ -251,7 +251,7 @@ def _exported_methods(self):
# been explicitly configured to be exported
configured_exported = self._ho.exported_attributes.keys()

rh = AdapterResourceHandlerFactory.get_handler(self.__class__.__name__.lower())
rh = ResourceHandlerFactory.get_handler(self.__class__.__name__.lower())

if rh:
for export in rh.commands:
Expand Down
6 changes: 3 additions & 3 deletions mxcubeweb/core/adapter/beamline_action_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
HOActuatorValueChangeModel,
NStateModel,
)
from mxcubeweb.core.models.configmodels import AdapterResourceHandlerConfigModel
from mxcubeweb.core.models.configmodels import ResourceHandlerConfigModel

resource_handler_config = AdapterResourceHandlerConfigModel(
resource_handler_config = ResourceHandlerConfigModel(
commands=["stop", "run_action"], attributes=["data", "get_all_actions"]
)

Expand Down Expand Up @@ -62,7 +62,7 @@ def __init__(
ho: HardwareObject,
role: str,
app,
resource_handler_config: AdapterResourceHandlerConfigModel = resource_handler_config, # noqa: E501
resource_handler_config: ResourceHandlerConfigModel = resource_handler_config,
):
"""
Args:
Expand Down
4 changes: 2 additions & 2 deletions mxcubeweb/core/adapter/detector_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
from mxcubecore.HardwareObjects.abstract import AbstractDetector

from mxcubeweb.core.adapter.adapter_base import AdapterBase
from mxcubeweb.core.models.configmodels import AdapterResourceHandlerConfigModel
from mxcubeweb.core.models.configmodels import ResourceHandlerConfigModel

resource_handler_config = AdapterResourceHandlerConfigModel(
resource_handler_config = ResourceHandlerConfigModel(
name="detector_test",
url_prefix="/mxcube/api/v0.1/detectortest",
attributes=["data"],
Expand Down
4 changes: 2 additions & 2 deletions mxcubeweb/core/adapter/energy_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

from mxcubeweb.core.adapter.actuator_adapter import ActuatorAdapter
from mxcubeweb.core.adapter.wavelength_adapter import WavelengthAdapter
from mxcubeweb.core.models.configmodels import AdapterResourceHandlerConfigModel
from mxcubeweb.core.models.configmodels import ResourceHandlerConfigModel

resource_handler_config = AdapterResourceHandlerConfigModel(
resource_handler_config = ResourceHandlerConfigModel(
commands=["get_value", "set_value", "stop", "get_resolution_limits_for_energy"],
attributes=["data"],
)
Expand Down
4 changes: 2 additions & 2 deletions mxcubeweb/core/adapter/motor_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
from mxcubeweb.core.models.adaptermodels import (
FloatValueModel,
)
from mxcubeweb.core.models.configmodels import AdapterResourceHandlerConfigModel
from mxcubeweb.core.models.configmodels import ResourceHandlerConfigModel
from mxcubeweb.core.util.networkutils import RateLimited

resource_handler_config = AdapterResourceHandlerConfigModel(
resource_handler_config = ResourceHandlerConfigModel(
url_prefix="/mxcube/api/v0.1/motor_test",
commands=["set_value", "get_value", "stop"],
attributes=["data"],
Expand Down
4 changes: 2 additions & 2 deletions mxcubeweb/core/adapter/nstate_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
NStateModel,
StrValueModel,
)
from mxcubeweb.core.models.configmodels import AdapterResourceHandlerConfigModel
from mxcubeweb.core.models.configmodels import ResourceHandlerConfigModel

resource_handler_config = AdapterResourceHandlerConfigModel(
resource_handler_config = ResourceHandlerConfigModel(
commands=["get_value", "set_value", "stop"], attributes=["data"]
)

Expand Down
20 changes: 19 additions & 1 deletion mxcubeweb/core/components/component_base.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
import importlib
import logging

from mxcubeweb.core.server.resource_handler import (
ResourceHandlerFactory,
)


class ComponentBase:
def __init__(self, app, config):
def __init__(self, app, config, resource_handler_config=None):
self.app = app
self.config = config

if resource_handler_config:
cls_name = self.__class__.__name__.lower()

ResourceHandlerFactory.create_or_get(
name=cls_name,
url_prefix="/mxcube/api/v0.1/" + cls_name,
handler_dict={cls_name: self},
app=self.app,
exports=resource_handler_config.exports,
commands=resource_handler_config.commands,
attributes=resource_handler_config.attributes,
handler_type="component",
)


def import_component(config, package="", module=""):
_module = "mxcubeweb.core"
Expand Down
58 changes: 58 additions & 0 deletions mxcubeweb/core/components/log.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import json
import logging

from mxcubeweb import logging_handler
from mxcubeweb.core.components.component_base import ComponentBase
from mxcubeweb.core.models.configmodels import (
ResourceHandlerConfigModel,
)

hwr_logger = logging.getLogger("MX3.HWR")


class Log(ComponentBase):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log.py in routes no longer needed, everything is contained in the Component route definition and handler methods. The input and return data are serialized and handled the same way as for Adapters, making it much easier to handle the "data flow"

def __init__(self, app, config):
super().__init__(
app,
config,
resource_handler_config=ResourceHandlerConfigModel(
exports=[
{
"attr": "log",
"method": "GET",
"url": "/",
"decorators": [app.server.restrict],
},
{
"attr": "log_frontend_traceback",
"method": "POST",
"url": "/log_frontend_traceback",
"decorators": [app.server.restrict],
},
]
),
)

def log(self):
"""
Retrieve log messages
"""
messages = []

for handler in logging.getLogger("MX3.HWR").handlers:
if isinstance(handler, logging_handler.MX3LoggingHandler):
messages = handler.buffer

return messages

def log_frontend_traceback(self, args):
"""
Logs a UI traceback to the UI logger
"""
logging.getLogger("MX3.UI").error("------ Start of UI trace back ------")
logging.getLogger("MX3.UI").error("Traceback: %s", args["stack"])
logging.getLogger("MX3.UI").error(
"State: %s", json.dumps(args["state"], indent=4)
)
logging.getLogger("MX3.UI").error("------ End of UI trace back ------")
return {}
9 changes: 3 additions & 6 deletions mxcubeweb/core/models/configmodels.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
Literal,
)

from pydantic.v1 import (
BaseModel,
Field,
)
from pydantic.v1 import BaseModel, Field


class FlaskConfigModel(BaseModel):
Expand Down Expand Up @@ -208,7 +205,7 @@ class AppConfigModel(BaseModel):
sso: SSOConfigModel | None


class AdapterResourceHandlerConfigModel(BaseModel):
class ResourceHandlerConfigModel(BaseModel):
"""
Used to define which adapter properties and methods that are
exported over HTTP. An endpoint for each method and/or property
Expand Down Expand Up @@ -255,7 +252,7 @@ class AdapterResourceHandlerConfigModel(BaseModel):
"""

url_prefix: str = Field("", description="URL prefix")
exports: list[dict[str, str]] = Field(
exports: list[dict[str, str | list]] = Field(
[],
description=(
"List of dictionaires specifying each of the exported attributes or"
Expand Down
Loading