mirror of
https://github.com/jlengrand/github-api.git
synced 2026-03-30 00:11:23 +00:00
239 lines
12 KiB
HTML
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> > <a href="index.source.html" class="el_package">org.kohsuke.github</a> > <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.
|
|
*
|
|
* <p>
|
|
* This class supports two modes of retrieving notifications that can be controlled via {@link #nonBlocking(boolean)}.
|
|
*
|
|
* <p>
|
|
* 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.
|
|
*
|
|
* <p>
|
|
* 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<GHThread> {
|
|
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<GHThread> iterator() {
|
|
// capture the configuration setting here
|
|
<span class="fc" id="L102"> final Requester req = root.createRequest()</span>
|
|
<span class="fc" id="L103"> .with("all", all)</span>
|
|
<span class="fc" id="L104"> .with("participating", participating)</span>
|
|
<span class="fc" id="L105"> .with("since", since);</span>
|
|
|
|
<span class="fc" id="L107"> return new Iterator<GHThread>() {</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 "If-Modified-Since" 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 >= 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 >= 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 && nextCheckTime >= 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 < 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("If-Modified-Since", lastModified);</span>
|
|
|
|
<span class="fc" id="L181"> Requester requester = req.withUrlPath(apiUrl);</span>
|
|
<span class="fc" id="L182"> GitHubResponse<GHThread[]> response = ((GitHubPageContentsIterable<GHThread>) 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("Last-Modified");</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<GHThread[]> response) {
|
|
<span class="fc" id="L203"> String v = response.headerField("X-Poll-Interval");</span>
|
|
<span class="pc bpc" id="L204" title="1 of 2 branches missed."> if (v == null)</span>
|
|
<span class="nc" id="L205"> v = "60";</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 >= 0)</span>
|
|
<span class="nc" id="L233"> req.with("last_read_at", 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> |