github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/core/location/generator/generator.go (about)

     1  /*
     2   * Copyright (C) 2017 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package main
    19  
    20  import (
    21  	"bytes"
    22  	"compress/gzip"
    23  	"encoding/base64"
    24  	"flag"
    25  	"fmt"
    26  	"os"
    27  	"path/filepath"
    28  	"text/template"
    29  
    30  	"github.com/pkg/errors"
    31  )
    32  
    33  const undefinedDb = ""
    34  
    35  var outputDirectory = flag.String("output", "generated", "Name of output source directory with binary data")
    36  var dbFilename = flag.String("dbname", undefinedDb, "Name of the db file to import")
    37  var compress = flag.Bool("compress", false, "Compress data before storing")
    38  
    39  func main() {
    40  	flag.Parse()
    41  	if *dbFilename == undefinedDb {
    42  		fmt.Println("dbname parameter expected")
    43  		os.Exit(1)
    44  	}
    45  
    46  	binaryData, err := os.ReadFile(*dbFilename)
    47  	exitOnError(err)
    48  	originalDataSize := len(binaryData)
    49  
    50  	if *compress {
    51  		binaryData, err = compressData(binaryData)
    52  		exitOnError(err)
    53  	}
    54  
    55  	encodedData, err := encodeToBase64(binaryData)
    56  	exitOnError(err)
    57  
    58  	//split into 1mb size parts (1part one file)
    59  	parts := splitToFixedLengthSlices(encodedData, 2*1024*1024)
    60  	var dbParts []dbPart
    61  	for i := 0; i < len(parts); i++ {
    62  		dbParts = append(dbParts, newDbPart(i, parts[i]))
    63  	}
    64  
    65  	tmpl, err := template.New("dbDataTemplate").Parse(dbPartFileOutput)
    66  	exitOnError(err)
    67  	for partIdx, dbPart := range dbParts {
    68  		dbFile, err := os.Create(filepath.Join(*outputDirectory, fmt.Sprintf("db_part_%d.go", partIdx)))
    69  		exitOnError(err)
    70  		err = tmpl.Execute(dbFile, dbPart)
    71  		exitOnError(err)
    72  	}
    73  
    74  	tmpl, err = template.New("dbIndexTemplate").Parse(dbIndexFileOutput)
    75  	exitOnError(err)
    76  	idxFile, err := os.Create(filepath.Join(*outputDirectory, "db_index.go"))
    77  	exitOnError(err)
    78  	err = tmpl.Execute(
    79  		idxFile,
    80  		struct {
    81  			DbParts      []dbPart
    82  			Compressed   bool
    83  			OriginalSize int
    84  		}{
    85  			DbParts:      dbParts,
    86  			Compressed:   *compress,
    87  			OriginalSize: originalDataSize,
    88  		},
    89  	)
    90  	exitOnError(err)
    91  }
    92  
    93  func splitToFixedLengthSlices(input []byte, strSize int) [][]byte {
    94  	var res [][]byte
    95  
    96  	fullStringCount := len(input) / strSize
    97  
    98  	for i := 0; i < fullStringCount; i++ {
    99  		offsetStart := i * strSize
   100  		res = append(res, input[offsetStart:offsetStart+strSize])
   101  	}
   102  
   103  	if len(input)%strSize > 0 {
   104  		res = append(res, input[fullStringCount*strSize:])
   105  	}
   106  	return res
   107  }
   108  
   109  func encodeToBase64(data []byte) ([]byte, error) {
   110  	encodedDataBuffer := &bytes.Buffer{}
   111  	encodingWriter := base64.NewEncoder(base64.RawStdEncoding, encodedDataBuffer)
   112  	written, err := encodingWriter.Write(data)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	if written != len(data) {
   117  		return nil, errors.New("written and expected data length mismatch")
   118  	}
   119  	encodingWriter.Close()
   120  	return encodedDataBuffer.Bytes(), nil
   121  }
   122  
   123  func compressData(data []byte) ([]byte, error) {
   124  	buff := &bytes.Buffer{}
   125  	compressingWriter, err := gzip.NewWriterLevel(buff, gzip.BestCompression)
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  
   130  	written, err := compressingWriter.Write(data)
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  	if written != len(data) {
   135  		return nil, errors.New("unexpected written and original data size")
   136  	}
   137  	compressingWriter.Close()
   138  	return buff.Bytes(), nil
   139  }
   140  
   141  func exitOnError(err error) {
   142  	if err != nil {
   143  		fmt.Println("Error: ", err.Error())
   144  		os.Exit(1)
   145  	}
   146  }
   147  
   148  type dbPart struct {
   149  	ID    int
   150  	Lines []string
   151  }
   152  
   153  func newDbPart(id int, binaryData []byte) dbPart {
   154  	var lines []string
   155  	for _, binaryPart := range splitToFixedLengthSlices(binaryData, 10*1024*1024) {
   156  		lines = append(lines, string(binaryPart))
   157  	}
   158  
   159  	return dbPart{
   160  		ID:    id,
   161  		Lines: lines,
   162  	}
   163  }
   164  
   165  var dbPartFileOutput = `/*
   166   * Copyright (C) 2017 The "MysteriumNetwork/node" Authors.
   167   *
   168   * This program is free software: you can redistribute it and/or modify
   169   * it under the terms of the GNU General Public License as published by
   170   * the Free Software Foundation, either version 3 of the License, or
   171   * (at your option) any later version.
   172   *
   173   * This program is distributed in the hope that it will be useful,
   174   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   175   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   176   * GNU General Public License for more details.
   177   *
   178   * You should have received a copy of the GNU General Public License
   179   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   180   */
   181  
   182  package gendb
   183  
   184  // generated by generator.go - DO NOT EDIT
   185  
   186  const dbDataPart{{.ID}} = {{range .Lines}}"{{.}}" +
   187  	{{end}}""
   188  `
   189  
   190  var dbIndexFileOutput = `/*
   191   * Copyright (C) 2017 The "MysteriumNetwork/node" Authors.
   192   *
   193   * This program is free software: you can redistribute it and/or modify
   194   * it under the terms of the GNU General Public License as published by
   195   * the Free Software Foundation, either version 3 of the License, or
   196   * (at your option) any later version.
   197   *
   198   * This program is distributed in the hope that it will be useful,
   199   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   200   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   201   * GNU General Public License for more details.
   202   *
   203   * You should have received a copy of the GNU General Public License
   204   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   205   */
   206  
   207  package gendb
   208  
   209  // generated by generator.go - DO NOT EDIT
   210  
   211  const originalSize = {{.OriginalSize}}
   212  const dbData = ""{{range .DbParts}} + dbDataPart{{.ID}}{{end}}
   213  
   214  // LoadData returns emmbeded database as byte array
   215  func LoadData() ([]byte, error) {
   216  	return EncodedDataLoader(dbData, originalSize, {{.Compressed}})
   217  }
   218  `