<commit_before>package mobile

import (
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"time"

	"gx/ipfs/QmRCrPXk2oUwpK1Cj2FXrUotRpddUxz56setkny2gz13Cx/go-libp2p-routing-helpers"
	"gx/ipfs/QmSY3nkMNLzh9GdbFKK5tT7YMfLpf52iUZ8ZRkr29MJaa5/go-libp2p-kad-dht"
	"gx/ipfs/QmSY3nkMNLzh9GdbFKK5tT7YMfLpf52iUZ8ZRkr29MJaa5/go-libp2p-kad-dht/opts"
	ma "gx/<KEY>"
	ipfsconfig "gx/ipfs/QmUAuYuiafnJRZxDDX7MuruMNsicYNuyub5vUeAcupUBNs/go-ipfs-config"
	ds "gx/ipfs/QmUadX5EcvrBmxAV9sE7wUWtWSqxns5K84qKJBixmcT1w9/go-datastore"
	ipnspb "gx/ipfs/QmUwMnKKjH3JwGKNVZ3TcP37W93xzqNA4ECFFiMo6sXkkc/go-ipns/pb"
	"gx/ipfs/QmYVXrKrKHDC9FobgmcmshCDyWwdrfwfanNQN4oxJ9Fk3h/go-libp2p-peer"
	p2phost "gx/ipfs/QmYrWiWM4qtrnCeT3R14jY3ZZyirDNJgwK57q4qFYePgbd/go-libp2p-host"
	"gx/ipfs/QmYxUdYY9S6yg5tSPVin5GFTvtfsLauVcr7reHDD3dM8xf/go-libp2p-routing"
	"gx/ipfs/QmbeHtaBy9nZsW4cHRcvgVY4CnDhXudE2Dr6qDxS7yg9rX/go-libp2p-record"
	ipfslogging "<KEY>"
	"<KEY>"
	"gx/ipfs/QmddjPSGZb3ieihSseFeCfVRpZzcqczPNsD2DvarSwnjJB/gogo-protobuf/proto"

	"github.com/OpenBazaar/openbazaar-go/api"
	"github.com/OpenBazaar/openbazaar-go/core"
	"github.com/OpenBazaar/openbazaar-go/ipfs"
	obnet "github.com/OpenBazaar/openbazaar-go/net"
	rep "github.com/OpenBazaar/openbazaar-go/net/repointer"
	ret "github.com/OpenBazaar/openbazaar-go/net/retriever"
	"github.com/OpenBazaar/openbazaar-go/net/service"
	"github.com/OpenBazaar/openbazaar-go/repo"
	"github.com/OpenBazaar/openbazaar-go/repo/db"
	"github.com/OpenBazaar/openbazaar-go/repo/migrations"
	"github.com/OpenBazaar/openbazaar-go/schema"
	apiSchema "github.com/OpenBazaar/openbazaar-go/schema"
	"github.com/OpenBazaar/openbazaar-go/storage/selfhosted"
	"github.com/OpenBazaar/openbazaar-go/wallet"
	lis "github.com/OpenBazaar/openbazaar-go/wallet/listeners"
	"github.com/OpenBazaar/openbazaar-go/wallet/resync"
	wi "github.com/OpenBazaar/wallet-interface"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcutil/hdkeychain"
	"github.com/ipfs/go-ipfs/commands"
	ipfscore "github.com/ipfs/go-ipfs/core"
	"github.com/ipfs/go-ipfs/core/corehttp"
	"github.com/ipfs/go-ipfs/namesys"
	"github.com/ipfs/go-ipfs/repo/fsrepo"
	"github.com/natefinch/lumberjack"
	"github.com/op/go-logging"
	"github.com/tyler-smith/go-bip39"
)

var log = logging.MustGetLogger("mobile")

// Node configuration structure
type Node struct {
	OpenBazaarNode *core.OpenBazaarNode
	config         NodeConfig
	cancel         context.CancelFunc
	ipfsConfig     *ipfscore.BuildCfg
	apiConfig      *apiSchema.APIConfig
}

var (
	fileLogFormat = logging.MustStringFormatter(
		`%{time:15:04:05.000} [%{level}] [%{module}/%{shortfunc}] %{message}`,
	)
	mainLoggingBackend logging.Backend
)

