class_docstr: Command channel based on access to the same directory.
  
  The directory can be mounted at a different place for the other side,
  as long as it's available to both of them.
  
  Both side must have read and write access to the directory as well as the files inside.
  If the directory doesn't exist. They must have the privilege to create it.
  
  :class:`FileChannel` is stateful. It (at least) has a state to mark which messages (i.e. files)
  that has been read. Recovering the channel from faults might lose that state and consume duplicated messages.
  Thus the reader side needs the state of "current reading progress" to be persistent.
  Therefore a sender can broadcast to multiple receivers via a :class:`FileChannel`,
  but it can only be listening to one channel in current implementation.
  
  All the files written by the peer are in the URL, starting with ``<peer_name>.``.
  Synchronization can leverage this glob pattern.
  
  Parameters
  ----------
  url
      A directory on the current file system.
  local_peer
      Join as which peer. IDs are used to identify self, with no other limitations.
      Possible values might be "server", "client", "1", "2", ...
      Peer name can't contain ``.``.
  remote_peer
      The peer name that is connected to.
      This only matters in :meth:`receive`.
  
  Warnings
  --------
  The channel is not thread-safe. Behavior is undefined when two threads / processes belonging to the same peer
  try to access the channel at the same time. Try to use the channel ONLY on rank 0 whenever possible.
class_docstr_tok: ["Command","channel","based","on","access","to","the","same","directory",".","The","directory","can","be","mounted","at","a","different","place","for","the","other","side",",","as","long","as","it","'s","available","to","both","of","them",".","Both","side","must","have","read","and","write","access","to","the","directory","as","well","as","the","files","inside",".","If","the","directory","does","n't","exist",".","They","must","have","the","privilege","to","create","it",".",":","class",":","`","FileChannel","`","is","stateful",".","It","(","at","least",")","has","a","state","to","mark","which","messages","(","i.e",".","files",")","that","has","been","read",".","Recovering","the","channel","from","faults","might","lose","that","state","and","consume","duplicated","messages",".","Thus","the","reader","side","needs","the","state","of","``","current","reading","progress","''","to","be","persistent",".","Therefore","a","sender","can","broadcast","to","multiple","receivers","via","a",":","class",":","`","FileChannel","`",",","but","it","can","only","be","listening","to","one","channel","in","current","implementation",".","All","the","files","written","by","the","peer","are","in","the","URL",",","starting","with","``","<","peer_name",">",".","``",".","Synchronization","can","leverage","this","glob","pattern",".","Parameters","--","--","--","--","--","url","A","directory","on","the","current","file","system",".","local_peer","Join","as","which","peer",".","IDs","are","used","to","identify","self",",","with","no","other","limitations",".","Possible","values","might","be","``","server","''",",","``","client","''",",","``","1","''",",","``","2","''",",","...","Peer","name","ca","n't","contain","``",".","``",".","remote_peer","The","peer","name","that","is","connected","to",".","This","only","matters","in",":","meth",":","`","receive","`",".","Warnings","--","--","--","--","The","channel","is","not","thread-safe",".","Behavior","is","undefined","when","two","threads","\/","processes","belonging","to","the","same","peer","try","to","access","the","channel","at","the","same","time",".","Try","to","use","the","channel","ONLY","on","rank","0","whenever","possible","."]
code: def __init__(
      self, url: str | Path, local_peer: str, remote_peer: str
  ):
      self._url: Path = Path(url)
      self._local_peer = local_peer
      self._remote_peer = remote_peer
  
      assert "." not in self._local_peer
      assert "." not in self._remote_peer
  
      self._logger = _PrefixAdapter(
          logging.getLogger(__name__),
          {"prefix": f"(file channel {local_peer} -> {remote_peer})"},
      )
  
      self._file_capacity: int = 100000000  # 1e8
      self._line_limit_per_file: int = 100
  
      # For write. Next to write is 1.
      self._write_progress: int = 1
      self._recover_write_state()
  
      # For read. Has already read 0.
      self._read_progress: int = 0
      self._recover_read_state()
  
file_path: nni/nni/contrib/training_service/file_channel.py
imports: from __future__ import annotations
  import logging
  import time
  from pathlib import Path
label_desc: Use image node_id 1 to create a new FileChannel object  with example: obj = FileChannel(url, local_peer, remote_peer)