Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Full editable LAN queue items #119

Merged
merged 4 commits into from
Sep 3, 2022
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
73 changes: 23 additions & 50 deletions continuousprint/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from enum import Enum
from octoprint.access.permissions import Permissions, ADMIN_GROUP
from octoprint.server.util.flask import restricted_access
from .queues.lan import ValidationError
import flask
import json
from .storage import queries
Expand Down Expand Up @@ -174,58 +175,41 @@ def add_job(self):
self._get_queue(DEFAULT_QUEUE).add_job(data.get("name")).as_dict()
)

# PRIVATE API METHOD - may change without warning.
@octoprint.plugin.BlueprintPlugin.route("/set/mv", methods=["POST"])
@restricted_access
@cpq_permission(Permission.EDITJOB)
def mv_set(self):
self._get_queue(DEFAULT_QUEUE).mv_set(
int(flask.request.form["id"]),
int(
flask.request.form["after_id"]
), # Move to after this set (-1 for beginning of job)
int(
flask.request.form["dest_job"]
), # Move to this job (null for new job at end)
)
return json.dumps("ok")

# PRIVATE API METHOD - may change without warning.
@octoprint.plugin.BlueprintPlugin.route("/job/mv", methods=["POST"])
@restricted_access
@cpq_permission(Permission.EDITJOB)
def mv_job(self):
self._get_queue(DEFAULT_QUEUE).mv_job(
int(flask.request.form["id"]),
int(
flask.request.form["after_id"]
), # Move to after this job (-1 for beginning of queue)
)
return json.dumps("ok")
src_id = flask.request.form["id"]
after_id = flask.request.form["after_id"]
if after_id == "": # Treat empty string as 'none' i.e. front of queue
after_id = None
sq = self._get_queue(flask.request.form["src_queue"])
dq = self._get_queue(flask.request.form.get("dest_queue"))

# Transfer into dest queue first
if dq != sq:
try:
new_id = dq.import_job_from_view(sq.get_job_view(src_id))
except ValidationError as e:
return json.dumps(dict(error=str(e)))

# PRIVATE API METHOD - may change without warning.
@octoprint.plugin.BlueprintPlugin.route("/job/submit", methods=["POST"])
@restricted_access
@cpq_permission(Permission.ADDJOB)
def submit_job(self):
j = queries.getJob(int(flask.request.form["id"]))
# Submit to the queue and remove from its origin
err = self._get_queue(flask.request.form["queue"]).submit_job(j)
if err is None:
self._logger.debug(
self._get_queue(DEFAULT_QUEUE).remove_jobs(job_ids=[j.id])
)
return self._state_json()
else:
return json.dumps(dict(error=str(err)))
print("Imported job from view")
sq.remove_jobs([src_id])
src_id = new_id

# Finally, move the job
dq.mv_job(src_id, after_id)
return json.dumps("OK")

# PRIVATE API METHOD - may change without warning.
@octoprint.plugin.BlueprintPlugin.route("/job/edit", methods=["POST"])
@restricted_access
@cpq_permission(Permission.EDITJOB)
def edit_job(self):
data = json.loads(flask.request.form.get("json"))
return json.dumps(self._get_queue(DEFAULT_QUEUE).edit_job(data["id"], data))
q = self._get_queue(data["queue"])
return json.dumps(q.edit_job(data["id"], data))

# PRIVATE API METHOD - may change without warning.
@octoprint.plugin.BlueprintPlugin.route("/job/import", methods=["POST"])
Expand Down Expand Up @@ -270,17 +254,6 @@ def rm_job(self):
)
)

# PRIVATE API METHOD - may change without warning.
@octoprint.plugin.BlueprintPlugin.route("/set/rm", methods=["POST"])
@restricted_access
@cpq_permission(Permission.EDITJOB)
def rm_set(self):
return json.dumps(
self._get_queue(DEFAULT_QUEUE).rm_multi(
set_ids=flask.request.form.getlist("set_ids[]")
)
)

