github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/cmd/puppeth/module_wallet.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:33</date>
    10  //</624450069583630336>
    11  
    12  
    13  package main
    14  
    15  import (
    16  	"bytes"
    17  	"fmt"
    18  	"html/template"
    19  	"math/rand"
    20  	"path/filepath"
    21  	"strconv"
    22  	"strings"
    23  
    24  	"github.com/ethereum/go-ethereum/log"
    25  )
    26  
    27  //
    28  var walletDockerfile = `
    29  FROM puppeth/wallet:latest
    30  
    31  ADD genesis.json /genesis.json
    32  
    33  RUN \
    34    echo 'node server.js &'                     > wallet.sh && \
    35  	echo 'geth --cache 512 init /genesis.json' >> wallet.sh && \
    36  	echo $'exec geth --networkid {{.NetworkID}} --port {{.NodePort}} --bootnodes {{.Bootnodes}} --ethstats \'{{.Ethstats}}\' --cache=512 --rpc --rpcaddr=0.0.0.0 --rpccorsdomain "*" --rpcvhosts "*"' >> wallet.sh
    37  
    38  RUN \
    39  	sed -i 's/PuppethNetworkID/{{.NetworkID}}/g' dist/js/etherwallet-master.js && \
    40  	sed -i 's/PuppethNetwork/{{.Network}}/g'     dist/js/etherwallet-master.js && \
    41  	sed -i 's/PuppethDenom/{{.Denom}}/g'         dist/js/etherwallet-master.js && \
    42  	sed -i 's/PuppethHost/{{.Host}}/g'           dist/js/etherwallet-master.js && \
    43  	sed -i 's/PuppethRPCPort/{{.RPCPort}}/g'     dist/js/etherwallet-master.js
    44  
    45  ENTRYPOINT ["/bin/sh", "wallet.sh"]
    46  `
    47  
    48  //walletcomposefile是部署和
    49  //
    50  var walletComposefile = `
    51  version: '2'
    52  services:
    53    wallet:
    54      build: .
    55      image: {{.Network}}/wallet
    56      container_name: {{.Network}}_wallet_1
    57      ports:
    58        - "{{.NodePort}}:{{.NodePort}}"
    59        - "{{.NodePort}}:{{.NodePort}}/udp"
    60        - "{{.RPCPort}}:8545"{{if not .VHost}}
    61        - "{{.WebPort}}:80"{{end}}
    62      volumes:
    63        - {{.Datadir}}:/root/.ethereum
    64      environment:
    65        - NODE_PORT={{.NodePort}}/tcp
    66        - STATS={{.Ethstats}}{{if .VHost}}
    67        - VIRTUAL_HOST={{.VHost}}
    68        - VIRTUAL_PORT=80{{end}}
    69      logging:
    70        driver: "json-file"
    71        options:
    72          max-size: "1m"
    73          max-file: "10"
    74      restart: always
    75  `
    76  
    77  //
    78  //Docker和Docker组合。如果具有指定网络名称的实例
    79  //已经存在,将被覆盖!
    80  func deployWallet(client *sshClient, network string, bootnodes []string, config *walletInfos, nocache bool) ([]byte, error) {
    81  //生成要上载到服务器的内容
    82  	workdir := fmt.Sprintf("%d", rand.Int63())
    83  	files := make(map[string][]byte)
    84  
    85  	dockerfile := new(bytes.Buffer)
    86  	template.Must(template.New("").Parse(walletDockerfile)).Execute(dockerfile, map[string]interface{}{
    87  		"Network":   strings.ToTitle(network),
    88  		"Denom":     strings.ToUpper(network),
    89  		"NetworkID": config.network,
    90  		"NodePort":  config.nodePort,
    91  		"RPCPort":   config.rpcPort,
    92  		"Bootnodes": strings.Join(bootnodes, ","),
    93  		"Ethstats":  config.ethstats,
    94  		"Host":      client.address,
    95  	})
    96  	files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes()
    97  
    98  	composefile := new(bytes.Buffer)
    99  	template.Must(template.New("").Parse(walletComposefile)).Execute(composefile, map[string]interface{}{
   100  		"Datadir":  config.datadir,
   101  		"Network":  network,
   102  		"NodePort": config.nodePort,
   103  		"RPCPort":  config.rpcPort,
   104  		"VHost":    config.webHost,
   105  		"WebPort":  config.webPort,
   106  		"Ethstats": config.ethstats[:strings.Index(config.ethstats, ":")],
   107  	})
   108  	files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes()
   109  
   110  	files[filepath.Join(workdir, "genesis.json")] = config.genesis
   111  
   112  //将部署文件上载到远程服务器(然后清理)
   113  	if out, err := client.Upload(files); err != nil {
   114  		return out, err
   115  	}
   116  	defer client.Run("rm -rf " + workdir)
   117  
   118  //构建和部署引导或密封节点服务
   119  	if nocache {
   120  		return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network))
   121  	}
   122  	return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network))
   123  }
   124  
   125  //
   126  //各种配置参数。
   127  type walletInfos struct {
   128  	genesis  []byte
   129  	network  int64
   130  	datadir  string
   131  	ethstats string
   132  	nodePort int
   133  	rpcPort  int
   134  	webHost  string
   135  	webPort  int
   136  }
   137  
   138  //报表将类型化结构转换为纯字符串->字符串映射,其中包含
   139  //大多数(但不是全部)字段用于向用户报告。
   140  func (info *walletInfos) Report() map[string]string {
   141  	report := map[string]string{
   142  		"Data directory":         info.datadir,
   143  		"Ethstats username":      info.ethstats,
   144  		"Node listener port ":    strconv.Itoa(info.nodePort),
   145  		"RPC listener port ":     strconv.Itoa(info.rpcPort),
   146  		"Website address ":       info.webHost,
   147  		"Website listener port ": strconv.Itoa(info.webPort),
   148  	}
   149  	return report
   150  }
   151  
   152  //check wallet对web wallet服务器进行健康检查,以验证
   153  //
   154  func checkWallet(client *sshClient, network string) (*walletInfos, error) {
   155  //
   156  	infos, err := inspectContainer(client, fmt.Sprintf("%s_wallet_1", network))
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  	if !infos.running {
   161  		return nil, ErrServiceOffline
   162  	}
   163  //从主机或反向代理解析端口
   164  	webPort := infos.portmap["80/tcp"]
   165  	if webPort == 0 {
   166  		if proxy, _ := checkNginx(client, network); proxy != nil {
   167  			webPort = proxy.port
   168  		}
   169  	}
   170  	if webPort == 0 {
   171  		return nil, ErrNotExposed
   172  	}
   173  //从反向代理和配置值解析主机
   174  	host := infos.envvars["VIRTUAL_HOST"]
   175  	if host == "" {
   176  		host = client.server
   177  	}
   178  //
   179  	nodePort := infos.portmap[infos.envvars["NODE_PORT"]]
   180  	if err = checkPort(client.server, nodePort); err != nil {
   181  		log.Warn(fmt.Sprintf("Wallet devp2p port seems unreachable"), "server", client.server, "port", nodePort, "err", err)
   182  	}
   183  	rpcPort := infos.portmap["8545/tcp"]
   184  	if err = checkPort(client.server, rpcPort); err != nil {
   185  		log.Warn(fmt.Sprintf("Wallet RPC port seems unreachable"), "server", client.server, "port", rpcPort, "err", err)
   186  	}
   187  //收集并返回有用的信息
   188  	stats := &walletInfos{
   189  		datadir:  infos.volumes["/root/.ethereum"],
   190  		nodePort: nodePort,
   191  		rpcPort:  rpcPort,
   192  		webHost:  host,
   193  		webPort:  webPort,
   194  		ethstats: infos.envvars["STATS"],
   195  	}
   196  	return stats, nil
   197  }
   198