// NewNode create the configuration file for a new node
func NewNode(repoPath string, authenticationToken string, testnet bool, userAgent string, walletTrustedPeer string, password string, mnemonic string) *Node {
	// Node config
	nodeconfig := &NodeConfig{
		RepoPath:            repoPath,
		AuthenticationToken: authenticationToken,
		Testnet:             testnet,
		UserAgent:           userAgent,
		WalletTrustedPeer:   walletTrustedPeer,
	}

	// Use Mobile struct to carry config data
	node, err := NewNodeWithConfig(nodeconfig, password, mnemonic)
	if err != nil {
		fmt.Println(err)
	}
	return node
}

// NewNodeWithConfig create a new node using the configuration file from NewNode()
func NewNodeWithConfig(config *NodeConfig, password string, mnemonic string) (*Node, error) {
	// Lockfile
	repoLockFile := filepath.Join(config.RepoPath, fsrepo.LockFile)
	os.Remove(repoLockFile)

	ipfs.UpdateIPFSGlobalProtocolVars(config.Testnet)

	// Logging
	ipfsLog := &lumberjack.Logger{
		Filename:   path.Join(config.RepoPath, "logs", "ipfs.log"),
		MaxSize:    5, // Megabytes
		MaxBackups: 3,
		MaxAge:     30, // Days
	}
	ipfslogging.LdJSONFormatter()
	ipfslogging.Output(ipfsLog)()

	obLog := &lumberjack.Logger{
		Filename:   path.Join(config.RepoPath, "logs", "ob.log"),
		MaxSize:    5, // Megabytes
		MaxBackups: 3,
		MaxAge:     30, // Days
	}
	obFileBackend := logging.NewLogBackend(obLog, "", 0)
	obFileBackendFormatted := logging.NewBackendFormatter(obFileBackend, fileLogFormat)
	mainLoggingBackend = logging.SetBackend(obFileBackendFormatted)
	logging.SetLevel(logging.INFO, "")

	migrations.WalletCoinType = config.CoinType

	sqliteDB, err := initializeRepo(config.RepoPath, "", "", true, time.Now(), config.CoinType)
	if err != nil && err != repo.ErrRepoExists {
		return nil, err
	}

	// Get creation date. Ignore the error and use a default timestamp.
	creationDate, _ := sqliteDB.Config().GetCreationDate()

	// Load configs
	configFile, err := ioutil.ReadFile(path.Join(config.RepoPath, "config"))
	if err != nil {
		return nil, err
	}

	apiConfig, err := apiSchema.GetAPIConfig(configFile)
	if err != nil {
		return nil, err
	}

	dataSharing, err := apiSchema.GetDataSharing(configFile)
	if err != nil {
		return nil, err
	}

	walletsConfig, err := apiSchema.GetWalletsConfig(configFile)
	if err != nil {
		return nil, err
	}

	ipnsExtraConfig, err := apiSchema.GetIPNSExtraConfig(configFile)
	if err != nil {
		return nil, err
	}

	// Create user-agent file
	userAgentBytes := []byte(core.USERAGENT + config.UserAgent)
	ioutil.WriteFile(path.Join(config.RepoPath, "root", "user_agent"), userAgentBytes, os.ModePerm)

	// IPFS node setup
	r, err := fsrepo.Open(config.RepoPath)
	if err != nil {
		return nil, err
	}

	cfg, err := r.Config()
	if err != nil {
		return nil, err
	}

	identityKey, err := sqliteDB.Config().GetIdentityKey()
	if err != nil {
		return nil, err
	}
	identity, err := ipfs.IdentityFromKey(identityKey)
	if err != nil {
		return nil, err
	}
	cfg.Identity = identity
	cfg.Swarm.DisableNatPortMap = true

	// Setup testnet
	if config.Testnet {
		// set testnet bootstrap addrs
		testnetBootstrapAddrs, err := apiSchema.GetTestnetBootstrapAddrs(configFile)<commit_msg>[#1618] Enable temporary IPv6 bootstrap nodes for mobile package<commit_after>package mobile

import (
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"time"

	"gx/ipfs/QmRCrPXk2oUwpK1Cj2FXrUotRpddUxz56setkny2gz13Cx/go-libp2p-routing-helpers"
	"gx/ipfs/QmSY3nkMNLzh9GdbFKK5tT7YMfLpf52iUZ8ZRkr29MJaa5/go-libp2p-kad-dht"
	"gx/ipfs/QmSY3nkMNLzh9GdbFKK5tT7YMfLpf52iUZ8ZRkr29MJaa5/go-libp2p-kad-dht/opts"
	ma "<KEY>"
	ipfsconfig "gx/<KEY>"
	ds "gx/ipfs/QmUadX5EcvrBmxAV9sE7wUWtWSqxns5K84qKJBixmcT1w9/go-datastore"
	ipnspb "gx/ipfs/QmUwMnKKjH3JwGKNVZ3TcP37W93xzqNA4ECFFiMo6sXkkc/go-ipns/pb"
	"gx/ipfs/QmYVXrKrKHDC9FobgmcmshCDyWwdrfwfanNQN4oxJ9Fk3h/go-libp2p-peer"
	p2phost "gx/ipfs/QmYrWiWM4qtrnCeT3R14jY3ZZyirDNJgwK57q4qFYePgbd/go-libp2p-host"
	"gx/ipfs/QmYxUdYY9S6yg5tSPVin5GFTvtfsLauVcr7reHDD3dM8xf/go-libp2p-routing"
	"gx/ipfs/QmbeHtaBy9nZsW4cHRcvgVY4CnDhXudE2Dr6qDxS7yg9rX/go-libp2p-record"
	ipfslogging "gx/ipfs/QmbkT7eMTyXfpeyB3ZMxxcxg7XH8t6uXp49jqzz4HB7BGF/go-log/writer"
	"gx/ipfs/Qmc85NSvmSG4Frn9Vb2cBc1rMyULH6D3TNVEfCzSKoUpip/go-multiaddr-net"
	"gx/ipfs/QmddjPSGZb3ieihSseFeCfVRpZzcqczPNsD2DvarSwnjJB/gogo-protobuf/proto"

	"github.com/OpenBazaar/openbazaar-go/api"
	"github.com/OpenBazaar/openbazaar-go/core"
	"github.com/OpenBazaar/openbazaar-go/ipfs"
	obnet "github.com/OpenBazaar/openbazaar-go/net"
	rep "github.com/OpenBazaar/openbazaar-go/net/repointer"
	ret "github.com/OpenBazaar/openbazaar-go/net/retriever"
	"github.com/OpenBazaar/openbazaar-go/net/service"
	"github.com/OpenBazaar/openbazaar-go/repo"
	"github.com/OpenBazaar/openbazaar-go/repo/db"
	"github.com/OpenBazaar/openbazaar-go/repo/migrations"
	"github.com/OpenBazaar/openbazaar-go/schema"
	apiSchema "github.com/OpenBazaar/openbazaar-go/schema"
	"github.com/OpenBazaar/openbazaar-go/storage/selfhosted"
	"github.com/OpenBazaar/openbazaar-go/wallet"
	lis "github.com/OpenBazaar/openbazaar-go/wallet/listeners"
	"github.com/OpenBazaar/openbazaar-go/wallet/resync"
	wi "github.com/OpenBazaar/wallet-interface"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcutil/hdkeychain"
	"github.com/ipfs/go-ipfs/commands"
	ipfscore "github.com/ipfs/go-ipfs/core"
	"github.com/ipfs/go-ipfs/core/corehttp"
	"github.com/ipfs/go-ipfs/namesys"
	"github.com/ipfs/go-ipfs/repo/fsrepo"
	"github.com/natefinch/lumberjack"
	"github.com/op/go-logging"
	"github.com/tyler-smith/go-bip39"
)

var log = logging.MustGetLogger("mobile")

// Node configuration structure
type Node struct {
	OpenBazaarNode *core.OpenBazaarNode
	config         NodeConfig
	cancel         context.CancelFunc
	ipfsConfig     *ipfscore.BuildCfg
	apiConfig      *apiSchema.APIConfig
}

var (
	fileLogFormat = logging.MustStringFormatter(
		`%{time:15:04:05.000} [%{level}] [%{module}/%{shortfunc}] %{message}`,
	)
	mainLoggingBackend logging.Backend
)

// NewNode create the configuration file for a new node
func NewNode(repoPath string, authenticationToken string, testnet bool, userAgent string, walletTrustedPeer string, password string, mnemonic string) *Node {
	// Node config
	nodeconfig := &NodeConfig{
		RepoPath:            repoPath,
		AuthenticationToken: authenticationToken,
		Testnet:             testnet,
		UserAgent:           userAgent,
		WalletTrustedPeer:   walletTrustedPeer,
	}

	// Use Mobile struct to carry config data
	node, err := NewNodeWithConfig(nodeconfig, password, mnemonic)
	if err != nil {
		fmt.Println(err)
	}
	return node
}

// NewNodeWithConfig create a new node using the configuration file from NewNode()
func NewNodeWithConfig(config *NodeConfig, password string, mnemonic string) (*Node, error) {
	// Lockfile
	repoLockFile := filepath.Join(config.RepoPath, fsrepo.LockFile)
	os.Remove(repoLockFile)

	ipfs.UpdateIPFSGlobalProtocolVars(config.Testnet)

	// Logging
	ipfsLog := &lumberjack.Logger{
		Filename:   path.Join(config.RepoPath, "logs", "ipfs.log"),
		MaxSize:    5, // Megabytes
		MaxBackups: 3,
		MaxAge:     30, // Days
	}
	ipfslogging.LdJSONFormatter()
	ipfslogging.Output(ipfsLog)()

	obLog := &lumberjack.Logger{
		Filename:   path.Join(config.RepoPath, "logs", "ob.log"),
		MaxSize:    5, // Megabytes
		MaxBackups: 3,
		MaxAge:     30, // Days
	}
	obFileBackend := logging.NewLogBackend(obLog, "", 0)
	obFileBackendFormatted := logging.NewBackendFormatter(obFileBackend, fileLogFormat)
	mainLoggingBackend = logging.SetBackend(obFileBackendFormatted)
	logging.SetLevel(logging.INFO, "")

	migrations.WalletCoinType = config.CoinType

	sqliteDB, err := initializeRepo(config.RepoPath, "", "", true, time.Now(), config.CoinType)
	if err != nil && err != repo.ErrRepoExists {
		return nil, err
	}

	// Get creation date. Ignore the error and use a default timestamp.
	creationDate, _ := sqliteDB.Config().GetCreationDate()

	// Load configs
	configFile, err := ioutil.ReadFile(path.Join(config.RepoPath, "config"))
	if err != nil {
		return nil, err
	}

	apiConfig, err := apiSchema.GetAPIConfig(configFile)
	if err != nil {
		return nil, err
	}

	dataSharing, err := apiSchema.GetDataSharing(configFile)
	if err != nil {
		return nil, err
	}

	walletsConfig, err := apiSchema.GetWalletsConfig(configFile)
	if err != nil {
		return nil, err
	}

	ipnsExtraConfig, err := apiSchema.GetIPNSExtraConfig(configFile)
	if err != nil {
		return nil, err
	}

	// Create user-agent file
	userAgentBytes := []byte(core.USERAGENT + config.UserAgent)
	ioutil.WriteFile(path.Join(config.RepoPath, "root", "user_agent"), userAgentBytes, os.ModePerm)

	// IPFS node setup
	r, err := fsrepo.Open(config.RepoPath)
	if err != nil {
		return nil, err
	}

	cfg, err := r.Config()
	if err != nil {
		return nil, err
	}

	identityKey, err := sqliteDB.Config().GetIdentityKey()
	if err != nil {
		return nil, err
	}
	identity, err := ipfs.IdentityFromKey(identityKey)
	if err != nil {
		return nil, err
	}
	cfg.Identity = identity
	cfg.Swarm.DisableNatPortMap = false
	cfg.Swarm.EnableAutoRelay = true
	cfg.Swarm.EnableAutoNATService = false

	// Temporary override of bootstrap nodes
	cfg.Bootstrap = []string{
		"/ip6/2604:fc00:e968:6179::de52:7100:9001/tcp/4001/ipfs/QmWUdwXW3bTXS19MtMjmfpnRYgssmbJCwnq8Lf9vjZwDii",
		"/ip6/2604:fc00:e968:6179::de52:7100:2001/tcp/4001/ipfs/QmcXwJePGLsP1x7gTXLE51BmE7peUKe2eQuR5LGbmasekt",
		"/ip6/2604:fc00:e968:6179::de52:7100:8001/tcp/4001/ipfs/Qmb8i7uy6rk47hNorNLMVRMer4Nv9YWRhzZrWVqnvk5mSk",
		"/ip4/192.168.3.11/tcp/4001/ipfs/QmWUdwXW3bTXS19MtMjmfpnRYgssmbJCwnq8Lf9vjZwDii",
		"/ip4/157.230.59.219/tcp/4001/ipfs/QmcXwJePGLsP1x7gTXLE51BmE7peUKe2eQuR5LGbmasekt",
		"/ip4/172.16.17.32/tcp/4001/ipfs/Qmb8i7uy6rk47hNorNLMVRMer4Nv9YWRhzZrWVqnvk5mSk",
	}

	// Setup testnet
	if config.Testnet {
		// set testnet bootstrap addrs
		testnetBootstrapAddrs, err := apiSchema.GetTestnetBootstrapAddrs(configFile)
{'fraction_non_alphanumeric': 0.12485183721849072, 'fraction_numerical': 0.030975898854207824, 'mean_word_length': 4.805504587155963, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 3, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6223055', 'n_tokens_mistral': 5693, 'n_tokens_neox': 5461, 'n_words': 742}