Skip to content

Filesharing Worker

FileSharingWorker(inventory: Any, broker: str, worker_name: str, exit_event: Any = None, init_done_event: Any = None, log_level: str = 'WARNING') ¤

Bases: NFPWorker, GitTasks, LocalFilesTasks

File Sharing worker providing Git-based remote synchronization and file access.

Supports managing multiple configured Git remotes with automatic periodic synchronization. Provides tasks for listing, fetching, and walking published remote content via a safe filesystem interface.

Source code in norfab\workers\filesharing_worker\filesharing_worker.py
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
def __init__(
    self,
    inventory: Any,
    broker: str,
    worker_name: str,
    exit_event: Any = None,
    init_done_event: Any = None,
    log_level: str = "WARNING",
) -> None:
    super().__init__(inventory, broker, SERVICE, worker_name, exit_event, log_level)
    self.init_done_event = init_done_event

    # get inventory from broker
    inventory_data = self.load_inventory()
    validated_inventory = FileSharingInventory.model_validate(inventory_data)

    self.runtime_dir = self.base_dir
    self.filesharing_inventory = validated_inventory.model_dump()
    self.base_dir = os.path.abspath(validated_inventory.base_dir)

    self.setup_remotes(validated_inventory)

    self.init_done_event.set()
    log.debug(f"{self.name} - Started")

setup_remotes(validated_inventory: FileSharingInventory) -> None ¤

Set up all configured remotes and start synchronization thread.

Initializes remote locks, validates each remote's type, and starts the automatic synchronization thread if any remotes have auto_sync enabled.

Parameters:

Name Type Description Default
validated_inventory FileSharingInventory

Validated FileSharingInventory instance.

required

Raises:

Type Description
ValueError

If any remote has an unsupported type.

Source code in norfab\workers\filesharing_worker\filesharing_worker.py
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
def setup_remotes(self, validated_inventory: FileSharingInventory) -> None:
    """Set up all configured remotes and start synchronization thread.

    Initializes remote locks, validates each remote's type, and starts the
    automatic synchronization thread if any remotes have auto_sync enabled.

    Args:
        validated_inventory: Validated FileSharingInventory instance.

    Raises:
        ValueError: If any remote has an unsupported type.
    """
    self.remotes = {}
    self.remote_sync_stop = threading.Event()
    self.remote_sync_thread = None
    os.makedirs(self.base_dir, exist_ok=True)
    os.makedirs(os.path.join(self.runtime_dir, "remotes"), exist_ok=True)

    # Initialize each configured remote based on its type
    for remote in validated_inventory.remotes:
        if remote.type == "git":
            result = self.create_remote_git(None, **remote.model_dump())
            if result.failed:
                log.error(f"{self.name} - Failed to create remote '{remote.name}'")
        else:
            raise ValueError(
                f"Remote type '{remote.type}' is not supported. "
                f"Supported types: git"
            )

    if self.remote_sync_thread is None:
        self.remote_sync_thread = self.start_git_sync()

get_version() -> Result ¤

Return runtime versions reported by the File Sharing worker.

Returns:

Type Description
Result

A result mapping runtime component names to version strings. Python

Result

and platform information are always included.

Source code in norfab\workers\filesharing_worker\filesharing_worker.py
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
@Task(
    input=GetVersionInput,
    output=GetVersionResult,
    fastapi={"methods": ["GET"]},
    agent={"enabled": False},
    mcp={
        "annotations": {
            "title": "Get Version",
            "readOnlyHint": True,
            "destructiveHint": False,
            "idempotentHint": True,
            "openWorldHint": False,
        }
    },
)
def get_version(self) -> Result:
    """Return runtime versions reported by the File Sharing worker.

    Returns:
        A result mapping runtime component names to version strings. Python
        and platform information are always included.
    """
    libs = {
        "python": sys.version.split(" ")[0],
        "platform": sys.platform,
        "gitpython": "",
    }
    # get version of packages installed
    for pkg in libs.keys():
        try:
            libs[pkg] = importlib.metadata.version(pkg)
        except importlib.metadata.PackageNotFoundError:
            pass

    return Result(result=libs)

