Skip to content

Commit

Permalink
Refactor to match go-ma.
Browse files Browse the repository at this point in the history
  • Loading branch information
bahner committed Nov 20, 2023
1 parent ed07489 commit 850ac69
Show file tree
Hide file tree
Showing 22 changed files with 585 additions and 541 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ go-space-thumb*
.env
*secret
go-ma-actor
go-home
41 changes: 14 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,64 +1,51 @@
# github.com/bahner/go-space-thumb
# github.com/bahner/go-home

This is go-space-thumb based on [an example from go-libp2p][src].
This is go-home based on [an example from go-libp2p][src].

Now you can either run with `go run`, or build and run the binary:

```shell
go run . -identity foobar -room myTopic

# or, build and run separately
go build .
export GO_MA_ACTOR_IDENTITY=fooBar
./go-space-thumb -room myTopic
./go-home -genenv -forcPublish > .env // Generate persistent environment variables of *SECRET* keysets
. .env // Load the environment variables
./go-home // Run the app
```

## Configuration

type `./go-space-thumb -help`. Most config settings can be set with environment variables, as follows:
type `./go-home -help`. Most config settings can be set with environment variables, as follows:

```bash
export GO_MA_ACTOR_LOG_LEVEL="error"
export GO_MA_ACTOR_RENDEZVOUS="space"
export GO_MA_ACTOR_SERVICE_NAME="space"
export GO_MA_ACTOR_ROOM="mytopic"
export GO_MA_ACTOR_IDENTITY="myBase58EncodedPrivkeyGeneratedByGenerate"
export GO_HOME_LOG_LEVEL="error"
export GO_HOME_DISCOVERY_TIMEOUT="300"
export GO_HOME_ACTOR_KEYSET="myBase58EncodedPrivkeyGeneratedByGenerate"
export GO_HOME_ROOM_KEYSET="myBase58EncodedPrivkeyGeneratedByGenerate"
```

## Identity

A `-generate` parameter to generate a text version of a secret key.
A `-generate` or `genenv` parameter to generate a text version of a secret key.
The key is text formatted privKey for your node.

This key can and should be kept safely on a PostIt note on your monitor :-)
Just don't store somewhere insecure. It's your future identity.

```bash
unset HISTFILE
export GO_MA_ACTOR_IDENTITY=FooBarABCDEFbase58
export GO_HOME_ACTOR_KEYSET=FooBarABCDEFbase58
export GO_HOME_ROOM_KEYSET=FooBarABCDEFGHIbase58
```

or specified on the command line:

```bash
./go-space-thumb -identity FooBarABCDEFbase58
./go-home -actorKeyset FooBarABCDEFbase58 -roomKeyset FooBarABCDEFGHIbase58
```