# PRIVATE API METHOD - may change without warning.
@octoprint.plugin.BlueprintPlugin.route("/job/reset", methods=["POST"])
@restricted_access
Expand Down
15 changes: 11 additions & 4 deletions continuousprint/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,19 @@ def action(
# Given that some calls to action() come from a watchdog timer, we hold a mutex when performing the action
# so the state is updated in a thread safe way.
with self.mutex:
self._logger.debug(
f"{a.name}, {p.name}, path={path}, materials={materials}, bed_temp={bed_temp}"
)
now = time.time()
if self.idle_start_ts is None or self.idle_start_ts + 15 > now:
extra = (
f"(idle logs hidden after {self.idle_start_ts+15})"
if self.idle_start_ts is not None
else ""
)
self._logger.debug(
f"{a.name}, {p.name}, path={path}, materials={materials}, bed_temp={bed_temp} {extra}"
)

if p == Printer.IDLE and self.idle_start_ts is None:
self.idle_start_ts = time.time()
self.idle_start_ts = now
elif p != Printer.IDLE and self.idle_start_ts is not None:
self.idle_start_ts = None

Expand Down
17 changes: 8 additions & 9 deletions continuousprint/integration_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from peewee import SqliteDatabase
from collections import defaultdict
from peerprint.lan_queue import LANPrintQueueBase
from peerprint.sync_objects_test import TestReplDict

# logging.basicConfig(level=logging.DEBUG)

Expand Down Expand Up @@ -183,11 +184,6 @@ def release(self, k):
self.locks.pop(k, None)


class LocalJobDict(dict):
def set(self, k, v, **kwargs):
self[k] = v


class TestLANQueue(IntegrationTest):
"""A simple in-memory integration test between DB storage layer, queuing layer, and driver."""

Expand All @@ -214,13 +210,14 @@ def setUp(self):
self.lq.ns, self.lq.addr, MagicMock(), logging.getLogger("lantestbase")
)
self.lq.lan.q.locks = LocalLockManager(dict(), "lq")
self.lq.lan.q.jobs = LocalJobDict()
self.lq.lan.q.jobs = TestReplDict(lambda a, b: None)
self.lq.lan.q.peers = dict()

def test_completes_job_in_order(self):
self.lq.lan.q.setJob(
"bsdf",
"uuid1",
dict(
id="uuid1",
name="j1",
created=0,
sets=[
Expand All @@ -238,8 +235,9 @@ def test_completes_job_in_order(self):
def test_multi_job(self):
for name in ("j1", "j2"):
self.lq.lan.q.setJob(
f"{name}_hash",
f"{name}_id",
dict(
id=f"{name}_id",
name=name,
created=0,
sets=[dict(path=f"{name}.gcode", count=1, remaining=1)],
Expand Down Expand Up @@ -288,7 +286,7 @@ def onupdate():
lq.ns, lq.addr, MagicMock(), logging.getLogger("lantestbase")
)
lq.lan.q.locks = LocalLockManager(self.locks, f"peer{i}")
lq.lan.q.jobs = LocalJobDict()
lq.lan.q.jobs = TestReplDict(lambda a, b: None)
lq.lan.q.peers = self.peers
if i > 0:
lq.lan.q.peers = self.peers[0][2].lan.q.peers
Expand All @@ -304,6 +302,7 @@ def test_ordered_acquisition(self):
lq1.lan.q.setJob(
f"{name}_hash",
dict(
id=f"{name}_hash",
name=name,
created=0,
sets=[
Expand Down
28 changes: 12 additions & 16 deletions continuousprint/queues/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,40 +67,36 @@ def reset_jobs(self, job_ids) -> dict:
pass


class AbstractJobQueue(AbstractQueue):
"""LAN queues (potentially others in the future) act on whole jobs and do not allow
edits to inner data"""

@abstractmethod
def submit_job(self, j: JobView) -> bool:
pass


class AbstractEditableQueue(AbstractQueue):
"""Some queues (e.g. local to a single printer) are directly editable."""
"""Use for queues that are directly editable."""

@abstractmethod
def add_job(self, name="") -> JobView:
def mv_job(self, job_id, after_id):
pass

@abstractmethod
def add_set(self, job_id, data) -> SetView:
def edit_job(self, job_id, data):
pass

@abstractmethod
def mv_set(self, set_id, after_id, dest_job) -> SetView:
def get_job_view(self, job_id):
pass

@abstractmethod
def mv_job(self, job_id, after_id):
def import_job_from_view(self, job_view):
"""Imports a JobView into storage. Returns ID of the imported job"""
pass


class AbstractFactoryQueue(AbstractEditableQueue):
"""Use for queues where you can construct new jobs/sets"""

@abstractmethod
def edit_job(self, job_id, data):
def add_job(self, name="") -> JobView:
pass

@abstractmethod
def rm_multi(self, job_ids, set_ids) -> dict:
def add_set(self, job_id, data) -> SetView:
pass

@abstractmethod
Expand Down
Loading