Skip to content

Commit 0c63c8d

Browse files
authored
Merge pull request #3492 from ControlSystemStudio/pva_server_info
PVA: Open server info API
2 parents ae777dd + d30d7b0 commit 0c63c8d

File tree

4 files changed

+81
-12
lines changed

4 files changed

+81
-12
lines changed

core/pva/src/main/java/org/epics/pva/client/PVAClientMain.java

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
package org.epics.pva.client;
99

1010
import java.util.ArrayList;
11+
import java.util.Arrays;
1112
import java.util.Iterator;
1213
import java.util.List;
1314
import java.util.concurrent.CountDownLatch;
@@ -17,9 +18,11 @@
1718
import java.util.logging.Level;
1819
import java.util.logging.LogManager;
1920
import java.util.logging.Logger;
21+
import java.util.stream.Collectors;
2022

2123
import org.epics.pva.PVASettings;
2224
import org.epics.pva.data.PVAData;
25+
import org.epics.pva.data.PVAStructure;
2326

2427
/** Command line tool for PVA client
2528
*
@@ -37,9 +40,17 @@ public class PVAClientMain
3740
private static boolean completion = false;
3841
private static String request = "";
3942

43+
/** Commands */
44+
private static enum Cmd
45+
{
46+
info, get, monitor, put, call, beacons
47+
}
48+
4049
private static void help()
4150
{
42-
System.out.println("USAGE: pvaclient info|get|monitor|put|beacons [options] <PV name>...");
51+
System.out.println("USAGE: pvaclient " +
52+
Arrays.stream(Cmd.values()).map(Object::toString).collect(Collectors.joining("|")) +
53+
" [options] <PV name>...");
4354
System.out.println();
4455
System.out.println("Options:");
4556
System.out.println(" -h Help");
@@ -54,6 +65,7 @@ private static void help()
5465
System.out.println("get <PV name> Read PV's value");
5566
System.out.println("monitor <PV name> Subscribe to PV's value changes");
5667
System.out.println("put <PV name> <value> Write value to PV");
68+
System.out.println("call <PV name> Call RPC PV (no request params)");
5769
System.out.println("beacons Display received beacons");
5870
}
5971

@@ -240,6 +252,36 @@ private static void put(final String name, final String value) throws Exception
240252
}
241253
}
242254

255+
private static void call(final String name, final PVAStructure request) throws Exception
256+
{
257+
try (final PVAClient pva = new PVAClient())
258+
{
259+
final CountDownLatch connected = new CountDownLatch(1);
260+
final PVAChannel pv = pva.getChannel(name, (ch, state) ->
261+
{
262+
if (state == ClientChannelState.CONNECTED)
263+
connected.countDown();
264+
});
265+
final long timeout_ms = Math.round(seconds*1000);
266+
if (! connected.await(timeout_ms, TimeUnit.MILLISECONDS))
267+
{
268+
System.err.println("Timeout waiting for " + name);
269+
return;
270+
}
271+
272+
try
273+
{
274+
PVAStructure result = pv.invoke(request).get(timeout_ms, TimeUnit.MILLISECONDS);
275+
System.out.println(result);
276+
}
277+
catch (TimeoutException ex)
278+
{
279+
System.err.println("Call timed out");
280+
}
281+
pv.close();
282+
}
283+
}
284+
243285
/** Watch received beacons
244286
* @throws Exception on error
245287
*/
@@ -336,21 +378,27 @@ else if (arg.startsWith("-"))
336378

337379
final String command = names.remove(0);
338380

339-
if (command.equals("beacons") && names.size() == 0)
381+
if (command.equals(Cmd.beacons.name()) && names.size() == 0)
340382
beacons();
341-
else if (command.equals("info") && names.size() > 0)
383+
else if (command.equals(Cmd.info.name()) && names.size() > 0)
342384
info(names);
343-
else if (command.equals("get") && names.size() > 0)
385+
else if (command.equals(Cmd.get.name()) && names.size() > 0)
344386
get(names);
345-
else if (command.equals("monitor") && names.size() > 0)
387+
else if (command.equals(Cmd.monitor.name()) && names.size() > 0)
346388
monitor(names);
347-
else if (command.equals("put") && names.size() == 2)
389+
else if (command.equals(Cmd.put.name()) && names.size() == 2)
348390
{
349391
// By default, write to the 'value' element data structure
350392
if (request.isEmpty())
351393
request = "value";
352394
put(names.get(0), names.get(1));
353395
}
396+
else if (command.equals(Cmd.call.name()) && names.size() > 0)
397+
{
398+
// For now not supporting any request detail from cmdline
399+
PVAStructure request = new PVAStructure("", "");
400+
call(names.get(0), request);
401+
}
354402
else
355403
help();
356404
}

core/pva/src/main/java/org/epics/pva/data/nt/PVATable.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@
4848
*/
4949
public class PVATable extends PVAStructure {
5050
public static final String STRUCT_NAME = "epics:nt/NTTable:1.0";
51-
private static final String LABELS_NAME = "labels";
52-
private static final String VALUE_NAME = "value";
53-
private static final String DESCRIPTOR_NAME = "descriptor";
51+
public static final String LABELS_NAME = "labels";
52+
public static final String VALUE_NAME = "value";
53+
public static final String DESCRIPTOR_NAME = "descriptor";
5454

5555
private final PVAStringArray labels;
5656
private final PVAStructure value;

core/pva/src/main/java/org/epics/pva/server/PVAServer.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import static org.epics.pva.PVASettings.logger;
1111

1212
import java.net.InetSocketAddress;
13+
import java.util.Collection;
1314
import java.util.concurrent.ConcurrentHashMap;
1415
import java.util.concurrent.ConcurrentHashMap.KeySetView;
1516
import java.util.concurrent.ForkJoinPool;
@@ -161,6 +162,26 @@ ServerPV getPV(final int sid)
161162
return pv_by_sid.get(sid);
162163
}
163164

165+
166+
/** Info about a client to the PVA server:
167+
* Network address and authentication info
168+
*/
169+
public static record ClientInfo(InetSocketAddress address,
170+
ServerAuth authentication)
171+
{
172+
}
173+
174+
/** Get information about clients to this PVA server
175+
* @return {@link ClientInfo}s
176+
*/
177+
public Collection<ClientInfo> getClientInfos()
178+
{
179+
return tcp_handlers.stream()
180+
.map(tcp -> new ClientInfo(tcp.getRemoteAddress(),
181+
tcp.getAuth()))
182+
.toList();
183+
}
184+
164185
/** Special address used in TCP search reply to indicate "Use this TCP connection" */
165186
private static final InetSocketAddress USE_THIS_TCP_CONNECTION = new InetSocketAddress(0);
166187

core/pva/src/main/java/org/epics/pva/server/ServerAuth.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2019-2023 Oak Ridge National Laboratory.
2+
* Copyright (c) 2019-2025 Oak Ridge National Laboratory.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -20,7 +20,7 @@
2020
* @author Kay Kasemir
2121
*/
2222
@SuppressWarnings("nls")
23-
abstract class ServerAuth
23+
public abstract class ServerAuth
2424
{
2525
/** @param channel Channel for which to check write access
2626
* @return Does client have write access?
@@ -62,7 +62,7 @@ public static ServerAuth decode(final ServerTCPHandler tcp, final ByteBuffer buf
6262

6363
if (PVAAuth.X509.equals(auth))
6464
return new X509ServerAuth(tls_info);
65-
65+
6666
return Anonymous;
6767
}
6868

0 commit comments

Comments
 (0)