Ejemplo n.º 1
0
// Startup establishes a connection to the RPC source, and spins up all
// goroutines required to handle incoming messages.
func (l *LightningWallet) Startup() error {
	// Already started?
	if atomic.AddInt32(&l.started, 1) != 1 {
		return nil
	}
	// TODO(roasbeef): config...

	rpcc, err := chain.NewClient(ActiveNetParams,
		l.cfg.RpcHost, l.cfg.RpcUser, l.cfg.RpcPass, l.cfg.CACert, false)
	if err != nil {
		return err
	}

	// Start the goroutines in the underlying wallet.
	l.rpc = rpcc
	if err := l.rpc.Start(); err != nil {
		return err
	}

	l.Start(rpcc)

	l.wg.Add(1)
	// TODO(roasbeef): multiple request handlers?
	go l.requestHandler()

	return nil
}
Ejemplo n.º 2
0
// walletMain is a work-around main function that is required since deferred
// functions (such as log flushing) are not called with calls to os.Exit.
// Instead, main runs this function and checks for a non-nil error, at which
// point any defers have already run, and if the error is non-nil, the program
// can be exited with an error exit status.
func walletMain() error {
	// Load configuration and parse command line.  This function also
	// initializes logging and configures it accordingly.
	tcfg, _, err := loadConfig()
	if err != nil {
		return err
	}
	cfg = tcfg
	defer backendLog.Flush()

	if cfg.Profile != "" {
		go func() {
			listenAddr := net.JoinHostPort("", cfg.Profile)
			log.Infof("Profile server listening on %s", listenAddr)
			profileRedirect := http.RedirectHandler("/debug/pprof",
				http.StatusSeeOther)
			http.Handle("/", profileRedirect)
			log.Errorf("%v", http.ListenAndServe(listenAddr, nil))
		}()
	}

	// Load the wallet database.  It must have been created with the
	// --create option already or this will return an appropriate error.
	wallet, db, err := openWallet()
	if err != nil {
		log.Errorf("%v", err)
		return err
	}
	defer db.Close()

	// Create and start HTTP server to serve wallet client connections.
	// This will be updated with the wallet and chain server RPC client
	// created below after each is created.
	server, err := newRPCServer(cfg.SvrListeners, cfg.RPCMaxClients,
		cfg.RPCMaxWebsockets)
	if err != nil {
		log.Errorf("Unable to create HTTP server: %v", err)
		return err
	}
	server.Start()
	server.SetWallet(wallet)

	// Shutdown the server if an interrupt signal is received.
	addInterruptHandler(server.Stop)

	go func() {
		for {
			// Read CA certs and create the RPC client.
			var certs []byte
			if !cfg.DisableClientTLS {
				certs, err = ioutil.ReadFile(cfg.CAFile)
				if err != nil {
					log.Warnf("Cannot open CA file: %v", err)
					// If there's an error reading the CA file, continue
					// with nil certs and without the client connection
					certs = nil
				}
			} else {
				log.Info("Client TLS is disabled")
			}
			rpcc, err := chain.NewClient(activeNet.Params, cfg.RPCConnect,
				cfg.BtcdUsername, cfg.BtcdPassword, certs, cfg.DisableClientTLS)
			if err != nil {
				log.Errorf("Cannot create chain server RPC client: %v", err)
				return
			}
			err = rpcc.Start()
			if err != nil {
				log.Warnf("Connection to Bitcoin RPC chain server " +
					"unsuccessful -- available RPC methods will be limited")
			}
			// Even if Start errored, we still add the server disconnected.
			// All client methods will then error, so it's obvious to a
			// client that the there was a connection problem.
			server.SetChainServer(rpcc)

			// Start wallet goroutines and handle RPC client notifications
			// if the server is not shutting down.
			select {
			case <-server.quit:
				return
			default:
				wallet.Start(rpcc)
			}

			// Block goroutine until the client is finished.
			rpcc.WaitForShutdown()

			wallet.SetChainSynced(false)
			wallet.Stop()

			// Reconnect only if the server is not shutting down.
			select {
			case <-server.quit:
				return
			default:
			}
		}
	}()

	// Wait for the server to shutdown either due to a stop RPC request
	// or an interrupt.
	server.WaitForShutdown()
	log.Info("Shutdown complete")
	return nil
}