This commit is contained in:
Orion Kindel 2023-04-20 01:58:43 -05:00
parent c4bd8c6273
commit b8e9eaceb0
Signed by untrusted user who does not match committer: orion
GPG Key ID: 6D4165AE4C928719
11 changed files with 103 additions and 47 deletions

View File

@ -1,8 +1,8 @@
package dev.toad; package dev.toad;
import dev.toad.msg.Code; import dev.toad.msg.Code;
import dev.toad.msg.Type;
import dev.toad.msg.Message; import dev.toad.msg.Message;
import dev.toad.msg.Type;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Optional; import java.util.Optional;
@ -16,12 +16,16 @@ public final class Client implements AutoCloseable {
this.toad = toad; this.toad = toad;
} }
public CompletableFuture<Message> get(String uri) throws URISyntaxException, UnknownHostException { public CompletableFuture<Message> get(String uri)
throws URISyntaxException, UnknownHostException {
return this.get(Type.CON, uri); return this.get(Type.CON, uri);
} }
public CompletableFuture<Message> get(Type ty, String uri) throws URISyntaxException, UnknownHostException { public CompletableFuture<Message> get(Type ty, String uri)
return this.send(Message.builder().uri(uri).type(ty).code(Code.GET).build()); throws URISyntaxException, UnknownHostException {
return this.send(
Message.builder().uri(uri).type(ty).code(Code.GET).build()
);
} }
public CompletableFuture<Message> send(Message message) { public CompletableFuture<Message> send(Message message) {

View File

@ -2,8 +2,8 @@ package dev.toad.msg;
import dev.toad.msg.option.Accept; import dev.toad.msg.option.Accept;
import dev.toad.msg.option.ContentFormat; import dev.toad.msg.option.ContentFormat;
import dev.toad.msg.option.Path;
import dev.toad.msg.option.Host; import dev.toad.msg.option.Host;
import dev.toad.msg.option.Path;
import dev.toad.msg.option.Query; import dev.toad.msg.option.Query;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.List; import java.util.List;
@ -34,27 +34,27 @@ public interface Message {
public byte[] toBytes(); public byte[] toBytes();
default public Optional<Option> getOption(long number) { public default Optional<Option> getOption(long number) {
return this.options().stream().filter(o -> o.number() == number).findAny(); return this.options().stream().filter(o -> o.number() == number).findAny();
} }
default public Optional<Accept> getAccept() { public default Optional<Accept> getAccept() {
return this.getOption(Accept.number).map(o -> new Accept(o)); return this.getOption(Accept.number).map(o -> new Accept(o));
} }
default public Optional<ContentFormat> getContentFormat() { public default Optional<ContentFormat> getContentFormat() {
return this.getOption(ContentFormat.number).map(o -> new ContentFormat(o)); return this.getOption(ContentFormat.number).map(o -> new ContentFormat(o));
} }
default public Optional<Path> getPath() { public default Optional<Path> getPath() {
return this.getOption(Path.number).map(o -> new Path(o)); return this.getOption(Path.number).map(o -> new Path(o));
} }
default public Optional<Host> getHost() { public default Optional<Host> getHost() {
return this.getOption(Host.number).map(o -> new Host(o)); return this.getOption(Host.number).map(o -> new Host(o));
} }
default public Optional<Query> getQuery() { public default Optional<Query> getQuery() {
return this.getOption(Query.number).map(o -> new Query(o)); return this.getOption(Query.number).map(o -> new Query(o));
} }
} }

View File

@ -1,10 +1,11 @@
package dev.toad.msg; package dev.toad.msg;
import java.util.Optional;
import dev.toad.msg.option.ContentFormat; import dev.toad.msg.option.ContentFormat;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Optional;
public final class Payload { public final class Payload {
final byte[] bytes; final byte[] bytes;
final Optional<ContentFormat> contentFormat; final Optional<ContentFormat> contentFormat;

View File

@ -1,18 +1,18 @@
package dev.toad.msg.build; package dev.toad.msg.build;
import dev.toad.msg.Payload;
import dev.toad.msg.Code; import dev.toad.msg.Code;
import dev.toad.msg.Id; import dev.toad.msg.Id;
import dev.toad.msg.Payload;
import dev.toad.msg.Token; import dev.toad.msg.Token;
import dev.toad.msg.Type; import dev.toad.msg.Type;
import dev.toad.msg.option.Host;
import dev.toad.msg.option.Path; import dev.toad.msg.option.Path;
import dev.toad.msg.option.Query; import dev.toad.msg.option.Query;
import dev.toad.msg.option.Host;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.net.URI;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -38,14 +38,16 @@ public final class Message
return new Message(); return new Message();
} }
public MessageNeeds.Type uri(String uriStr) throws URISyntaxException, UnknownHostException { public MessageNeeds.Type uri(String uriStr)
throws URISyntaxException, UnknownHostException {
var uri = new URI(uriStr); var uri = new URI(uriStr);
var addr = InetAddress.getByName(uri.getHost()); var addr = InetAddress.getByName(uri.getHost());
var port = uri.getPort() > 0 ? uri.getPort() : uri.getScheme().equals("coaps") ? 5684 : 5683; var port = uri.getPort() > 0
? uri.getPort()
: uri.getScheme().equals("coaps") ? 5684 : 5683;
this.addr = Optional.of(new InetSocketAddress(addr, port)); this.addr = Optional.of(new InetSocketAddress(addr, port));
return this return this.option(new Host(uri.getHost()))
.option(new Host(uri.getHost()))
.option(new Query(uri.getQuery())) .option(new Query(uri.getQuery()))
.option(new Path(uri.getPath())); .option(new Path(uri.getPath()));
} }
@ -108,7 +110,7 @@ public final class Message
this.code.get(), this.code.get(),
this.id.orElse(Id.defaultId()), this.id.orElse(Id.defaultId()),
this.token.orElse(Token.defaultToken()), this.token.orElse(Token.defaultToken()),
this.payload.map(p -> p.bytes()).orElse(new byte[]{}), this.payload.map(p -> p.bytes()).orElse(new byte[] {}),
this.options.entrySet() this.options.entrySet()
.stream() .stream()
.map(ent -> new dev.toad.msg.owned.Option(ent.getKey(), ent.getValue())) .map(ent -> new dev.toad.msg.owned.Option(ent.getKey(), ent.getValue()))

View File

@ -1,13 +1,14 @@
package dev.toad.msg.build; package dev.toad.msg.build;
import java.net.InetSocketAddress;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.net.InetSocketAddress;
public final class MessageNeeds { public final class MessageNeeds {
public interface Destination { public interface Destination {
MessageNeeds.Type uri(String uri) throws URISyntaxException, UnknownHostException; MessageNeeds.Type uri(String uri)
throws URISyntaxException, UnknownHostException;
MessageNeeds.Type addr(InetSocketAddress addr); MessageNeeds.Type addr(InetSocketAddress addr);
} }

View File

@ -1,13 +1,13 @@
package dev.toad.msg.option; package dev.toad.msg.option;
import java.util.Arrays;
import java.util.stream.Collectors;
import dev.toad.ffi.u16; import dev.toad.ffi.u16;
import dev.toad.msg.Option; import dev.toad.msg.Option;
import dev.toad.msg.OptionValue; import dev.toad.msg.OptionValue;
import java.util.ArrayList;
import java.util.List;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public sealed class ContentFormat implements Option permits Accept { public sealed class ContentFormat implements Option permits Accept {
@ -17,11 +17,22 @@ public sealed class ContentFormat implements Option permits Accept {
public ContentFormat(Option o) { public ContentFormat(Option o) {
if (o.number() != ContentFormat.number) { if (o.number() != ContentFormat.number) {
throw new IllegalArgumentException(String.format("%d != ContentFormat number %d", o.number(), Path.number)); throw new IllegalArgumentException(
String.format("%d != ContentFormat number %d", o.number(), Path.number)
);
} }
if (o.values().size() > 1) { if (o.values().size() > 1) {
throw new IllegalArgumentException(String.format("ContentFormat is not repeatable, %s", o.values().stream().map(v -> v.asString()).collect(Collectors.toList()))); throw new IllegalArgumentException(
String.format(
"ContentFormat is not repeatable, %s",
o
.values()
.stream()
.map(v -> v.asString())
.collect(Collectors.toList())
)
);
} }
var bytes = o.values().get(0).asBytes(); var bytes = o.values().get(0).asBytes();
@ -32,7 +43,7 @@ public sealed class ContentFormat implements Option permits Accept {
} else if (bytes.length == 2) { } else if (bytes.length == 2) {
this.value = new u16(buf.getShort()); this.value = new u16(buf.getShort());
} else if (bytes.length == 3) { } else if (bytes.length == 3) {
buf.put(0, (byte)0); buf.put(0, (byte) 0);
this.value = new u16(buf.getInt()); this.value = new u16(buf.getInt());
} else { } else {
this.value = new u16(buf.getInt()); this.value = new u16(buf.getInt());

View File

@ -3,22 +3,34 @@ package dev.toad.msg.option;
import dev.toad.msg.Option; import dev.toad.msg.Option;
import dev.toad.msg.OptionValue; import dev.toad.msg.OptionValue;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public final class Host implements Option { public final class Host implements Option {
final String host; final String host;
public static final long number = 3; public static final long number = 3;
public Host(Option o) { public Host(Option o) {
if (o.number() != Host.number) { if (o.number() != Host.number) {
throw new IllegalArgumentException(String.format("%d != Host number %d", o.number(), Path.number)); throw new IllegalArgumentException(
String.format("%d != Host number %d", o.number(), Path.number)
);
} }
if (o.values().size() > 1) { if (o.values().size() > 1) {
throw new IllegalArgumentException(String.format("Host is not repeatable, %s", o.values().stream().map(v -> v.asString()).collect(Collectors.toList()))); throw new IllegalArgumentException(
String.format(
"Host is not repeatable, %s",
o
.values()
.stream()
.map(v -> v.asString())
.collect(Collectors.toList())
)
);
} }
this.host = o.values().get(0).asString(); this.host = o.values().get(0).asString();
@ -40,7 +52,7 @@ public final class Host implements Option {
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
return switch(other) { return switch (other) {
case Host h -> this.toString().equals(h.toString()); case Host h -> this.toString().equals(h.toString());
default -> false; default -> false;
}; };

View File

@ -3,21 +3,29 @@ package dev.toad.msg.option;
import dev.toad.msg.Option; import dev.toad.msg.Option;
import dev.toad.msg.OptionValue; import dev.toad.msg.OptionValue;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public final class Path implements Option { public final class Path implements Option {
final ArrayList<String> segments; final ArrayList<String> segments;
public static final long number = 11; public static final long number = 11;
public Path(Option o) { public Path(Option o) {
if (o.number() != Path.number) { if (o.number() != Path.number) {
throw new IllegalArgumentException(String.format("%d != Path number %d", o.number(), Path.number)); throw new IllegalArgumentException(
String.format("%d != Path number %d", o.number(), Path.number)
);
} }
this.segments = o.values().stream().map(v -> v.asString()).collect(Collectors.toCollection(() -> new ArrayList<>())); this.segments =
o
.values()
.stream()
.map(v -> v.asString())
.collect(Collectors.toCollection(() -> new ArrayList<>()));
} }
public Path(String path) { public Path(String path) {
@ -52,6 +60,8 @@ public final class Path implements Option {
@Override @Override
public List<OptionValue> values() { public List<OptionValue> values() {
return this.segments.stream().map(s -> new dev.toad.msg.owned.OptionValue(s)).collect(Collectors.toList()); return this.segments.stream()
.map(s -> new dev.toad.msg.owned.OptionValue(s))
.collect(Collectors.toList());
} }
} }

View File

@ -2,12 +2,12 @@ package dev.toad.msg.option;
import dev.toad.msg.Option; import dev.toad.msg.Option;
import dev.toad.msg.OptionValue; import dev.toad.msg.OptionValue;
import java.util.Optional;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.function.BinaryOperator; import java.util.function.BinaryOperator;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -20,10 +20,17 @@ public final class Query implements Option {
public Query(Option o) { public Query(Option o) {
if (o.number() != Query.number) { if (o.number() != Query.number) {
throw new IllegalArgumentException(String.format("%d != Query number %d", o.number(), Query.number)); throw new IllegalArgumentException(
String.format("%d != Query number %d", o.number(), Query.number)
);
} }
this.query = o.values().stream().map(v -> v.asString()).collect(Collectors.toCollection(() -> new ArrayList<>())); this.query =
o
.values()
.stream()
.map(v -> v.asString())
.collect(Collectors.toCollection(() -> new ArrayList<>()));
} }
public Query(String query) { public Query(String query) {
@ -79,6 +86,7 @@ public final class Query implements Option {
} }
public static final class Value { public static final class Value {
final Optional<String> val; final Optional<String> val;
public Value(String val) { public Value(String val) {
@ -100,7 +108,7 @@ public final class Query implements Option {
@Override @Override
public String toString() { public String toString() {
if (!this.value().isEmpty()) { if (!this.value().isEmpty()) {
return "Query.Value(\""+this.value().get()+"\")"; return "Query.Value(\"" + this.value().get() + "\")";
} else { } else {
return "Query.Value.empty()"; return "Query.Value.empty()";
} }
@ -112,7 +120,7 @@ public final class Query implements Option {
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
return switch(other) { return switch (other) {
case Value v -> this.equals(v); case Value v -> this.equals(v);
default -> false; default -> false;
}; };

View File

@ -81,7 +81,10 @@ class MessageBuilder extends munit.FunSuite {
.code(Code.GET) .code(Code.GET)
.build .build
assertEquals(Seq.from(msg.getPath.get.segments.asScala), Seq("cheese", "gruyere")) assertEquals(
Seq.from(msg.getPath.get.segments.asScala),
Seq("cheese", "gruyere")
)
} }
test("uri sets query to query section of uri") { test("uri sets query to query section of uri") {

View File

@ -41,8 +41,12 @@ class Options extends munit.FunSuite {
), ),
Map( Map(
"foo" -> Seq(Query.Value("test")), "foo" -> Seq(Query.Value("test")),
"bar" -> Seq(Query.Value.empty, Query.Value.empty, Query.Value("third")), "bar" -> Seq(
"quux" -> Seq(Query.Value("a"), Query.Value("b")), Query.Value.empty,
Query.Value.empty,
Query.Value("third")
),
"quux" -> Seq(Query.Value("a"), Query.Value("b"))
) )
) )
} }