You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

471 lines
36 KiB
HTML

<!DOCTYPE html>
<html >
<head>
<meta charset="utf-8" />
<title>seiscomp.client &#8212; SeisComP Release documentation</title>
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../_static/seiscomp.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="../_static/graphviz.css" />
<script type="text/javascript" src="../_static/seiscomp.js"></script>
<script type="text/javascript" id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/language_data.js"></script>
<link rel="shortcut icon" href="../_static/favicon.ico"/>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="Examples" href="sdk-python-examples.html" />
<link rel="prev" title="seiscomp.datamodel" href="api-python.html" />
</head>
<body>
<div class="header">
<div class="container">
<div class="brand">
<img class="logo" src="../_static/brands/seiscomp/text/white.svg"/>
<!-- span class="title">SeisComP Release</span -->
<span class="version">5.3.0</span>
</div>
</div>
</div>
<div class="nav">
<div class="container">
<div class="content"><a class="pull-right" id="sidebar-toggle">TOC</a>
<div class="related" role="navigation" aria-label="related navigation">
<ul>
<li class="right">
<a href="../genindex.html" title="General Index"
accesskey="I">
index
</a>
</li>
<li class="right">
<a href="sdk-python-examples.html" title="Examples"
accesskey="N">
next
</a>
</li>
<li class="right">
<a href="api-python.html" title="seiscomp.datamodel"
accesskey="P">
previous
</a>
</li>
<li class="nav-item nav-item-0">
<a href="../index.html">Home</a>
</li>
<li class="nav-item nav-item-1">
<a href="sdk.html" >Software Development Kit</a>
</li>
<li class="nav-item nav-item-2">
<a href="sdk-python.html" >Python</a>
</li>
<li class="nav-item nav-item-3">
<a href="sdk-python-packages.html" accesskey="U">Packages</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="container">
<div class="fitted content" id="anchors-container">
<div class="body" role="main">
<div class="section" id="module-seiscomp.client">
<span id="seiscomp-client"></span><span id="api-client-python"></span><h1>seiscomp.client<a class="headerlink" href="#module-seiscomp.client" title="Permalink to this headline"></a></h1>
<p>Modules are meant to be standalone programs doing a particular job. The
seiscomp.client package focuses on three main aspects:</p>
<ul class="simple">
<li><p>Communicate with other modules</p></li>
<li><p>Access station- and event metadata through a database</p></li>
<li><p>Fetch waveform data</p></li>
</ul>
<p>Therefore a client package has been developed combining these concepts in an
easy way with only a couple of API calls. Since <cite>SeisComP</cite> has been developed in
C++ and uses the object oriented paradigm forcefully, modules build on the
Application (C++: <code class="xref py py-class docutils literal notranslate"><span class="pre">Seiscomp::Client::Application</span></code>, Python:
<code class="xref py py-class docutils literal notranslate"><span class="pre">seiscomp.client.Application</span></code>) class. It manages the messaging connection
and waveform sources in a transparent way.</p>
<p>The class <code class="xref py py-class docutils literal notranslate"><span class="pre">Seiscomp::Client::Application</span></code> is the base class for
all <cite>SeisComP</cite> applications. It manages messaging and database
connections, provides access to command line options and configuration
parameters and also handles and interprets notifier messages.</p>
<p>Blocking network operations like reading messages are moved into threads that
are synchronized in a single blocking message queue. This queue allows pushing
elements from different threads and unblocks when a new element is ready to be
popped. If the queue is full (currently 10 elements are allowed) the pushing
threads also block until an element can be pushed again.</p>
<p>This way applications do not have to poll and thus do not burn CPU cycles.</p>
<p>The application class is event driven. It runs the event loop which pops the
message queue and dispatches events with their handlers. Handler methods are
prefixed with <em>handle</em>, e.g. <code class="xref py py-func docutils literal notranslate"><span class="pre">handleMessage()</span></code>.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>When overriding handlers it is always good practise to call the base
handlers before running custom code.</p>
</div>
<div class="section" id="application-class">
<h2>Application class<a class="headerlink" href="#application-class" title="Permalink to this headline"></a></h2>
<p>The application class is part of the seiscomp.client package. It needs to
be imported first.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">seiscomp.client</span>
</pre></div>
</div>
<p>A common strategy to write a module with that class is to derive from it and
run it in a Python main method.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">seiscomp.client</span>
<span class="c1"># Class definition</span>
<span class="k">class</span> <span class="nc">MyApp</span><span class="p">(</span><span class="n">seiscomp</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">Application</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">argc</span><span class="p">,</span> <span class="n">argv</span><span class="p">):</span>
<span class="n">seiscomp</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">Application</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">argc</span><span class="p">,</span> <span class="n">argv</span><span class="p">)</span>
<span class="c1"># Main method to call the app</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">argc</span><span class="p">,</span> <span class="n">argv</span><span class="p">):</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">MyApp</span><span class="p">(</span><span class="n">argc</span><span class="p">,</span> <span class="n">argv</span><span class="p">)</span>
<span class="k">return</span> <span class="n">app</span><span class="p">()</span>
<span class="c1"># Call the main method if run as script</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&quot;__main__&quot;</span><span class="p">:</span>
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="n">main</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">),</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">))</span>
</pre></div>
</div>
<p>An application can be called with the parenthesis operator <code class="xref py py-func docutils literal notranslate"><span class="pre">()</span></code> which
returns the applications result code and serves as input to <code class="xref py py-func docutils literal notranslate"><span class="pre">sys.exit()</span></code>.
Operator() is a wrapper for <code class="xref py py-func docutils literal notranslate"><span class="pre">Application.exec()</span></code>.</p>
<p>The workflow of <code class="xref py py-func docutils literal notranslate"><span class="pre">Application.exec()</span></code> looks as follows:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">exec</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">returnCode</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">init</span><span class="p">()</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">run</span><span class="p">():</span>
<span class="bp">self</span><span class="o">.</span><span class="n">returnCode</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">done</span><span class="p">()</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">returnCode</span>
</pre></div>
</div>
<p><code class="xref py py-func docutils literal notranslate"><span class="pre">init()</span></code>, <code class="xref py py-func docutils literal notranslate"><span class="pre">run()</span></code> and <code class="xref py py-func docutils literal notranslate"><span class="pre">done()</span></code> are explained in more detail in
the next sections.</p>
<div class="section" id="constructor">
<h3>Constructor<a class="headerlink" href="#constructor" title="Permalink to this headline"></a></h3>
<p>To create an application, derive from the seiscomp.client.Application class
and configure it in the constructor.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MyApp</span><span class="p">(</span><span class="n">seiscomp</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">Application</span><span class="p">):</span>
<span class="c1"># MyApp constructor</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">argc</span><span class="p">,</span> <span class="n">argv</span><span class="p">):</span>
<span class="c1"># IMPORTANT: call the base class constructor</span>
<span class="n">seiscomp</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">Application</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">argc</span><span class="p">,</span> <span class="n">argv</span><span class="p">)</span>
<span class="c1"># Default is TRUE</span>
<span class="hll"> <span class="bp">self</span><span class="o">.</span><span class="n">setMessagingEnabled</span><span class="p">(</span><span class="bp">False</span><span class="p">)</span>
</span> <span class="c1"># Default is TRUE, TRUE</span>
<span class="hll"> <span class="bp">self</span><span class="o">.</span><span class="n">setDatabaseEnabled</span><span class="p">(</span><span class="bp">False</span><span class="p">,</span> <span class="bp">False</span><span class="p">)</span>
</span> <span class="c1"># Default is TRUE</span>
<span class="hll"> <span class="bp">self</span><span class="o">.</span><span class="n">setDaemonEnabled</span><span class="p">(</span><span class="bp">False</span><span class="p">)</span>
</span></pre></div>
</td></tr></table></div>
<p>As marked in line 4, the call of the constructor of the base class is very
important. It takes the command line parameters and sets up internal
application variables. Without this call the application will either not run
at all or show undefined/unexpected behaviour.</p>
<p>The constructor takes also the initial parameters of the application such as
enabling a messaging connection and enabling database access.</p>
<p>Messaging, database and daemon mode is enabled by default. The daemon mode is
important if the application should be started as service and therefore should
support the option <code class="docutils literal notranslate"><span class="pre">-D,</span> <span class="pre">--daemon</span></code>. Utilities and non daemon applications
should disable that mode.</p>
<p>Example calls to this options are shown in the highlighted lines of the above
code block.</p>
<p>If messaging is enabled, the messaging username is derived from the binary
called (<em>not the class name</em>). If the script is called test.py then the username
selected is <strong>test</strong>. The username can be overridden either in the configuration
file (<a class="reference internal" href="../apps/global.html#global"><span class="std std-ref">Global parameters</span></a>) or using the API.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="bp">self</span><span class="o">.</span><span class="n">setMessagingUsername</span><span class="p">(</span><span class="s2">&quot;test&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Setting the username to an empty string results in a random username selected
by the messaging server.</p>
<p>All application methods are defined in the C++ header file
<code class="file docutils literal notranslate"><span class="pre">src/trunk/libs/seiscomp/client/application.h</span></code>.</p>
</div>
<div class="section" id="init">
<h3>Init<a class="headerlink" href="#init" title="Permalink to this headline"></a></h3>
<p>The workflow of the init function looks like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">init</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="n">initConfiguration</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="n">initCommandLine</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="n">createCommandLineDescription</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="n">parseCommandLine</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="n">printUsage</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="n">validateParameters</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="n">loadPlugins</span>
<span class="n">forkDaemon</span>
<span class="n">initMessaging</span>
<span class="n">initDatabase</span>
<span class="n">loadInventory</span> <span class="ow">or</span> <span class="n">loadStations</span>
<span class="n">loadDBConfigModule</span>
<span class="n">loadCities</span>
</pre></div>
</div>
<p>Methods marked with virtual can be overridden. <code class="xref py py-func docutils literal notranslate"><span class="pre">init()</span></code> itself calls
a lot of handlers that can be customized. Typical handlers are
<code class="xref py py-func docutils literal notranslate"><span class="pre">initConfiguration()</span></code>, <code class="xref py py-func docutils literal notranslate"><span class="pre">createCommandLineDescription()</span></code>
and <code class="xref py py-func docutils literal notranslate"><span class="pre">validateParameters()</span></code>.</p>
<p><code class="xref py py-func docutils literal notranslate"><span class="pre">initConfiguration()</span></code> is used to read parameters of the configuration files
and to populate the internal state. If something fails or if configured values
are out of bounds, False can be returned which causes <code class="xref py py-func docutils literal notranslate"><span class="pre">init()</span></code> to return
False and to exit the application with a non-zero result code.</p>
<p>An example is show below:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">initConfiguration</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">seiscomp</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">Application</span><span class="o">.</span><span class="n">initConfiguration</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">False</span>
<span class="k">try</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_directory</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">configGetString</span><span class="p">(</span><span class="s2">&quot;directory&quot;</span><span class="p">)</span>
<span class="k">except</span><span class="p">:</span>
<span class="k">pass</span>
<span class="k">return</span> <span class="bp">True</span>
</pre></div>
</div>
<p>This method reads the directory parameter from the configuration file(s) and
sets it internally. If the directory is not given in any of the modules
configuration files, it logs an error and aborts the application by returning
False.</p>
<p><code class="xref py py-func docutils literal notranslate"><span class="pre">createCommandLineDescription()</span></code> is used to add custom command line options.
This is a void function and does not return any value. It is also not necessary
to call the base class method although it does not hurt.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">createCommandLineDescription</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">commandline</span><span class="p">()</span><span class="o">.</span><span class="n">addGroup</span><span class="p">(</span><span class="s2">&quot;Storage&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">commandline</span><span class="p">()</span><span class="o">.</span><span class="n">addStringOption</span><span class="p">(</span><span class="s2">&quot;Storage&quot;</span><span class="p">,</span> <span class="s2">&quot;directory,o&quot;</span><span class="p">,</span> <span class="s2">&quot;Specify the storage directory&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>A new command line option group is added with <code class="xref py py-func docutils literal notranslate"><span class="pre">addGroup()</span></code> and then a new
option is added to this group which is a string option.
Four types can be added
as options: string, int, double and bool: <code class="xref py py-func docutils literal notranslate"><span class="pre">addStringOption()</span></code>, <code class="xref py py-func docutils literal notranslate"><span class="pre">addIntOption()</span></code>,
<code class="xref py py-func docutils literal notranslate"><span class="pre">addDoubleOption()</span></code> and <code class="xref py py-func docutils literal notranslate"><span class="pre">addBoolOption()</span></code>.</p>
<p><code class="xref py py-func docutils literal notranslate"><span class="pre">validateParameters()</span></code> can be used to fetch the values of previously added
command line options and to validate each parameter. If False is returned, the
application is aborted with a non-zero result code.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">validateParameters</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_directory</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">commandline</span><span class="p">()</span><span class="o">.</span><span class="n">optionString</span><span class="p">(</span><span class="s2">&quot;directory&quot;</span><span class="p">)</span>
<span class="k">except</span><span class="p">:</span>
<span class="k">pass</span>
<span class="c1"># The directory validity is checked to avoid duplicate checks in</span>
<span class="c1"># initConfiguration.</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_directory</span><span class="p">:</span>
<span class="n">seiscomp</span><span class="o">.</span><span class="n">logging</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">&quot;directory not set&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">False</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">exists</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_directory</span><span class="p">):</span>
<span class="n">seiscomp</span><span class="o">.</span><span class="n">logging</span><span class="o">.</span><span class="n">error</span><span class="p">(</span>
<span class="s2">&quot;directory {} does not exist&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_directory</span><span class="p">))</span>
<span class="k">return</span> <span class="bp">False</span>
<span class="k">return</span> <span class="bp">True</span>
</pre></div>
</div>
<p>Custom initialization code after checking all parameters can be placed in the
overridden method <code class="xref py py-func docutils literal notranslate"><span class="pre">init()</span></code>.</p>
<p>But be aware that the process forked already if started as daemon. To run before
the fork, it needs to be put into <code class="xref py py-func docutils literal notranslate"><span class="pre">validateParameters()</span></code>.</p>
</div>
<div class="section" id="run">
<h3>Run<a class="headerlink" href="#run" title="Permalink to this headline"></a></h3>
<p>The workflow of the run method looks like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">run</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="n">startMessageThread</span>
<span class="n">messageLoop</span>
<span class="n">readMessage</span>
<span class="n">dispatchMessage</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="n">handleMessage</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="n">addObject</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="n">updateObject</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="n">removeObject</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="n">handleReconnect</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="n">handleDisconnect</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="n">handleTimeout</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="n">handleAutoShutdown</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
</pre></div>
</div>
<p>The run method starts the event loop and waits for new events in the queue.
In case of messaging a thread is started that sits and waits for messages
and feeds them to the queue and to the event loop in <code class="xref py py-func docutils literal notranslate"><span class="pre">run()</span></code>. Without
messaging the run loop would do nothing but waiting for SIGTERM or
a timer event enabled with <code class="xref py py-func docutils literal notranslate"><span class="pre">enableTimer()</span></code>. If the event loop is not needed
because no timer and messages are needed, it should be overridden and the
code should be placed there. This will disable the event loop.</p>
<p><code class="xref py py-func docutils literal notranslate"><span class="pre">run()</span></code> is expected to return True on success and False otherwise. If False
is returned the application exists with a non-zero return code. Custom return
codes can always be set with <code class="xref py py-func docutils literal notranslate"><span class="pre">Application.exit()</span></code>.</p>
<p>If the scmaster sends a message to the client it is received in the applications
message thread and pushed to the queue. The event loop pops the message from
the queue and calls <code class="xref py py-func docutils literal notranslate"><span class="pre">handleMessage()</span></code>. The default implementation uses two
settings when handling a messages that can be controlled with
<code class="xref py py-func docutils literal notranslate"><span class="pre">enableInterpretNotifier()</span></code> and <code class="xref py py-func docutils literal notranslate"><span class="pre">enableAutoApplyNotifier()</span></code>.</p>
<p><code class="xref py py-func docutils literal notranslate"><span class="pre">enableInterpretNotifier()</span></code> controls whether the Application queries the
message type and extracts notifier objects. For each notifier it parses the
operation and dispatches the parentID and the object either to
<code class="xref py py-func docutils literal notranslate"><span class="pre">addObject()</span></code>, <code class="xref py py-func docutils literal notranslate"><span class="pre">updateObject()</span></code> or <code class="xref py py-func docutils literal notranslate"><span class="pre">removeObject()</span></code> handler. This
behaviour is enabled by default. If disabled, a clients needs to parse the
messages by itself and implement this method.</p>
<p><code class="xref py py-func docutils literal notranslate"><span class="pre">enableAutoApplyNotifier()</span></code> controls whether incoming notifier objects are
applied automatically to objects in local memory. If the client has already
an object in memory and an update notifier for this object is received, the object
in the notifier is copied to the local object. This behaviour is enabled by default.</p>
</div>
<div class="section" id="done">
<h3>Done<a class="headerlink" href="#done" title="Permalink to this headline"></a></h3>
<p>The workflow of the done method looks like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">done</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="n">closeTimer</span>
<span class="n">closeMessaging</span>
<span class="n">closeDatabase</span>
</pre></div>
</div>
<p><code class="xref py py-func docutils literal notranslate"><span class="pre">done()</span></code> is usually not overridden. If custom code and clean up procedures
need to be placed in <code class="xref py py-func docutils literal notranslate"><span class="pre">done()</span></code>, the base class <strong>must</strong> be called. <code class="xref py py-func docutils literal notranslate"><span class="pre">done()</span></code> is a
void function.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">done</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">seiscomp</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">Application</span><span class="o">.</span><span class="n">done</span><span class="p">()</span>
<span class="c1"># Custom clean ups</span>
<span class="n">closeMyDataFiles</span><span class="p">()</span>
<span class="n">closeCustomConnections</span><span class="p">()</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="streamapplication-class">
<h2>StreamApplication class<a class="headerlink" href="#streamapplication-class" title="Permalink to this headline"></a></h2>
<p>The application class has another occurrence: <code class="xref py py-class docutils literal notranslate"><span class="pre">seiscomp.client.StreamApplication</span></code>.</p>
<p>The class <code class="xref py py-class docutils literal notranslate"><span class="pre">StreamApplication</span></code> extends the <code class="xref py py-class docutils literal notranslate"><span class="pre">Application</span></code>
in terms of record acquisition. It spawns another thread that reads the records
from a configurable source and adds a new handler method
<code class="xref py py-func docutils literal notranslate"><span class="pre">StreamApplication.handleRecord()</span></code> to handle these records.</p>
<p>Its workflow looks like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">init</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="o">+</span><span class="n">initRecordStream</span>
<span class="n">run</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="o">+</span><span class="n">startAcquisitionThread</span>
<span class="o">+</span><span class="n">storeRecord</span>
<span class="n">Application</span><span class="o">.</span><span class="n">messageLoop</span>
<span class="n">dispatchMessage</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="o">+</span><span class="n">handleRecord</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="n">done</span> <span class="p">(</span><span class="n">virtual</span><span class="p">)</span>
<span class="o">+</span><span class="n">closeRecordStream</span>
</pre></div>
</div>
<p>Received records can be handled with <code class="xref py py-func docutils literal notranslate"><span class="pre">handleRecord()</span></code>.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">handleRecord</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">rec</span><span class="p">):</span>
<span class="k">print</span> <span class="n">rec</span><span class="o">.</span><span class="n">streamID</span><span class="p">()</span>
</pre></div>
</div>
<p>The stream subscription should be done in <code class="xref py py-func docutils literal notranslate"><span class="pre">init()</span></code>. <code class="xref py py-func docutils literal notranslate"><span class="pre">recordStream()</span></code>
returns the RecordStream instance which can be used to add stream requests.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">seiscomp</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">StreamApplication</span><span class="o">.</span><span class="n">init</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">False</span>
<span class="c1"># Subscribe to some streams</span>
<span class="bp">self</span><span class="o">.</span><span class="n">recordStream</span><span class="p">()</span><span class="o">.</span><span class="n">addStream</span><span class="p">(</span><span class="s2">&quot;GE&quot;</span><span class="p">,</span> <span class="s2">&quot;MORC&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="s2">&quot;BHZ&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">True</span>
</pre></div>
</div>
<p>The record stream service is configured either with configuration files
(<a class="reference internal" href="../apps/global.html#confval-recordstream"><code class="xref std std-confval docutils literal notranslate"><span class="pre">recordstream</span></code></a>) or
via command-line options <code class="docutils literal notranslate"><span class="pre">-I`,</span> <span class="pre">``--record-url</span></code>.</p>
<p>The application finishes if the record stream read EOF. Running a <code class="xref py py-class docutils literal notranslate"><span class="pre">StreamApplication</span></code>
with <a class="reference internal" href="../apps/seedlink.html#seedlink"><span class="std std-ref">Seedlink</span></a> would probably never terminate since it is a
real time connection and handles reconnects automatically.</p>
</div>
</div>
<div id="anchors-bottom"></div>
</div>
<div class="sidebar" role="navigation" aria-label="main navigation">
<div id="anchors-top"></div>
<div id="anchors" class="content">
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">seiscomp.client</a><ul>
<li><a class="reference internal" href="#application-class">Application class</a><ul>
<li><a class="reference internal" href="#constructor">Constructor</a></li>
<li><a class="reference internal" href="#init">Init</a></li>
<li><a class="reference internal" href="#run">Run</a></li>
<li><a class="reference internal" href="#done">Done</a></li>
</ul>
</li>
<li><a class="reference internal" href="#streamapplication-class">StreamApplication class</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="api-python.html"
title="previous chapter">seiscomp.datamodel</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="sdk-python-examples.html"
title="next chapter">Examples</a></p>
<div role="note" aria-label="source link">
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="../_sources/base/api-python-client.rst.txt"
rel="nofollow">Show Source</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="footer">
<div class="container">
<div class="horizontal layout content">
<a class="fade-in" href="https://www.gempa.de" target="_blank">
<img class="brand" src="../_static/brands/gempa.svg"/>
</a>
<div class="stretched align-center fitted content">
<div>
Version <b>5.3.0</b> Release
</div>
<div class="copyright">
Copyright &copy; gempa GmbH, GFZ Potsdam.
</div>
</div>
<a class="fade-in" href="https://www.gfz-potsdam.de" target="_blank">
<img class="brand" src="../_static/brands/gfz.svg"/>
</a>
</div>
</div>
</div>
</body>
</html>