diff --git a/core/auth.go b/core/auth.go index e0c19ea..f2263a3 100644 --- a/core/auth.go +++ b/core/auth.go @@ -24,6 +24,19 @@ func determineNetworkMode(networkConfigPath string) pb.RpcAccountNetworkMode { return pb.RpcAccount_DefaultConfig } +func newAccountSelectRequest(accountId, apiAddr, rootPath string, networkMode pb.RpcAccountNetworkMode, networkConfigPath string) *pb.RpcAccountSelectRequest { + return &pb.RpcAccountSelectRequest{ + Id: accountId, + JsonApiListenAddr: apiAddr, + RootPath: rootPath, + NetworkMode: networkMode, + NetworkCustomConfigFilePath: networkConfigPath, + // Headless deployments can run on networks where QUIC is unavailable + // or unreliable. anytype-heart provides Yamux/TCP for this case. + PreferYamuxTransport: true, + } +} + // Authenticate performs the full authentication flow for a bot account using an account key. // This includes wallet recovery, session creation, account recovery, account selection, and config persistence. // If networkConfigPath is provided, connects to that custom network. @@ -113,13 +126,7 @@ func Authenticate(accountKey, rootPath, apiAddr, networkConfigPath string) error var techSpaceId string err = GRPCCall(func(ctx context.Context, client service.ClientCommandsClient) error { - resp, err := client.AccountSelect(ctx, &pb.RpcAccountSelectRequest{ - Id: accountId, - JsonApiListenAddr: apiAddr, - RootPath: rootPath, - NetworkMode: networkMode, - NetworkCustomConfigFilePath: networkConfigPath, - }) + resp, err := client.AccountSelect(ctx, newAccountSelectRequest(accountId, apiAddr, rootPath, networkMode, networkConfigPath)) if err != nil { return fmt.Errorf("failed to select account: %w", err) } diff --git a/core/auth_test.go b/core/auth_test.go index ae6a3d2..0ef6046 100644 --- a/core/auth_test.go +++ b/core/auth_test.go @@ -3,8 +3,39 @@ package core import ( "strings" "testing" + + "github.com/anyproto/anytype-heart/pb" ) +func TestNewAccountSelectRequestPrefersYamuxTransport(t *testing.T) { + req := newAccountSelectRequest( + "account-id", + "127.0.0.1:31012", + "/tmp/anytype-data", + pb.RpcAccount_CustomConfig, + "/tmp/network.yml", + ) + + if !req.PreferYamuxTransport { + t.Fatal("headless account selection must prefer Yamux/TCP to avoid QUIC invite timeouts") + } + if req.Id != "account-id" { + t.Errorf("Id = %q, want %q", req.Id, "account-id") + } + if req.JsonApiListenAddr != "127.0.0.1:31012" { + t.Errorf("JsonApiListenAddr = %q, want %q", req.JsonApiListenAddr, "127.0.0.1:31012") + } + if req.RootPath != "/tmp/anytype-data" { + t.Errorf("RootPath = %q, want %q", req.RootPath, "/tmp/anytype-data") + } + if req.NetworkMode != pb.RpcAccount_CustomConfig { + t.Errorf("NetworkMode = %v, want %v", req.NetworkMode, pb.RpcAccount_CustomConfig) + } + if req.NetworkCustomConfigFilePath != "/tmp/network.yml" { + t.Errorf("NetworkCustomConfigFilePath = %q, want %q", req.NetworkCustomConfigFilePath, "/tmp/network.yml") + } +} + func TestValidateAccountKey(t *testing.T) { tests := []struct { name string