Files
github-api/jacoco/org.kohsuke.github/GHNotificationStream.java.html
2021-06-02 11:09:28 -07:00

239 lines
12 KiB
HTML

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>GHNotificationStream.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">GitHub API for Java</a> &gt; <a href="index.source.html" class="el_package">org.kohsuke.github</a> &gt; <span class="el_source">GHNotificationStream.java</span></div><h1>GHNotificationStream.java</h1><pre class="source lang-java linenums">package org.kohsuke.github;
import java.io.IOException;
import java.util.Date;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Listens to GitHub notification stream.
*
* &lt;p&gt;
* This class supports two modes of retrieving notifications that can be controlled via {@link #nonBlocking(boolean)}.
*
* &lt;p&gt;
* In the blocking mode, which is the default, iterator will be infinite. The call to {@link Iterator#next()} will block
* until a new notification arrives. This is useful for application that runs perpetually and reacts to notifications.
*
* &lt;p&gt;
* In the non-blocking mode, the iterator will only report the set of notifications initially retrieved from GitHub,
* then quit. This is useful for a batch application to process the current set of notifications.
*
* @author Kohsuke Kawaguchi
* @see GitHub#listNotifications() GitHub#listNotifications()
* @see GHRepository#listNotifications() GHRepository#listNotifications()
*/
public class GHNotificationStream extends GitHubInteractiveObject implements Iterable&lt;GHThread&gt; {
private Boolean all, participating;
private String since;
private String apiUrl;
<span class="fc" id="L30"> private boolean nonBlocking = false;</span>
<span class="fc" id="L32"> GHNotificationStream(GitHub root, String apiUrl) {</span>
<span class="fc" id="L33"> this.root = root;</span>
<span class="fc" id="L34"> this.apiUrl = apiUrl;</span>
<span class="fc" id="L35"> }</span>
/**
* Should the stream include notifications that are already read?
*
* @param v
* the v
* @return the gh notification stream
*/
public GHNotificationStream read(boolean v) {
<span class="fc" id="L45"> all = v;</span>
<span class="fc" id="L46"> return this;</span>
}
/**
* Should the stream be restricted to notifications in which the user is directly participating or mentioned?
*
* @param v
* the v
* @return the gh notification stream
*/
public GHNotificationStream participating(boolean v) {
<span class="nc" id="L57"> participating = v;</span>
<span class="nc" id="L58"> return this;</span>
}
/**
* Since gh notification stream.
*
* @param timestamp
* the timestamp
* @return the gh notification stream
*/
public GHNotificationStream since(long timestamp) {
<span class="nc" id="L69"> return since(new Date(timestamp));</span>
}
/**
* Since gh notification stream.
*
* @param dt
* the dt
* @return the gh notification stream
*/
public GHNotificationStream since(Date dt) {
<span class="nc" id="L80"> since = GitHubClient.printDate(dt);</span>
<span class="nc" id="L81"> return this;</span>
}
/**
* If set to true, {@link #iterator()} will stop iterating instead of blocking and waiting for the updates to
* arrive.
*
* @param v
* the v
* @return the gh notification stream
*/
public GHNotificationStream nonBlocking(boolean v) {
<span class="fc" id="L93"> this.nonBlocking = v;</span>
<span class="fc" id="L94"> return this;</span>
}
/**
* Returns an infinite blocking {@link Iterator} that returns {@link GHThread} as notifications arrive.
*/
public Iterator&lt;GHThread&gt; iterator() {
// capture the configuration setting here
<span class="fc" id="L102"> final Requester req = root.createRequest()</span>
<span class="fc" id="L103"> .with(&quot;all&quot;, all)</span>
<span class="fc" id="L104"> .with(&quot;participating&quot;, participating)</span>
<span class="fc" id="L105"> .with(&quot;since&quot;, since);</span>
<span class="fc" id="L107"> return new Iterator&lt;GHThread&gt;() {</span>
/**
* Stuff we've fetched but haven't returned to the caller. Newer ones first.
*/
<span class="fc" id="L111"> private GHThread[] threads = EMPTY_ARRAY;</span>
/**
* Next element in {@link #threads} to return. This counts down.
*/
<span class="fc" id="L116"> private int idx = -1;</span>
/**
* threads whose updated_at is older than this should be ignored.
*/
<span class="fc" id="L121"> private long lastUpdated = -1;</span>
/**
* Next request should have &quot;If-Modified-Since&quot; header with this value.
*/
private String lastModified;
/**
* When is the next polling allowed?
*/
<span class="fc" id="L131"> private long nextCheckTime = -1;</span>
private GHThread next;
public GHThread next() {
<span class="pc bpc" id="L136" title="1 of 2 branches missed."> if (next == null) {</span>
<span class="nc" id="L137"> next = fetch();</span>
<span class="nc bnc" id="L138" title="All 2 branches missed."> if (next == null)</span>
<span class="nc" id="L139"> throw new NoSuchElementException();</span>
}
<span class="fc" id="L142"> GHThread r = next;</span>
<span class="fc" id="L143"> next = null;</span>
<span class="fc" id="L144"> return r;</span>
}
public boolean hasNext() {
<span class="pc bpc" id="L148" title="1 of 2 branches missed."> if (next == null)</span>
<span class="fc" id="L149"> next = fetch();</span>
<span class="fc bfc" id="L150" title="All 2 branches covered."> return next != null;</span>
}
GHThread fetch() {
try {
while (true) {// loop until we get new threads to return
// if we have fetched un-returned threads, use them first
<span class="fc bfc" id="L158" title="All 2 branches covered."> while (idx &gt;= 0) {</span>
<span class="fc" id="L159"> GHThread n = threads[idx--];</span>
<span class="fc" id="L160"> long nt = n.getUpdatedAt().getTime();</span>
<span class="fc bfc" id="L161" title="All 2 branches covered."> if (nt &gt;= lastUpdated) {</span>
<span class="fc" id="L162"> lastUpdated = nt;</span>
<span class="fc" id="L163"> return n.wrap(root);</span>
}
<span class="fc" id="L165"> }</span>
<span class="pc bpc" id="L167" title="1 of 4 branches missed."> if (nonBlocking &amp;&amp; nextCheckTime &gt;= 0)</span>
<span class="fc" id="L168"> return null; // nothing more to report, and we aren't blocking</span>
// observe the polling interval before making the call
while (true) {
<span class="fc" id="L172"> long now = System.currentTimeMillis();</span>
<span class="pc bpc" id="L173" title="1 of 2 branches missed."> if (nextCheckTime &lt; now)</span>
<span class="fc" id="L174"> break;</span>
<span class="nc" id="L175"> long waitTime = Math.min(Math.max(nextCheckTime - now, 1000), 60 * 1000);</span>
<span class="nc" id="L176"> Thread.sleep(waitTime);</span>
<span class="nc" id="L177"> }</span>
<span class="fc" id="L179"> req.setHeader(&quot;If-Modified-Since&quot;, lastModified);</span>
<span class="fc" id="L181"> Requester requester = req.withUrlPath(apiUrl);</span>
<span class="fc" id="L182"> GitHubResponse&lt;GHThread[]&gt; response = ((GitHubPageContentsIterable&lt;GHThread&gt;) requester</span>
<span class="fc" id="L183"> .toIterable(GHThread[].class, null)).toResponse();</span>
<span class="fc" id="L184"> threads = response.body();</span>
<span class="pc bpc" id="L186" title="1 of 2 branches missed."> if (threads == null) {</span>
<span class="nc" id="L187"> threads = EMPTY_ARRAY; // if unmodified, we get empty array</span>
} else {
// we get a new batch, but we want to ignore the ones that we've seen
<span class="fc" id="L190"> lastUpdated++;</span>
}
<span class="fc" id="L192"> idx = threads.length - 1;</span>
<span class="fc" id="L194"> nextCheckTime = calcNextCheckTime(response);</span>
<span class="fc" id="L195"> lastModified = response.headerField(&quot;Last-Modified&quot;);</span>
<span class="fc" id="L196"> }</span>
<span class="nc" id="L197"> } catch (IOException | InterruptedException e) {</span>
<span class="nc" id="L198"> throw new RuntimeException(e);</span>
}
}
private long calcNextCheckTime(GitHubResponse&lt;GHThread[]&gt; response) {
<span class="fc" id="L203"> String v = response.headerField(&quot;X-Poll-Interval&quot;);</span>
<span class="pc bpc" id="L204" title="1 of 2 branches missed."> if (v == null)</span>
<span class="nc" id="L205"> v = &quot;60&quot;;</span>
<span class="fc" id="L206"> long seconds = Integer.parseInt(v);</span>
<span class="fc" id="L207"> return System.currentTimeMillis() + seconds * 1000;</span>
}
};
}
/**
* Mark as read.
*
* @throws IOException
* the io exception
*/
public void markAsRead() throws IOException {
<span class="fc" id="L219"> markAsRead(-1);</span>
<span class="fc" id="L220"> }</span>
/**
* Marks all the notifications as read.
*
* @param timestamp
* the timestamp
* @throws IOException
* the io exception
*/
public void markAsRead(long timestamp) throws IOException {
<span class="fc" id="L231"> final Requester req = root.createRequest();</span>
<span class="pc bpc" id="L232" title="1 of 2 branches missed."> if (timestamp &gt;= 0)</span>
<span class="nc" id="L233"> req.with(&quot;last_read_at&quot;, GitHubClient.printDate(new Date(timestamp)));</span>
<span class="fc" id="L234"> req.withUrlPath(apiUrl).fetchHttpStatusCode();</span>
<span class="fc" id="L235"> }</span>
<span class="fc" id="L237"> private static final GHThread[] EMPTY_ARRAY = new GHThread[0];</span>
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.7.202105040129</span></div></body></html>