mirror of
https://github.com/AsamK/signal-cli.git
synced 2026-03-14 02:30:15 +00:00
Add JSON-RPC commands for voice call control
Add startCall, acceptCall, hangupCall, rejectCall, and listCalls commands for the JSON-RPC daemon interface. Register commands and update GraalVM metadata for native image support. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
fafc5e3563
commit
32ada51c44
@ -91,6 +91,14 @@ dependencies {
|
||||
implementation(libs.logback)
|
||||
implementation(libs.zxing)
|
||||
implementation(project(":libsignal-cli"))
|
||||
|
||||
testImplementation(libs.junit.jupiter)
|
||||
testImplementation(platform(libs.junit.jupiter.bom))
|
||||
testRuntimeOnly(libs.junit.launcher)
|
||||
}
|
||||
|
||||
tasks.named<Test>("test") {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
configurations {
|
||||
|
||||
@ -0,0 +1,78 @@
|
||||
package org.asamk.signal.commands;
|
||||
|
||||
import net.sourceforge.argparse4j.inf.Namespace;
|
||||
import net.sourceforge.argparse4j.inf.Subparser;
|
||||
|
||||
import org.asamk.signal.commands.exceptions.CommandException;
|
||||
import org.asamk.signal.commands.exceptions.IOErrorException;
|
||||
import org.asamk.signal.commands.exceptions.UserErrorException;
|
||||
import org.asamk.signal.manager.Manager;
|
||||
import org.asamk.signal.output.JsonWriter;
|
||||
import org.asamk.signal.output.OutputWriter;
|
||||
import org.asamk.signal.output.PlainTextWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class AcceptCallCommand implements JsonRpcLocalCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "acceptCall";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachToSubparser(final Subparser subparser) {
|
||||
subparser.help("Accept an incoming voice call.");
|
||||
subparser.addArgument("--call-id")
|
||||
.type(long.class)
|
||||
.required(true)
|
||||
.help("The call ID to accept.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(
|
||||
final Namespace ns,
|
||||
final Manager m,
|
||||
final OutputWriter outputWriter
|
||||
) throws CommandException {
|
||||
final var callIdNumber = ns.get("call-id");
|
||||
if (callIdNumber == null) {
|
||||
throw new UserErrorException("No call ID given");
|
||||
}
|
||||
final long callId = ((Number) callIdNumber).longValue();
|
||||
|
||||
try {
|
||||
var callInfo = m.acceptCall(callId);
|
||||
switch (outputWriter) {
|
||||
case PlainTextWriter writer -> {
|
||||
writer.println("Call accepted:");
|
||||
writer.println(" Call ID: {}", callInfo.callId());
|
||||
writer.println(" State: {}", callInfo.state());
|
||||
writer.println(" Input device: {}", callInfo.inputDeviceName());
|
||||
writer.println(" Output device: {}", callInfo.outputDeviceName());
|
||||
}
|
||||
case JsonWriter writer -> writer.write(new JsonCallInfo(callInfo.callId(),
|
||||
callInfo.state().name(),
|
||||
callInfo.inputDeviceName(),
|
||||
callInfo.outputDeviceName(),
|
||||
"opus",
|
||||
48000,
|
||||
1,
|
||||
20));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IOErrorException("Failed to accept call: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private record JsonCallInfo(
|
||||
long callId,
|
||||
String state,
|
||||
String inputDeviceName,
|
||||
String outputDeviceName,
|
||||
String codec,
|
||||
int sampleRate,
|
||||
int channels,
|
||||
int ptimeMs
|
||||
) {}
|
||||
}
|
||||
@ -10,18 +10,21 @@ public class Commands {
|
||||
private static final Map<String, SubparserAttacher> commandSubparserAttacher = new TreeMap<>();
|
||||
|
||||
static {
|
||||
addCommand(new AcceptCallCommand());
|
||||
addCommand(new AddDeviceCommand());
|
||||
addCommand(new BlockCommand());
|
||||
addCommand(new DaemonCommand());
|
||||
addCommand(new DeleteLocalAccountDataCommand());
|
||||
addCommand(new FinishChangeNumberCommand());
|
||||
addCommand(new FinishLinkCommand());
|
||||
addCommand(new HangupCallCommand());
|
||||
addCommand(new GetAttachmentCommand());
|
||||
addCommand(new GetAvatarCommand());
|
||||
addCommand(new GetStickerCommand());
|
||||
addCommand(new GetUserStatusCommand());
|
||||
addCommand(new AddStickerPackCommand());
|
||||
addCommand(new JoinGroupCommand());
|
||||
addCommand(new ListCallsCommand());
|
||||
addCommand(new JsonRpcDispatcherCommand());
|
||||
addCommand(new LinkCommand());
|
||||
addCommand(new ListAccountsCommand());
|
||||
@ -32,6 +35,7 @@ public class Commands {
|
||||
addCommand(new ListStickerPacksCommand());
|
||||
addCommand(new QuitGroupCommand());
|
||||
addCommand(new ReceiveCommand());
|
||||
addCommand(new RejectCallCommand());
|
||||
addCommand(new RegisterCommand());
|
||||
addCommand(new RemoveContactCommand());
|
||||
addCommand(new RemoveDeviceCommand());
|
||||
@ -52,6 +56,7 @@ public class Commands {
|
||||
addCommand(new SendTypingCommand());
|
||||
addCommand(new SendUnpinMessageCommand());
|
||||
addCommand(new SetPinCommand());
|
||||
addCommand(new StartCallCommand());
|
||||
addCommand(new SubmitRateLimitChallengeCommand());
|
||||
addCommand(new StartChangeNumberCommand());
|
||||
addCommand(new StartLinkCommand());
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
package org.asamk.signal.commands;
|
||||
|
||||
import net.sourceforge.argparse4j.inf.Namespace;
|
||||
import net.sourceforge.argparse4j.inf.Subparser;
|
||||
|
||||
import org.asamk.signal.commands.exceptions.CommandException;
|
||||
import org.asamk.signal.commands.exceptions.IOErrorException;
|
||||
import org.asamk.signal.commands.exceptions.UserErrorException;
|
||||
import org.asamk.signal.manager.Manager;
|
||||
import org.asamk.signal.output.JsonWriter;
|
||||
import org.asamk.signal.output.OutputWriter;
|
||||
import org.asamk.signal.output.PlainTextWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class HangupCallCommand implements JsonRpcLocalCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "hangupCall";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachToSubparser(final Subparser subparser) {
|
||||
subparser.help("Hang up an active voice call.");
|
||||
subparser.addArgument("--call-id")
|
||||
.type(long.class)
|
||||
.required(true)
|
||||
.help("The call ID to hang up.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(
|
||||
final Namespace ns,
|
||||
final Manager m,
|
||||
final OutputWriter outputWriter
|
||||
) throws CommandException {
|
||||
final var callIdNumber = ns.get("call-id");
|
||||
if (callIdNumber == null) {
|
||||
throw new UserErrorException("No call ID given");
|
||||
}
|
||||
final long callId = ((Number) callIdNumber).longValue();
|
||||
|
||||
try {
|
||||
m.hangupCall(callId);
|
||||
switch (outputWriter) {
|
||||
case PlainTextWriter writer -> writer.println("Call {} hung up.", callId);
|
||||
case JsonWriter writer -> writer.write(new JsonResult(callId, "hung_up"));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IOErrorException("Failed to hang up call: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private record JsonResult(long callId, String status) {}
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
package org.asamk.signal.commands;
|
||||
|
||||
import net.sourceforge.argparse4j.inf.Namespace;
|
||||
import net.sourceforge.argparse4j.inf.Subparser;
|
||||
|
||||
import org.asamk.signal.commands.exceptions.CommandException;
|
||||
import org.asamk.signal.manager.Manager;
|
||||
import org.asamk.signal.manager.api.CallInfo;
|
||||
import org.asamk.signal.output.JsonWriter;
|
||||
import org.asamk.signal.output.OutputWriter;
|
||||
import org.asamk.signal.output.PlainTextWriter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ListCallsCommand implements JsonRpcLocalCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "listCalls";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachToSubparser(final Subparser subparser) {
|
||||
subparser.help("List active voice calls.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(
|
||||
final Namespace ns,
|
||||
final Manager m,
|
||||
final OutputWriter outputWriter
|
||||
) throws CommandException {
|
||||
var calls = m.listActiveCalls();
|
||||
switch (outputWriter) {
|
||||
case PlainTextWriter writer -> {
|
||||
if (calls.isEmpty()) {
|
||||
writer.println("No active calls.");
|
||||
} else {
|
||||
for (var call : calls) {
|
||||
writer.println("- Call {}:", call.callId());
|
||||
writer.indent(w -> {
|
||||
w.println("State: {}", call.state());
|
||||
w.println("Recipient: {}", call.recipient());
|
||||
w.println("Direction: {}", call.isOutgoing() ? "outgoing" : "incoming");
|
||||
if (call.inputDeviceName() != null) {
|
||||
w.println("Input device: {}", call.inputDeviceName());
|
||||
}
|
||||
if (call.outputDeviceName() != null) {
|
||||
w.println("Output device: {}", call.outputDeviceName());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
case JsonWriter writer -> {
|
||||
var jsonCalls = calls.stream()
|
||||
.map(c -> new JsonCall(c.callId(),
|
||||
c.state().name(),
|
||||
c.recipient().number().orElse(null),
|
||||
c.recipient().uuid().map(java.util.UUID::toString).orElse(null),
|
||||
c.isOutgoing(),
|
||||
c.inputDeviceName(),
|
||||
c.outputDeviceName()))
|
||||
.toList();
|
||||
writer.write(jsonCalls);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private record JsonCall(
|
||||
long callId,
|
||||
String state,
|
||||
String number,
|
||||
String uuid,
|
||||
boolean isOutgoing,
|
||||
String inputDeviceName,
|
||||
String outputDeviceName
|
||||
) {}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package org.asamk.signal.commands;
|
||||
|
||||
import net.sourceforge.argparse4j.inf.Namespace;
|
||||
import net.sourceforge.argparse4j.inf.Subparser;
|
||||
|
||||
import org.asamk.signal.commands.exceptions.CommandException;
|
||||
import org.asamk.signal.commands.exceptions.IOErrorException;
|
||||
import org.asamk.signal.commands.exceptions.UserErrorException;
|
||||
import org.asamk.signal.manager.Manager;
|
||||
import org.asamk.signal.output.JsonWriter;
|
||||
import org.asamk.signal.output.OutputWriter;
|
||||
import org.asamk.signal.output.PlainTextWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class RejectCallCommand implements JsonRpcLocalCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "rejectCall";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachToSubparser(final Subparser subparser) {
|
||||
subparser.help("Reject an incoming voice call.");
|
||||
subparser.addArgument("--call-id")
|
||||
.type(long.class)
|
||||
.required(true)
|
||||
.help("The call ID to reject.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(
|
||||
final Namespace ns,
|
||||
final Manager m,
|
||||
final OutputWriter outputWriter
|
||||
) throws CommandException {
|
||||
final var callIdNumber = ns.get("call-id");
|
||||
if (callIdNumber == null) {
|
||||
throw new UserErrorException("No call ID given");
|
||||
}
|
||||
final long callId = ((Number) callIdNumber).longValue();
|
||||
|
||||
try {
|
||||
m.rejectCall(callId);
|
||||
switch (outputWriter) {
|
||||
case PlainTextWriter writer -> writer.println("Call {} rejected.", callId);
|
||||
case JsonWriter writer -> writer.write(new JsonResult(callId, "rejected"));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IOErrorException("Failed to reject call: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private record JsonResult(long callId, String status) {}
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
package org.asamk.signal.commands;
|
||||
|
||||
import net.sourceforge.argparse4j.inf.Namespace;
|
||||
import net.sourceforge.argparse4j.inf.Subparser;
|
||||
|
||||
import org.asamk.signal.commands.exceptions.CommandException;
|
||||
import org.asamk.signal.commands.exceptions.IOErrorException;
|
||||
import org.asamk.signal.commands.exceptions.UserErrorException;
|
||||
import org.asamk.signal.manager.Manager;
|
||||
import org.asamk.signal.manager.api.UnregisteredRecipientException;
|
||||
import org.asamk.signal.output.JsonWriter;
|
||||
import org.asamk.signal.output.OutputWriter;
|
||||
import org.asamk.signal.output.PlainTextWriter;
|
||||
import org.asamk.signal.util.CommandUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class StartCallCommand implements JsonRpcLocalCommand {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "startCall";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachToSubparser(final Subparser subparser) {
|
||||
subparser.help("Start an outgoing voice call.");
|
||||
subparser.addArgument("recipient").help("Specify the recipient's phone number or UUID.").nargs(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(
|
||||
final Namespace ns,
|
||||
final Manager m,
|
||||
final OutputWriter outputWriter
|
||||
) throws CommandException {
|
||||
final var recipientStrings = ns.<String>getList("recipient");
|
||||
if (recipientStrings == null || recipientStrings.isEmpty()) {
|
||||
throw new UserErrorException("No recipient given");
|
||||
}
|
||||
|
||||
final var recipient = CommandUtil.getSingleRecipientIdentifier(recipientStrings.getFirst(), m.getSelfNumber());
|
||||
|
||||
try {
|
||||
var callInfo = m.startCall(recipient);
|
||||
switch (outputWriter) {
|
||||
case PlainTextWriter writer -> {
|
||||
writer.println("Call started:");
|
||||
writer.println(" Call ID: {}", callInfo.callId());
|
||||
writer.println(" State: {}", callInfo.state());
|
||||
writer.println(" Input device: {}", callInfo.inputDeviceName());
|
||||
writer.println(" Output device: {}", callInfo.outputDeviceName());
|
||||
}
|
||||
case JsonWriter writer -> writer.write(new JsonCallInfo(callInfo.callId(),
|
||||
callInfo.state().name(),
|
||||
callInfo.inputDeviceName(),
|
||||
callInfo.outputDeviceName(),
|
||||
"opus",
|
||||
48000,
|
||||
1,
|
||||
20));
|
||||
}
|
||||
} catch (UnregisteredRecipientException e) {
|
||||
throw new UserErrorException("Recipient not registered: " + e.getMessage(), e);
|
||||
} catch (IOException e) {
|
||||
throw new IOErrorException("Failed to start call: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private record JsonCallInfo(
|
||||
long callId,
|
||||
String state,
|
||||
String inputDeviceName,
|
||||
String outputDeviceName,
|
||||
String codec,
|
||||
int sampleRate,
|
||||
int channels,
|
||||
int ptimeMs
|
||||
) {}
|
||||
}
|
||||
@ -1947,6 +1947,40 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "org.asamk.signal.commands.AcceptCallCommand$JsonCallInfo",
|
||||
"allDeclaredFields": true,
|
||||
"methods": [
|
||||
{
|
||||
"name": "callId",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "channels",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "codec",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "mediaSocketPath",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "ptimeMs",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "sampleRate",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "state",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "org.asamk.signal.commands.FinishLinkCommand$FinishLinkParams",
|
||||
"allDeclaredFields": true,
|
||||
@ -1984,6 +2018,20 @@
|
||||
"allDeclaredMethods": true,
|
||||
"allDeclaredConstructors": true
|
||||
},
|
||||
{
|
||||
"type": "org.asamk.signal.commands.HangupCallCommand$JsonResult",
|
||||
"allDeclaredFields": true,
|
||||
"methods": [
|
||||
{
|
||||
"name": "callId",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "status",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "org.asamk.signal.commands.ListAccountsCommand$JsonAccount",
|
||||
"allDeclaredFields": true,
|
||||
@ -1994,6 +2042,39 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "org.asamk.signal.commands.ListCallsCommand$JsonCall",
|
||||
"allDeclaredFields": true,
|
||||
"methods": [
|
||||
{
|
||||
"name": "callId",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "isOutgoing",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "mediaSocketPath",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "number",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "state",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "uuid",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "org.asamk.signal.commands.ListCallsCommand$JsonCall[]"
|
||||
},
|
||||
{
|
||||
"type": "org.asamk.signal.commands.ListContactsCommand$JsonContact",
|
||||
"allDeclaredFields": true,
|
||||
@ -2159,6 +2240,54 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "org.asamk.signal.commands.RejectCallCommand$JsonResult",
|
||||
"allDeclaredFields": true,
|
||||
"methods": [
|
||||
{
|
||||
"name": "callId",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "status",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "org.asamk.signal.commands.StartCallCommand$JsonCallInfo",
|
||||
"allDeclaredFields": true,
|
||||
"methods": [
|
||||
{
|
||||
"name": "callId",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "channels",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "codec",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "mediaSocketPath",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "ptimeMs",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "sampleRate",
|
||||
"parameterTypes": []
|
||||
},
|
||||
{
|
||||
"name": "state",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "org.asamk.signal.commands.StartLinkCommand$JsonLink",
|
||||
"allDeclaredFields": true,
|
||||
@ -9782,4 +9911,4 @@
|
||||
"bundle": "net.sourceforge.argparse4j.internal.ArgumentParserImpl"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,79 @@
|
||||
package org.asamk.signal.commands;
|
||||
|
||||
import net.sourceforge.argparse4j.inf.Namespace;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* Verifies that call commands correctly handle call IDs from JSON-RPC,
|
||||
* where Jackson may deserialize large numbers as BigInteger instead of Long.
|
||||
*/
|
||||
class CallCommandParsingTest {
|
||||
|
||||
/**
|
||||
* Simulates what Jackson produces for a JSON-RPC call with a large call ID.
|
||||
* Jackson deserializes numbers that overflow int as BigInteger in untyped maps.
|
||||
*/
|
||||
private static Namespace namespaceWithBigIntegerCallId(long value) {
|
||||
// JsonRpcNamespace converts "call-id" to "callId" lookup
|
||||
return new JsonRpcNamespace(Map.of("callId", BigInteger.valueOf(value)));
|
||||
}
|
||||
|
||||
private static Namespace namespaceWithLongCallId(long value) {
|
||||
return new JsonRpcNamespace(Map.of("callId", value));
|
||||
}
|
||||
|
||||
@Test
|
||||
void hangupCallHandlesBigIntegerCallId() {
|
||||
var ns = namespaceWithBigIntegerCallId(8230211930154373276L);
|
||||
var callIdNumber = ns.get("call-id");
|
||||
long callId = ((Number) callIdNumber).longValue();
|
||||
assertEquals(8230211930154373276L, callId);
|
||||
}
|
||||
|
||||
@Test
|
||||
void hangupCallHandlesLongCallId() {
|
||||
var ns = namespaceWithLongCallId(8230211930154373276L);
|
||||
var callIdNumber = ns.get("call-id");
|
||||
long callId = ((Number) callIdNumber).longValue();
|
||||
assertEquals(8230211930154373276L, callId);
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptCallHandlesBigIntegerCallId() {
|
||||
var ns = namespaceWithBigIntegerCallId(1234567890123456789L);
|
||||
var callIdNumber = ns.get("call-id");
|
||||
long callId = ((Number) callIdNumber).longValue();
|
||||
assertEquals(1234567890123456789L, callId);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectCallHandlesBigIntegerCallId() {
|
||||
var ns = namespaceWithBigIntegerCallId(Long.MAX_VALUE);
|
||||
var callIdNumber = ns.get("call-id");
|
||||
long callId = ((Number) callIdNumber).longValue();
|
||||
assertEquals(Long.MAX_VALUE, callId);
|
||||
}
|
||||
|
||||
@Test
|
||||
void camelCaseKeyLookupWorks() {
|
||||
// Verify JsonRpcNamespace maps "call-id" -> "callId"
|
||||
var ns = new JsonRpcNamespace(Map.of("callId", BigInteger.valueOf(42L)));
|
||||
Number result = ns.get("call-id");
|
||||
assertEquals(42L, result.longValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
void smallIntegerCallIdWorks() {
|
||||
// Jackson may produce Integer for small values
|
||||
var ns = new JsonRpcNamespace(Map.of("callId", 42));
|
||||
var callIdNumber = ns.get("call-id");
|
||||
long callId = ((Number) callIdNumber).longValue();
|
||||
assertEquals(42L, callId);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user