The first is the best. (Noticed that in most shells the empty space before the command, means that the line isn't saved in history.)

## Usage

You can join a specific chat room with the `-room` flag:

```shell
go run . -room=planet-express
```

It's usually more fun to chat with others, so open a new terminal and run the app again.
If you set a custom chat room name with the `-room` flag, make sure you use the same one
for both apps. Once the new instance starts, the two chat apps should discover each other
automatically using mDNS, and typing a message into one app will send it to any others that are open.

To quit, hit `Ctrl-C`, or type `/quit` into the input field.

## Commands
Expand Down
5 changes: 1 addition & 4 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
* redirect logs from stdout to file

## Features
* integrate ipld
- store message as ipld
- sign dagcid
* integrate ipns
- publish did with key

- There is some logical error wityh handling existing keys
73 changes: 0 additions & 73 deletions actor.go

This file was deleted.

104 changes: 104 additions & 0 deletions actor/actor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package actor

import (
"context"
"fmt"

"github.com/bahner/go-ma/entity"
"github.com/bahner/go-ma/key/set"
"github.com/bahner/go-ma/msg"
pubsub "github.com/libp2p/go-libp2p-pubsub"

log "github.com/sirupsen/logrus"
)

const MESSAGES_BUFFERSIZE = 100

type Actor struct {

// This context is used to cancel the Listen() function.
ctx context.Context

// ps service ointer
ps *pubsub.PubSub

// All actors must be entities.
// Ideally they should be the same, but then ma becomes a bit too opinionated.
Entity *entity.Entity

// Private is the topic where we receive envelopes from other actors.
// It's basically a private channel with the DIDDocument keyAgreement as topic.
Private *pubsub.Topic

// We basically receive signed messages from the room we're in here.
// It's basically a public channel with the assertionMethod from the DIDDocument of
// the room we're in as topic.
// Others can subscribe to this topic and send us messages, as long as they are signed.
Public *pubsub.Topic

// Incoming messages from the actor to AssertionMethod topic. It's bascially a broadcast channel.
// But you could use it to send messages to a specific actor or to all actors in a group.
// This is a public channel. There will need to be some generic To (recipients) in the mesage
// for example "broadcast", so that one actor can send a message to everybody in the room.
// That is a TODO.
// We receive the message contents here after verification or decryption.
Messages chan *msg.Message
}

// Creates a new actor from an entity.
// Takes a pubsub.PubSub service, an entity and a forcePublish flag.
// The forcePublish is to override existing keys in IPFS.
func New(ctx context.Context, ps *pubsub.PubSub, e *entity.Entity, forcePublish bool) (*Actor, error) {

log.Debugf("actor/new: Setting Actor Entity: %v", e)

var err error
a := &Actor{}

// Assign provided resource pointers
a.ctx = ctx
a.ps = ps

// Firstly create assign entity to actor
a.Entity = e

// Create topic for incoming envelopes
a.Private, err = ps.Join(a.Entity.Doc.KeyAgreement)
if err != nil {
if err.Error() != "topic already exists" {
return nil, fmt.Errorf("new_actor: Failed to join topic: %v", err)
}
}

// Create subscription to topic for incoming messages
a.Public, err = ps.Join(a.Entity.Doc.AssertionMethod)
if err != nil {
return nil, fmt.Errorf("new_actor: Failed to join topic: %v", err)
}

// Set the messages channel
a.Messages = make(chan *msg.Message, MESSAGES_BUFFERSIZE)

// Publish the entity
err = a.Entity.Publish(forcePublish)
if err != nil {
return nil, fmt.Errorf("new_actor: Failed to publish Entity: %v", err)
}

log.Debugf("new_actor: Actor initialized: %s", a.Entity.DID.Fragment)
return a, nil

}

// Creates a new actor from a keyset.
// Takes a pubsub.PubSub service, a keyset and a forcePublish flag.
func NewFromKeyset(ctx context.Context, ps *pubsub.PubSub, k *set.Keyset, forcePublish bool) (*Actor, error) {

log.Debugf("Setting Actor Entity: %v", k)
e, err := entity.NewFromKeyset(k)
if err != nil {
return nil, fmt.Errorf("new_actor: Failed to create Entity: %v", err)
}

return New(ctx, ps, e, forcePublish)
}
20 changes: 20 additions & 0 deletions actor/enter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package actor

import "fmt"

// Takes a room topic and joins it. The room is the DID of the room actor.
func (a *Actor) Enter(room string) error {

var err error

// First close the current subscription
a.Public.Close()

a.Public, err = a.ps.Join(room)
if err != nil {
return fmt.Errorf("home: %v failed to join topic: %v", a, err)
}

return nil

}
32 changes: 32 additions & 0 deletions actor/listen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package actor

import (
"fmt"
)

func (a *Actor) Listen(outputChannel chan<- string) error {
// Subscribe to Inbox topic
inboxSub, err := a.Private.Subscribe()
if err != nil {
return fmt.Errorf("failed to subscribe to Inbox topic: %v", err)
}
defer inboxSub.Cancel()

// Subscribe to Space topic
spaceSub, err := a.Public.Subscribe()
if err != nil {
return fmt.Errorf("failed to subscribe to Space topic: %v", err)
}
defer spaceSub.Cancel()

// Start a goroutine for Inbox subscription
go a.handlePrivateMessages(inboxSub)

// Start a goroutine for Space subscription
// Assuming you have a similar function for Space
go a.handlePublicMessages(spaceSub)

// Wait for context cancellation (or other exit conditions)
<-a.ctx.Done()
return a.ctx.Err()
}
44 changes: 44 additions & 0 deletions actor/private.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package actor

import (
"fmt"

"github.com/bahner/go-ma/msg"
"github.com/bahner/go-ma/msg/envelope"
pubsub "github.com/libp2p/go-libp2p-pubsub"
)

func (a *Actor) receivePrivateEnvelopes(sub *pubsub.Subscription) (*msg.Message, error) {

msgData, err := sub.Next(a.ctx)
if err != nil {
return nil, fmt.Errorf("failed to receive message from inbox: %v", err)
}

e, err := envelope.UnmarshalFromCBOR(msgData.Data)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal envelope from CBOR: %v", err)
}

message, err := e.Open(a.Entity.Keyset.EncryptionKey.PrivKey)
if err != nil {
return nil, fmt.Errorf("failed to open envelope: %v", err)
}

return message, nil
}

func (a *Actor) handlePrivateMessages(sub *pubsub.Subscription) {
for {
select {
case <-a.ctx.Done():
// Exit goroutine when context is cancelled
return
default:
// Read message from Inbox subscription
if msg, err := a.receivePrivateEnvelopes(sub); err == nil {
a.Messages <- msg
}
}
}
}
Loading

0 comments on commit 850ac69

Please sign in to comment.