Skip to content

Commit c1da786

Browse files
committed
Merge remote-tracking branch 'upstream'
2 parents f70f74b + 1213397 commit c1da786

File tree

188 files changed

+6870
-1536
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

188 files changed

+6870
-1536
lines changed

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
<!-- ^^^ Describe your changes here ^^^ -->
3+
4+
## Checklist
5+
6+
<!--
7+
Check all that apply.
8+
9+
Note that these are not all required,
10+
but serves as information for reviewers.
11+
-->
12+
13+
- Testing:
14+
- [ ] The feature has automated tests
15+
- [ ] Tests were run
16+
- If not, explain how you tested your changes
17+
18+
- Documentation:
19+
- [ ] The feature is documented
20+
- [ ] The documentation is up to date
21+
- Release notes:
22+
- [ ] Added an entry if the change is breaking or significant
23+
- [ ] Added an entry when adding a new feature

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,5 @@ phoebus-product/settings_template.ini
123123

124124
# doc files generated by docs/source/conf.py
125125
docs/source/applications.rst
126-
docs/source/preference_properties.rst
127126
docs/source/services.rst
128127

app/alarm/examples/talk.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/bin/sh
2+
#
3+
# Send talk message
4+
5+
if [ $# -ne 2 ]
6+
then
7+
echo "Usage: talk.sh Accelerator Message"
8+
exit 1
9+
fi
10+
11+
topic="$1"
12+
text="$2"
13+
14+
kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --property 'parse.key=true' --property key.separator=" : " --topic ${topic}Talk <<END
15+
talk:/$topic/pv : {"severity":"MAJOR", "standout":true, "talk":"$text"}
16+
END
17+
18+

app/alarm/model/src/main/java/org/phoebus/applications/alarm/talk/TalkClient.java

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,19 @@
77
*******************************************************************************/
88
package org.phoebus.applications.alarm.talk;
99

10+
import static java.lang.Thread.sleep;
1011
import static org.phoebus.applications.alarm.AlarmSystem.logger;
12+
import static org.phoebus.applications.alarm.AlarmSystem.nag_period_ms;
1113

14+
import java.time.Duration;
15+
import java.time.Instant;
1216
import java.util.Collections;
1317
import java.util.List;
1418
import java.util.Objects;
19+
import java.util.Optional;
1520
import java.util.concurrent.CopyOnWriteArrayList;
1621
import java.util.concurrent.atomic.AtomicBoolean;
22+
import java.util.concurrent.atomic.AtomicReference;
1723
import java.util.logging.Level;
1824

1925
import org.apache.kafka.clients.consumer.Consumer;
@@ -41,7 +47,10 @@ public class TalkClient
4147
private final CopyOnWriteArrayList<TalkClientListener> listeners = new CopyOnWriteArrayList<>();
4248
private final AtomicBoolean running = new AtomicBoolean(true);
4349
private final Consumer<String, String> consumer;
50+
private final Consumer<String, String> heartbeatConsumer;
4451
private final Thread thread;
52+
private final Thread updateHeartbeatTimestampThread;
53+
private final Thread annunciateDisconnectionThread;
4554

4655
/** @param server - Kafka Server host:port
4756
* @param config_name - Name of kafka config topic that the talk topic accompanies.
@@ -56,6 +65,16 @@ public TalkClient(final String server, final String config_name)
5665

5766
thread = new Thread(this::run, "TalkClient");
5867
thread.setDaemon(true);
68+
69+
{
70+
heartbeatConsumer = KafkaHelper.connectConsumer(server, List.of(config_name), Collections.emptyList(), AlarmSystem.kafka_properties);
71+
updateHeartbeatTimestampThread = new Thread(() -> updateHeartbeatTimestampLoop(), "UpdateHeartbeatTimestampThread");
72+
updateHeartbeatTimestampThread.setDaemon(false);
73+
updateHeartbeatTimestampThread.start();
74+
annunciateDisconnectionThread = new Thread(() -> annunciateDisconnectionLoop(), "AnnunciateDisconnectionThread");
75+
annunciateDisconnectionThread.setDaemon(false);
76+
annunciateDisconnectionThread.start();
77+
}
5978
}
6079

6180
/** @param listener - Listener to add */
@@ -144,11 +163,62 @@ private void checkUpdates()
144163
}
145164
}
146165

