diff --git a/build/gobind/build.sh b/build/gobind/build.sh new file mode 100644 index 000000000..3a80d374a --- /dev/null +++ b/build/gobind/build.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +gomobile bind -v \ + -ldflags "-X $github.com/yggdrasil-network/yggdrasil-go/src/version.buildName=riot-ios-p2p" \ + -target ios \ + github.com/matrix-org/dendrite/build/gobind \ No newline at end of file diff --git a/build/gobind/monolith.go b/build/gobind/monolith.go new file mode 100644 index 000000000..deb80771d --- /dev/null +++ b/build/gobind/monolith.go @@ -0,0 +1,153 @@ +package gobind + +import ( + "context" + "crypto/tls" + "fmt" + "net" + "net/http" + "time" + + "github.com/matrix-org/dendrite/appservice" + "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing" + "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/yggconn" + "github.com/matrix-org/dendrite/eduserver" + "github.com/matrix-org/dendrite/eduserver/cache" + "github.com/matrix-org/dendrite/federationsender" + "github.com/matrix-org/dendrite/internal" + "github.com/matrix-org/dendrite/internal/basecomponent" + "github.com/matrix-org/dendrite/internal/config" + "github.com/matrix-org/dendrite/internal/setup" + "github.com/matrix-org/dendrite/publicroomsapi/storage" + "github.com/matrix-org/dendrite/roomserver" + "github.com/matrix-org/gomatrixserverlib" + "github.com/sirupsen/logrus" +) + +type DendriteMonolith struct { + StorageDirectory string + listener net.Listener +} + +func (m *DendriteMonolith) BaseURL() string { + return fmt.Sprintf("http://%s", m.listener.Addr().String()) +} + +func (m *DendriteMonolith) Start() { + logger := logrus.Logger{ + Out: BindLogger{}, + } + + var err error + m.listener, err = net.Listen("tcp", "localhost:0") + if err != nil { + panic(err) + } + + // Build both ends of a HTTP multiplex. + httpServer := &http.Server{ + Addr: ":0", + TLSNextProto: map[string]func(*http.Server, *tls.Conn, http.Handler){}, + ReadTimeout: 15 * time.Second, + WriteTimeout: 45 * time.Second, + IdleTimeout: 60 * time.Second, + BaseContext: func(_ net.Listener) context.Context { + return context.Background() + }, + } + + ygg, err := yggconn.Setup("dendrite", "", m.StorageDirectory) + if err != nil { + panic(err) + } + + cfg := &config.Dendrite{} + cfg.SetDefaults() + cfg.Matrix.ServerName = gomatrixserverlib.ServerName(ygg.DerivedServerName()) + cfg.Matrix.PrivateKey = ygg.SigningPrivateKey() + cfg.Matrix.KeyID = gomatrixserverlib.KeyID(signing.KeyID) + cfg.Kafka.UseNaffka = true + cfg.Kafka.Topics.OutputRoomEvent = "roomserverOutput" + cfg.Kafka.Topics.OutputClientData = "clientapiOutput" + cfg.Kafka.Topics.OutputTypingEvent = "typingServerOutput" + cfg.Database.Account = config.DataSource(fmt.Sprintf("file:%s/dendrite-account.db", m.StorageDirectory)) + cfg.Database.Device = config.DataSource(fmt.Sprintf("file:%s/dendrite-device.db", m.StorageDirectory)) + cfg.Database.MediaAPI = config.DataSource(fmt.Sprintf("file:%s/dendrite-mediaapi.db", m.StorageDirectory)) + cfg.Database.SyncAPI = config.DataSource(fmt.Sprintf("file:%s/dendrite-syncapi.db", m.StorageDirectory)) + cfg.Database.RoomServer = config.DataSource(fmt.Sprintf("file:%s/dendrite-roomserver.db", m.StorageDirectory)) + cfg.Database.ServerKey = config.DataSource(fmt.Sprintf("file:%s/dendrite-serverkey.db", m.StorageDirectory)) + cfg.Database.FederationSender = config.DataSource(fmt.Sprintf("file:%s/dendrite-federationsender.db", m.StorageDirectory)) + cfg.Database.AppService = config.DataSource(fmt.Sprintf("file:%s/dendrite-appservice.db", m.StorageDirectory)) + cfg.Database.PublicRoomsAPI = config.DataSource(fmt.Sprintf("file:%s/dendrite-publicroomsa.db", m.StorageDirectory)) + cfg.Database.Naffka = config.DataSource(fmt.Sprintf("file:%s/dendrite-naffka.db", m.StorageDirectory)) + if err = cfg.Derive(); err != nil { + panic(err) + } + + base := basecomponent.NewBaseDendrite(cfg, "Monolith", false) + defer base.Close() // nolint: errcheck + + accountDB := base.CreateAccountsDB() + deviceDB := base.CreateDeviceDB() + federation := ygg.CreateFederationClient(base) + + serverKeyAPI := &signing.YggdrasilKeys{} + keyRing := serverKeyAPI.KeyRing() + + rsComponent := roomserver.NewInternalAPI( + base, keyRing, federation, + ) + rsAPI := rsComponent + + eduInputAPI := eduserver.NewInternalAPI( + base, cache.New(), deviceDB, + ) + + asAPI := appservice.NewInternalAPI(base, accountDB, deviceDB, rsAPI) + + fsAPI := federationsender.NewInternalAPI( + base, federation, rsAPI, keyRing, + ) + + rsComponent.SetFederationSenderAPI(fsAPI) + + publicRoomsDB, err := storage.NewPublicRoomsServerDatabase(string(base.Cfg.Database.PublicRoomsAPI), base.Cfg.DbProperties(), cfg.Matrix.ServerName) + if err != nil { + logger.WithError(err).Panicf("failed to connect to public rooms db") + } + + monolith := setup.Monolith{ + Config: base.Cfg, + AccountDB: accountDB, + DeviceDB: deviceDB, + FedClient: federation, + KeyRing: keyRing, + KafkaConsumer: base.KafkaConsumer, + KafkaProducer: base.KafkaProducer, + + AppserviceAPI: asAPI, + EDUInternalAPI: eduInputAPI, + FederationSenderAPI: fsAPI, + RoomserverAPI: rsAPI, + + PublicRoomsDB: publicRoomsDB, + } + monolith.AddAllPublicRoutes(base.PublicAPIMux) + + internal.SetupHTTPAPI( + http.DefaultServeMux, + base.PublicAPIMux, + base.InternalAPIMux, + cfg, + base.UseHTTPAPIs, + ) + + go func() { + logger.Info("Listening on ", ygg.DerivedServerName()) + logger.Fatal(httpServer.Serve(ygg)) + }() + go func() { + logger.Info("Listening on ", m.BaseURL()) + logger.Fatal(http.Serve(m.listener, nil)) + }() +} diff --git a/build/gobind/platform_ios.go b/build/gobind/platform_ios.go new file mode 100644 index 000000000..7e27fa381 --- /dev/null +++ b/build/gobind/platform_ios.go @@ -0,0 +1,25 @@ +// build +ios + +package gobind + +/* +#cgo CFLAGS: -x objective-c +#cgo LDFLAGS: -framework Foundation +#import +void Log(const char *text) { + NSString *nss = [NSString stringWithUTF8String:text]; + NSLog(@"%@", nss); +} +*/ +import "C" +import "unsafe" + +type BindLogger struct { +} + +func (nsl BindLogger) Write(p []byte) (n int, err error) { + p = append(p, 0) + cstr := (*C.char)(unsafe.Pointer(&p[0])) + C.Log(cstr) + return len(p), nil +} diff --git a/build/gobind/platform_other.go b/build/gobind/platform_other.go new file mode 100644 index 000000000..fdfb13bc0 --- /dev/null +++ b/build/gobind/platform_other.go @@ -0,0 +1,12 @@ +// +build !ios + +package gobind + +import "log" + +type BindLogger struct{} + +func (nsl BindLogger) Write(p []byte) (n int, err error) { + log.Println(string(p)) + return len(p), nil +} diff --git a/cmd/dendrite-demo-yggdrasil/main.go b/cmd/dendrite-demo-yggdrasil/main.go index 6ef56d325..d217ee145 100644 --- a/cmd/dendrite-demo-yggdrasil/main.go +++ b/cmd/dendrite-demo-yggdrasil/main.go @@ -16,18 +16,14 @@ package main import ( "context" - "crypto/ed25519" "crypto/tls" - "encoding/hex" "flag" "fmt" "net" "net/http" - "strings" "time" "github.com/matrix-org/dendrite/appservice" - "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/convert" "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/embed" "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing" "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/yggconn" @@ -51,46 +47,6 @@ var ( instancePeer = flag.String("peer", "", "an internet Yggdrasil peer to connect to") ) -type yggroundtripper struct { - inner *http.Transport -} - -func (y *yggroundtripper) RoundTrip(req *http.Request) (*http.Response, error) { - req.URL.Scheme = "http" - return y.inner.RoundTrip(req) -} - -func createFederationClient( - base *basecomponent.BaseDendrite, n *yggconn.Node, -) *gomatrixserverlib.FederationClient { - yggdialer := func(_, address string) (net.Conn, error) { - tokens := strings.Split(address, ":") - raw, err := hex.DecodeString(tokens[0]) - if err != nil { - return nil, fmt.Errorf("hex.DecodeString: %w", err) - } - converted := convert.Ed25519PublicKeyToCurve25519(ed25519.PublicKey(raw)) - convhex := hex.EncodeToString(converted) - return n.Dial("curve25519", convhex) - } - yggdialerctx := func(ctx context.Context, network, address string) (net.Conn, error) { - return yggdialer(network, address) - } - tr := &http.Transport{} - tr.RegisterProtocol( - "matrix", &yggroundtripper{ - inner: &http.Transport{ - ResponseHeaderTimeout: 15 * time.Second, - IdleConnTimeout: 60 * time.Second, - DialContext: yggdialerctx, - }, - }, - ) - return gomatrixserverlib.NewFederationClientWithTransport( - base.Cfg.Matrix.ServerName, base.Cfg.Matrix.KeyID, base.Cfg.Matrix.PrivateKey, tr, - ) -} - // nolint:gocyclo func main() { flag.Parse() @@ -107,7 +63,7 @@ func main() { }, } - ygg, err := yggconn.Setup(*instanceName, *instancePeer) + ygg, err := yggconn.Setup(*instanceName, *instancePeer, ".") if err != nil { panic(err) } @@ -140,7 +96,7 @@ func main() { accountDB := base.CreateAccountsDB() deviceDB := base.CreateDeviceDB() - federation := createFederationClient(base, ygg) + federation := ygg.CreateFederationClient(base) serverKeyAPI := &signing.YggdrasilKeys{} keyRing := serverKeyAPI.KeyRing() diff --git a/cmd/dendrite-demo-yggdrasil/yggconn/client.go b/cmd/dendrite-demo-yggdrasil/yggconn/client.go new file mode 100644 index 000000000..36ea32973 --- /dev/null +++ b/cmd/dendrite-demo-yggdrasil/yggconn/client.go @@ -0,0 +1,56 @@ +package yggconn + +import ( + "context" + "crypto/ed25519" + "encoding/hex" + "fmt" + "net" + "net/http" + "strings" + "time" + + "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/convert" + "github.com/matrix-org/dendrite/internal/basecomponent" + "github.com/matrix-org/gomatrixserverlib" +) + +type yggroundtripper struct { + inner *http.Transport +} + +func (y *yggroundtripper) RoundTrip(req *http.Request) (*http.Response, error) { + req.URL.Scheme = "http" + return y.inner.RoundTrip(req) +} + +func (n *Node) CreateFederationClient( + base *basecomponent.BaseDendrite, +) *gomatrixserverlib.FederationClient { + yggdialer := func(_, address string) (net.Conn, error) { + tokens := strings.Split(address, ":") + raw, err := hex.DecodeString(tokens[0]) + if err != nil { + return nil, fmt.Errorf("hex.DecodeString: %w", err) + } + converted := convert.Ed25519PublicKeyToCurve25519(ed25519.PublicKey(raw)) + convhex := hex.EncodeToString(converted) + return n.Dial("curve25519", convhex) + } + yggdialerctx := func(ctx context.Context, network, address string) (net.Conn, error) { + return yggdialer(network, address) + } + tr := &http.Transport{} + tr.RegisterProtocol( + "matrix", &yggroundtripper{ + inner: &http.Transport{ + ResponseHeaderTimeout: 15 * time.Second, + IdleConnTimeout: 60 * time.Second, + DialContext: yggdialerctx, + }, + }, + ) + return gomatrixserverlib.NewFederationClientWithTransport( + base.Cfg.Matrix.ServerName, base.Cfg.Matrix.KeyID, base.Cfg.Matrix.PrivateKey, tr, + ) +} diff --git a/cmd/dendrite-demo-yggdrasil/yggconn/node.go b/cmd/dendrite-demo-yggdrasil/yggconn/node.go index a625f8d8d..b8b70f985 100644 --- a/cmd/dendrite-demo-yggdrasil/yggconn/node.go +++ b/cmd/dendrite-demo-yggdrasil/yggconn/node.go @@ -49,7 +49,7 @@ type Node struct { } // nolint:gocyclo -func Setup(instanceName, instancePeer string) (*Node, error) { +func Setup(instanceName, instancePeer, storageDirectory string) (*Node, error) { n := &Node{ core: &yggdrasil.Core{}, config: yggdrasilconfig.GenerateConfig(), @@ -59,7 +59,7 @@ func Setup(instanceName, instancePeer string) (*Node, error) { incoming: make(chan *yamux.Stream), } - yggfile := fmt.Sprintf("%s-yggdrasil.conf", instanceName) + yggfile := fmt.Sprintf("%s/%s-yggdrasil.conf", storageDirectory, instanceName) if _, err := os.Stat(yggfile); !os.IsNotExist(err) { yggconf, e := ioutil.ReadFile(yggfile) if e != nil { @@ -69,7 +69,7 @@ func Setup(instanceName, instancePeer string) (*Node, error) { panic(err) } } else { - n.config.AdminListen = fmt.Sprintf("unix://./%s-yggdrasil.sock", instanceName) + n.config.AdminListen = "none" // fmt.Sprintf("unix://%s/%s-yggdrasil.sock", storageDirectory, instanceName) n.config.MulticastInterfaces = []string{".*"} n.config.EncryptionPrivateKey = hex.EncodeToString(n.EncryptionPrivateKey()) n.config.EncryptionPublicKey = hex.EncodeToString(n.EncryptionPublicKey()) @@ -96,20 +96,22 @@ func Setup(instanceName, instancePeer string) (*Node, error) { panic(err) } } - if err = n.admin.Init(n.core, n.state, n.log, nil); err != nil { - panic(err) - } - if err = n.admin.Start(); err != nil { - panic(err) - } + /* + if err = n.admin.Init(n.core, n.state, n.log, nil); err != nil { + panic(err) + } + if err = n.admin.Start(); err != nil { + panic(err) + } + */ if err = n.multicast.Init(n.core, n.state, n.log, nil); err != nil { panic(err) } if err = n.multicast.Start(); err != nil { panic(err) } - n.admin.SetupAdminHandlers(n.admin) - n.multicast.SetupAdminHandlers(n.admin) + //n.admin.SetupAdminHandlers(n.admin) + //n.multicast.SetupAdminHandlers(n.admin) n.listener, err = n.core.ConnListen() if err != nil { panic(err)