Skip to content

Commit

Permalink
wip(sites): init remote site on group creation
Browse files Browse the repository at this point in the history
  • Loading branch information
juligasa authored and ericvicenti committed Sep 18, 2023
1 parent 84a25f3 commit 7ae5129
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 38 deletions.
2 changes: 1 addition & 1 deletion backend/cmd/mintter-site/sites/sites.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func (ws *Website) RegisterSite(ctx context.Context, hostname string) (link stri
}

// GetSiteInfo exposes the public information of a site. Which group is serving and how to reach the site via p2p.
func (ws Website) GetSiteInfo(ctx context.Context, _ *groups.GetSiteInfoRequest) (*groups.PublicSiteInfo, error) {
func (ws Website) GetSiteInfo(ctx context.Context, in *groups.GetSiteInfoRequest) (*groups.PublicSiteInfo, error) {
n, ok := ws.Net.Get()
if !ok {
return nil, errNodeNotReadyYet
Expand Down
36 changes: 2 additions & 34 deletions backend/cmd/monitord/server/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,13 @@ package server
import (
"context"
"fmt"
"io"
groups "mintter/backend/genproto/groups/v1alpha"
"net/http"
groups "mintter/backend/daemon/api/groups/v1alpha"
"time"

peer "github.com/libp2p/go-libp2p/core/peer"
peerstore "github.com/libp2p/go-libp2p/core/peerstore"
ping "github.com/libp2p/go-libp2p/p2p/protocol/ping"
"github.com/multiformats/go-multiaddr"
"google.golang.org/protobuf/encoding/protojson"
)

func (s *Srv) checkP2P(ctx context.Context, peer peer.AddrInfo, numPings int) (time.Duration, error) {
Expand Down Expand Up @@ -59,7 +56,7 @@ func (s *Srv) checkP2P(ctx context.Context, peer peer.AddrInfo, numPings int) (t
}

func (s *Srv) checkMintterAddrs(ctx context.Context, hostname, mustInclude string) (info peer.AddrInfo, err error) {
resp, err := s.getSiteInfoHTTP(ctx, hostname)
resp, err := groups.GetSiteInfoHTTP(ctx, hostname)
if err != nil {
return info, err
}
Expand All @@ -84,32 +81,3 @@ func (s *Srv) checkMintterAddrs(ctx context.Context, hostname, mustInclude strin

return info, nil
}

func (s *Srv) getSiteInfoHTTP(ctx context.Context, SiteHostname string) (*groups.PublicSiteInfo, error) {
requestURL := fmt.Sprintf("%s/%s", SiteHostname, ".well-known/hypermedia-site")

req, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL, nil)
if err != nil {
return nil, fmt.Errorf("could not create request to well-known site: %w ", err)
}

res, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("could not contact to provided site [%s]: %w ", requestURL, err)
}
defer res.Body.Close()
if res.StatusCode < 200 || res.StatusCode > 299 {
return nil, fmt.Errorf("site info url [%s] not working. Status code: %d", requestURL, res.StatusCode)
}

data, err := io.ReadAll(res.Body)
if err != nil {
return nil, fmt.Errorf("failed to read json body: %w", err)
}

resp := &groups.PublicSiteInfo{}
if err := protojson.Unmarshal(data, resp); err != nil {
return nil, fmt.Errorf("failed to unmarshal JSON body: %w", err)
}
return resp, nil
}
92 changes: 89 additions & 3 deletions backend/daemon/api/groups/v1alpha/groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"context"
"encoding/json"
"fmt"
"io"
"mintter/backend/core"
groups "mintter/backend/genproto/groups/v1alpha"
"mintter/backend/hlc"
Expand All @@ -15,14 +16,17 @@ import (
"mintter/backend/pkg/errutil"
"mintter/backend/pkg/future"
"mintter/backend/pkg/maputil"
"net/http"
"strings"
"time"

"crawshaw.io/sqlite"
"crawshaw.io/sqlite/sqlitex"
"github.com/ipfs/go-cid"
"github.com/libp2p/go-libp2p/core/peer"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/types/known/timestamppb"
)

Expand All @@ -47,9 +51,13 @@ func (srv *Server) CreateGroup(ctx context.Context, in *groups.CreateGroupReques
if in.Title == "" {
return nil, errutil.MissingArgument("title")
}

var n *mttnet.Node
var ok bool
if in.SiteSetupUrl != "" {
return nil, status.Errorf(codes.Unimplemented, "site setup is not implemented yet")
n, ok = srv.node.Get()
if !ok {
return nil, fmt.Errorf("Node not ready yet")
}
}

me, err := srv.getMe()
Expand Down Expand Up @@ -83,6 +91,7 @@ func (srv *Server) CreateGroup(ctx context.Context, in *groups.CreateGroupReques
if err != nil {
return nil, err
}

hb, err := e.CreateChange(ts, me.DeviceKey(), del, patch, hyper.WithAction("Create"))
if err != nil {
return nil, err
Expand All @@ -92,6 +101,27 @@ func (srv *Server) CreateGroup(ctx context.Context, in *groups.CreateGroupReques
return nil, err
}

if in.SiteSetupUrl != "" {
siteURL := strings.Split(in.SiteSetupUrl, "/secret-invite/")[0]
resp, err := GetSiteInfoHTTP(ctx, siteURL)
if err != nil {
return nil, fmt.Errorf("Could not contact site at %s: %w", siteURL, err)
}
pid, err := peer.Decode(resp.PeerInfo.PeerId)
if err != nil {
return nil, fmt.Errorf("failed to decode peer ID %s: %w", resp.PeerInfo.PeerId, err)
}
c, err := n.SiteClient(ctx, pid)
if err != nil {
return nil, fmt.Errorf("Could not contact site via P2P: %w", err)
}
if _, err := c.InitializeServer(ctx, &groups.InitializeServerRequest{
Secret: in.SiteSetupUrl,
GroupId: id,
}); err != nil {
return nil, fmt.Errorf("Could not publish group to site. P2P group, however, was created successfully: %w", err)
}
}
return groupToProto(srv.blobs, e)
}

Expand Down Expand Up @@ -132,8 +162,13 @@ func (srv *Server) UpdateGroup(ctx context.Context, in *groups.UpdateGroupReques
return nil, errutil.MissingArgument("id")
}

var n *mttnet.Node
var ok bool
if in.SiteSetupUrl != "" {
return nil, status.Errorf(codes.Unimplemented, "site setup is not implemented yet")
n, ok = srv.node.Get()
if !ok {
return nil, fmt.Errorf("Node not ready yet")
}
}

me, err := srv.getMe()
Expand Down Expand Up @@ -195,6 +230,27 @@ func (srv *Server) UpdateGroup(ctx context.Context, in *groups.UpdateGroupReques
return nil, err
}

if in.SiteSetupUrl != "" {
siteURL := strings.Split(in.SiteSetupUrl, "/secret-invite/")[0]
resp, err := GetSiteInfoHTTP(ctx, siteURL)
if err != nil {
return nil, fmt.Errorf("Could not contact site at %s: %w", siteURL, err)
}
pid, err := peer.Decode(resp.PeerInfo.PeerId)
if err != nil {
return nil, fmt.Errorf("failed to decode peer ID %s: %w", resp.PeerInfo.PeerId, err)
}
c, err := n.SiteClient(ctx, pid)
if err != nil {
return nil, fmt.Errorf("Could not contact site via P2P: %w", err)
}
if _, err := c.InitializeServer(ctx, &groups.InitializeServerRequest{
Secret: in.SiteSetupUrl,
GroupId: in.Id,
}); err != nil {
return nil, fmt.Errorf("Could not publish group to site. P2P group, however, was updated successfully: %w", err)
}
}
return groupToProto(srv.blobs, e)
}

Expand Down Expand Up @@ -565,3 +621,33 @@ func (srv *Server) getDelegation(ctx context.Context) (cid.Cid, error) {

return out, nil
}

// GetSiteInfoHTTP gets public information from a site.
func GetSiteInfoHTTP(ctx context.Context, SiteUrl string) (*groups.PublicSiteInfo, error) {
requestURL := fmt.Sprintf("%s/%s", SiteUrl, ".well-known/hypermedia-site")

req, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL, nil)
if err != nil {
return nil, fmt.Errorf("could not create request to well-known site: %w ", err)
}

res, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("could not contact to provided site [%s]: %w ", requestURL, err)
}
defer res.Body.Close()
if res.StatusCode < 200 || res.StatusCode > 299 {
return nil, fmt.Errorf("site info url [%s] not working. Status code: %d", requestURL, res.StatusCode)
}

data, err := io.ReadAll(res.Body)
if err != nil {
return nil, fmt.Errorf("failed to read json body: %w", err)
}

resp := &groups.PublicSiteInfo{}
if err := protojson.Unmarshal(data, resp); err != nil {
return nil, fmt.Errorf("failed to unmarshal JSON body: %w", err)
}
return resp, nil
}
26 changes: 26 additions & 0 deletions backend/mttnet/mttnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io"
"mintter/backend/config"
"mintter/backend/core"
groups "mintter/backend/genproto/groups/v1alpha"
p2p "mintter/backend/genproto/p2p/v1alpha"
"mintter/backend/hyper"
"mintter/backend/hyper/hypersql"
Expand Down Expand Up @@ -50,6 +51,18 @@ const (

var userAgent = "mintter/<dev>"

// WebsiteClient is the bridge to talk to remote sites.
type WebsiteClient interface {
// InitializeServer instruct the website that starts serving a given group.
InitializeServer(context.Context, *groups.InitializeServerRequest, ...grpc.CallOption) (*groups.InitializeServerResponse, error)

// GetSiteInfo gets public site information, to be also found in /.well-known/hypermedia-site
GetSiteInfo(context.Context, *groups.GetSiteInfoRequest, ...grpc.CallOption) (*groups.PublicSiteInfo, error)

// PublishBlobs pushes given blobs to the site.
PublishBlobs(context.Context, *groups.PublishBlobsRequest, ...grpc.CallOption) (*groups.PublishBlobsResponse, error)
}

// DefaultRelays bootstrap mintter-owned relays so they can reserve slots to do holepunch.
func DefaultRelays() []peer.AddrInfo {
return []peer.AddrInfo{
Expand Down Expand Up @@ -204,6 +217,19 @@ func (n *Node) Client(ctx context.Context, pid peer.ID) (p2p.P2PClient, error) {
return n.client.Dial(ctx, pid)
}

// SiteClient opens a connection with a remote website.
func (n *Node) SiteClient(ctx context.Context, pid peer.ID) (WebsiteClient, error) {
if err := n.Connect(ctx, n.p2p.Peerstore().PeerInfo(pid)); err != nil {
return nil, err
}

conn, err := n.client.dialPeer(ctx, pid)
if err != nil {
return nil, err
}
return groups.NewWebsiteClient(conn), nil
}

// ArePrivateIPsAllowed check if private IPs (local) are allowed to connect.
func (n *Node) ArePrivateIPsAllowed() bool {
return !n.cfg.NoPrivateIps
Expand Down

0 comments on commit 7ae5129

Please sign in to comment.