166+
private Optional<Instant> nextDisconnectedAnnunciation = Optional.empty(); // When alarm server is disconnected: point in time for next annunciation of disconnection.
167+
private final Duration disconnectionAnnunciationPeriod = Duration.ofMillis(AlarmSystem.nag_period_ms);
168+
private final Duration idleTimeoutDuration = Duration.ofMillis(AlarmSystem.idle_timeout_ms).multipliedBy(3);
169+
private AtomicReference<Instant> lastReceivedUpdateFromAlarmServer = new AtomicReference<>(Instant.now());
170+
171+
private void updateHeartbeatTimestampLoop() {
172+
while (running.get()) {
173+
final ConsumerRecords<String, String> records = heartbeatConsumer.poll(100);
174+
if (!records.isEmpty()) {
175+
lastReceivedUpdateFromAlarmServer.set(Instant.now());
176+
}
177+
try {
178+
sleep(1000);
179+
} catch (InterruptedException e) {
180+
logger.log(Level.WARNING, "updateHeartbeatTimestampLoop() was interrupted when sleeping.");
181+
}
182+
}
183+
}
184+
185+
/** Background thread loop that detects and annunciates disconnections. */
186+
private void annunciateDisconnectionLoop() {
187+
while (running.get()) {
188+
Instant now = Instant.now();
189+
if (Duration.between(lastReceivedUpdateFromAlarmServer.get(), now).compareTo(idleTimeoutDuration) > 0) {
190+
if (nextDisconnectedAnnunciation.isEmpty() || nextDisconnectedAnnunciation.get().isBefore(now)) {
191+
try {
192+
for (final TalkClientListener listener : listeners) {
193+
listener.messageReceived(SeverityLevel.UNDEFINED, true, "Alarm Server Disconnected");
194+
}
195+
} catch (final Exception ex) {
196+
logger.log(Level.WARNING, "Talk error for " + SeverityLevel.UNDEFINED + ", " + "Alarm Server Disconnected", ex);
197+
}
198+
if (nag_period_ms > 0) {
199+
nextDisconnectedAnnunciation = Optional.of(now.plus(disconnectionAnnunciationPeriod)); // Annunciate disconnect again after nag period_ms
200+
}
201+
else {
202+
nextDisconnectedAnnunciation = Optional.of(Instant.MAX); // When nag_period_ms == 0, don't annunciate the disconnection again.
203+
}
204+
}
205+
} else {
206+
nextDisconnectedAnnunciation = Optional.empty(); // Connection to the Alarm Server exists.
207+
}
208+
try {
209+
sleep(1000);
210+
} catch (InterruptedException e) {
211+
logger.log(Level.WARNING, "annunciateDisconnectionLoop() was interrupted when sleeping.");
212+
}
213+
}
214+
}
215+
147216
/** Stop client */
148217
public void shutdown()
149218
{
150219
running.set(false);
151220
consumer.wakeup();
221+
heartbeatConsumer.wakeup();
152222
try
153223
{
154224
thread.join(2000);
@@ -157,6 +227,22 @@ public void shutdown()
157227
{
158228
logger.log(Level.WARNING, "Talk client thread doesn't shut down", ex);
159229
}
230+
try
231+
{
232+
annunciateDisconnectionThread.join(2000);
233+
}
234+
catch (final InterruptedException ex)
235+
{
236+
logger.log(Level.WARNING, "Annunciate Disconnection from Alarm Server thread doesn't shut down", ex);
237+
}
238+
try
239+
{
240+
updateHeartbeatTimestampThread.join(2000);
241+
}
242+
catch (final InterruptedException ex)
243+
{
244+
logger.log(Level.WARNING, "Update Alarm Server Heartbeat thread doesn't shut down", ex);
245+
}
160246
logger.info(thread.getName() + " shut down");
161247
}
162248
}

app/alarm/ui/src/main/resources/org/phoebus/applications/alarm/ui/messages_fr.properties

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ error=Erreur
22
acknowledgeFailed=\u00C9chec de l\u0027acquittement de(s) (\u0027)alarme(s)
33
addComponentFailed=\u00C9chec de l\u0027ajout du composant
44
disableAlarmFailed=\u00C9chec de la d\u00E9sactivation de l\u0027alarme
5+
disabled=D\u00E9sactiv\u00E9
6+
disabledUntil=D\u00E9sactiv\u00E9 jusqu\u0027\u00E0
57
enableAlarmFailed=\u00C9chec de l\u0027activation de l\u0027alarme
68
moveItemFailed=\u00C9chec du d\u00E9placement de l\u0027\u00E9l\u00E9ment
9+
partlyDisabled=Partiellement d\u00E9sactiv\u00E9
710
removeComponentFailed=\u00C9chec de la suppression du composant
811
renameItemFailed=\u00C9chec du renommage de l\u0027\u00E9l\u00E9ment
12+
timer=Minuteur
913
unacknowledgeFailed=\u00C9chec de la d\u00E9sacquittement de(s) (l\u0027)alarme(s)
3.55 KB
Loading
Binary file not shown.
30 KB
Loading
34.7 KB
Loading

app/credentials-management/doc/index.rst

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,25 @@ Further, Phoebus may be configured to store the credentials entered by the user
88
In order to also support an explicit logout capability, the Credentials Management application offers means to
99
remove stored credentials.
1010

11-
In some cases an explicit login procedure can be useful, e.g. login to service for the purpose of storing
12-
user credentials and thereby support automated creation of logbook entries.
13-
1411
The application is launched using the dedicated button in the (bottom) status bar.
1512

16-
The below screen shot shows an example where credentials have been stored for the "logbook" scope,
17-
plus an option to login to the "<remote service>" scope. User may also choose to "logout" from all scopes,
13+
The below screen shot shows an example where credentials have been stored for the "Logbook" scope,
14+
plus an option to login to the "<remote service>" scope. User may also choose to "Logout from all" services,
1815
i.e. to remove all stored credentials.
1916

2017
.. image:: images/CredentialsManagement.png
2118

22-
If no credentials are stored in the credentials store, and if no services supporting authentication have been configured,
19+
If no credentials are stored in the credentials store, and if no services supporting authentication are available,
2320
the Credentials Management UI will show a static message:
2421

25-
.. image:: images/CredentialsManagement_Empty.png
22+
.. image:: images/CredentialsManagement_empty.png
23+
24+
The "Login To All" button can be used to login to all services as a single action.
25+
In this case credentials entered in the text fields of toolbar at the top are used for all services, irrespective of
26+
the credentials (if any) entered in other input fields.
27+
28+
If login to a service fails (service off-line or invalid credentials), this is indicated in the "Login Result" column.
29+
30+
.. image:: images/CredentialsManagement_one_failed.png
31+
32+
If on the other hand login succeeds to a single or all services, the dialog is closed automatically.

0 commit comments

Comments
 (0)