diff --git a/README.md b/README.md index 18d3dee..9701cdb 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,48 @@ To create a package and upload it to PyPI, first update the package version in t twine upload dist/* ``` +Mapped Datasets +--------------- + +The `client.map` wrapper exposes the agent's mapped-dataset RPCs (`map`, +`pull`, `push`, `diff`) as a small Python API. The four RPCs return as soon +as the agent has accepted the work — `pull` and `push` then run in the +background inside the agent — so `client.map` also ships two blocking +helpers: `wait_for_pull` and `wait_for_push`. + +```python +client.map.map(dataset_id="N:dataset:...", target_folder="/data/foo") +client.map.pull("/data/foo/subfolder") +client.map.wait_for_pull("/data/foo", expected_relative_paths=[...]) + +client.map.push("/data/foo") +client.map.wait_for_push(expected_files=N, subscriber_id=os.getpid()) +``` + +### Timeouts + +Both wait helpers use an **idle timeout** rather than a total-duration +timeout — the deadline resets each time progress is observed, so a +multi-hour single-file transfer is fine as long as the agent keeps making +progress. You only hit a `TimeoutError` when the agent goes silent. + +**`wait_for_pull`** — default `idle_timeout=1800` (30 min) +- *Progress signal:* a new file entry appears in `.pennsieve/state.json`, which the agent writes on each file's completion. +- *Why 30 min:* the window has to cover the worst-case single-file download end-to-end, since there is no per-chunk progress for pulls. + +**`wait_for_push`** — default `idle_timeout=300` (5 min) +- *Progress signal:* any `UPLOAD_STATUS` event (`INIT` / `IN_PROGRESS` / `COMPLETE`). The agent emits `IN_PROGRESS` on every S3 chunk read, so events stream continuously during healthy uploads. +- *Why 5 min:* events are frequent during healthy uploads, so 5 minutes of silence indicates a real stall (network hang, agent wedge) rather than slow progress. + +Override either default by passing `idle_timeout=` when you know +your transfer characteristics — e.g. pulls over a very slow link with large +individual files, or tighter CI smoke-tests where you want to fail faster. + +```python +client.map.wait_for_pull(target_folder, idle_timeout=3600) # 1 hour +client.map.wait_for_push(expected_files=N, subscriber_id=..., idle_timeout=60) # 1 minute +``` + Documentation ------------- diff --git a/pyproject.toml b/pyproject.toml index 419f991..eeb433d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,9 +69,15 @@ exclude = ''' | build | dist | docs + | src/pennsieve/protos )/ ''' +[tool.isort] +profile = "black" +line_length = 99 +skip_glob = ["src/pennsieve/protos/*"] + [build-system] requires = [ diff --git a/src/pennsieve/map.py b/src/pennsieve/map.py new file mode 100644 index 0000000..20add13 --- /dev/null +++ b/src/pennsieve/map.py @@ -0,0 +1,254 @@ +""" +Pennsieve Map feature — client-side wrapper. + +Mirrors the `pennsieve map` / `map pull` / `map push` / `map diff` CLI +commands that live in the Go agent. The gRPC calls return as soon as the +agent has started the work; long-running operations (pull, push) execute +in goroutines on the agent side. The `wait_for_*` helpers here let callers +block until completion when needed. +""" + +from __future__ import annotations + +import json +import os +import threading +import time +from pathlib import Path +from typing import Iterable, Optional + +from .protos import agent_pb2 + + +class Map: + """Operations on a Pennsieve Mapped Dataset. + + A mapped dataset is a local folder that mirrors a Pennsieve dataset's + tree as empty placeholder files, with a hidden `.pennsieve/` directory + holding the workspace manifest and pull state. Users pull selected + subfolders to get real bytes, and push to upload new files back. + + Methods: + -------- + map(dataset_id, target_folder): + Create a new mapped dataset at target_folder. + pull(path): + Download real content for files under `path` in a mapped dataset. + push(path): + Upload any new local files under `path` back to the mapped dataset. + diff(path): + Return added / changed / renamed / moved / deleted file status. + wait_for_pull(target_folder, idle_timeout=...): + Block until pulled files appear in state.json. Fails only if no new + files appear within `idle_timeout` seconds — total duration unbounded. + wait_for_push(expected_files, subscriber_id, idle_timeout=...): + Block until upload_status COMPLETE events match expected_files. Fails + only if no upload-status event arrives within `idle_timeout` seconds. + """ + + def __init__(self, stub): + self._stub = stub + + # ---------- RPCs ---------- + + def map(self, dataset_id: str, target_folder: str): + """Create a new mapped dataset on disk. + + Returns a SimpleStatusResponse. The agent downloads the workspace + manifest and creates placeholder files for every entry. + """ + request = agent_pb2.MapRequest( + dataset_id=dataset_id, + target_folder=_abspath(target_folder), + ) + return self._stub.Map(request=request) + + def pull(self, path: str): + """Pull real file bytes for files under `path`. + + `path` can be any file or folder inside a mapped dataset; the agent + walks up to find the dataset root. Returns a SimpleStatusResponse + once the pull has been kicked off — work continues in the background. + Use `wait_for_pull` to block until it finishes. + """ + request = agent_pb2.PullRequest(path=_abspath(path)) + return self._stub.Pull(request=request) + + def push(self, path: str): + """Push new local files under `path` back to the mapped dataset. + + Only ADDED files are uploaded (CHANGED / RENAMED / MOVED / DELETED + are ignored by the agent today). Returns immediately; use + `wait_for_push` with the expected file count to block. + """ + request = agent_pb2.PushRequest(path=_abspath(path)) + return self._stub.Push(request=request) + + def diff(self, path: str): + """Return local vs. remote diff for the mapped dataset at `path`.""" + request = agent_pb2.MapDiffRequest(path=_abspath(path)) + return self._stub.GetMapDiff(request=request) + + # ---------- wait helpers ---------- + + def wait_for_pull( + self, + target_folder: str, + expected_relative_paths: Optional[Iterable[str]] = None, + idle_timeout: float = 1800.0, + poll_interval: float = 0.5, + ) -> None: + """Block until expected files are pulled. + + Polls `/.pennsieve/state.json`. A file counts as + pulled when it has an entry in the state file with `isLocal=true`. + + Pull only records files that were actually requested, so when + `expected_relative_paths` is None we wait for any non-zero set of + local files to appear — which is only useful when the caller knows + pull has been issued against an empty prior state. Prefer passing + the set of paths you asked to pull. + + Paths are matched against the `path` field of state.json records, + which the agent writes with forward slashes relative to the + dataset root. + + `idle_timeout` is the max seconds allowed between progress events + (a new file appearing in state.json). The deadline resets each time + the local-files set grows, so total duration is unbounded — fits + TB/PB-scale pulls where a single file can take hours. Raises + TimeoutError only if no new file appears within `idle_timeout`. + """ + state_path = Path(target_folder) / ".pennsieve" / "state.json" + expected: Optional[set[str]] = None + if expected_relative_paths is not None: + expected = {p.replace("\\", "/").lstrip("/") for p in expected_relative_paths} + + last_progress = time.monotonic() + last_count = 0 + while True: + local_paths = _read_local_state_paths(state_path) + + if expected is None: + if local_paths: + return + else: + if expected.issubset(local_paths): + return + + if len(local_paths) > last_count: + last_count = len(local_paths) + last_progress = time.monotonic() + + if time.monotonic() - last_progress >= idle_timeout: + missing = expected - local_paths if expected is not None else set() + raise TimeoutError( + f"wait_for_pull: no new files in {idle_timeout}s " + f"(have {last_count}); " + f"missing {len(missing)} file(s): {sorted(missing)[:5]}" + ) + time.sleep(poll_interval) + + def wait_for_push( + self, + expected_files: int, + subscriber_id: int, + idle_timeout: float = 300.0, + ) -> int: + """Block until `expected_files` upload-status COMPLETE events arrive. + + Opens a Subscribe stream against the agent and counts + SubscribeResponse messages whose `upload_status.status` is COMPLETE + (enum value 2). Returns the number of COMPLETE events observed + (should equal `expected_files` on success). + + `subscriber_id` must be unique per subscriber within the agent's + lifetime. Picking os.getpid() + a counter works for most cases. + + `idle_timeout` is the max seconds allowed between upload-status + events (INIT / IN_PROGRESS / COMPLETE all count as progress). Each + event resets the idle window, so total duration is unbounded — a + multi-hour single-file upload is fine as long as the agent keeps + emitting progress. Raises TimeoutError only when the stream goes + silent for `idle_timeout` seconds. + """ + completed = 0 + progress = threading.Event() + done = threading.Event() + error: list[BaseException] = [] + + def consume(): + nonlocal completed + try: + request = agent_pb2.SubscribeRequest(id=subscriber_id) + for response in self._stub.Subscribe(request=request): + # type==1 is UPLOAD_STATUS in the SubscribeResponse enum + if response.type == 1: + progress.set() + if response.upload_status.status == 2: + completed += 1 + if completed >= expected_files: + done.set() + return + except BaseException as exc: # includes grpc.RpcError on cancel + error.append(exc) + done.set() + + t = threading.Thread(target=consume, daemon=True) + t.start() + + finished = False + while not finished: + progress.clear() + if done.wait(timeout=idle_timeout): + finished = True + break + if not progress.is_set(): + # No upload-status event arrived during the whole window. + break + + # Stop the subscriber so the stream closes promptly. + try: + self._stub.Unsubscribe( + request=agent_pb2.SubscribeRequest(id=subscriber_id), + ) + except Exception: + pass + + if not finished: + raise TimeoutError( + f"wait_for_push: no upload-status event in {idle_timeout}s; " + f"observed {completed}/{expected_files} COMPLETE event(s)" + ) + if error and completed < expected_files: + # Surface the stream error only if we didn't get enough events + # first; otherwise the error is just the stream shutdown and + # is expected. + raise error[0] + return completed + + +def _abspath(path: str) -> str: + return os.path.abspath(os.path.expanduser(str(path))) + + +def _read_local_state_paths(state_path: Path) -> set[str]: + """Return the set of relative paths in state.json with isLocal=True. + + Returns an empty set if the file doesn't exist or isn't yet valid JSON + (the agent writes the file after pulling every batch; a partial write + is rare but possible, so we treat parse errors as "not ready"). + """ + if not state_path.exists(): + return set() + try: + with state_path.open("r") as fh: + data = json.load(fh) + except (OSError, json.JSONDecodeError): + return set() + + out: set[str] = set() + for record in data.get("files") or []: + if record.get("isLocal") and record.get("path"): + out.add(record["path"]) + return out diff --git a/src/pennsieve/pennsieve.py b/src/pennsieve/pennsieve.py index 49073af..5c5ccb7 100644 --- a/src/pennsieve/pennsieve.py +++ b/src/pennsieve/pennsieve.py @@ -1,6 +1,7 @@ """ Copyright (c) 2022 Patryk Orzechowski | Wagenaar Lab | University of Pennsylvania """ + from __future__ import annotations import logging @@ -12,6 +13,7 @@ from .direct import API2_HOST_DEFAULT, API_HOST_DEFAULT from .direct.client import AbstractClient, BaseHttpApiClient, HttpApiClient from .manifest import Manifest +from .map import Map from .protos import agent_pb2, agent_pb2_grpc from .protos.agent_pb2_grpc import AgentStub from .session import APISession, APISessionProvider @@ -111,6 +113,7 @@ def __init__( self.dataset = None self.manifest = None self.timeseries = None + self.map = None if http_api_client is None: self.http_api = self.build_no_auth_http_api_client() else: @@ -167,6 +170,7 @@ def connect( self.manifest = Manifest(self.stub) self.timeseries = TimeSeries(self.stub) + self.map = Map(self.stub) print("Please set the dataset with use_dataset([name])") return self @@ -211,11 +215,13 @@ def get_datasets(self): if isinstance(response, list) and len(response) > 0: self._datasets = dict( map( - lambda x: (x["content"]["name"], x["content"]["id"]) - if "content" in x.keys() - and "name" in x["content"].keys() - and "id" in x["content"].keys() - else None, + lambda x: ( + (x["content"]["name"], x["content"]["id"]) + if "content" in x.keys() + and "name" in x["content"].keys() + and "id" in x["content"].keys() + else None + ), response, ) ) diff --git a/src/pennsieve/protos/agent.proto b/src/pennsieve/protos/agent.proto index 7bbadad..2c4b216 100644 --- a/src/pennsieve/protos/agent.proto +++ b/src/pennsieve/protos/agent.proto @@ -25,6 +25,7 @@ service Agent { rpc CancelDownload(CancelDownloadRequest) returns (SimpleStatusResponse) {} rpc Map(MapRequest) returns (SimpleStatusResponse) {} rpc Pull(PullRequest) returns (SimpleStatusResponse) {} + rpc Push(PushRequest) returns (SimpleStatusResponse) {} rpc GetMapDiff(MapDiffRequest) returns (MapDiffResponse) {} // Server Endpoints @@ -47,6 +48,7 @@ service Agent { // Account Endpoints rpc Register(RegisterRequest) returns (RegisterResponse){} + rpc Deregister(DeregisterRequest) returns (DeregisterResponse){} // Timeseries Endpoints rpc GetTimeseriesChannels(GetTimeseriesChannelsRequest) returns (GetTimeseriesChannelsResponse) {} @@ -58,6 +60,10 @@ message PullRequest { string path = 1; } +message PushRequest { + string path = 1; +} + message SubscribeRequest { int32 id = 1; } @@ -395,6 +401,16 @@ message RegisterResponse{ string account_id = 1; } +message DeregisterRequest{ + Account account = 1; + Credentials credentials = 2; + bool force = 3; +} +message DeregisterResponse{ + string account_id = 1; + string role_name = 2; +} + message Account { enum AccountType { AWS = 0; diff --git a/src/pennsieve/protos/agent_pb2.py b/src/pennsieve/protos/agent_pb2.py index 7361199..1c333f9 100644 --- a/src/pennsieve/protos/agent_pb2.py +++ b/src/pennsieve/protos/agent_pb2.py @@ -14,7 +14,7 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1cpennsieve/protos/agent.proto\x12\x02v1\"\x1b\n\x0bPullRequest\x12\x0c\n\x04path\x18\x01 \x01(\t\"\x1e\n\x10SubscribeRequest\x12\n\n\x02id\x18\x01 \x01(\x05\"+\n\x11ResetCacheRequest\x12\x0f\n\x02id\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x05\n\x03_id\"W\n\x1cGetTimeseriesChannelsRequest\x12\x12\n\ndataset_id\x18\x01 \x01(\t\x12\x12\n\npackage_id\x18\x02 \x01(\t\x12\x0f\n\x07refresh\x18\x03 \x01(\x08\"o\n\x11TimeseriesChannel\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x12\n\nstart_time\x18\x03 \x01(\x04\x12\x10\n\x08\x65nd_time\x18\x04 \x01(\x04\x12\x0c\n\x04unit\x18\x05 \x01(\t\x12\x0c\n\x04rate\x18\x06 \x01(\x02\"G\n\x1dGetTimeseriesChannelsResponse\x12&\n\x07\x63hannel\x18\x01 \x03(\x0b\x32\x15.v1.TimeseriesChannel\"\xa6\x01\n\x19GetTimeseriesRangeRequest\x12\x12\n\ndataset_id\x18\x01 \x01(\t\x12\x12\n\npackage_id\x18\x02 \x01(\t\x12\x13\n\x0b\x63hannel_ids\x18\x03 \x03(\t\x12\x12\n\nstart_time\x18\x04 \x01(\x02\x12\x10\n\x08\x65nd_time\x18\x05 \x01(\x02\x12\x0f\n\x07refresh\x18\x06 \x01(\x08\x12\x15\n\rrelative_time\x18\x07 \x01(\x08\"\xa9\x04\n\x1aGetTimeseriesRangeResponse\x12\x38\n\x04type\x18\x01 \x01(\x0e\x32*.v1.GetTimeseriesRangeResponse.MessageType\x12\x39\n\x05\x65rror\x18\x02 \x01(\x0b\x32(.v1.GetTimeseriesRangeResponse.ErrorDataH\x00\x12\x38\n\x04\x64\x61ta\x18\x03 \x01(\x0b\x32(.v1.GetTimeseriesRangeResponse.RangeDataH\x00\x12=\n\x07\x63hannel\x18\x04 \x01(\x0b\x32*.v1.GetTimeseriesRangeResponse.ChannelInfoH\x00\x1aK\n\x0b\x43hannelInfo\x12\x12\n\nchannel_id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0c\n\x04unit\x18\x03 \x01(\t\x12\x0c\n\x04rate\x18\x04 \x01(\x02\x1aW\n\tRangeData\x12\r\n\x05start\x18\x01 \x01(\x04\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x04\x12\x0c\n\x04rate\x18\x03 \x01(\x02\x12\x12\n\nchannel_id\x18\x04 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x05 \x03(\x02\x1a\x19\n\tErrorData\x12\x0c\n\x04info\x18\x01 \x01(\t\"L\n\x0bMessageType\x12\x10\n\x0cRANGE_STATUS\x10\x00\x12\x0e\n\nRANGE_DATA\x10\x01\x12\x10\n\x0c\x43HANNEL_INFO\x10\x02\x12\t\n\x05\x45RROR\x10\x03\x42\x0e\n\x0cmessage_data\"\xd2\x08\n\x11SubscribeResponse\x12/\n\x04type\x18\x08 \x01(\x0e\x32!.v1.SubscribeResponse.MessageType\x12=\n\rupload_status\x18\t \x01(\x0b\x32$.v1.SubscribeResponse.UploadResponseH\x00\x12\x39\n\nevent_info\x18\n \x01(\x0b\x32#.v1.SubscribeResponse.EventResponseH\x00\x12\x39\n\x0bsync_status\x18\x0b \x01(\x0b\x32\".v1.SubscribeResponse.SyncResponseH\x00\x12G\n\x0f\x64ownload_status\x18\x0c \x01(\x0b\x32,.v1.SubscribeResponse.DownloadStatusResponseH\x00\x1a \n\rEventResponse\x12\x0f\n\x07\x64\x65tails\x18\x01 \x01(\t\x1a\xd0\x01\n\x0eUploadResponse\x12\x0f\n\x07\x66ile_id\x18\x01 \x01(\t\x12\r\n\x05total\x18\x02 \x01(\x03\x12\x0f\n\x07\x63urrent\x18\x03 \x01(\x03\x12\x11\n\tworker_id\x18\x04 \x01(\x05\x12\x41\n\x06status\x18\x05 \x01(\x0e\x32\x31.v1.SubscribeResponse.UploadResponse.UploadStatus\"7\n\x0cUploadStatus\x12\x08\n\x04INIT\x10\x00\x12\x0f\n\x0bIN_PROGRESS\x10\x01\x12\x0c\n\x08\x43OMPLETE\x10\x02\x1a\xd1\x01\n\x16\x44ownloadStatusResponse\x12\x0f\n\x07\x66ile_id\x18\x01 \x01(\t\x12\r\n\x05total\x18\x02 \x01(\x03\x12\x0f\n\x07\x63urrent\x18\x03 \x01(\x03\x12K\n\x06status\x18\x04 \x01(\x0e\x32;.v1.SubscribeResponse.DownloadStatusResponse.DownloadStatus\"9\n\x0e\x44ownloadStatus\x12\x08\n\x04INIT\x10\x00\x12\x0f\n\x0bIN_PROGRESS\x10\x01\x12\x0c\n\x08\x43OMPLETE\x10\x02\x1a\xb9\x01\n\x0cSyncResponse\x12=\n\x06status\x18\x01 \x01(\x0e\x32-.v1.SubscribeResponse.SyncResponse.SyncStatus\x12\r\n\x05total\x18\x02 \x01(\x03\x12\x11\n\tnr_synced\x18\x03 \x01(\x03\x12\x11\n\tworker_id\x18\x04 \x01(\x05\"5\n\nSyncStatus\x12\x08\n\x04INIT\x10\x00\x12\x0f\n\x0bIN_PROGRESS\x10\x01\x12\x0c\n\x08\x43OMPLETE\x10\x02\"y\n\x0bMessageType\x12\t\n\x05\x45VENT\x10\x00\x12\x11\n\rUPLOAD_STATUS\x10\x01\x12\x11\n\rUPLOAD_CANCEL\x10\x02\x12\x0f\n\x0bSYNC_STATUS\x10\x03\x12\x13\n\x0f\x44OWNLOAD_STATUS\x10\x04\x12\x13\n\x0f\x44OWNLOAD_CANCEL\x10\x05\x42\x0e\n\x0cmessage_data\"&\n\x14SimpleStatusResponse\x12\x0e\n\x06status\x18\x01 \x01(\t\">\n\x13\x43\x61ncelUploadRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\x12\x12\n\ncancel_all\x18\x02 \x01(\x08\"C\n\x15\x43\x61ncelDownloadRequest\x12\x0f\n\x02id\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x12\n\ncancel_all\x18\x02 \x01(\x08\x42\x05\n\x03_id\"f\n\x15\x43reateManifestRequest\x12\x11\n\tbase_path\x18\x01 \x01(\t\x12\x18\n\x10target_base_path\x18\x02 \x01(\t\x12\x11\n\trecursive\x18\x03 \x01(\x08\x12\r\n\x05\x66iles\x18\x04 \x03(\t\">\n\x16\x43reateManifestResponse\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\x12\x0f\n\x07message\x18\x02 \x01(\t\"z\n\x14\x41\x64\x64ToManifestRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\x12\x11\n\tbase_path\x18\x02 \x01(\t\x12\x18\n\x10target_base_path\x18\x03 \x01(\t\x12\x11\n\trecursive\x18\x04 \x01(\x08\x12\r\n\x05\x66iles\x18\x05 \x03(\t\"E\n\x19RemoveFromManifestRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\x12\x13\n\x0bremove_path\x18\x03 \x01(\t\"\x10\n\x0eVersionRequest\"5\n\x0fVersionResponse\x12\x0f\n\x07version\x18\x01 \x01(\t\x12\x11\n\tlog_level\x18\x02 \x01(\t\"\r\n\x0bPingRequest\"\x1f\n\x0cPingResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"\r\n\x0bStopRequest\"\x1f\n\x0cStopResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"\x16\n\x14ListManifestsRequest\"\x8a\x02\n\x15ListManifestsResponse\x12\x35\n\tmanifests\x18\x01 \x03(\x0b\x32\".v1.ListManifestsResponse.Manifest\x1a\xb9\x01\n\x08Manifest\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0f\n\x07node_id\x18\x02 \x01(\t\x12\x11\n\tuser_name\x18\x03 \x01(\t\x12\x0f\n\x07user_id\x18\x04 \x01(\t\x12\x19\n\x11organization_name\x18\x05 \x01(\t\x12\x17\n\x0forganization_id\x18\x06 \x01(\t\x12\x14\n\x0c\x64\x61taset_name\x18\x07 \x01(\t\x12\x12\n\ndataset_id\x18\x08 \x01(\t\x12\x0e\n\x06status\x18\t \x01(\t\",\n\x15\x44\x65leteManifestRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\"N\n\x18ListManifestFilesRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\x12\x0e\n\x06offset\x18\x02 \x01(\x05\x12\r\n\x05limit\x18\x03 \x01(\x05\"\x90\x03\n\x19ListManifestFilesResponse\x12\x36\n\x04\x66ile\x18\x01 \x03(\x0b\x32(.v1.ListManifestFilesResponse.FileUpload\x1a\xa4\x01\n\nFileUpload\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x13\n\x0bmanifest_id\x18\x02 \x01(\x05\x12\x13\n\x0bsource_path\x18\x03 \x01(\t\x12\x13\n\x0btarget_path\x18\x04 \x01(\t\x12\x11\n\tupload_id\x18\x05 \x01(\t\x12\x38\n\x06status\x18\x06 \x01(\x0e\x32(.v1.ListManifestFilesResponse.StatusType\"\x93\x01\n\nStatusType\x12\t\n\x05LOCAL\x10\x00\x12\x0e\n\nREGISTERED\x10\x01\x12\x0c\n\x08IMPORTED\x10\x02\x12\r\n\tFINALIZED\x10\x03\x12\x0c\n\x08VERIFIED\x10\x04\x12\n\n\x06\x46\x41ILED\x10\x05\x12\x0b\n\x07REMOVED\x10\x06\x12\x0b\n\x07UNKNOWN\x10\x07\x12\x0b\n\x07\x43HANGED\x10\x08\x12\x0c\n\x08UPLOADED\x10\t\",\n\x15UploadManifestRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\"\x10\n\x0eGetUserRequest\"\xd4\x01\n\x0cUserResponse\x12\n\n\x02id\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x15\n\rsession_token\x18\x04 \x01(\t\x12\x14\n\x0ctoken_expire\x18\x05 \x01(\x03\x12\x0f\n\x07profile\x18\x08 \x01(\t\x12\x13\n\x0b\x65nvironment\x18\t \x01(\t\x12\x17\n\x0forganization_id\x18\n \x01(\t\x12\x19\n\x11organization_name\x18\x0b \x01(\t\x12\x10\n\x08\x61pi_host\x18\x0c \x01(\t\x12\x11\n\tapi2_host\x18\r \x01(\t\"\'\n\x14SwitchProfileRequest\x12\x0f\n\x07profile\x18\x01 \x01(\t\"\x17\n\x15ReAuthenticateRequest\"\'\n\x11UseDatasetRequest\x12\x12\n\ndataset_id\x18\x01 \x01(\t\"(\n\x12UseDatasetResponse\x12\x12\n\ndataset_id\x18\x01 \x01(\t\"*\n\x13SyncManifestRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\"}\n\x14SyncManifestResponse\x12\x18\n\x10manifest_node_id\x18\x01 \x01(\t\x12\x18\n\x10nr_files_updated\x18\x02 \x01(\x05\x12\x18\n\x10nr_files_removed\x18\x03 \x01(\x05\x12\x17\n\x0fnr_files_failed\x18\x04 \x01(\x05\"+\n\x14ResetManifestRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\"W\n\x1cRelocateManifestFilesRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\x12\x0c\n\x04path\x18\x02 \x01(\t\x12\x14\n\x0cupdated_path\x18\x03 \x01(\t\"A\n\x14StartWorkflowRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\x12\x14\n\x0cworkflowFlag\x18\x02 \x01(\t\"\x96\x01\n\x10WorkflowResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x13\n\x0b\x64\x65rivatives\x18\x02 \x01(\t\x12\x37\n\x0cworkflowType\x18\x03 \x01(\x0e\x32!.v1.WorkflowResponse.WorkflowType\"#\n\x0cWorkflowType\x12\x08\n\x04PATH\x10\x00\x12\t\n\x05NAMED\x10\x01\"U\n\x0fRegisterRequest\x12\x1c\n\x07\x61\x63\x63ount\x18\x01 \x01(\x0b\x32\x0b.v1.Account\x12$\n\x0b\x63redentials\x18\x02 \x01(\x0b\x32\x0f.v1.Credentials\"&\n\x10RegisterResponse\x12\x12\n\naccount_id\x18\x01 \x01(\t\"S\n\x07\x41\x63\x63ount\x12%\n\x04type\x18\x01 \x01(\x0e\x32\x17.v1.Account.AccountType\"!\n\x0b\x41\x63\x63ountType\x12\x07\n\x03\x41WS\x10\x00\x12\t\n\x05\x41zure\x10\x01\"\x1e\n\x0b\x43redentials\x12\x0f\n\x07profile\x18\x01 \x01(\t\"7\n\nMapRequest\x12\x12\n\ndataset_id\x18\x01 \x01(\t\x12\x15\n\rtarget_folder\x18\x02 \x01(\t\"\xd1\x01\n\x0f\x44ownloadRequest\x12.\n\x04type\x18\x01 \x01(\x0e\x32 .v1.DownloadRequest.DownloadType\x12-\n\x07\x64\x61taset\x18\t \x01(\x0b\x32\x1a.v1.DownloadDatasetRequestH\x00\x12-\n\x07package\x18\n \x01(\x0b\x32\x1a.v1.DownloadPackageRequestH\x00\"(\n\x0c\x44ownloadType\x12\x0b\n\x07PACKAGE\x10\x00\x12\x0b\n\x07\x44\x41TASET\x10\x01\x42\x06\n\x04\x64\x61ta\"C\n\x16\x44ownloadDatasetRequest\x12\x12\n\ndataset_id\x18\x01 \x01(\t\x12\x15\n\rtarget_folder\x18\x02 \x01(\t\"G\n\x16\x44ownloadPackageRequest\x12\x12\n\npackage_id\x18\x01 \x01(\t\x12\x19\n\x11get_presigned_url\x18\x02 \x01(\x08\"\x91\x01\n\x10\x44ownloadResponse\x12/\n\x04type\x18\x01 \x01(\x0e\x32!.v1.DownloadResponse.ResponseType\x12\x0e\n\x06status\x18\x02 \x01(\t\x12\x0b\n\x03url\x18\x03 \x03(\t\"/\n\x0cResponseType\x12\x11\n\rPRESIGNED_URL\x10\x00\x12\x0c\n\x08\x44OWNLOAD\x10\x01\"\x1e\n\x0eMapDiffRequest\x12\x0c\n\x04path\x18\x01 \x01(\t\"K\n\x08\x66ileInfo\x12\x12\n\npackage_id\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x0f\n\x07message\x18\x04 \x01(\t\"\xbe\x01\n\rpackageStatus\x12\x1d\n\x07\x63ontent\x18\x01 \x01(\x0b\x32\x0c.v1.fileInfo\x12\x30\n\nchangeType\x18\x02 \x01(\x0e\x32\x1c.v1.packageStatus.StatusType\"\\\n\nStatusType\x12\t\n\x05\x41\x44\x44\x45\x44\x10\x00\x12\x0b\n\x07RENAMED\x10\x01\x12\x0b\n\x07\x44\x45LETED\x10\x02\x12\x0b\n\x07\x43HANGED\x10\x03\x12\t\n\x05MOVED\x10\x04\x12\x11\n\rMOVED_RENAMED\x10\x05\"3\n\x0fMapDiffResponse\x12 \n\x05\x66iles\x18\x01 \x03(\x0b\x32\x11.v1.packageStatus2\xe2\x0f\n\x05\x41gent\x12I\n\x0e\x43reateManifest\x12\x19.v1.CreateManifestRequest\x1a\x1a.v1.CreateManifestResponse\"\x00\x12\x45\n\rAddToManifest\x12\x18.v1.AddToManifestRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12O\n\x12RemoveFromManifest\x12\x1d.v1.RemoveFromManifestRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12G\n\x0e\x44\x65leteManifest\x12\x19.v1.DeleteManifestRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12\x46\n\rListManifests\x12\x18.v1.ListManifestsRequest\x1a\x19.v1.ListManifestsResponse\"\x00\x12R\n\x11ListManifestFiles\x12\x1c.v1.ListManifestFilesRequest\x1a\x1d.v1.ListManifestFilesResponse\"\x00\x12U\n\x15RelocateManifestFiles\x12 .v1.RelocateManifestFilesRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12\x43\n\x0cSyncManifest\x12\x17.v1.SyncManifestRequest\x1a\x18.v1.SyncManifestResponse\"\x00\x12\x45\n\rResetManifest\x12\x18.v1.ResetManifestRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12G\n\x0eUploadManifest\x12\x19.v1.UploadManifestRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12\x43\n\x0c\x43\x61ncelUpload\x12\x17.v1.CancelUploadRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12\x37\n\x08\x44ownload\x12\x13.v1.DownloadRequest\x1a\x14.v1.DownloadResponse\"\x00\x12G\n\x0e\x43\x61ncelDownload\x12\x19.v1.CancelDownloadRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12\x31\n\x03Map\x12\x0e.v1.MapRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12\x33\n\x04Pull\x12\x0f.v1.PullRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12\x37\n\nGetMapDiff\x12\x12.v1.MapDiffRequest\x1a\x13.v1.MapDiffResponse\"\x00\x12\x34\n\x07Version\x12\x12.v1.VersionRequest\x1a\x13.v1.VersionResponse\"\x00\x12<\n\tSubscribe\x12\x14.v1.SubscribeRequest\x1a\x15.v1.SubscribeResponse\"\x00\x30\x01\x12<\n\x0bUnsubscribe\x12\x14.v1.SubscribeRequest\x1a\x15.v1.SubscribeResponse\"\x00\x12+\n\x04Stop\x12\x0f.v1.StopRequest\x1a\x10.v1.StopResponse\"\x00\x12+\n\x04Ping\x12\x0f.v1.PingRequest\x1a\x10.v1.PingResponse\"\x00\x12\x31\n\x07GetUser\x12\x12.v1.GetUserRequest\x1a\x10.v1.UserResponse\"\x00\x12=\n\rSwitchProfile\x12\x18.v1.SwitchProfileRequest\x1a\x10.v1.UserResponse\"\x00\x12?\n\x0eReAuthenticate\x12\x19.v1.ReAuthenticateRequest\x1a\x10.v1.UserResponse\"\x00\x12=\n\nUseDataset\x12\x15.v1.UseDatasetRequest\x1a\x16.v1.UseDatasetResponse\"\x00\x12\x41\n\rStartWorkflow\x12\x18.v1.StartWorkflowRequest\x1a\x14.v1.WorkflowResponse\"\x00\x12\x37\n\x08Register\x12\x13.v1.RegisterRequest\x1a\x14.v1.RegisterResponse\"\x00\x12^\n\x15GetTimeseriesChannels\x12 .v1.GetTimeseriesChannelsRequest\x1a!.v1.GetTimeseriesChannelsResponse\"\x00\x12\x62\n\x1dGetTimeseriesRangeForChannels\x12\x1d.v1.GetTimeseriesRangeRequest\x1a\x1e.v1.GetTimeseriesRangeResponse\"\x00\x30\x01\x12?\n\nResetCache\x12\x15.v1.ResetCacheRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x42-Z+github.com/pennsieve/pennsieve-agent/api/v1b\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1cpennsieve/protos/agent.proto\x12\x02v1\"\x1b\n\x0bPullRequest\x12\x0c\n\x04path\x18\x01 \x01(\t\"\x1b\n\x0bPushRequest\x12\x0c\n\x04path\x18\x01 \x01(\t\"\x1e\n\x10SubscribeRequest\x12\n\n\x02id\x18\x01 \x01(\x05\"+\n\x11ResetCacheRequest\x12\x0f\n\x02id\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x05\n\x03_id\"W\n\x1cGetTimeseriesChannelsRequest\x12\x12\n\ndataset_id\x18\x01 \x01(\t\x12\x12\n\npackage_id\x18\x02 \x01(\t\x12\x0f\n\x07refresh\x18\x03 \x01(\x08\"o\n\x11TimeseriesChannel\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x12\n\nstart_time\x18\x03 \x01(\x04\x12\x10\n\x08\x65nd_time\x18\x04 \x01(\x04\x12\x0c\n\x04unit\x18\x05 \x01(\t\x12\x0c\n\x04rate\x18\x06 \x01(\x02\"G\n\x1dGetTimeseriesChannelsResponse\x12&\n\x07\x63hannel\x18\x01 \x03(\x0b\x32\x15.v1.TimeseriesChannel\"\xa6\x01\n\x19GetTimeseriesRangeRequest\x12\x12\n\ndataset_id\x18\x01 \x01(\t\x12\x12\n\npackage_id\x18\x02 \x01(\t\x12\x13\n\x0b\x63hannel_ids\x18\x03 \x03(\t\x12\x12\n\nstart_time\x18\x04 \x01(\x02\x12\x10\n\x08\x65nd_time\x18\x05 \x01(\x02\x12\x0f\n\x07refresh\x18\x06 \x01(\x08\x12\x15\n\rrelative_time\x18\x07 \x01(\x08\"\xa9\x04\n\x1aGetTimeseriesRangeResponse\x12\x38\n\x04type\x18\x01 \x01(\x0e\x32*.v1.GetTimeseriesRangeResponse.MessageType\x12\x39\n\x05\x65rror\x18\x02 \x01(\x0b\x32(.v1.GetTimeseriesRangeResponse.ErrorDataH\x00\x12\x38\n\x04\x64\x61ta\x18\x03 \x01(\x0b\x32(.v1.GetTimeseriesRangeResponse.RangeDataH\x00\x12=\n\x07\x63hannel\x18\x04 \x01(\x0b\x32*.v1.GetTimeseriesRangeResponse.ChannelInfoH\x00\x1aK\n\x0b\x43hannelInfo\x12\x12\n\nchannel_id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0c\n\x04unit\x18\x03 \x01(\t\x12\x0c\n\x04rate\x18\x04 \x01(\x02\x1aW\n\tRangeData\x12\r\n\x05start\x18\x01 \x01(\x04\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x04\x12\x0c\n\x04rate\x18\x03 \x01(\x02\x12\x12\n\nchannel_id\x18\x04 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x05 \x03(\x02\x1a\x19\n\tErrorData\x12\x0c\n\x04info\x18\x01 \x01(\t\"L\n\x0bMessageType\x12\x10\n\x0cRANGE_STATUS\x10\x00\x12\x0e\n\nRANGE_DATA\x10\x01\x12\x10\n\x0c\x43HANNEL_INFO\x10\x02\x12\t\n\x05\x45RROR\x10\x03\x42\x0e\n\x0cmessage_data\"\xd2\x08\n\x11SubscribeResponse\x12/\n\x04type\x18\x08 \x01(\x0e\x32!.v1.SubscribeResponse.MessageType\x12=\n\rupload_status\x18\t \x01(\x0b\x32$.v1.SubscribeResponse.UploadResponseH\x00\x12\x39\n\nevent_info\x18\n \x01(\x0b\x32#.v1.SubscribeResponse.EventResponseH\x00\x12\x39\n\x0bsync_status\x18\x0b \x01(\x0b\x32\".v1.SubscribeResponse.SyncResponseH\x00\x12G\n\x0f\x64ownload_status\x18\x0c \x01(\x0b\x32,.v1.SubscribeResponse.DownloadStatusResponseH\x00\x1a \n\rEventResponse\x12\x0f\n\x07\x64\x65tails\x18\x01 \x01(\t\x1a\xd0\x01\n\x0eUploadResponse\x12\x0f\n\x07\x66ile_id\x18\x01 \x01(\t\x12\r\n\x05total\x18\x02 \x01(\x03\x12\x0f\n\x07\x63urrent\x18\x03 \x01(\x03\x12\x11\n\tworker_id\x18\x04 \x01(\x05\x12\x41\n\x06status\x18\x05 \x01(\x0e\x32\x31.v1.SubscribeResponse.UploadResponse.UploadStatus\"7\n\x0cUploadStatus\x12\x08\n\x04INIT\x10\x00\x12\x0f\n\x0bIN_PROGRESS\x10\x01\x12\x0c\n\x08\x43OMPLETE\x10\x02\x1a\xd1\x01\n\x16\x44ownloadStatusResponse\x12\x0f\n\x07\x66ile_id\x18\x01 \x01(\t\x12\r\n\x05total\x18\x02 \x01(\x03\x12\x0f\n\x07\x63urrent\x18\x03 \x01(\x03\x12K\n\x06status\x18\x04 \x01(\x0e\x32;.v1.SubscribeResponse.DownloadStatusResponse.DownloadStatus\"9\n\x0e\x44ownloadStatus\x12\x08\n\x04INIT\x10\x00\x12\x0f\n\x0bIN_PROGRESS\x10\x01\x12\x0c\n\x08\x43OMPLETE\x10\x02\x1a\xb9\x01\n\x0cSyncResponse\x12=\n\x06status\x18\x01 \x01(\x0e\x32-.v1.SubscribeResponse.SyncResponse.SyncStatus\x12\r\n\x05total\x18\x02 \x01(\x03\x12\x11\n\tnr_synced\x18\x03 \x01(\x03\x12\x11\n\tworker_id\x18\x04 \x01(\x05\"5\n\nSyncStatus\x12\x08\n\x04INIT\x10\x00\x12\x0f\n\x0bIN_PROGRESS\x10\x01\x12\x0c\n\x08\x43OMPLETE\x10\x02\"y\n\x0bMessageType\x12\t\n\x05\x45VENT\x10\x00\x12\x11\n\rUPLOAD_STATUS\x10\x01\x12\x11\n\rUPLOAD_CANCEL\x10\x02\x12\x0f\n\x0bSYNC_STATUS\x10\x03\x12\x13\n\x0f\x44OWNLOAD_STATUS\x10\x04\x12\x13\n\x0f\x44OWNLOAD_CANCEL\x10\x05\x42\x0e\n\x0cmessage_data\"&\n\x14SimpleStatusResponse\x12\x0e\n\x06status\x18\x01 \x01(\t\">\n\x13\x43\x61ncelUploadRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\x12\x12\n\ncancel_all\x18\x02 \x01(\x08\"C\n\x15\x43\x61ncelDownloadRequest\x12\x0f\n\x02id\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x12\n\ncancel_all\x18\x02 \x01(\x08\x42\x05\n\x03_id\"f\n\x15\x43reateManifestRequest\x12\x11\n\tbase_path\x18\x01 \x01(\t\x12\x18\n\x10target_base_path\x18\x02 \x01(\t\x12\x11\n\trecursive\x18\x03 \x01(\x08\x12\r\n\x05\x66iles\x18\x04 \x03(\t\">\n\x16\x43reateManifestResponse\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\x12\x0f\n\x07message\x18\x02 \x01(\t\"z\n\x14\x41\x64\x64ToManifestRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\x12\x11\n\tbase_path\x18\x02 \x01(\t\x12\x18\n\x10target_base_path\x18\x03 \x01(\t\x12\x11\n\trecursive\x18\x04 \x01(\x08\x12\r\n\x05\x66iles\x18\x05 \x03(\t\"E\n\x19RemoveFromManifestRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\x12\x13\n\x0bremove_path\x18\x03 \x01(\t\"\x10\n\x0eVersionRequest\"5\n\x0fVersionResponse\x12\x0f\n\x07version\x18\x01 \x01(\t\x12\x11\n\tlog_level\x18\x02 \x01(\t\"\r\n\x0bPingRequest\"\x1f\n\x0cPingResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"\r\n\x0bStopRequest\"\x1f\n\x0cStopResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"\x16\n\x14ListManifestsRequest\"\x8a\x02\n\x15ListManifestsResponse\x12\x35\n\tmanifests\x18\x01 \x03(\x0b\x32\".v1.ListManifestsResponse.Manifest\x1a\xb9\x01\n\x08Manifest\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0f\n\x07node_id\x18\x02 \x01(\t\x12\x11\n\tuser_name\x18\x03 \x01(\t\x12\x0f\n\x07user_id\x18\x04 \x01(\t\x12\x19\n\x11organization_name\x18\x05 \x01(\t\x12\x17\n\x0forganization_id\x18\x06 \x01(\t\x12\x14\n\x0c\x64\x61taset_name\x18\x07 \x01(\t\x12\x12\n\ndataset_id\x18\x08 \x01(\t\x12\x0e\n\x06status\x18\t \x01(\t\",\n\x15\x44\x65leteManifestRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\"N\n\x18ListManifestFilesRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\x12\x0e\n\x06offset\x18\x02 \x01(\x05\x12\r\n\x05limit\x18\x03 \x01(\x05\"\x90\x03\n\x19ListManifestFilesResponse\x12\x36\n\x04\x66ile\x18\x01 \x03(\x0b\x32(.v1.ListManifestFilesResponse.FileUpload\x1a\xa4\x01\n\nFileUpload\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x13\n\x0bmanifest_id\x18\x02 \x01(\x05\x12\x13\n\x0bsource_path\x18\x03 \x01(\t\x12\x13\n\x0btarget_path\x18\x04 \x01(\t\x12\x11\n\tupload_id\x18\x05 \x01(\t\x12\x38\n\x06status\x18\x06 \x01(\x0e\x32(.v1.ListManifestFilesResponse.StatusType\"\x93\x01\n\nStatusType\x12\t\n\x05LOCAL\x10\x00\x12\x0e\n\nREGISTERED\x10\x01\x12\x0c\n\x08IMPORTED\x10\x02\x12\r\n\tFINALIZED\x10\x03\x12\x0c\n\x08VERIFIED\x10\x04\x12\n\n\x06\x46\x41ILED\x10\x05\x12\x0b\n\x07REMOVED\x10\x06\x12\x0b\n\x07UNKNOWN\x10\x07\x12\x0b\n\x07\x43HANGED\x10\x08\x12\x0c\n\x08UPLOADED\x10\t\",\n\x15UploadManifestRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\"\x10\n\x0eGetUserRequest\"\xd4\x01\n\x0cUserResponse\x12\n\n\x02id\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x15\n\rsession_token\x18\x04 \x01(\t\x12\x14\n\x0ctoken_expire\x18\x05 \x01(\x03\x12\x0f\n\x07profile\x18\x08 \x01(\t\x12\x13\n\x0b\x65nvironment\x18\t \x01(\t\x12\x17\n\x0forganization_id\x18\n \x01(\t\x12\x19\n\x11organization_name\x18\x0b \x01(\t\x12\x10\n\x08\x61pi_host\x18\x0c \x01(\t\x12\x11\n\tapi2_host\x18\r \x01(\t\"\'\n\x14SwitchProfileRequest\x12\x0f\n\x07profile\x18\x01 \x01(\t\"\x17\n\x15ReAuthenticateRequest\"\'\n\x11UseDatasetRequest\x12\x12\n\ndataset_id\x18\x01 \x01(\t\"(\n\x12UseDatasetResponse\x12\x12\n\ndataset_id\x18\x01 \x01(\t\"*\n\x13SyncManifestRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\"}\n\x14SyncManifestResponse\x12\x18\n\x10manifest_node_id\x18\x01 \x01(\t\x12\x18\n\x10nr_files_updated\x18\x02 \x01(\x05\x12\x18\n\x10nr_files_removed\x18\x03 \x01(\x05\x12\x17\n\x0fnr_files_failed\x18\x04 \x01(\x05\"+\n\x14ResetManifestRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\"W\n\x1cRelocateManifestFilesRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\x12\x0c\n\x04path\x18\x02 \x01(\t\x12\x14\n\x0cupdated_path\x18\x03 \x01(\t\"A\n\x14StartWorkflowRequest\x12\x13\n\x0bmanifest_id\x18\x01 \x01(\x05\x12\x14\n\x0cworkflowFlag\x18\x02 \x01(\t\"\x96\x01\n\x10WorkflowResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x13\n\x0b\x64\x65rivatives\x18\x02 \x01(\t\x12\x37\n\x0cworkflowType\x18\x03 \x01(\x0e\x32!.v1.WorkflowResponse.WorkflowType\"#\n\x0cWorkflowType\x12\x08\n\x04PATH\x10\x00\x12\t\n\x05NAMED\x10\x01\"U\n\x0fRegisterRequest\x12\x1c\n\x07\x61\x63\x63ount\x18\x01 \x01(\x0b\x32\x0b.v1.Account\x12$\n\x0b\x63redentials\x18\x02 \x01(\x0b\x32\x0f.v1.Credentials\"&\n\x10RegisterResponse\x12\x12\n\naccount_id\x18\x01 \x01(\t\"f\n\x11\x44\x65registerRequest\x12\x1c\n\x07\x61\x63\x63ount\x18\x01 \x01(\x0b\x32\x0b.v1.Account\x12$\n\x0b\x63redentials\x18\x02 \x01(\x0b\x32\x0f.v1.Credentials\x12\r\n\x05\x66orce\x18\x03 \x01(\x08\";\n\x12\x44\x65registerResponse\x12\x12\n\naccount_id\x18\x01 \x01(\t\x12\x11\n\trole_name\x18\x02 \x01(\t\"S\n\x07\x41\x63\x63ount\x12%\n\x04type\x18\x01 \x01(\x0e\x32\x17.v1.Account.AccountType\"!\n\x0b\x41\x63\x63ountType\x12\x07\n\x03\x41WS\x10\x00\x12\t\n\x05\x41zure\x10\x01\"\x1e\n\x0b\x43redentials\x12\x0f\n\x07profile\x18\x01 \x01(\t\"7\n\nMapRequest\x12\x12\n\ndataset_id\x18\x01 \x01(\t\x12\x15\n\rtarget_folder\x18\x02 \x01(\t\"\xd1\x01\n\x0f\x44ownloadRequest\x12.\n\x04type\x18\x01 \x01(\x0e\x32 .v1.DownloadRequest.DownloadType\x12-\n\x07\x64\x61taset\x18\t \x01(\x0b\x32\x1a.v1.DownloadDatasetRequestH\x00\x12-\n\x07package\x18\n \x01(\x0b\x32\x1a.v1.DownloadPackageRequestH\x00\"(\n\x0c\x44ownloadType\x12\x0b\n\x07PACKAGE\x10\x00\x12\x0b\n\x07\x44\x41TASET\x10\x01\x42\x06\n\x04\x64\x61ta\"C\n\x16\x44ownloadDatasetRequest\x12\x12\n\ndataset_id\x18\x01 \x01(\t\x12\x15\n\rtarget_folder\x18\x02 \x01(\t\"G\n\x16\x44ownloadPackageRequest\x12\x12\n\npackage_id\x18\x01 \x01(\t\x12\x19\n\x11get_presigned_url\x18\x02 \x01(\x08\"\x91\x01\n\x10\x44ownloadResponse\x12/\n\x04type\x18\x01 \x01(\x0e\x32!.v1.DownloadResponse.ResponseType\x12\x0e\n\x06status\x18\x02 \x01(\t\x12\x0b\n\x03url\x18\x03 \x03(\t\"/\n\x0cResponseType\x12\x11\n\rPRESIGNED_URL\x10\x00\x12\x0c\n\x08\x44OWNLOAD\x10\x01\"\x1e\n\x0eMapDiffRequest\x12\x0c\n\x04path\x18\x01 \x01(\t\"K\n\x08\x66ileInfo\x12\x12\n\npackage_id\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x0f\n\x07message\x18\x04 \x01(\t\"\xbe\x01\n\rpackageStatus\x12\x1d\n\x07\x63ontent\x18\x01 \x01(\x0b\x32\x0c.v1.fileInfo\x12\x30\n\nchangeType\x18\x02 \x01(\x0e\x32\x1c.v1.packageStatus.StatusType\"\\\n\nStatusType\x12\t\n\x05\x41\x44\x44\x45\x44\x10\x00\x12\x0b\n\x07RENAMED\x10\x01\x12\x0b\n\x07\x44\x45LETED\x10\x02\x12\x0b\n\x07\x43HANGED\x10\x03\x12\t\n\x05MOVED\x10\x04\x12\x11\n\rMOVED_RENAMED\x10\x05\"3\n\x0fMapDiffResponse\x12 \n\x05\x66iles\x18\x01 \x03(\x0b\x32\x11.v1.packageStatus2\xd6\x10\n\x05\x41gent\x12I\n\x0e\x43reateManifest\x12\x19.v1.CreateManifestRequest\x1a\x1a.v1.CreateManifestResponse\"\x00\x12\x45\n\rAddToManifest\x12\x18.v1.AddToManifestRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12O\n\x12RemoveFromManifest\x12\x1d.v1.RemoveFromManifestRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12G\n\x0e\x44\x65leteManifest\x12\x19.v1.DeleteManifestRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12\x46\n\rListManifests\x12\x18.v1.ListManifestsRequest\x1a\x19.v1.ListManifestsResponse\"\x00\x12R\n\x11ListManifestFiles\x12\x1c.v1.ListManifestFilesRequest\x1a\x1d.v1.ListManifestFilesResponse\"\x00\x12U\n\x15RelocateManifestFiles\x12 .v1.RelocateManifestFilesRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12\x43\n\x0cSyncManifest\x12\x17.v1.SyncManifestRequest\x1a\x18.v1.SyncManifestResponse\"\x00\x12\x45\n\rResetManifest\x12\x18.v1.ResetManifestRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12G\n\x0eUploadManifest\x12\x19.v1.UploadManifestRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12\x43\n\x0c\x43\x61ncelUpload\x12\x17.v1.CancelUploadRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12\x37\n\x08\x44ownload\x12\x13.v1.DownloadRequest\x1a\x14.v1.DownloadResponse\"\x00\x12G\n\x0e\x43\x61ncelDownload\x12\x19.v1.CancelDownloadRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12\x31\n\x03Map\x12\x0e.v1.MapRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12\x33\n\x04Pull\x12\x0f.v1.PullRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12\x33\n\x04Push\x12\x0f.v1.PushRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x12\x37\n\nGetMapDiff\x12\x12.v1.MapDiffRequest\x1a\x13.v1.MapDiffResponse\"\x00\x12\x34\n\x07Version\x12\x12.v1.VersionRequest\x1a\x13.v1.VersionResponse\"\x00\x12<\n\tSubscribe\x12\x14.v1.SubscribeRequest\x1a\x15.v1.SubscribeResponse\"\x00\x30\x01\x12<\n\x0bUnsubscribe\x12\x14.v1.SubscribeRequest\x1a\x15.v1.SubscribeResponse\"\x00\x12+\n\x04Stop\x12\x0f.v1.StopRequest\x1a\x10.v1.StopResponse\"\x00\x12+\n\x04Ping\x12\x0f.v1.PingRequest\x1a\x10.v1.PingResponse\"\x00\x12\x31\n\x07GetUser\x12\x12.v1.GetUserRequest\x1a\x10.v1.UserResponse\"\x00\x12=\n\rSwitchProfile\x12\x18.v1.SwitchProfileRequest\x1a\x10.v1.UserResponse\"\x00\x12?\n\x0eReAuthenticate\x12\x19.v1.ReAuthenticateRequest\x1a\x10.v1.UserResponse\"\x00\x12=\n\nUseDataset\x12\x15.v1.UseDatasetRequest\x1a\x16.v1.UseDatasetResponse\"\x00\x12\x41\n\rStartWorkflow\x12\x18.v1.StartWorkflowRequest\x1a\x14.v1.WorkflowResponse\"\x00\x12\x37\n\x08Register\x12\x13.v1.RegisterRequest\x1a\x14.v1.RegisterResponse\"\x00\x12=\n\nDeregister\x12\x15.v1.DeregisterRequest\x1a\x16.v1.DeregisterResponse\"\x00\x12^\n\x15GetTimeseriesChannels\x12 .v1.GetTimeseriesChannelsRequest\x1a!.v1.GetTimeseriesChannelsResponse\"\x00\x12\x62\n\x1dGetTimeseriesRangeForChannels\x12\x1d.v1.GetTimeseriesRangeRequest\x1a\x1e.v1.GetTimeseriesRangeResponse\"\x00\x30\x01\x12?\n\nResetCache\x12\x15.v1.ResetCacheRequest\x1a\x18.v1.SimpleStatusResponse\"\x00\x42-Z+github.com/pennsieve/pennsieve-agent/api/v1b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -24,150 +24,156 @@ _globals['DESCRIPTOR']._serialized_options = b'Z+github.com/pennsieve/pennsieve-agent/api/v1' _globals['_PULLREQUEST']._serialized_start=36 _globals['_PULLREQUEST']._serialized_end=63 - _globals['_SUBSCRIBEREQUEST']._serialized_start=65 - _globals['_SUBSCRIBEREQUEST']._serialized_end=95 - _globals['_RESETCACHEREQUEST']._serialized_start=97 - _globals['_RESETCACHEREQUEST']._serialized_end=140 - _globals['_GETTIMESERIESCHANNELSREQUEST']._serialized_start=142 - _globals['_GETTIMESERIESCHANNELSREQUEST']._serialized_end=229 - _globals['_TIMESERIESCHANNEL']._serialized_start=231 - _globals['_TIMESERIESCHANNEL']._serialized_end=342 - _globals['_GETTIMESERIESCHANNELSRESPONSE']._serialized_start=344 - _globals['_GETTIMESERIESCHANNELSRESPONSE']._serialized_end=415 - _globals['_GETTIMESERIESRANGEREQUEST']._serialized_start=418 - _globals['_GETTIMESERIESRANGEREQUEST']._serialized_end=584 - _globals['_GETTIMESERIESRANGERESPONSE']._serialized_start=587 - _globals['_GETTIMESERIESRANGERESPONSE']._serialized_end=1140 - _globals['_GETTIMESERIESRANGERESPONSE_CHANNELINFO']._serialized_start=855 - _globals['_GETTIMESERIESRANGERESPONSE_CHANNELINFO']._serialized_end=930 - _globals['_GETTIMESERIESRANGERESPONSE_RANGEDATA']._serialized_start=932 - _globals['_GETTIMESERIESRANGERESPONSE_RANGEDATA']._serialized_end=1019 - _globals['_GETTIMESERIESRANGERESPONSE_ERRORDATA']._serialized_start=1021 - _globals['_GETTIMESERIESRANGERESPONSE_ERRORDATA']._serialized_end=1046 - _globals['_GETTIMESERIESRANGERESPONSE_MESSAGETYPE']._serialized_start=1048 - _globals['_GETTIMESERIESRANGERESPONSE_MESSAGETYPE']._serialized_end=1124 - _globals['_SUBSCRIBERESPONSE']._serialized_start=1143 - _globals['_SUBSCRIBERESPONSE']._serialized_end=2249 - _globals['_SUBSCRIBERESPONSE_EVENTRESPONSE']._serialized_start=1467 - _globals['_SUBSCRIBERESPONSE_EVENTRESPONSE']._serialized_end=1499 - _globals['_SUBSCRIBERESPONSE_UPLOADRESPONSE']._serialized_start=1502 - _globals['_SUBSCRIBERESPONSE_UPLOADRESPONSE']._serialized_end=1710 - _globals['_SUBSCRIBERESPONSE_UPLOADRESPONSE_UPLOADSTATUS']._serialized_start=1655 - _globals['_SUBSCRIBERESPONSE_UPLOADRESPONSE_UPLOADSTATUS']._serialized_end=1710 - _globals['_SUBSCRIBERESPONSE_DOWNLOADSTATUSRESPONSE']._serialized_start=1713 - _globals['_SUBSCRIBERESPONSE_DOWNLOADSTATUSRESPONSE']._serialized_end=1922 - _globals['_SUBSCRIBERESPONSE_DOWNLOADSTATUSRESPONSE_DOWNLOADSTATUS']._serialized_start=1865 - _globals['_SUBSCRIBERESPONSE_DOWNLOADSTATUSRESPONSE_DOWNLOADSTATUS']._serialized_end=1922 - _globals['_SUBSCRIBERESPONSE_SYNCRESPONSE']._serialized_start=1925 - _globals['_SUBSCRIBERESPONSE_SYNCRESPONSE']._serialized_end=2110 - _globals['_SUBSCRIBERESPONSE_SYNCRESPONSE_SYNCSTATUS']._serialized_start=2057 - _globals['_SUBSCRIBERESPONSE_SYNCRESPONSE_SYNCSTATUS']._serialized_end=2110 - _globals['_SUBSCRIBERESPONSE_MESSAGETYPE']._serialized_start=2112 - _globals['_SUBSCRIBERESPONSE_MESSAGETYPE']._serialized_end=2233 - _globals['_SIMPLESTATUSRESPONSE']._serialized_start=2251 - _globals['_SIMPLESTATUSRESPONSE']._serialized_end=2289 - _globals['_CANCELUPLOADREQUEST']._serialized_start=2291 - _globals['_CANCELUPLOADREQUEST']._serialized_end=2353 - _globals['_CANCELDOWNLOADREQUEST']._serialized_start=2355 - _globals['_CANCELDOWNLOADREQUEST']._serialized_end=2422 - _globals['_CREATEMANIFESTREQUEST']._serialized_start=2424 - _globals['_CREATEMANIFESTREQUEST']._serialized_end=2526 - _globals['_CREATEMANIFESTRESPONSE']._serialized_start=2528 - _globals['_CREATEMANIFESTRESPONSE']._serialized_end=2590 - _globals['_ADDTOMANIFESTREQUEST']._serialized_start=2592 - _globals['_ADDTOMANIFESTREQUEST']._serialized_end=2714 - _globals['_REMOVEFROMMANIFESTREQUEST']._serialized_start=2716 - _globals['_REMOVEFROMMANIFESTREQUEST']._serialized_end=2785 - _globals['_VERSIONREQUEST']._serialized_start=2787 - _globals['_VERSIONREQUEST']._serialized_end=2803 - _globals['_VERSIONRESPONSE']._serialized_start=2805 - _globals['_VERSIONRESPONSE']._serialized_end=2858 - _globals['_PINGREQUEST']._serialized_start=2860 - _globals['_PINGREQUEST']._serialized_end=2873 - _globals['_PINGRESPONSE']._serialized_start=2875 - _globals['_PINGRESPONSE']._serialized_end=2906 - _globals['_STOPREQUEST']._serialized_start=2908 - _globals['_STOPREQUEST']._serialized_end=2921 - _globals['_STOPRESPONSE']._serialized_start=2923 - _globals['_STOPRESPONSE']._serialized_end=2954 - _globals['_LISTMANIFESTSREQUEST']._serialized_start=2956 - _globals['_LISTMANIFESTSREQUEST']._serialized_end=2978 - _globals['_LISTMANIFESTSRESPONSE']._serialized_start=2981 - _globals['_LISTMANIFESTSRESPONSE']._serialized_end=3247 - _globals['_LISTMANIFESTSRESPONSE_MANIFEST']._serialized_start=3062 - _globals['_LISTMANIFESTSRESPONSE_MANIFEST']._serialized_end=3247 - _globals['_DELETEMANIFESTREQUEST']._serialized_start=3249 - _globals['_DELETEMANIFESTREQUEST']._serialized_end=3293 - _globals['_LISTMANIFESTFILESREQUEST']._serialized_start=3295 - _globals['_LISTMANIFESTFILESREQUEST']._serialized_end=3373 - _globals['_LISTMANIFESTFILESRESPONSE']._serialized_start=3376 - _globals['_LISTMANIFESTFILESRESPONSE']._serialized_end=3776 - _globals['_LISTMANIFESTFILESRESPONSE_FILEUPLOAD']._serialized_start=3462 - _globals['_LISTMANIFESTFILESRESPONSE_FILEUPLOAD']._serialized_end=3626 - _globals['_LISTMANIFESTFILESRESPONSE_STATUSTYPE']._serialized_start=3629 - _globals['_LISTMANIFESTFILESRESPONSE_STATUSTYPE']._serialized_end=3776 - _globals['_UPLOADMANIFESTREQUEST']._serialized_start=3778 - _globals['_UPLOADMANIFESTREQUEST']._serialized_end=3822 - _globals['_GETUSERREQUEST']._serialized_start=3824 - _globals['_GETUSERREQUEST']._serialized_end=3840 - _globals['_USERRESPONSE']._serialized_start=3843 - _globals['_USERRESPONSE']._serialized_end=4055 - _globals['_SWITCHPROFILEREQUEST']._serialized_start=4057 - _globals['_SWITCHPROFILEREQUEST']._serialized_end=4096 - _globals['_REAUTHENTICATEREQUEST']._serialized_start=4098 - _globals['_REAUTHENTICATEREQUEST']._serialized_end=4121 - _globals['_USEDATASETREQUEST']._serialized_start=4123 - _globals['_USEDATASETREQUEST']._serialized_end=4162 - _globals['_USEDATASETRESPONSE']._serialized_start=4164 - _globals['_USEDATASETRESPONSE']._serialized_end=4204 - _globals['_SYNCMANIFESTREQUEST']._serialized_start=4206 - _globals['_SYNCMANIFESTREQUEST']._serialized_end=4248 - _globals['_SYNCMANIFESTRESPONSE']._serialized_start=4250 - _globals['_SYNCMANIFESTRESPONSE']._serialized_end=4375 - _globals['_RESETMANIFESTREQUEST']._serialized_start=4377 - _globals['_RESETMANIFESTREQUEST']._serialized_end=4420 - _globals['_RELOCATEMANIFESTFILESREQUEST']._serialized_start=4422 - _globals['_RELOCATEMANIFESTFILESREQUEST']._serialized_end=4509 - _globals['_STARTWORKFLOWREQUEST']._serialized_start=4511 - _globals['_STARTWORKFLOWREQUEST']._serialized_end=4576 - _globals['_WORKFLOWRESPONSE']._serialized_start=4579 - _globals['_WORKFLOWRESPONSE']._serialized_end=4729 - _globals['_WORKFLOWRESPONSE_WORKFLOWTYPE']._serialized_start=4694 - _globals['_WORKFLOWRESPONSE_WORKFLOWTYPE']._serialized_end=4729 - _globals['_REGISTERREQUEST']._serialized_start=4731 - _globals['_REGISTERREQUEST']._serialized_end=4816 - _globals['_REGISTERRESPONSE']._serialized_start=4818 - _globals['_REGISTERRESPONSE']._serialized_end=4856 - _globals['_ACCOUNT']._serialized_start=4858 - _globals['_ACCOUNT']._serialized_end=4941 - _globals['_ACCOUNT_ACCOUNTTYPE']._serialized_start=4908 - _globals['_ACCOUNT_ACCOUNTTYPE']._serialized_end=4941 - _globals['_CREDENTIALS']._serialized_start=4943 - _globals['_CREDENTIALS']._serialized_end=4973 - _globals['_MAPREQUEST']._serialized_start=4975 - _globals['_MAPREQUEST']._serialized_end=5030 - _globals['_DOWNLOADREQUEST']._serialized_start=5033 - _globals['_DOWNLOADREQUEST']._serialized_end=5242 - _globals['_DOWNLOADREQUEST_DOWNLOADTYPE']._serialized_start=5194 - _globals['_DOWNLOADREQUEST_DOWNLOADTYPE']._serialized_end=5234 - _globals['_DOWNLOADDATASETREQUEST']._serialized_start=5244 - _globals['_DOWNLOADDATASETREQUEST']._serialized_end=5311 - _globals['_DOWNLOADPACKAGEREQUEST']._serialized_start=5313 - _globals['_DOWNLOADPACKAGEREQUEST']._serialized_end=5384 - _globals['_DOWNLOADRESPONSE']._serialized_start=5387 - _globals['_DOWNLOADRESPONSE']._serialized_end=5532 - _globals['_DOWNLOADRESPONSE_RESPONSETYPE']._serialized_start=5485 - _globals['_DOWNLOADRESPONSE_RESPONSETYPE']._serialized_end=5532 - _globals['_MAPDIFFREQUEST']._serialized_start=5534 - _globals['_MAPDIFFREQUEST']._serialized_end=5564 - _globals['_FILEINFO']._serialized_start=5566 - _globals['_FILEINFO']._serialized_end=5641 - _globals['_PACKAGESTATUS']._serialized_start=5644 - _globals['_PACKAGESTATUS']._serialized_end=5834 - _globals['_PACKAGESTATUS_STATUSTYPE']._serialized_start=5742 - _globals['_PACKAGESTATUS_STATUSTYPE']._serialized_end=5834 - _globals['_MAPDIFFRESPONSE']._serialized_start=5836 - _globals['_MAPDIFFRESPONSE']._serialized_end=5887 - _globals['_AGENT']._serialized_start=5890 - _globals['_AGENT']._serialized_end=7908 + _globals['_PUSHREQUEST']._serialized_start=65 + _globals['_PUSHREQUEST']._serialized_end=92 + _globals['_SUBSCRIBEREQUEST']._serialized_start=94 + _globals['_SUBSCRIBEREQUEST']._serialized_end=124 + _globals['_RESETCACHEREQUEST']._serialized_start=126 + _globals['_RESETCACHEREQUEST']._serialized_end=169 + _globals['_GETTIMESERIESCHANNELSREQUEST']._serialized_start=171 + _globals['_GETTIMESERIESCHANNELSREQUEST']._serialized_end=258 + _globals['_TIMESERIESCHANNEL']._serialized_start=260 + _globals['_TIMESERIESCHANNEL']._serialized_end=371 + _globals['_GETTIMESERIESCHANNELSRESPONSE']._serialized_start=373 + _globals['_GETTIMESERIESCHANNELSRESPONSE']._serialized_end=444 + _globals['_GETTIMESERIESRANGEREQUEST']._serialized_start=447 + _globals['_GETTIMESERIESRANGEREQUEST']._serialized_end=613 + _globals['_GETTIMESERIESRANGERESPONSE']._serialized_start=616 + _globals['_GETTIMESERIESRANGERESPONSE']._serialized_end=1169 + _globals['_GETTIMESERIESRANGERESPONSE_CHANNELINFO']._serialized_start=884 + _globals['_GETTIMESERIESRANGERESPONSE_CHANNELINFO']._serialized_end=959 + _globals['_GETTIMESERIESRANGERESPONSE_RANGEDATA']._serialized_start=961 + _globals['_GETTIMESERIESRANGERESPONSE_RANGEDATA']._serialized_end=1048 + _globals['_GETTIMESERIESRANGERESPONSE_ERRORDATA']._serialized_start=1050 + _globals['_GETTIMESERIESRANGERESPONSE_ERRORDATA']._serialized_end=1075 + _globals['_GETTIMESERIESRANGERESPONSE_MESSAGETYPE']._serialized_start=1077 + _globals['_GETTIMESERIESRANGERESPONSE_MESSAGETYPE']._serialized_end=1153 + _globals['_SUBSCRIBERESPONSE']._serialized_start=1172 + _globals['_SUBSCRIBERESPONSE']._serialized_end=2278 + _globals['_SUBSCRIBERESPONSE_EVENTRESPONSE']._serialized_start=1496 + _globals['_SUBSCRIBERESPONSE_EVENTRESPONSE']._serialized_end=1528 + _globals['_SUBSCRIBERESPONSE_UPLOADRESPONSE']._serialized_start=1531 + _globals['_SUBSCRIBERESPONSE_UPLOADRESPONSE']._serialized_end=1739 + _globals['_SUBSCRIBERESPONSE_UPLOADRESPONSE_UPLOADSTATUS']._serialized_start=1684 + _globals['_SUBSCRIBERESPONSE_UPLOADRESPONSE_UPLOADSTATUS']._serialized_end=1739 + _globals['_SUBSCRIBERESPONSE_DOWNLOADSTATUSRESPONSE']._serialized_start=1742 + _globals['_SUBSCRIBERESPONSE_DOWNLOADSTATUSRESPONSE']._serialized_end=1951 + _globals['_SUBSCRIBERESPONSE_DOWNLOADSTATUSRESPONSE_DOWNLOADSTATUS']._serialized_start=1894 + _globals['_SUBSCRIBERESPONSE_DOWNLOADSTATUSRESPONSE_DOWNLOADSTATUS']._serialized_end=1951 + _globals['_SUBSCRIBERESPONSE_SYNCRESPONSE']._serialized_start=1954 + _globals['_SUBSCRIBERESPONSE_SYNCRESPONSE']._serialized_end=2139 + _globals['_SUBSCRIBERESPONSE_SYNCRESPONSE_SYNCSTATUS']._serialized_start=2086 + _globals['_SUBSCRIBERESPONSE_SYNCRESPONSE_SYNCSTATUS']._serialized_end=2139 + _globals['_SUBSCRIBERESPONSE_MESSAGETYPE']._serialized_start=2141 + _globals['_SUBSCRIBERESPONSE_MESSAGETYPE']._serialized_end=2262 + _globals['_SIMPLESTATUSRESPONSE']._serialized_start=2280 + _globals['_SIMPLESTATUSRESPONSE']._serialized_end=2318 + _globals['_CANCELUPLOADREQUEST']._serialized_start=2320 + _globals['_CANCELUPLOADREQUEST']._serialized_end=2382 + _globals['_CANCELDOWNLOADREQUEST']._serialized_start=2384 + _globals['_CANCELDOWNLOADREQUEST']._serialized_end=2451 + _globals['_CREATEMANIFESTREQUEST']._serialized_start=2453 + _globals['_CREATEMANIFESTREQUEST']._serialized_end=2555 + _globals['_CREATEMANIFESTRESPONSE']._serialized_start=2557 + _globals['_CREATEMANIFESTRESPONSE']._serialized_end=2619 + _globals['_ADDTOMANIFESTREQUEST']._serialized_start=2621 + _globals['_ADDTOMANIFESTREQUEST']._serialized_end=2743 + _globals['_REMOVEFROMMANIFESTREQUEST']._serialized_start=2745 + _globals['_REMOVEFROMMANIFESTREQUEST']._serialized_end=2814 + _globals['_VERSIONREQUEST']._serialized_start=2816 + _globals['_VERSIONREQUEST']._serialized_end=2832 + _globals['_VERSIONRESPONSE']._serialized_start=2834 + _globals['_VERSIONRESPONSE']._serialized_end=2887 + _globals['_PINGREQUEST']._serialized_start=2889 + _globals['_PINGREQUEST']._serialized_end=2902 + _globals['_PINGRESPONSE']._serialized_start=2904 + _globals['_PINGRESPONSE']._serialized_end=2935 + _globals['_STOPREQUEST']._serialized_start=2937 + _globals['_STOPREQUEST']._serialized_end=2950 + _globals['_STOPRESPONSE']._serialized_start=2952 + _globals['_STOPRESPONSE']._serialized_end=2983 + _globals['_LISTMANIFESTSREQUEST']._serialized_start=2985 + _globals['_LISTMANIFESTSREQUEST']._serialized_end=3007 + _globals['_LISTMANIFESTSRESPONSE']._serialized_start=3010 + _globals['_LISTMANIFESTSRESPONSE']._serialized_end=3276 + _globals['_LISTMANIFESTSRESPONSE_MANIFEST']._serialized_start=3091 + _globals['_LISTMANIFESTSRESPONSE_MANIFEST']._serialized_end=3276 + _globals['_DELETEMANIFESTREQUEST']._serialized_start=3278 + _globals['_DELETEMANIFESTREQUEST']._serialized_end=3322 + _globals['_LISTMANIFESTFILESREQUEST']._serialized_start=3324 + _globals['_LISTMANIFESTFILESREQUEST']._serialized_end=3402 + _globals['_LISTMANIFESTFILESRESPONSE']._serialized_start=3405 + _globals['_LISTMANIFESTFILESRESPONSE']._serialized_end=3805 + _globals['_LISTMANIFESTFILESRESPONSE_FILEUPLOAD']._serialized_start=3491 + _globals['_LISTMANIFESTFILESRESPONSE_FILEUPLOAD']._serialized_end=3655 + _globals['_LISTMANIFESTFILESRESPONSE_STATUSTYPE']._serialized_start=3658 + _globals['_LISTMANIFESTFILESRESPONSE_STATUSTYPE']._serialized_end=3805 + _globals['_UPLOADMANIFESTREQUEST']._serialized_start=3807 + _globals['_UPLOADMANIFESTREQUEST']._serialized_end=3851 + _globals['_GETUSERREQUEST']._serialized_start=3853 + _globals['_GETUSERREQUEST']._serialized_end=3869 + _globals['_USERRESPONSE']._serialized_start=3872 + _globals['_USERRESPONSE']._serialized_end=4084 + _globals['_SWITCHPROFILEREQUEST']._serialized_start=4086 + _globals['_SWITCHPROFILEREQUEST']._serialized_end=4125 + _globals['_REAUTHENTICATEREQUEST']._serialized_start=4127 + _globals['_REAUTHENTICATEREQUEST']._serialized_end=4150 + _globals['_USEDATASETREQUEST']._serialized_start=4152 + _globals['_USEDATASETREQUEST']._serialized_end=4191 + _globals['_USEDATASETRESPONSE']._serialized_start=4193 + _globals['_USEDATASETRESPONSE']._serialized_end=4233 + _globals['_SYNCMANIFESTREQUEST']._serialized_start=4235 + _globals['_SYNCMANIFESTREQUEST']._serialized_end=4277 + _globals['_SYNCMANIFESTRESPONSE']._serialized_start=4279 + _globals['_SYNCMANIFESTRESPONSE']._serialized_end=4404 + _globals['_RESETMANIFESTREQUEST']._serialized_start=4406 + _globals['_RESETMANIFESTREQUEST']._serialized_end=4449 + _globals['_RELOCATEMANIFESTFILESREQUEST']._serialized_start=4451 + _globals['_RELOCATEMANIFESTFILESREQUEST']._serialized_end=4538 + _globals['_STARTWORKFLOWREQUEST']._serialized_start=4540 + _globals['_STARTWORKFLOWREQUEST']._serialized_end=4605 + _globals['_WORKFLOWRESPONSE']._serialized_start=4608 + _globals['_WORKFLOWRESPONSE']._serialized_end=4758 + _globals['_WORKFLOWRESPONSE_WORKFLOWTYPE']._serialized_start=4723 + _globals['_WORKFLOWRESPONSE_WORKFLOWTYPE']._serialized_end=4758 + _globals['_REGISTERREQUEST']._serialized_start=4760 + _globals['_REGISTERREQUEST']._serialized_end=4845 + _globals['_REGISTERRESPONSE']._serialized_start=4847 + _globals['_REGISTERRESPONSE']._serialized_end=4885 + _globals['_DEREGISTERREQUEST']._serialized_start=4887 + _globals['_DEREGISTERREQUEST']._serialized_end=4989 + _globals['_DEREGISTERRESPONSE']._serialized_start=4991 + _globals['_DEREGISTERRESPONSE']._serialized_end=5050 + _globals['_ACCOUNT']._serialized_start=5052 + _globals['_ACCOUNT']._serialized_end=5135 + _globals['_ACCOUNT_ACCOUNTTYPE']._serialized_start=5102 + _globals['_ACCOUNT_ACCOUNTTYPE']._serialized_end=5135 + _globals['_CREDENTIALS']._serialized_start=5137 + _globals['_CREDENTIALS']._serialized_end=5167 + _globals['_MAPREQUEST']._serialized_start=5169 + _globals['_MAPREQUEST']._serialized_end=5224 + _globals['_DOWNLOADREQUEST']._serialized_start=5227 + _globals['_DOWNLOADREQUEST']._serialized_end=5436 + _globals['_DOWNLOADREQUEST_DOWNLOADTYPE']._serialized_start=5388 + _globals['_DOWNLOADREQUEST_DOWNLOADTYPE']._serialized_end=5428 + _globals['_DOWNLOADDATASETREQUEST']._serialized_start=5438 + _globals['_DOWNLOADDATASETREQUEST']._serialized_end=5505 + _globals['_DOWNLOADPACKAGEREQUEST']._serialized_start=5507 + _globals['_DOWNLOADPACKAGEREQUEST']._serialized_end=5578 + _globals['_DOWNLOADRESPONSE']._serialized_start=5581 + _globals['_DOWNLOADRESPONSE']._serialized_end=5726 + _globals['_DOWNLOADRESPONSE_RESPONSETYPE']._serialized_start=5679 + _globals['_DOWNLOADRESPONSE_RESPONSETYPE']._serialized_end=5726 + _globals['_MAPDIFFREQUEST']._serialized_start=5728 + _globals['_MAPDIFFREQUEST']._serialized_end=5758 + _globals['_FILEINFO']._serialized_start=5760 + _globals['_FILEINFO']._serialized_end=5835 + _globals['_PACKAGESTATUS']._serialized_start=5838 + _globals['_PACKAGESTATUS']._serialized_end=6028 + _globals['_PACKAGESTATUS_STATUSTYPE']._serialized_start=5936 + _globals['_PACKAGESTATUS_STATUSTYPE']._serialized_end=6028 + _globals['_MAPDIFFRESPONSE']._serialized_start=6030 + _globals['_MAPDIFFRESPONSE']._serialized_end=6081 + _globals['_AGENT']._serialized_start=6084 + _globals['_AGENT']._serialized_end=8218 # @@protoc_insertion_point(module_scope) diff --git a/src/pennsieve/protos/agent_pb2_grpc.py b/src/pennsieve/protos/agent_pb2_grpc.py index 4e87fe8..6816ac6 100644 --- a/src/pennsieve/protos/agent_pb2_grpc.py +++ b/src/pennsieve/protos/agent_pb2_grpc.py @@ -89,6 +89,11 @@ def __init__(self, channel): request_serializer=pennsieve_dot_protos_dot_agent__pb2.PullRequest.SerializeToString, response_deserializer=pennsieve_dot_protos_dot_agent__pb2.SimpleStatusResponse.FromString, ) + self.Push = channel.unary_unary( + '/v1.Agent/Push', + request_serializer=pennsieve_dot_protos_dot_agent__pb2.PushRequest.SerializeToString, + response_deserializer=pennsieve_dot_protos_dot_agent__pb2.SimpleStatusResponse.FromString, + ) self.GetMapDiff = channel.unary_unary( '/v1.Agent/GetMapDiff', request_serializer=pennsieve_dot_protos_dot_agent__pb2.MapDiffRequest.SerializeToString, @@ -149,6 +154,11 @@ def __init__(self, channel): request_serializer=pennsieve_dot_protos_dot_agent__pb2.RegisterRequest.SerializeToString, response_deserializer=pennsieve_dot_protos_dot_agent__pb2.RegisterResponse.FromString, ) + self.Deregister = channel.unary_unary( + '/v1.Agent/Deregister', + request_serializer=pennsieve_dot_protos_dot_agent__pb2.DeregisterRequest.SerializeToString, + response_deserializer=pennsieve_dot_protos_dot_agent__pb2.DeregisterResponse.FromString, + ) self.GetTimeseriesChannels = channel.unary_unary( '/v1.Agent/GetTimeseriesChannels', request_serializer=pennsieve_dot_protos_dot_agent__pb2.GetTimeseriesChannelsRequest.SerializeToString, @@ -262,6 +272,12 @@ def Pull(self, request, context): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def Push(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def GetMapDiff(self, request, context): """Missing associated documentation comment in .proto file.""" context.set_code(grpc.StatusCode.UNIMPLEMENTED) @@ -339,6 +355,12 @@ def Register(self, request, context): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def Deregister(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def GetTimeseriesChannels(self, request, context): """Timeseries Endpoints """ @@ -436,6 +458,11 @@ def add_AgentServicer_to_server(servicer, server): request_deserializer=pennsieve_dot_protos_dot_agent__pb2.PullRequest.FromString, response_serializer=pennsieve_dot_protos_dot_agent__pb2.SimpleStatusResponse.SerializeToString, ), + 'Push': grpc.unary_unary_rpc_method_handler( + servicer.Push, + request_deserializer=pennsieve_dot_protos_dot_agent__pb2.PushRequest.FromString, + response_serializer=pennsieve_dot_protos_dot_agent__pb2.SimpleStatusResponse.SerializeToString, + ), 'GetMapDiff': grpc.unary_unary_rpc_method_handler( servicer.GetMapDiff, request_deserializer=pennsieve_dot_protos_dot_agent__pb2.MapDiffRequest.FromString, @@ -496,6 +523,11 @@ def add_AgentServicer_to_server(servicer, server): request_deserializer=pennsieve_dot_protos_dot_agent__pb2.RegisterRequest.FromString, response_serializer=pennsieve_dot_protos_dot_agent__pb2.RegisterResponse.SerializeToString, ), + 'Deregister': grpc.unary_unary_rpc_method_handler( + servicer.Deregister, + request_deserializer=pennsieve_dot_protos_dot_agent__pb2.DeregisterRequest.FromString, + response_serializer=pennsieve_dot_protos_dot_agent__pb2.DeregisterResponse.SerializeToString, + ), 'GetTimeseriesChannels': grpc.unary_unary_rpc_method_handler( servicer.GetTimeseriesChannels, request_deserializer=pennsieve_dot_protos_dot_agent__pb2.GetTimeseriesChannelsRequest.FromString, @@ -776,6 +808,23 @@ def Pull(request, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + @staticmethod + def Push(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/v1.Agent/Push', + pennsieve_dot_protos_dot_agent__pb2.PushRequest.SerializeToString, + pennsieve_dot_protos_dot_agent__pb2.SimpleStatusResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + @staticmethod def GetMapDiff(request, target, @@ -980,6 +1029,23 @@ def Register(request, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + @staticmethod + def Deregister(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/v1.Agent/Deregister', + pennsieve_dot_protos_dot_agent__pb2.DeregisterRequest.SerializeToString, + pennsieve_dot_protos_dot_agent__pb2.DeregisterResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + @staticmethod def GetTimeseriesChannels(request, target, diff --git a/tests/test_map.py b/tests/test_map.py new file mode 100644 index 0000000..edbabc5 --- /dev/null +++ b/tests/test_map.py @@ -0,0 +1,191 @@ +import json +import threading +import time +from pathlib import Path +from unittest.mock import MagicMock + +import pytest + +from pennsieve.map import Map, _read_local_state_paths +from pennsieve.protos import agent_pb2 + + +def test_map_rpc_wraps_request_with_dataset_id_and_target(): + stub = MagicMock() + m = Map(stub) + + m.map("N:dataset:abc", "/tmp/mapped") + + stub.Map.assert_called_once() + req = stub.Map.call_args.kwargs["request"] + assert isinstance(req, agent_pb2.MapRequest) + assert req.dataset_id == "N:dataset:abc" + assert req.target_folder == "/tmp/mapped" + + +def test_pull_push_diff_forward_to_stub(): + stub = MagicMock() + m = Map(stub) + + m.pull("/tmp/mapped/folder") + assert isinstance(stub.Pull.call_args.kwargs["request"], agent_pb2.PullRequest) + assert stub.Pull.call_args.kwargs["request"].path == "/tmp/mapped/folder" + + m.push("/tmp/mapped") + assert isinstance(stub.Push.call_args.kwargs["request"], agent_pb2.PushRequest) + assert stub.Push.call_args.kwargs["request"].path == "/tmp/mapped" + + m.diff("/tmp/mapped") + assert isinstance(stub.GetMapDiff.call_args.kwargs["request"], agent_pb2.MapDiffRequest) + assert stub.GetMapDiff.call_args.kwargs["request"].path == "/tmp/mapped" + + +def _write_state(target: Path, records): + pennsieve_dir = target / ".pennsieve" + pennsieve_dir.mkdir(parents=True, exist_ok=True) + (pennsieve_dir / "state.json").write_text( + json.dumps( + { + "lastFetch": "2026-04-20T00:00:00Z", + "lastPull": "2026-04-20T00:00:00Z", + "files": records, + } + ) + ) + + +def test_wait_for_pull_returns_when_expected_paths_local(tmp_path): + m = Map(MagicMock()) + + _write_state( + tmp_path, + [ + {"path": "folder/a.lay", "isLocal": True, "pullTime": "2026-04-20T00:00:00Z"}, + {"path": "folder/b.lay", "isLocal": True, "pullTime": "2026-04-20T00:00:00Z"}, + ], + ) + + m.wait_for_pull( + target_folder=str(tmp_path), + expected_relative_paths=["folder/a.lay", "folder/b.lay"], + idle_timeout=1.0, + poll_interval=0.01, + ) # must not raise + + +def test_wait_for_pull_times_out_when_paths_missing(tmp_path): + m = Map(MagicMock()) + _write_state(tmp_path, [{"path": "folder/a.lay", "isLocal": True}]) + + with pytest.raises(TimeoutError) as exc: + m.wait_for_pull( + target_folder=str(tmp_path), + expected_relative_paths=["folder/a.lay", "folder/missing.lay"], + idle_timeout=0.2, + poll_interval=0.05, + ) + assert "folder/missing.lay" in str(exc.value) + + +def test_wait_for_pull_ignores_non_local_records(tmp_path): + m = Map(MagicMock()) + _write_state( + tmp_path, + [ + {"path": "folder/a.lay", "isLocal": False}, + {"path": "folder/a.lay", "isLocal": True}, + ], + ) + # Latest-wins isn't defined; presence of any isLocal=True record is enough. + m.wait_for_pull( + target_folder=str(tmp_path), + expected_relative_paths=["folder/a.lay"], + idle_timeout=0.5, + poll_interval=0.01, + ) + + +def test_wait_for_pull_polls_until_state_appears(tmp_path): + m = Map(MagicMock()) + + def write_later(): + time.sleep(0.05) + _write_state( + tmp_path, + [{"path": "folder/a.lay", "isLocal": True}], + ) + + t = threading.Thread(target=write_later) + t.start() + try: + m.wait_for_pull( + target_folder=str(tmp_path), + expected_relative_paths=["folder/a.lay"], + idle_timeout=1.0, + poll_interval=0.01, + ) + finally: + t.join() + + +def test_read_local_state_paths_returns_empty_when_missing(tmp_path): + assert _read_local_state_paths(tmp_path / "nope.json") == set() + + +def test_read_local_state_paths_tolerates_invalid_json(tmp_path): + p = tmp_path / "state.json" + p.write_text("{not valid") + assert _read_local_state_paths(p) == set() + + +class _FakeSubscribeResponse: + """Minimal duck-type for SubscribeResponse used by wait_for_push.""" + + class _UploadStatus: + def __init__(self, status): + self.status = status + + def __init__(self, type_, upload_status_code=None): + self.type = type_ + self.upload_status = self._UploadStatus(upload_status_code or 0) + + +def test_wait_for_push_counts_complete_events(): + events = [ + _FakeSubscribeResponse(type_=0), # general info -- ignored + _FakeSubscribeResponse(type_=1, upload_status_code=1), # IN_PROGRESS + _FakeSubscribeResponse(type_=1, upload_status_code=2), # COMPLETE #1 + _FakeSubscribeResponse(type_=1, upload_status_code=2), # COMPLETE #2 + ] + + stub = MagicMock() + + def subscribe(request): + for e in events: + yield e + # Then block so the thread doesn't exit immediately after yielding + # (simulating a live stream). + while True: + time.sleep(0.05) + + stub.Subscribe.side_effect = lambda request: subscribe(request) + + m = Map(stub) + count = m.wait_for_push(expected_files=2, subscriber_id=9001, idle_timeout=2.0) + assert count == 2 + stub.Unsubscribe.assert_called_once() + + +def test_wait_for_push_times_out_when_not_enough_events(): + stub = MagicMock() + + def subscribe(request): + yield _FakeSubscribeResponse(type_=1, upload_status_code=2) # one COMPLETE + while True: + time.sleep(0.05) + + stub.Subscribe.side_effect = lambda request: subscribe(request) + + m = Map(stub) + with pytest.raises(TimeoutError): + m.wait_for_push(expected_files=2, subscriber_id=9002, idle_timeout=0.3)