Provide a more flexible way to label messages.

I'm not quite sure about chans yet
This commit is contained in:
Christian Basler 2016-04-11 15:10:59 +02:00
parent 4f7f80c12a
commit e8ddf90363
9 changed files with 158 additions and 22 deletions

View File

@ -6,7 +6,7 @@ subprojects {
sourceCompatibility = 1.7
group = 'ch.dissem.jabit'
version = '1.0.2-SNAPSHOT'
version = '1.1.0-SNAPSHOT'
ext.isReleaseVersion = !version.endsWith("SNAPSHOT")

View File

@ -17,7 +17,10 @@
package ch.dissem.bitmessage;
import ch.dissem.bitmessage.entity.*;
import ch.dissem.bitmessage.entity.payload.*;
import ch.dissem.bitmessage.entity.payload.Broadcast;
import ch.dissem.bitmessage.entity.payload.Msg;
import ch.dissem.bitmessage.entity.payload.ObjectPayload;
import ch.dissem.bitmessage.entity.payload.ObjectType;
import ch.dissem.bitmessage.entity.payload.Pubkey.Feature;
import ch.dissem.bitmessage.entity.valueobject.Label;
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
@ -65,6 +68,7 @@ public class BitmessageContext {
private final InternalContext ctx;
private final Labeler labeler;
private final Listener listener;
private final NetworkHandler.MessageListener networkListener;
@ -72,8 +76,9 @@ public class BitmessageContext {
private BitmessageContext(Builder builder) {
ctx = new InternalContext(builder);
labeler = builder.labeler;
listener = builder.listener;
networkListener = new DefaultMessageListener(ctx, listener);
networkListener = new DefaultMessageListener(ctx, labeler, listener);
// As this thread is used for parts that do POW, which itself uses parallel threads, only
// one should be executed at any time.
@ -97,6 +102,10 @@ public class BitmessageContext {
return ctx.getMessageRepository();
}
public Labeler labeler() {
return labeler;
}
public BitmessageAddress createIdentity(boolean shorter, Feature... features) {
final BitmessageAddress identity = new BitmessageAddress(new PrivateKey(
shorter,
@ -280,7 +289,9 @@ public class BitmessageContext {
try {
Broadcast broadcast = (Broadcast) object.getPayload();
broadcast.decrypt(address);
listener.receive(broadcast.getPlaintext());
// This decrypts it twice, but on the other hand it doesn't try to decrypt the objects with
// other subscriptions and the interface stays as simple as possible.
networkListener.receive(object);
} catch (DecryptionFailedException ignore) {
} catch (Exception e) {
LOG.debug(e.getMessage(), e);
@ -318,6 +329,7 @@ public class BitmessageContext {
Cryptography cryptography;
MessageCallback messageCallback;
CustomCommandHandler customCommandHandler;
Labeler labeler;
Listener listener;
int connectionLimit = 150;
long connectionTTL = 30 * MINUTE;
@ -378,6 +390,11 @@ public class BitmessageContext {
return this;
}
public Builder labeler(Labeler labeler) {
this.labeler = labeler;
return this;
}
public Builder listener(Listener listener) {
this.listener = listener;
return this;
@ -430,6 +447,9 @@ public class BitmessageContext {
if (messageCallback == null) {
messageCallback = new BaseMessageCallback();
}
if (labeler == null) {
labeler = new DefaultLabeler();
}
if (customCommandHandler == null) {
customCommandHandler = new CustomCommandHandler() {
@Override

View File

@ -20,8 +20,9 @@ import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.ObjectMessage;
import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.payload.*;
import ch.dissem.bitmessage.entity.valueobject.Label;
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
import ch.dissem.bitmessage.exception.DecryptionFailedException;
import ch.dissem.bitmessage.ports.Labeler;
import ch.dissem.bitmessage.ports.NetworkHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -36,10 +37,12 @@ import static ch.dissem.bitmessage.utils.UnixTime.DAY;
class DefaultMessageListener implements NetworkHandler.MessageListener {
private final static Logger LOG = LoggerFactory.getLogger(DefaultMessageListener.class);
private final InternalContext ctx;
private final Labeler labeler;
private final BitmessageContext.Listener listener;
public DefaultMessageListener(InternalContext context, BitmessageContext.Listener listener) {
public DefaultMessageListener(InternalContext context, Labeler labeler, BitmessageContext.Listener listener) {
this.ctx = context;
this.labeler = labeler;
this.listener = listener;
}
@ -127,12 +130,7 @@ class DefaultMessageListener implements NetworkHandler.MessageListener {
if (!object.isSignatureValid(msg.getPlaintext().getFrom().getPubkey())) {
LOG.warn("Msg with IV " + object.getInventoryVector() + " was successfully decrypted, but signature check failed. Ignoring.");
} else {
msg.getPlaintext().setStatus(RECEIVED);
msg.getPlaintext().addLabels(ctx.getMessageRepository().getLabels(Label.Type.INBOX, Label.Type.UNREAD));
msg.getPlaintext().setInventoryVector(object.getInventoryVector());
ctx.getMessageRepository().save(msg.getPlaintext());
listener.receive(msg.getPlaintext());
updatePubkey(msg.getPlaintext().getFrom(), msg.getPlaintext().getFrom().getPubkey());
receive(object.getInventoryVector(), msg.getPlaintext());
}
break;
} catch (DecryptionFailedException ignore) {
@ -151,15 +149,19 @@ class DefaultMessageListener implements NetworkHandler.MessageListener {
if (!object.isSignatureValid(broadcast.getPlaintext().getFrom().getPubkey())) {
LOG.warn("Broadcast with IV " + object.getInventoryVector() + " was successfully decrypted, but signature check failed. Ignoring.");
} else {
broadcast.getPlaintext().setStatus(RECEIVED);
broadcast.getPlaintext().addLabels(ctx.getMessageRepository().getLabels(Label.Type.INBOX, Label.Type.BROADCAST, Label.Type.UNREAD));
broadcast.getPlaintext().setInventoryVector(object.getInventoryVector());
ctx.getMessageRepository().save(broadcast.getPlaintext());
listener.receive(broadcast.getPlaintext());
updatePubkey(broadcast.getPlaintext().getFrom(), broadcast.getPlaintext().getFrom().getPubkey());
receive(object.getInventoryVector(), broadcast.getPlaintext());
}
} catch (DecryptionFailedException ignore) {
}
}
}
protected void receive(InventoryVector iv, Plaintext msg) {
msg.setStatus(RECEIVED);
msg.setInventoryVector(iv);
labeler.setLabels(msg);
ctx.getMessageRepository().save(msg);
listener.receive(msg);
updatePubkey(msg.getFrom(), msg.getFrom().getPubkey());
}
}

View File

@ -96,7 +96,7 @@ public class InternalContext {
init(cryptography, inventory, nodeRegistry, networkHandler, addressRepository, messageRepository,
proofOfWorkRepository, proofOfWorkService, proofOfWorkEngine,
messageCallback, customCommandHandler);
messageCallback, customCommandHandler, builder.labeler);
for (BitmessageAddress identity : addressRepository.getIdentities()) {
streams.add(identity.getStream());
}

View File

@ -0,0 +1,68 @@
/*
* Copyright 2016 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dissem.bitmessage.ports;
import ch.dissem.bitmessage.InternalContext;
import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.valueobject.Label;
import java.util.Iterator;
public class DefaultLabeler implements Labeler, InternalContext.ContextHolder {
private InternalContext ctx;
@Override
public void setLabels(Plaintext msg) {
if (msg.getType() == Plaintext.Type.BROADCAST) {
msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.INBOX, Label.Type.BROADCAST, Label.Type.UNREAD));
} else {
msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.INBOX, Label.Type.UNREAD));
}
}
@Override
public void markAsRead(Plaintext msg) {
Iterator<Label> iterator = msg.getLabels().iterator();
while (iterator.hasNext()) {
Label label = iterator.next();
if (label.getType() == Label.Type.UNREAD) {
iterator.remove();
}
}
}
@Override
public void markAsUnread(Plaintext msg) {
msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.UNREAD));
}
@Override
public void delete(Plaintext msg) {
msg.getLabels().clear();
msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.TRASH));
}
@Override
public void archive(Plaintext msg) {
msg.getLabels().clear();
}
@Override
public void setContext(InternalContext ctx) {
this.ctx = ctx;
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 2016 Christian Basler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dissem.bitmessage.ports;
import ch.dissem.bitmessage.entity.Plaintext;
/**
* Defines and sets labels
*/
public interface Labeler {
/**
* Sets the labels of a newly received message.
*
* @param msg an unlabeled message or broadcast
*/
void setLabels(Plaintext msg);
void markAsRead(Plaintext msg);
void markAsUnread(Plaintext msg);
void delete(Plaintext msg);
void archive(Plaintext msg);
}

View File

@ -143,10 +143,11 @@ public class BitmessageContextTest {
objects.add(TestUtils.loadObjectMessage(5, "V5Broadcast.payload"));
when(ctx.internals().getInventory().getObjects(eq(address.getStream()), anyLong(), any(ObjectType.class)))
.thenReturn(objects);
when(ctx.addresses().getSubscriptions(anyLong())).thenReturn(Collections.singletonList(address));
ctx.addSubscribtion(address);
verify(ctx.addresses(), times(1)).save(address);
verify(ctx.addresses(), atLeastOnce()).save(address);
assertThat(address.isSubscribed(), is(true));
verify(ctx.internals().getInventory()).getObjects(eq(address.getStream()), anyLong(), any(ObjectType.class));
verify(listener).receive(any(Plaintext.class));
@ -232,6 +233,7 @@ public class BitmessageContextTest {
expected.remove(a.getAddress());
}
}
@Test
public void ensureShortDeterministicAddressesAreCreated() {
final int expected_size = 1;

View File

@ -25,6 +25,7 @@ import ch.dissem.bitmessage.entity.payload.GetPubkey;
import ch.dissem.bitmessage.entity.payload.Msg;
import ch.dissem.bitmessage.factory.Factory;
import ch.dissem.bitmessage.ports.AddressRepository;
import ch.dissem.bitmessage.ports.Labeler;
import ch.dissem.bitmessage.ports.MessageRepository;
import ch.dissem.bitmessage.utils.Singleton;
import ch.dissem.bitmessage.utils.TestBase;
@ -62,7 +63,7 @@ public class DefaultMessageListenerTest extends TestBase {
when(ctx.getAddressRepository()).thenReturn(addressRepo);
when(ctx.getMessageRepository()).thenReturn(messageRepo);
listener = new DefaultMessageListener(ctx, mock(BitmessageContext.Listener.class));
listener = new DefaultMessageListener(ctx, mock(Labeler.class), mock(BitmessageContext.Listener.class));
}
@Test

View File

@ -21,6 +21,7 @@ import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.payload.Pubkey;
import ch.dissem.bitmessage.entity.valueobject.Label;
import ch.dissem.bitmessage.networking.DefaultNetworkHandler;
import ch.dissem.bitmessage.ports.MemoryNodeRegistry;
import ch.dissem.bitmessage.repository.*;
@ -30,6 +31,7 @@ import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.util.List;
import java.util.stream.Collectors;
import static ch.dissem.bitmessage.demo.CommandLine.COMMAND_BACK;
import static ch.dissem.bitmessage.demo.CommandLine.ERROR_UNKNOWN_COMMAND;
@ -325,8 +327,10 @@ public class Application {
System.out.println();
System.out.println(message.getText());
System.out.println();
System.out.println("Labels: " + message.getLabels());
System.out.println(message.getLabels().stream().map(Label::toString).collect(
Collectors.joining("Labels: ", ", ", "")));
System.out.println();
ctx.labeler().markAsRead(message);
String command;
do {
System.out.println("r) reply");