get_inventory() -> Result ¤

Return the validated File Sharing worker inventory.

Remote definitions are returned in their configured order. Every non-empty password or access token is replaced with *** before the inventory leaves the worker.

Returns:

Type Description
Result

A result containing the validated inventory with credentials

Result

redacted.

Source code in norfab\workers\filesharing_worker\filesharing_worker.py
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
@Task(
    input=GetInventoryInput,
    output=GetInventoryResult,
    fastapi={"methods": ["GET"]},
    agent={"enabled": False},
    mcp={
        "annotations": {
            "title": "Get Inventory",
            "readOnlyHint": True,
            "destructiveHint": False,
            "idempotentHint": True,
            "openWorldHint": False,
        }
    },
)
def get_inventory(self) -> Result:
    """Return the validated File Sharing worker inventory.

    Remote definitions are returned in their configured order. Every
    non-empty password or access token is replaced with ``***`` before the
    inventory leaves the worker.

    Returns:
        A result containing the validated inventory with credentials
        redacted.
    """
    inventory = self.filesharing_inventory.copy()
    inventory["remotes"] = []
    for configured_remote in self.filesharing_inventory.get("remotes", []):
        remote = configured_remote.copy()
        if remote.get("password") is not None:
            remote["password"] = "***"
        inventory["remotes"].append(remote)
    return Result(result=inventory)

get_remotes(name: str | None = None) -> Result ¤

Return all runtime remotes or one remote selected by name.

Parameters:

Name Type Description Default
name str | None

Optional remote name used to filter the result.

None

Returns:

Type Description
Result

A result containing remote inventory dictionaries. Passwords and

Result

access tokens are replaced with ***; public remotes retain a

Result

None password.

Source code in norfab\workers\filesharing_worker\filesharing_worker.py
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
@Task(
    input=GetRemotesInput,
    output=GetRemotesResult,
    fastapi={"methods": ["GET"]},
    agent={"enabled": False},
    mcp={
        "annotations": {
            "title": "Get File Sharing Remotes",
            "readOnlyHint": True,
            "destructiveHint": False,
            "idempotentHint": True,
            "openWorldHint": False,
        }
    },
)
def get_remotes(self, name: str | None = None) -> Result:
    """Return all runtime remotes or one remote selected by name.

    Args:
        name: Optional remote name used to filter the result.

    Returns:
        A result containing remote inventory dictionaries. Passwords and
        access tokens are replaced with ``***``; public remotes retain a
        ``None`` password.
    """
    remotes = []
    for configured_remote in self.remotes.values():
        if name is not None and configured_remote["name"] != name:
            continue
        remote = configured_remote.copy()
        remote.pop("lock")
        remote.pop("last_sync_timer")
        remote.pop("repository")
        if remote.get("password") is not None:
            remote["password"] = "***"
        remotes.append(remote)
    return Result(result=remotes)

get_status() -> Result ¤

Return the File Sharing worker health status.

Returns:

Type Description
Result

A result containing OK while the worker can process tasks.

Source code in norfab\workers\filesharing_worker\filesharing_worker.py
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
@Task(
    input=GetStatusInput,
    output=GetStatusResult,
    fastapi={"methods": ["GET"]},
    agent={"enabled": False},
    mcp={
        "annotations": {
            "title": "Get Status",
            "readOnlyHint": True,
            "destructiveHint": False,
            "idempotentHint": True,
            "openWorldHint": False,
        }
    },
)
def get_status(self) -> Result:
    """Return the File Sharing worker health status.

    Returns:
        A result containing ``OK`` while the worker can process tasks.
    """
    return Result(result="OK")